mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-20 23:47:16 -05:00
The split between d2ui and d2asset Font version caused incorrect caching between the two. After looking at d2interface.Font, I saw the d2asset was the most recent and more tightly and cleanly packaged. I therefore removed the old d2ui.Font and embedded the d2asset version in the d2ui.Label and d2ui.Button. Looking at the code of d2ui, it would be logical to completly swap it for their d2gui version. But at least for the moment, the d2ui.Button as more functionality since it embeds a Label (instead of a font), and this label now has multiline horizontal alignement.
266 lines
10 KiB
Go
266 lines
10 KiB
Go
package d2ui
|
|
|
|
import (
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
|
"image"
|
|
"image/color"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
|
)
|
|
|
|
// 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
|
|
|
|
// 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 {
|
|
XSegments int // 1
|
|
YSegments int // 1
|
|
ResourceName string // Font Name
|
|
PaletteName string // PaletteType
|
|
Toggleable bool // false
|
|
BaseFrame int // 0
|
|
DisabledFrame int // -1
|
|
FontPath string // ResourcePaths.FontExocet10
|
|
ClickableRect *image.Rectangle // nil
|
|
AllowFrameChange bool // true
|
|
TextOffset int // 0
|
|
}
|
|
|
|
// ButtonLayouts define the type of buttons you can have
|
|
var ButtonLayouts = map[ButtonType]ButtonLayout{
|
|
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
|
|
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
|
|
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
|
|
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
|
|
ButtonTypeOkCancel: {1, 1, d2resource.CancelButton, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
|
ButtonTypeRun: {1, 1, d2resource.RunButton, d2resource.PaletteSky, true, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
|
/*
|
|
{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 } },
|
|
// 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 } },
|
|
|
|
{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
|
|
*/
|
|
}
|
|
|
|
// Button defines a standard wide UI button
|
|
type Button struct {
|
|
enabled bool
|
|
x, y int
|
|
width, height int
|
|
visible bool
|
|
pressed bool
|
|
toggled bool
|
|
normalSurface d2interface.Surface
|
|
pressedSurface d2interface.Surface
|
|
toggledSurface d2interface.Surface
|
|
pressedToggledSurface d2interface.Surface
|
|
disabledSurface d2interface.Surface
|
|
buttonLayout ButtonLayout
|
|
onClick func()
|
|
}
|
|
|
|
// CreateButton creates an instance of Button
|
|
func CreateButton(renderer d2interface.Renderer, buttonType ButtonType, text string) Button {
|
|
result := Button{
|
|
width: 0,
|
|
height: 0,
|
|
visible: true,
|
|
enabled: true,
|
|
pressed: false,
|
|
}
|
|
buttonLayout := ButtonLayouts[buttonType]
|
|
result.buttonLayout = buttonLayout
|
|
lbl := CreateLabel(buttonLayout.FontPath, d2resource.PaletteUnits)
|
|
lbl.SetText(text)
|
|
lbl.Color = color.RGBA{R: 100, G: 100, B: 100, A: 255}
|
|
lbl.Alignment = d2gui.HorizontalAlignCenter
|
|
|
|
animation, _ := d2asset.LoadAnimation(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
|
buttonSprite, _ := LoadSprite(animation)
|
|
totalButtonTypes := buttonSprite.GetFrameCount() / (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.normalSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
|
_, labelHeight := lbl.GetSize()
|
|
|
|
textY := result.height / 2 - labelHeight / 2
|
|
xOffset := result.width / 2
|
|
|
|
buttonSprite.SetPosition(0, 0)
|
|
buttonSprite.SetBlend(true)
|
|
buttonSprite.RenderSegmented(result.normalSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
|
|
|
lbl.SetPosition(xOffset, textY)
|
|
lbl.Render(result.normalSurface)
|
|
if buttonLayout.AllowFrameChange {
|
|
if totalButtonTypes > 1 {
|
|
result.pressedSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
|
buttonSprite.RenderSegmented(result.pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
|
|
|
lbl.SetPosition(xOffset-2, textY + 2)
|
|
lbl.Render(result.pressedSurface)
|
|
}
|
|
if totalButtonTypes > 2 {
|
|
result.toggledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
|
buttonSprite.RenderSegmented(result.toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
|
|
|
lbl.SetPosition(xOffset, textY)
|
|
lbl.Render(result.toggledSurface)
|
|
}
|
|
if totalButtonTypes > 3 {
|
|
result.pressedToggledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
|
buttonSprite.RenderSegmented(result.pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
|
|
|
lbl.SetPosition(xOffset, textY)
|
|
lbl.Render(result.pressedToggledSurface)
|
|
}
|
|
if buttonLayout.DisabledFrame != -1 {
|
|
result.disabledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
|
buttonSprite.RenderSegmented(result.disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
|
|
|
lbl.SetPosition(xOffset, textY)
|
|
lbl.Render(result.disabledSurface)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// 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() {
|
|
if v.onClick == nil {
|
|
return
|
|
}
|
|
v.onClick()
|
|
}
|
|
|
|
// Render renders the button
|
|
func (v *Button) Render(target d2interface.Surface) {
|
|
target.PushCompositeMode(d2enum.CompositeModeSourceAtop)
|
|
target.PushFilter(d2enum.FilterNearest)
|
|
target.PushTranslation(v.x, v.y)
|
|
defer target.PopN(3)
|
|
|
|
if !v.enabled {
|
|
target.PushColor(color.RGBA{R: 128, G: 128, B: 128, A: 195})
|
|
defer target.Pop()
|
|
target.Render(v.disabledSurface)
|
|
} else if v.toggled && v.pressed {
|
|
target.Render(v.pressedToggledSurface)
|
|
} else if v.pressed {
|
|
target.Render(v.pressedSurface)
|
|
} else if v.toggled {
|
|
target.Render(v.toggledSurface)
|
|
} else {
|
|
target.Render(v.normalSurface)
|
|
}
|
|
}
|
|
|
|
func (v *Button) Toggle() {
|
|
v.toggled = !v.toggled
|
|
}
|
|
|
|
func (v *Button) Advance(elapsed float64) {
|
|
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// Size returns the size of the button
|
|
func (v *Button) GetSize() (int, int) {
|
|
return v.width, v.height
|
|
}
|
|
|
|
// SetPosition moves the button
|
|
func (v *Button) SetPosition(x, y int) {
|
|
v.x = x
|
|
v.y = y
|
|
}
|
|
|
|
// GetPosition returns the location of the button
|
|
func (v *Button) GetPosition() (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
|
|
}
|
|
|
|
// GetPressed returns the pressed state of the button
|
|
func (v *Button) GetPressed() bool {
|
|
return v.pressed
|
|
}
|
|
|
|
// SetPressed sets the pressed state of the button
|
|
func (v *Button) SetPressed(pressed bool) {
|
|
v.pressed = pressed
|
|
}
|