mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-06-03 06:20:43 +00:00
Add checkboxes, checkbox test scene
This commit is contained in:
parent
3731e631cf
commit
0cf47b9b57
|
@ -39,8 +39,10 @@ type Sprite interface {
|
|||
SetPlaySpeed(playSpeed time.Duration)
|
||||
SetPlayLength(playLength time.Duration)
|
||||
SetColorMod(colorMod color.Color)
|
||||
GetColorMod() color.Color
|
||||
GetPlayedCount() int
|
||||
ResetPlayedCount()
|
||||
SetEffect(effect d2enum.DrawEffect)
|
||||
GetEffect() d2enum.DrawEffect
|
||||
SetShadow(shadow bool)
|
||||
}
|
||||
|
|
|
@ -395,6 +395,10 @@ func (a *Sprite) SetColorMod(colorMod color.Color) {
|
|||
a.colorMod = colorMod
|
||||
}
|
||||
|
||||
func (a *Sprite) GetColorMod() color.Color {
|
||||
return a.colorMod
|
||||
}
|
||||
|
||||
// GetPlayedCount gets the number of times the application played
|
||||
func (a *Sprite) GetPlayedCount() int {
|
||||
return a.playedCount
|
||||
|
@ -410,6 +414,10 @@ func (a *Sprite) SetEffect(e d2enum.DrawEffect) {
|
|||
a.effect = e
|
||||
}
|
||||
|
||||
func (a *Sprite) GetEffect() d2enum.DrawEffect {
|
||||
return a.effect
|
||||
}
|
||||
|
||||
// SetShadow sets bool for whether or not to draw a shadow
|
||||
func (a *Sprite) SetShadow(shadow bool) {
|
||||
a.hasShadow = shadow
|
||||
|
|
150
d2core/d2checkbox/checkbox.go
Normal file
150
d2core/d2checkbox/checkbox.go
Normal file
|
@ -0,0 +1,150 @@
|
|||
package d2checkbox
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom/rectangle"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2label"
|
||||
"github.com/gravestench/akara"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type callbackFunc = func(this akara.Component) (preventPropagation bool)
|
||||
|
||||
// Button defines a standard wide UI button
|
||||
type Checkbox struct {
|
||||
Layout CheckboxLayout
|
||||
Sprite d2interface.Sprite
|
||||
Label *d2label.Label
|
||||
callback callbackFunc
|
||||
width, height int
|
||||
pressed bool
|
||||
enabled bool
|
||||
}
|
||||
|
||||
// CheckboxLayout defines the type of buttons
|
||||
type CheckboxLayout struct {
|
||||
X float64
|
||||
Y float64
|
||||
SpritePath string
|
||||
PalettePath string
|
||||
FontPath string
|
||||
ClickableRect *rectangle.Rectangle
|
||||
XSegments int
|
||||
YSegments int
|
||||
BaseFrame int
|
||||
DisabledFrame int
|
||||
DisabledColor uint32
|
||||
TextOffset float64
|
||||
FixedWidth int
|
||||
FixedHeight int
|
||||
LabelColor uint32
|
||||
Toggleable bool
|
||||
AllowFrameChange bool
|
||||
HasImage bool
|
||||
Tooltip int
|
||||
TooltipXOffset int
|
||||
TooltipYOffset int
|
||||
}
|
||||
|
||||
// New creates an instance of Button
|
||||
func New() *Checkbox {
|
||||
checkbox := &Checkbox{
|
||||
Layout: GetDefaultLayout(),
|
||||
}
|
||||
|
||||
return checkbox
|
||||
}
|
||||
|
||||
func GetDefaultLayout() CheckboxLayout {
|
||||
return CheckboxLayout{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
SpritePath: d2resource.Checkbox,
|
||||
PalettePath: d2resource.PaletteFechar,
|
||||
FontPath: d2resource.FontExocet10,
|
||||
XSegments: 1,
|
||||
YSegments: 1,
|
||||
BaseFrame: 0,
|
||||
DisabledFrame: -1,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
TextOffset: 18,
|
||||
FixedWidth: 16,
|
||||
FixedHeight: 15,
|
||||
LabelColor: goldAlpha100,
|
||||
Toggleable: true,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
Tooltip: 0,
|
||||
TooltipXOffset: 0,
|
||||
TooltipYOffset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// OnActivated defines the callback handler for the activate event
|
||||
func (v *Checkbox) OnActivated(callback callbackFunc) {
|
||||
v.callback = callback
|
||||
}
|
||||
|
||||
// Activate calls the on activated callback handler, if any
|
||||
func (v *Checkbox) Activate(thisComponent akara.Component) bool {
|
||||
if v.GetEnabled() {
|
||||
v.Toggle()
|
||||
}
|
||||
|
||||
if v.callback != nil {
|
||||
return v.callback(thisComponent)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Toggle negates the toggled state of the button
|
||||
func (v *Checkbox) Toggle() {
|
||||
v.SetPressed(!v.GetPressed())
|
||||
}
|
||||
|
||||
// GetEnabled returns the enabled state
|
||||
func (v *Checkbox) GetEnabled() bool {
|
||||
return v.enabled
|
||||
}
|
||||
|
||||
// SetEnabled sets the enabled state
|
||||
func (v *Checkbox) SetEnabled(enabled bool) {
|
||||
v.enabled = enabled
|
||||
}
|
||||
|
||||
// GetChecked returns the enabled state
|
||||
func (v *Checkbox) GetPressed() bool {
|
||||
return v.pressed
|
||||
}
|
||||
|
||||
// SetEnabled sets the enabled state
|
||||
func (v *Checkbox) SetPressed(pressed bool) {
|
||||
v.pressed = pressed
|
||||
}
|
||||
|
||||
func (v *Checkbox) Update() {
|
||||
if v.Sprite == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if v.GetEnabled() && v.GetPressed() {
|
||||
// checked, enabled
|
||||
_ = v.Sprite.SetCurrentFrame(1)
|
||||
} else if v.GetEnabled() {
|
||||
// unchecked, enabled
|
||||
_ = v.Sprite.SetCurrentFrame(0)
|
||||
} else if v.GetPressed() {
|
||||
// checked, disabled
|
||||
_ = v.Sprite.SetCurrentFrame(1)
|
||||
v.Sprite.SetColorMod(color.RGBA{R: uint8(rand.Uint32() % 255), B: uint8(rand.Uint32() % 255), G: uint8(rand.Uint32() % 255), A: 0xff})
|
||||
v.Sprite.SetEffect(d2enum.DrawEffectPctTransparency25)
|
||||
} else {
|
||||
// unchecked, disabled
|
||||
_ = v.Sprite.SetCurrentFrame(0)
|
||||
v.Sprite.SetColorMod(color.RGBA{R: uint8(rand.Uint32() % 255), B: uint8(rand.Uint32() % 255), G: uint8(rand.Uint32() % 255), A: 0xff})
|
||||
}
|
||||
}
|
8
d2core/d2checkbox/colors.go
Normal file
8
d2core/d2checkbox/colors.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package d2checkbox
|
||||
|
||||
const (
|
||||
greyAlpha100 = 0x646464ff
|
||||
lightGreyAlpha75 = 0x808080c3
|
||||
whiteAlpha100 = 0xffffffff
|
||||
goldAlpha100 = 0xc7_b3_77_ff
|
||||
)
|
|
@ -1,6 +1,7 @@
|
|||
package d2components
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom/rectangle"
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2input"
|
||||
|
@ -13,19 +14,21 @@ func noop() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Interactive is used to flag file entities with a file type
|
||||
// Interactive is used to define an input state and a callback function to execute when that state is reached
|
||||
type Interactive struct {
|
||||
Enabled bool
|
||||
*d2input.InputVector
|
||||
Callback func() (preventPropagation bool)
|
||||
CursorPosition *rectangle.Rectangle
|
||||
Callback func() (preventPropagation bool)
|
||||
}
|
||||
|
||||
// New returns a Interactive component. By default, it contains a nil instance.
|
||||
func (*Interactive) New() akara.Component {
|
||||
return &Interactive{
|
||||
Enabled: true,
|
||||
InputVector: d2input.NewInputVector(),
|
||||
Callback: noop,
|
||||
Enabled: true,
|
||||
InputVector: d2input.NewInputVector(),
|
||||
CursorPosition: nil,
|
||||
Callback: noop,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
43
d2core/d2components/ui_checkbox.go
Normal file
43
d2core/d2components/ui_checkbox.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
//nolint:dupl,golint,stylecheck // component declarations are supposed to look the same
|
||||
package d2components
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2checkbox"
|
||||
"github.com/gravestench/akara"
|
||||
)
|
||||
|
||||
// static check that Checkbox implements Component
|
||||
var _ akara.Component = &Checkbox{}
|
||||
|
||||
// Checkbox represents a UI checkbox. It contains an embedded *d2checkbox.Checkbox
|
||||
type Checkbox struct {
|
||||
*d2checkbox.Checkbox
|
||||
}
|
||||
|
||||
// New returns a Checkbox component. This contains an embedded *d2checkbox.Checkbox
|
||||
func (*Checkbox) New() akara.Component {
|
||||
return &Checkbox{
|
||||
Checkbox: d2checkbox.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// CheckboxFactory is a wrapper for the generic component factory that returns Checkbox component instances.
|
||||
// This can be embedded inside of a system to give them the methods for adding, retrieving, and removing a Checkbox.
|
||||
type CheckboxFactory struct {
|
||||
*akara.ComponentFactory
|
||||
}
|
||||
|
||||
// Add adds a Checkbox component to the given entity and returns it
|
||||
func (m *CheckboxFactory) Add(id akara.EID) *Checkbox {
|
||||
return m.ComponentFactory.Add(id).(*Checkbox)
|
||||
}
|
||||
|
||||
// Get returns the Button component for the given entity, and a bool for whether or not it exists
|
||||
func (m *CheckboxFactory) Get(id akara.EID) (*Checkbox, bool) {
|
||||
component, found := m.ComponentFactory.Get(id)
|
||||
if !found {
|
||||
return nil, found
|
||||
}
|
||||
|
||||
return component.(*Checkbox), found
|
||||
}
|
|
@ -37,9 +37,9 @@ const (
|
|||
skipSplashArg = "nosplash"
|
||||
skipSplashDesc = "skip the ebiten splash screen"
|
||||
|
||||
logLevelArg = "loglevel"
|
||||
logLevelShort = 'l'
|
||||
logLevelDesc = "sets the logging level for all loggers at startup"
|
||||
logLevelArg = "loglevel"
|
||||
logLevelShort = 'l'
|
||||
logLevelDesc = "sets the logging level for all loggers at startup"
|
||||
|
||||
profilerArg = "profile"
|
||||
profilerDesc = "Profiles the program, one of (cpu, mem, block, goroutine, trace, thread, mutex)"
|
||||
|
@ -285,6 +285,9 @@ func (m *AppBootstrap) parseCommandLineArgs() {
|
|||
case "buttons":
|
||||
m.Info("running button test scene")
|
||||
m.World.AddSystem(NewButtonTestScene())
|
||||
case "checkbox":
|
||||
m.Info("running checkbox test scene")
|
||||
m.World.AddSystem(NewCheckboxTestScene())
|
||||
default:
|
||||
m.World.AddSystem(&GameClientBootstrap{})
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ type InputSystem struct {
|
|||
d2interface.InputService
|
||||
configs *akara.Subscription
|
||||
interactives *akara.Subscription
|
||||
inputState *d2input.InputVector
|
||||
Components struct {
|
||||
GameConfig d2components.GameConfigFactory
|
||||
inputState *d2input.InputVector
|
||||
Components struct {
|
||||
GameConfig d2components.GameConfigFactory
|
||||
Interactive d2components.InteractiveFactory
|
||||
}
|
||||
}
|
||||
|
@ -143,9 +143,18 @@ func (m *InputSystem) applyInputState(id akara.EID) (preventPropagation bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
// verify that the current inputState matches the state specified in the InputVector
|
||||
if !v.Enabled || !m.inputState.Contains(v.InputVector) {
|
||||
return false
|
||||
}
|
||||
|
||||
// check if this Interactive specified a particular cursor position that the input must occur in
|
||||
if v.CursorPosition != nil {
|
||||
cursorX, cursorY := m.CursorPosition()
|
||||
if !v.CursorPosition.Contains(float64(cursorX), float64(cursorY)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return v.Callback()
|
||||
}
|
||||
|
|
|
@ -60,10 +60,12 @@ type sceneComponents struct {
|
|||
Alpha d2components.AlphaFactory
|
||||
DrawEffect d2components.DrawEffectFactory
|
||||
Rectangle d2components.RectangleFactory
|
||||
Label d2components.LabelFactory
|
||||
Checkbox d2components.CheckboxFactory
|
||||
Color d2components.ColorFactory
|
||||
CommandRegistration d2components.CommandRegistrationFactory
|
||||
Dirty d2components.DirtyFactory
|
||||
GameConfig d2components.GameConfigFactory
|
||||
GameConfig d2components.GameConfigFactory
|
||||
}
|
||||
|
||||
// BaseScene encapsulates common behaviors for systems that are considered "scenes",
|
||||
|
@ -87,7 +89,7 @@ type BaseScene struct {
|
|||
SceneObjects []akara.EID
|
||||
Graph *d2scene.Node // the root node
|
||||
backgroundColor color.Color
|
||||
gameConfigs *akara.Subscription
|
||||
gameConfigs *akara.Subscription
|
||||
}
|
||||
|
||||
// Booted returns whether or not the scene has booted
|
||||
|
@ -218,6 +220,8 @@ func (s *BaseScene) setupFactories() {
|
|||
s.InjectComponent(&d2components.Sprite{}, &s.Components.Sprite.ComponentFactory)
|
||||
s.InjectComponent(&d2components.SegmentedSprite{}, &s.Components.SegmentedSprite.ComponentFactory)
|
||||
s.InjectComponent(&d2components.Rectangle{}, &s.Components.Rectangle.ComponentFactory)
|
||||
s.InjectComponent(&d2components.Checkbox{}, &s.Components.Checkbox.ComponentFactory)
|
||||
s.InjectComponent(&d2components.Label{}, &s.Components.Label.ComponentFactory)
|
||||
s.InjectComponent(&d2components.Color{}, &s.Components.Color.ComponentFactory)
|
||||
s.InjectComponent(&d2components.CommandRegistration{}, &s.Components.CommandRegistration.ComponentFactory)
|
||||
s.InjectComponent(&d2components.Dirty{}, &s.Components.Dirty.ComponentFactory)
|
||||
|
|
|
@ -98,13 +98,6 @@ func (s *MouseCursorScene) updateCursorTransform() {
|
|||
|
||||
if int(tx) != cx || int(ty) != cy {
|
||||
s.lastTimeMoved = time.Now()
|
||||
|
||||
switch s.debug.enabled {
|
||||
case true:
|
||||
s.Infof("transform: (%d, %d)", int(tx), int(ty))
|
||||
default:
|
||||
s.Debugf("transform: (%d, %d)", int(tx), int(ty))
|
||||
}
|
||||
}
|
||||
|
||||
transform.Translation.X, transform.Translation.Y = float64(cx), float64(cy)
|
||||
|
|
|
@ -2,6 +2,7 @@ package d2systems
|
|||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2button"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2checkbox"
|
||||
"image/color"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -126,3 +127,30 @@ func (s *sceneObjectFactory) Label(text, fontSpritePath, palettePath string) aka
|
|||
|
||||
return eid
|
||||
}
|
||||
|
||||
// Checkbox creates a Checkbox in the scene, with an attached Label
|
||||
func (s *sceneObjectFactory) Checkbox(x, y float64, checkedState bool, enabled bool, text string, callback func(akara.Component) bool) akara.EID {
|
||||
checkboxEID := s.sceneSystems.UI.Checkbox(x, y, checkedState, enabled, callback)
|
||||
s.SceneObjects = append(s.SceneObjects, checkboxEID)
|
||||
|
||||
s.addBasicComponents(checkboxEID)
|
||||
|
||||
checkboxNode := s.Components.SceneGraphNode.Add(checkboxEID)
|
||||
|
||||
// create a Label as a child of the Checkbox if text was given
|
||||
if text != "" {
|
||||
layout := d2checkbox.GetDefaultLayout()
|
||||
labelEID := s.Label(text, layout.FontPath, layout.PalettePath)
|
||||
labelNode := s.Components.SceneGraphNode.Add(labelEID)
|
||||
labelNode.SetParent(checkboxNode.Node)
|
||||
|
||||
labelTrs := s.Components.Transform.Add(labelEID)
|
||||
labelTrs.Translation.X = layout.TextOffset
|
||||
|
||||
label, _ := s.Components.Label.Get(labelEID)
|
||||
checkbox, _ := s.Components.Checkbox.Get(checkboxEID)
|
||||
checkbox.Label = label.Label
|
||||
}
|
||||
|
||||
return checkboxEID
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ func (t *SpriteFactory) setupSubscriptions() {
|
|||
Build()
|
||||
|
||||
spritesToUpdate := t.NewComponentFilter().
|
||||
Require(&d2components.Sprite{}). // we want to process entities that have an sprite ...
|
||||
Require(&d2components.Sprite{}). // we want to process entities that have an sprite ...
|
||||
Require(&d2components.Texture{}). // ... but are missing a surface
|
||||
Build()
|
||||
|
||||
|
@ -316,8 +316,15 @@ func (t *SpriteFactory) renderSegmentedSprite(id akara.EID, seg *d2components.Se
|
|||
}
|
||||
|
||||
target.PushTranslation(x+offsetX, y+offsetY)
|
||||
// TODO: PushEffect and PushColor don't seem to be working?
|
||||
// see d2sprite/sprite.go for old implementation
|
||||
//target.PushEffect(sprite.GetEffect())
|
||||
//target.PushColor(sprite.GetColorMod())
|
||||
|
||||
target.Render(sprite.GetCurrentFrameSurface())
|
||||
target.Pop()
|
||||
//target.Pop()
|
||||
//target.Pop()
|
||||
|
||||
frameWidth, frameHeight := sprite.GetCurrentFrameSize()
|
||||
maxFrameHeight = d2math.MaxInt(maxFrameHeight, frameHeight)
|
||||
|
|
97
d2core/d2systems/scene_test_checkbox.go
Normal file
97
d2core/d2systems/scene_test_checkbox.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
"github.com/gravestench/akara"
|
||||
"image/color"
|
||||
"log"
|
||||
)
|
||||
|
||||
const (
|
||||
sceneKeyCheckboxTest = "Checkbox Test Scene"
|
||||
)
|
||||
|
||||
// NewCheckboxTestScene creates a new main menu scene. This is the first screen that the user
|
||||
// will see when launching the game.
|
||||
func NewCheckboxTestScene() *CheckboxTestScene {
|
||||
scene := &CheckboxTestScene{
|
||||
BaseScene: NewBaseScene(sceneKeyCheckboxTest),
|
||||
}
|
||||
|
||||
return scene
|
||||
}
|
||||
|
||||
// static check that CheckboxTestScene implements the scene interface
|
||||
var _ d2interface.Scene = &CheckboxTestScene{}
|
||||
|
||||
// CheckboxTestScene represents the game's main menu, where users can select single or multi player,
|
||||
// or start the map engine test.
|
||||
type CheckboxTestScene struct {
|
||||
*BaseScene
|
||||
booted bool
|
||||
checkboxes *akara.Subscription
|
||||
}
|
||||
|
||||
// Init the main menu scene
|
||||
func (s *CheckboxTestScene) Init(world *akara.World) {
|
||||
s.World = world
|
||||
|
||||
checkboxes := s.World.NewComponentFilter().
|
||||
Require(&d2components.Checkbox{}).
|
||||
Require(&d2components.Ready{}).
|
||||
Build()
|
||||
|
||||
s.checkboxes = s.World.AddSubscription(checkboxes)
|
||||
|
||||
s.Debug("initializing ...")
|
||||
}
|
||||
|
||||
func (s *CheckboxTestScene) boot() {
|
||||
if !s.BaseScene.booted {
|
||||
s.BaseScene.boot()
|
||||
return
|
||||
}
|
||||
|
||||
s.AddSystem(NewMouseCursorScene())
|
||||
|
||||
s.Add.Rectangle(0, 0, 640, 480, color.RGBA{R: 0xcc, G: 0xcc, B: 0xcc, A: 0xff})
|
||||
|
||||
s.createCheckboxes()
|
||||
|
||||
s.booted = true
|
||||
}
|
||||
|
||||
func (s *CheckboxTestScene) createCheckboxes() {
|
||||
s.Add.Checkbox(100, 100, true, true, "Expansion character", checkboxClickCallback)
|
||||
s.Add.Checkbox(100, 120, false, true, "Hardcore", checkboxClickCallback)
|
||||
s.Add.Checkbox(100, 140, true, false, "disabled checked test", checkboxClickCallback)
|
||||
s.Add.Checkbox(100, 160, false, false, "disabled unchecked test", checkboxClickCallback)
|
||||
}
|
||||
|
||||
// Update the main menu scene
|
||||
func (s *CheckboxTestScene) Update() {
|
||||
if s.Paused() {
|
||||
return
|
||||
}
|
||||
|
||||
if !s.booted {
|
||||
s.boot()
|
||||
}
|
||||
|
||||
s.BaseScene.Update()
|
||||
}
|
||||
|
||||
func checkboxClickCallback(thisComponent akara.Component) bool {
|
||||
this := thisComponent.(*d2components.Checkbox)
|
||||
if this.Checkbox.GetEnabled() {
|
||||
text := this.Checkbox.Label.GetText()
|
||||
if this.Checkbox.GetPressed() {
|
||||
log.Printf("%s enabled", text)
|
||||
} else {
|
||||
log.Printf("%s disabled", text)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
|
@ -3,6 +3,8 @@ package d2systems
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom/rectangle"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2input"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
@ -27,12 +29,13 @@ func NewUIWidgetFactory(
|
|||
shapeFactory *ShapeSystem,
|
||||
) *UIWidgetFactory {
|
||||
sys := &UIWidgetFactory{
|
||||
Logger: l,
|
||||
SpriteFactory: spriteFactory,
|
||||
ShapeSystem: shapeFactory,
|
||||
bitmapFontCache: d2cache.CreateCache(fontCacheBudget),
|
||||
buttonLoadQueue: make(buttonLoadQueue),
|
||||
labelLoadQueue: make(labelLoadQueue),
|
||||
Logger: l,
|
||||
SpriteFactory: spriteFactory,
|
||||
ShapeSystem: shapeFactory,
|
||||
bitmapFontCache: d2cache.CreateCache(fontCacheBudget),
|
||||
buttonLoadQueue: make(buttonLoadQueue),
|
||||
checkboxLoadQueue: make(checkboxLoadQueue),
|
||||
labelLoadQueue: make(labelLoadQueue),
|
||||
}
|
||||
|
||||
sys.BaseSystem = b
|
||||
|
@ -48,6 +51,12 @@ type buttonLoadQueueEntry struct {
|
|||
|
||||
type buttonLoadQueue = map[akara.EID]buttonLoadQueueEntry
|
||||
|
||||
type checkboxLoadQueueEntry struct {
|
||||
sprite akara.EID
|
||||
}
|
||||
|
||||
type checkboxLoadQueue = map[akara.EID]checkboxLoadQueueEntry
|
||||
|
||||
type labelLoadQueueEntry struct {
|
||||
table, sprite akara.EID
|
||||
}
|
||||
|
@ -62,12 +71,14 @@ type UIWidgetFactory struct {
|
|||
*SpriteFactory
|
||||
*ShapeSystem
|
||||
buttonLoadQueue
|
||||
checkboxLoadQueue
|
||||
labelLoadQueue
|
||||
bitmapFontCache d2interface.Cache
|
||||
labelsToUpdate *akara.Subscription
|
||||
buttonsToUpdate *akara.Subscription
|
||||
booted bool
|
||||
Components struct {
|
||||
bitmapFontCache d2interface.Cache
|
||||
labelsToUpdate *akara.Subscription
|
||||
buttonsToUpdate *akara.Subscription
|
||||
checkboxesToUpdate *akara.Subscription
|
||||
booted bool
|
||||
Components struct {
|
||||
File d2components.FileFactory
|
||||
Transform d2components.TransformFactory
|
||||
Interactive d2components.InteractiveFactory
|
||||
|
@ -76,6 +87,7 @@ type UIWidgetFactory struct {
|
|||
BitmapFont d2components.BitmapFontFactory
|
||||
Label d2components.LabelFactory
|
||||
Button d2components.ButtonFactory
|
||||
Checkbox d2components.CheckboxFactory
|
||||
Sprite d2components.SpriteFactory
|
||||
Color d2components.ColorFactory
|
||||
Texture d2components.TextureFactory
|
||||
|
@ -103,6 +115,7 @@ func (t *UIWidgetFactory) setupFactories() {
|
|||
t.InjectComponent(&d2components.BitmapFont{}, &t.Components.BitmapFont.ComponentFactory)
|
||||
t.InjectComponent(&d2components.Label{}, &t.Components.Label.ComponentFactory)
|
||||
t.InjectComponent(&d2components.Button{}, &t.Components.Button.ComponentFactory)
|
||||
t.InjectComponent(&d2components.Checkbox{}, &t.Components.Checkbox.ComponentFactory)
|
||||
t.InjectComponent(&d2components.Sprite{}, &t.Components.Sprite.ComponentFactory)
|
||||
t.InjectComponent(&d2components.Color{}, &t.Components.Color.ComponentFactory)
|
||||
t.InjectComponent(&d2components.Ready{}, &t.Components.Ready.ComponentFactory)
|
||||
|
@ -121,8 +134,14 @@ func (t *UIWidgetFactory) setupSubscriptions() {
|
|||
Require(&d2components.Ready{}).
|
||||
Build()
|
||||
|
||||
checkboxesToUpdate := t.NewComponentFilter().
|
||||
Require(&d2components.Checkbox{}).
|
||||
Require(&d2components.Ready{}).
|
||||
Build()
|
||||
|
||||
t.labelsToUpdate = t.AddSubscription(labelsToUpdate)
|
||||
t.buttonsToUpdate = t.AddSubscription(buttonsToUpdate)
|
||||
t.checkboxesToUpdate = t.AddSubscription(checkboxesToUpdate)
|
||||
}
|
||||
|
||||
func (t *UIWidgetFactory) boot() {
|
||||
|
@ -155,6 +174,14 @@ func (t *UIWidgetFactory) Update() {
|
|||
t.processButton(buttonEID)
|
||||
}
|
||||
|
||||
for checkboxEID := range t.checkboxLoadQueue {
|
||||
if time.Since(start) > maxTimePerUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
t.processCheckbox(checkboxEID)
|
||||
}
|
||||
|
||||
for labelEID := range t.labelLoadQueue {
|
||||
if time.Since(start) > maxTimePerUpdate {
|
||||
return
|
||||
|
@ -171,6 +198,14 @@ func (t *UIWidgetFactory) Update() {
|
|||
t.updateButton(buttonEID)
|
||||
}
|
||||
|
||||
for _, checkboxEID := range t.checkboxesToUpdate.GetEntities() {
|
||||
if time.Since(start) > maxTimePerUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
t.updateCheckbox(checkboxEID)
|
||||
}
|
||||
|
||||
for _, labelEID := range t.labelsToUpdate.GetEntities() {
|
||||
if time.Since(start) > maxTimePerUpdate {
|
||||
return
|
||||
|
@ -481,11 +516,10 @@ func (t *UIWidgetFactory) renderButtonStates(buttonEID akara.EID) {
|
|||
delete(t.buttonLoadQueue, buttonEID)
|
||||
}
|
||||
|
||||
|
||||
func (t *UIWidgetFactory) updateButton(buttonEID akara.EID) {
|
||||
button, btnFound := t.Components.Button.Get(buttonEID)
|
||||
|
||||
if ! btnFound {
|
||||
if !btnFound {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -512,3 +546,90 @@ func (t *UIWidgetFactory) updateButton(buttonEID akara.EID) {
|
|||
|
||||
texture.Texture = button.GetCurrentTexture()
|
||||
}
|
||||
|
||||
// Checkbox creates a checkbox ui widget. A Checkbox widget is composed of a Checkbox component that tracks the logic,
|
||||
// and a SegmentedSprite to be displayed in the scene.
|
||||
func (t *UIWidgetFactory) Checkbox(x, y float64, checkedState bool, enabled bool, callback func(akara.Component) bool) akara.EID {
|
||||
checkboxEID := t.NewEntity()
|
||||
|
||||
checkbox := t.Components.Checkbox.Add(checkboxEID)
|
||||
checkbox.Layout.X, checkbox.Layout.Y = x, y
|
||||
checkbox.Layout.ClickableRect = rectangle.New(x, y, float64(checkbox.Layout.FixedWidth), float64(checkbox.Layout.FixedHeight))
|
||||
|
||||
checkboxTrs := t.Components.Transform.Add(checkboxEID)
|
||||
checkboxTrs.Translation.X, checkboxTrs.Translation.Y = x, y
|
||||
|
||||
checkbox.Checkbox.SetPressed(checkedState)
|
||||
checkbox.Checkbox.SetEnabled(enabled)
|
||||
checkbox.Checkbox.OnActivated(callback)
|
||||
|
||||
img, pal := checkbox.Layout.SpritePath, checkbox.Layout.PalettePath
|
||||
sx, sy, base := checkbox.Layout.XSegments, checkbox.Layout.YSegments, checkbox.Layout.BaseFrame
|
||||
|
||||
spriteEID := t.SpriteFactory.SegmentedSprite(x, y, img, pal, sx, sy, base)
|
||||
|
||||
entry := checkboxLoadQueueEntry{
|
||||
sprite: spriteEID,
|
||||
}
|
||||
|
||||
t.checkboxLoadQueue[checkboxEID] = entry
|
||||
|
||||
return checkboxEID
|
||||
}
|
||||
|
||||
// processCheckbox creates a checkbox after all of the prerequisite components are ready.
|
||||
// This adds interactivity and prepares the checkbox for rendering in the scene.
|
||||
func (t *UIWidgetFactory) processCheckbox(checkboxEID akara.EID) {
|
||||
// get the queue entry
|
||||
entry, found := t.checkboxLoadQueue[checkboxEID]
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
spriteEID := entry.sprite
|
||||
|
||||
// check if sprite is ready to be used
|
||||
if _, spriteReady := t.Components.Ready.Get(spriteEID); !spriteReady {
|
||||
return
|
||||
}
|
||||
|
||||
checkbox, found := t.Components.Checkbox.Get(checkboxEID)
|
||||
if !found {
|
||||
checkbox = t.Components.Checkbox.Add(checkboxEID)
|
||||
}
|
||||
|
||||
checkboxNode := t.Components.SceneGraphNode.Add(checkboxEID)
|
||||
|
||||
sprite, found := t.Components.Sprite.Get(spriteEID)
|
||||
if found {
|
||||
checkbox.Sprite = sprite.Sprite
|
||||
t.Components.SceneGraphNode.Add(spriteEID).SetParent(checkboxNode.Node)
|
||||
}
|
||||
|
||||
interactive := t.Components.Interactive.Add(checkboxEID)
|
||||
interactive.InputVector.SetMouseButton(d2input.MouseButtonLeft)
|
||||
interactive.CursorPosition = checkbox.Layout.ClickableRect
|
||||
interactive.Callback = func() bool {
|
||||
return checkbox.Activate(checkbox)
|
||||
}
|
||||
|
||||
t.Components.Texture.Add(checkboxEID)
|
||||
|
||||
t.Components.Ready.Add(checkboxEID)
|
||||
|
||||
delete(t.checkboxLoadQueue, checkboxEID)
|
||||
}
|
||||
|
||||
// updateCheckbox refreshes the rendering logic for a checkbox,
|
||||
// causing any changes that have occurred to appear in the scene.
|
||||
func (t *UIWidgetFactory) updateCheckbox(checkboxEID akara.EID) {
|
||||
checkbox, found := t.Components.Checkbox.Get(checkboxEID)
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
checkbox.Update()
|
||||
|
||||
checkboxTexture, _ := t.Components.Texture.Get(checkboxEID)
|
||||
checkboxTexture.Texture = checkbox.Sprite.GetCurrentFrameSurface()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user