1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-10-31 16:27:18 -04:00
OpenDiablo2/d2render/d2ui/button.go

253 lines
10 KiB
Go
Raw Normal View History

2019-11-10 08:51:02 -05:00
package d2ui
import (
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
2019-10-25 23:41:54 -04:00
"image"
"image/color"
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
2019-11-10 08:51:02 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
2019-11-10 03:36:53 -05:00
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
2019-11-10 03:36:53 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
2019-11-10 03:36:53 -05:00
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
2019-11-10 03:36:53 -05:00
"github.com/hajimehoshi/ebiten"
)
2019-10-25 23:41:54 -04:00
// ButtonType defines the type of button
type ButtonType int
const (
ButtonTypeWide ButtonType = 1
ButtonTypeMedium ButtonType = 2
ButtonTypeNarrow ButtonType = 3
ButtonTypeCancel ButtonType = 4
ButtonTypeTall ButtonType = 5
ButtonTypeShort ButtonType = 6
ButtonTypeOkCancel ButtonType = 7
2019-10-25 23:41:54 -04:00
// Game UI
ButtonTypeSkill ButtonType = 7
ButtonTypeRun ButtonType = 8
ButtonTypeMenu ButtonType = 9
ButtonTypeGoldCoin ButtonType = 10
ButtonTypeClose ButtonType = 11
ButtonTypeSecondaryInvHand ButtonType = 12
ButtonTypeMinipanelCharacter ButtonType = 13
ButtonTypeMinipanelInventory ButtonType = 14
ButtonTypeMinipanelSkill ButtonType = 15
ButtonTypeMinipanelAutomap ButtonType = 16
ButtonTypeMinipanelMessage ButtonType = 17
ButtonTypeMinipanelQuest ButtonType = 18
ButtonTypeMinipanelMen ButtonType = 19
)
// ButtonLayout defines the type of buttons
type ButtonLayout struct {
2019-11-10 03:36:53 -05:00
XSegments int //1
YSegments int // 1
ResourceName string // Font Name
PaletteName d2enum.PaletteType // PaletteType
Toggleable bool // false
BaseFrame int // 0
DisabledFrame int // -1
FontPath string // ResourcePaths.FontExocet10
ClickableRect *image.Rectangle // nil
AllowFrameChange bool // true
TextOffset int // 0
2019-10-25 23:41:54 -04:00
}
// ButtonLayouts define the type of buttons you can have
var ButtonLayouts = map[ButtonType]ButtonLayout{
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2enum.Units, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2enum.Units, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2enum.Units, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2enum.Units, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
ButtonTypeOkCancel: {1, 1, d2resource.CancelButton, d2enum.Units, false, 0, -1, d2resource.FontRediculous, nil, true, 0},
2019-10-25 23:41:54 -04:00
/*
{eButtonType.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = PaletteDefs.Units } },
{eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = PaletteDefs.Units } },
{eButtonType.Cancel, new ButtonLayout { ResourceName = ResourcePaths.CancelButton, PaletteName = PaletteDefs.Units } },
2019-10-25 23:41:54 -04:00
// Minipanel
{eButtonType.MinipanelCharacter, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 0 } },
{eButtonType.MinipanelInventory, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 2 } },
{eButtonType.MinipanelSkill, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 4 } },
{eButtonType.MinipanelAutomap, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 8 } },
{eButtonType.MinipanelMessage, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 10 } },
{eButtonType.MinipanelQuest, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 12 } },
{eButtonType.MinipanelMenu, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 14 } },
2019-10-25 23:41:54 -04:00
{eButtonType.SecondaryInvHand, new ButtonLayout { ResourceName = ResourcePaths.InventoryWeaponsTab, PaletteName = PaletteDefs.Units, ClickableRect = new Rectangle(0, 0, 0, 20), AllowFrameChange = false } },
{eButtonType.Run, new ButtonLayout { ResourceName = ResourcePaths.RunButton, PaletteName = PaletteDefs.Units, Toggleable = true } },
{eButtonType.Menu, new ButtonLayout { ResourceName = ResourcePaths.MenuButton, PaletteName = PaletteDefs.Units, Toggleable = true } },
{eButtonType.GoldCoin, new ButtonLayout { ResourceName = ResourcePaths.GoldCoinButton, PaletteName = PaletteDefs.Units } },
{eButtonType.Close, new ButtonLayout { ResourceName = ResourcePaths.SquareButton, PaletteName = PaletteDefs.Units, BaseFrame = 10 } },
{eButtonType.Skill, new ButtonLayout { ResourceName = ResourcePaths.AddSkillButton, PaletteName = PaletteDefs.Units, DisabledFrame = 2
2019-10-25 23:41:54 -04:00
*/
}
// Button defines a standard wide UI button
type Button struct {
2019-10-25 23:41:54 -04:00
enabled bool
x, y int
width, height uint32
visible bool
pressed bool
toggled bool
2019-11-10 03:36:53 -05:00
fileProvider d2interface.FileProvider
2019-10-25 23:41:54 -04:00
normalImage *ebiten.Image
pressedImage *ebiten.Image
toggledImage *ebiten.Image
pressedToggledImage *ebiten.Image
disabledImage *ebiten.Image
buttonLayout ButtonLayout
2019-10-25 23:41:54 -04:00
onClick func()
}
// CreateButton creates an instance of Button
func CreateButton(buttonType ButtonType, fileProvider d2interface.FileProvider, text string) Button {
result := Button{
fileProvider: fileProvider,
2019-10-25 23:41:54 -04:00
width: 0,
height: 0,
visible: true,
enabled: true,
pressed: false,
}
2019-10-25 23:41:54 -04:00
buttonLayout := ButtonLayouts[buttonType]
result.buttonLayout = buttonLayout
2019-11-10 03:36:53 -05:00
font := GetFont(buttonLayout.FontPath, d2enum.Units, fileProvider)
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(buttonLayout.ResourceName), d2datadict.Palettes[buttonLayout.PaletteName])
buttonSprite := d2render.CreateSpriteFromDC6(dc6)
2019-10-25 23:41:54 -04:00
totalButtonTypes := buttonSprite.GetTotalFrames() / (buttonLayout.XSegments * buttonLayout.YSegments)
for i := 0; i < buttonLayout.XSegments; i++ {
w, _ := buttonSprite.GetFrameSize(i)
result.width += w
}
for i := 0; i < buttonLayout.YSegments; i++ {
_, h := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
result.height += h
}
result.normalImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
_, fontHeight := font.GetTextMetrics(text)
2019-10-27 02:58:37 -04:00
textY := int((result.height/2)-(fontHeight/2)) + buttonLayout.TextOffset
buttonSprite.MoveTo(0, 0)
buttonSprite.Blend = true
2019-10-26 00:06:54 -04:00
buttonSprite.DrawSegments(result.normalImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.normalImage)
2019-10-25 23:41:54 -04:00
if buttonLayout.AllowFrameChange {
if totalButtonTypes > 1 {
result.pressedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
2019-10-26 00:06:54 -04:00
buttonSprite.DrawSegments(result.pressedImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
font.Draw(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, result.pressedImage)
2019-10-25 23:41:54 -04:00
}
if totalButtonTypes > 2 {
result.toggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
2019-10-26 00:06:54 -04:00
buttonSprite.DrawSegments(result.toggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.toggledImage)
2019-10-25 23:41:54 -04:00
}
if totalButtonTypes > 3 {
result.pressedToggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
2019-10-26 00:06:54 -04:00
buttonSprite.DrawSegments(result.pressedToggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.pressedToggledImage)
2019-10-25 23:41:54 -04:00
}
if buttonLayout.DisabledFrame != -1 {
result.disabledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
2019-10-26 00:06:54 -04:00
buttonSprite.DrawSegments(result.disabledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledImage)
2019-10-25 23:41:54 -04:00
}
}
return result
}
2019-10-25 23:41:54 -04:00
// OnActivated defines the callback handler for the activate event
func (v *Button) OnActivated(callback func()) {
v.onClick = callback
}
// Activate calls the on activated callback handler, if any
func (v *Button) Activate() {
2019-10-25 23:41:54 -04:00
if v.onClick == nil {
return
}
v.onClick()
}
// Draw renders the button
func (v Button) Draw(target *ebiten.Image) {
opts := &ebiten.DrawImageOptions{
CompositeMode: ebiten.CompositeModeSourceAtop,
Filter: ebiten.FilterNearest,
}
opts.GeoM.Translate(float64(v.x), float64(v.y))
2019-10-25 23:41:54 -04:00
if !v.enabled {
//opts.CompositeMode = ebiten.CompositeModeLighter
opts.ColorM = d2corehelper.ColorToColorM(color.RGBA{128, 128, 128, 195})
2019-10-25 23:41:54 -04:00
target.DrawImage(v.disabledImage, opts)
} else if v.toggled && v.pressed {
target.DrawImage(v.pressedToggledImage, opts)
} else if v.pressed {
target.DrawImage(v.pressedImage, opts)
2019-10-25 23:41:54 -04:00
} else if v.toggled {
target.DrawImage(v.toggledImage, opts)
} else {
target.DrawImage(v.normalImage, opts)
}
}
// GetEnabled returns the enabled state
func (v Button) GetEnabled() bool {
return v.enabled
}
// SetEnabled sets the enabled state
func (v *Button) SetEnabled(enabled bool) {
v.enabled = enabled
}
// GetSize returns the size of the button
func (v Button) GetSize() (uint32, uint32) {
return v.width, v.height
}
// MoveTo moves the button
func (v *Button) MoveTo(x, y int) {
v.x = x
v.y = y
}
// GetLocation returns the location of the button
func (v Button) GetLocation() (x, y int) {
return v.x, v.y
}
// GetVisible returns the visibility of the button
func (v Button) GetVisible() bool {
return v.visible
}
// SetVisible sets the visibility of the button
func (v *Button) SetVisible(visible bool) {
v.visible = visible
}
2019-10-25 23:41:54 -04:00
// GetPressed returns the pressed state of the button
func (v Button) GetPressed() bool {
2019-10-25 23:41:54 -04:00
return v.pressed
}
// SetPressed sets the pressed state of the button
func (v *Button) SetPressed(pressed bool) {
v.pressed = pressed
}