2020-02-17 22:11:52 -05:00
|
|
|
package d2gui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image/color"
|
2020-09-23 13:30:54 -04:00
|
|
|
"log"
|
2020-02-17 22:11:52 -05:00
|
|
|
"math"
|
|
|
|
|
2020-06-29 00:41:58 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
2020-02-17 22:11:52 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
|
|
|
)
|
|
|
|
|
2020-10-22 02:41:21 -04:00
|
|
|
// GuiManager is a GUI widget manager that handles dynamic layout/positioning of widgets
|
2020-09-18 16:10:52 -04:00
|
|
|
type GuiManager struct {
|
2020-09-12 16:51:30 -04:00
|
|
|
asset *d2asset.AssetManager
|
2020-06-24 10:13:11 -04:00
|
|
|
layout *Layout
|
2020-07-05 13:01:44 -04:00
|
|
|
cursorAnim d2interface.Animation
|
2020-02-17 22:11:52 -05:00
|
|
|
cursorX int
|
|
|
|
cursorY int
|
2020-07-05 13:01:44 -04:00
|
|
|
loadingAnim d2interface.Animation
|
2020-02-17 22:11:52 -05:00
|
|
|
cursorVisible bool
|
2020-06-24 10:13:11 -04:00
|
|
|
loading bool
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// CreateGuiManager creates an instance of the GuiManager
|
|
|
|
func CreateGuiManager(asset *d2asset.AssetManager, inputManager d2interface.InputManager) (*GuiManager, error) {
|
2020-09-12 16:51:30 -04:00
|
|
|
cursorAnim, err := asset.LoadAnimation(d2resource.CursorDefault, d2resource.PaletteUnits)
|
2020-02-17 22:11:52 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-09-12 16:51:30 -04:00
|
|
|
loadingAnim, err := asset.LoadAnimation(d2resource.LoadingScreen, d2resource.PaletteLoading)
|
2020-02-17 22:11:52 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
manager := &GuiManager{
|
2020-09-12 16:51:30 -04:00
|
|
|
asset: asset,
|
2020-02-17 22:11:52 -05:00
|
|
|
cursorAnim: cursorAnim,
|
|
|
|
loadingAnim: loadingAnim,
|
|
|
|
cursorVisible: true,
|
|
|
|
}
|
|
|
|
|
2020-07-18 18:06:36 -04:00
|
|
|
manager.clear()
|
|
|
|
|
2020-07-13 20:29:17 -04:00
|
|
|
if err := inputManager.BindHandler(manager); err != nil {
|
2020-02-17 22:11:52 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return manager, nil
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// SetLayout sets the layout of the GuiManager
|
|
|
|
func (m *GuiManager) SetLayout(layout *Layout) {
|
2020-02-24 22:35:21 -05:00
|
|
|
m.layout = layout
|
2020-06-25 17:28:48 -04:00
|
|
|
if m.layout != nil {
|
|
|
|
m.layout.AdjustEntryPlacement()
|
|
|
|
}
|
2020-02-24 22:35:21 -05:00
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// OnMouseButtonDown handles mouse button click events
|
|
|
|
func (m *GuiManager) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
2020-02-24 22:35:21 -05:00
|
|
|
if m.layout == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.layout.onMouseButtonDown(event)
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// OnMouseButtonUp handles the mouse button release events
|
|
|
|
func (m *GuiManager) OnMouseButtonUp(event d2interface.MouseEvent) bool {
|
2020-02-24 22:35:21 -05:00
|
|
|
if m.layout == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.layout.onMouseButtonUp(event)
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// OnMouseMove handles mouse movement events
|
|
|
|
func (m *GuiManager) OnMouseMove(event d2interface.MouseMoveEvent) bool {
|
2020-07-03 15:09:16 -04:00
|
|
|
m.cursorX = event.X()
|
|
|
|
m.cursorY = event.Y()
|
2020-02-17 22:11:52 -05:00
|
|
|
|
2020-02-24 22:35:21 -05:00
|
|
|
if m.layout == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.layout.onMouseMove(event)
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// Render renders the GuiManager to the given surface
|
|
|
|
func (m *GuiManager) Render(target d2interface.Surface) error {
|
2020-02-17 22:11:52 -05:00
|
|
|
if m.loading {
|
2020-10-28 14:17:42 -04:00
|
|
|
m.renderLoadScreen(target)
|
2020-02-24 22:35:21 -05:00
|
|
|
} else if m.layout != nil {
|
|
|
|
m.layout.SetSize(target.GetSize())
|
2020-10-28 14:17:42 -04:00
|
|
|
m.layout.render(target)
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if m.cursorVisible {
|
2020-10-28 14:17:42 -04:00
|
|
|
m.renderCursor(target)
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-28 14:17:42 -04:00
|
|
|
func (m *GuiManager) renderLoadScreen(target d2interface.Surface) {
|
|
|
|
target.Clear(color.Black)
|
2020-07-18 18:06:36 -04:00
|
|
|
|
|
|
|
pushCount := 0
|
2020-02-17 22:11:52 -05:00
|
|
|
|
|
|
|
screenWidth, screenHeight := target.GetSize()
|
|
|
|
animWidth, animHeight := m.loadingAnim.GetCurrentFrameSize()
|
2020-07-18 18:06:36 -04:00
|
|
|
|
2020-02-17 22:11:52 -05:00
|
|
|
target.PushTranslation(screenWidth/2-animWidth/2, screenHeight/2+animHeight/2)
|
2020-07-18 18:06:36 -04:00
|
|
|
pushCount++
|
|
|
|
|
2020-02-17 22:11:52 -05:00
|
|
|
target.PushTranslation(0, -animHeight)
|
2020-07-18 18:06:36 -04:00
|
|
|
pushCount++
|
|
|
|
|
|
|
|
defer target.PopN(pushCount)
|
2020-02-17 22:11:52 -05:00
|
|
|
|
2020-10-28 14:17:42 -04:00
|
|
|
m.loadingAnim.Render(target)
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
2020-10-28 14:17:42 -04:00
|
|
|
func (m *GuiManager) renderCursor(target d2interface.Surface) {
|
2020-02-17 22:11:52 -05:00
|
|
|
_, height := m.cursorAnim.GetCurrentFrameSize()
|
2020-07-18 18:06:36 -04:00
|
|
|
pushCount := 0
|
|
|
|
|
2020-02-17 22:11:52 -05:00
|
|
|
target.PushTranslation(m.cursorX, m.cursorY)
|
2020-07-18 18:06:36 -04:00
|
|
|
pushCount++
|
|
|
|
|
2020-02-17 22:11:52 -05:00
|
|
|
target.PushTranslation(0, -height)
|
2020-07-18 18:06:36 -04:00
|
|
|
pushCount++
|
|
|
|
|
|
|
|
defer target.PopN(pushCount)
|
2020-02-17 22:11:52 -05:00
|
|
|
|
2020-10-28 14:17:42 -04:00
|
|
|
m.cursorAnim.Render(target)
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// Advance advances the GuiManager state
|
|
|
|
func (m *GuiManager) Advance(elapsed float64) error {
|
2020-02-24 22:35:21 -05:00
|
|
|
if !m.loading && m.layout != nil {
|
|
|
|
if err := m.layout.advance(elapsed); err != nil {
|
2020-02-17 22:11:52 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// ShowLoadScreen shows the loading screen with the given progress
|
|
|
|
func (m *GuiManager) ShowLoadScreen(progress float64) {
|
2020-02-17 22:11:52 -05:00
|
|
|
progress = math.Min(progress, 1.0)
|
|
|
|
progress = math.Max(progress, 0.0)
|
|
|
|
|
|
|
|
animation := m.loadingAnim
|
|
|
|
frameCount := animation.GetFrameCount()
|
2020-07-18 18:06:36 -04:00
|
|
|
|
2020-09-23 13:30:54 -04:00
|
|
|
err := animation.SetCurrentFrame(int(float64(frameCount-1) * progress))
|
|
|
|
if err != nil {
|
|
|
|
log.Print(err)
|
|
|
|
}
|
2020-02-17 22:11:52 -05:00
|
|
|
|
|
|
|
m.loading = true
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// HideLoadScreen hides the load screen
|
|
|
|
func (m *GuiManager) HideLoadScreen() {
|
2020-02-17 22:11:52 -05:00
|
|
|
m.loading = false
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// ShowCursor makes the cursor visible
|
|
|
|
func (m *GuiManager) ShowCursor() {
|
2020-02-17 22:11:52 -05:00
|
|
|
m.cursorVisible = true
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
// HideCursor hides the cursor
|
|
|
|
func (m *GuiManager) HideCursor() {
|
2020-02-17 22:11:52 -05:00
|
|
|
m.cursorVisible = false
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:52 -04:00
|
|
|
func (m *GuiManager) clear() {
|
2020-02-24 22:35:21 -05:00
|
|
|
m.SetLayout(nil)
|
2020-09-18 16:10:52 -04:00
|
|
|
m.HideLoadScreen()
|
2020-02-17 22:11:52 -05:00
|
|
|
}
|