1 Commits

Author SHA1 Message Date
430259475b holy crap click handling works too 2025-08-29 22:58:06 -04:00
9 changed files with 173 additions and 119 deletions

View File

@@ -9,7 +9,7 @@ import (
"github.com/hajimehoshi/ebiten/v2/vector" "github.com/hajimehoshi/ebiten/v2/vector"
) )
func New(ops ...Option) elements.ElementFunc { func New(ops ...Option) elements.InitFunc {
return func(d elements.Bounds) elements.Element { return func(d elements.Bounds) elements.Element {
b := Block{ b := Block{
ContainerBounds: d, ContainerBounds: d,
@@ -41,8 +41,8 @@ func (b *Block) Size() (w, h float64) {
return return
} }
func (b *Block) Draw(image *ebiten.Image) (w, h float64) { func (b *Block) Draw(image *ebiten.Image) {
w, h = b.Size() w, h := b.Size()
if b.backgroundColor != nil { if b.backgroundColor != nil {
vector.DrawFilledRect( vector.DrawFilledRect(
image, image,

View File

@@ -1,70 +0,0 @@
package elements
//
//import (
// "image/color"
//)
//
//type xAlign int
//type yAlign int
//
//const (
// AlignCente xAlign = iota
// AlignLeft
// AlignRight
//)
//
//const (
// AlignCenter yAlign = iota
// AlignTop
// AlignBottom
//)
//
//type Button struct {
// mouseHandler
// block
// Label string
// OnClick func() error
// OnRightClick func() error
// Style struct {
// MouseDownColor *color.Color
// }
//}
//
//func (b *Button) HandleClick(_ MouseState) error {
// if b.OnClick == nil {
// return nil
// }
// return b.OnClick()
//}
//
//
//func (b *Button) getFont() font.Face {
// if b.block.Font == nil {
// return ux.FontFace
// }
//
// return *b.block.block.Font
//}
//
//func (b *Button) backgroundColor() color.Color {
// var c *color.Color
// if b.block.block.BackgroundColor != nil {
// c = b.block.block.BackgroundColor
// } else {
// c = &ux.BackgroundColor
// }
//
// if (b.mouseState.RightDown || b.mouseState.LeftDown) && b.Style.MouseDownColor != nil {
// c = b.Style.MouseDownColor
// }
//
// return *c
//}
//
//func (b *Button) Draw(ctx context.Context, image *ebiten.Image) error {
//
// vector.StrokeRect(image, xz, yz, w, h, 1, b.backgroundColor(), true)
//
// return nil
//}

View File

@@ -0,0 +1,50 @@
package buttons
import (
"git.vezzani.net/ben/games/common/elements/v1"
"git.vezzani.net/ben/games/common/elements/v1/blocks"
"git.vezzani.net/ben/games/common/elements/v1/mouse"
)
func New(ops ...Option) elements.InitFunc {
return func(bounds elements.Bounds) elements.Element {
b := Button{
Block: blocks.Block{ContainerBounds: bounds},
}
for op := range ops {
ops[op](&b)
}
return &b
}
}
type Button struct {
blocks.Block
onClick func(ms mouse.State)
onMouseDown func(ms mouse.State)
onMouseUp func(ms mouse.State)
}
func (b *Button) HandleMouseEvent(ms mouse.State) bool {
if !b.Block.ContainerBounds.Contains(elements.Point{
X: float64(ms.X),
Y: float64(ms.Y),
}) {
return false
}
switch {
case b.onClick != nil && (ms.RightClicked || ms.LeftClicked):
b.onClick(ms)
return true
case b.onMouseUp != nil && (ms.RightChanged && !ms.RightDown || ms.LeftChanged && !ms.LeftDown):
b.onMouseUp(ms)
return true
case b.onMouseDown != nil && (ms.RightChanged && ms.RightDown || ms.LeftChanged && ms.LeftDown):
b.onMouseDown(ms)
return true
}
return false
}

View File

@@ -0,0 +1,32 @@
package buttons
import (
"git.vezzani.net/ben/games/common/elements/v1/blocks"
"git.vezzani.net/ben/games/common/elements/v1/mouse"
)
type Option func(button *Button)
func OnClick(f func(ms mouse.State)) Option {
return func(button *Button) {
button.onClick = f
}
}
func OnMouseDown(f func(ms mouse.State)) Option {
return func(button *Button) {
button.onMouseDown = f
}
}
func OnMouseUp(f func(ms mouse.State)) Option {
return func(button *Button) {
button.onMouseUp = f
}
}
func BlockOpt(o blocks.Option) Option {
return func(s *Button) {
o(&s.Block)
}
}

View File

@@ -1,22 +1,15 @@
package elements package elements
import ( import (
"git.vezzani.net/ben/games/common/elements/v1/mouse"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
type ElementFunc func(Bounds) Element type InitFunc func(Bounds) Element
type Clickable interface {
}
type Mouseable interface {
}
type Element interface { type Element interface {
HandleMouseEvent(s mouse.State) bool Size() (w, h float64)
Draw(image *ebiten.Image) (w, h float64) Draw(image *ebiten.Image)
} }
type Point struct { type Point struct {
@@ -27,3 +20,7 @@ type Bounds struct {
Min Point Min Point
Width, Height float64 Width, Height float64
} }
func (b *Bounds) Contains(p Point) bool {
return p.X >= b.Min.X && p.X <= b.Min.X+b.Width && p.Y >= b.Min.Y && p.Y <= b.Min.Y+b.Height
}

View File

@@ -1,6 +1,7 @@
package mouse package mouse
import ( import (
"git.vezzani.net/ben/games/common/elements/v1"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/inpututil"
) )
@@ -11,6 +12,14 @@ func (n NopHandler) HandleMouseEvent(s State) bool {
return false return false
} }
type ChildrenProvider interface {
GetChildren() []elements.Element
}
type EventHandler interface {
HandleMouseEvent(s State) bool
}
type State struct { type State struct {
X, Y int X, Y int
LeftDown, RightDown bool LeftDown, RightDown bool
@@ -19,13 +28,30 @@ type State struct {
Clicked bool Clicked bool
} }
//func ClickHandler(e elements.Element) func() bool { func Handler(e elements.Element) func() bool {
// newState := StateBuilder() newState := StateBuilder()
// return func() bool { ms := newState()
// _ = newState() return func() bool {
// if ms = newState()
// } return propagateMouse(e, ms)
//} }
}
func propagateMouse(e elements.Element, ms State) bool {
if p, ok := e.(ChildrenProvider); ok {
for _, c := range p.GetChildren() {
if propagateMouse(c, ms) {
return true
}
}
}
if e, ok := e.(EventHandler); ok {
return e.HandleMouseEvent(ms)
}
return false
}
func StateBuilder() func() State { func StateBuilder() func() State {
prevState := State{} prevState := State{}
@@ -57,6 +83,8 @@ func StateBuilder() func() State {
state.LeftChanged = state.LeftDown != prevState.LeftDown state.LeftChanged = state.LeftDown != prevState.LeftDown
state.RightChanged = state.RightDown != prevState.RightDown state.RightChanged = state.RightDown != prevState.RightDown
state.LeftClicked = state.LeftChanged && state.LeftDown
state.RightClicked = state.RightChanged && state.RightDown
prevState = state prevState = state
return state return state

View File

@@ -13,9 +13,9 @@ func BlockOpt(o blocks.Option) Option {
} }
} }
func Children(children ...elements.ElementFunc) Option { func Children(children ...elements.InitFunc) Option {
return func(s *Stack) { return func(s *Stack) {
s.children = children s.childrenInit = children
} }
} }

View File

@@ -8,7 +8,7 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
func New(ops ...Option) elements.ElementFunc { func New(ops ...Option) elements.InitFunc {
return func(d elements.Bounds) elements.Element { return func(d elements.Bounds) elements.Element {
s := Stack{ s := Stack{
Block: blocks.Block{ContainerBounds: d}, Block: blocks.Block{ContainerBounds: d},
@@ -16,6 +16,26 @@ func New(ops ...Option) elements.ElementFunc {
for op := range ops { for op := range ops {
ops[op](&s) ops[op](&s)
} }
d.Width, d.Height = s.Block.Size()
if s.horizontal {
d.Width /= float64(len(s.childrenInit))
} else {
d.Height /= float64(len(s.childrenInit))
}
s.Children = make([]elements.Element, len(s.childrenInit))
var offsetX, offsetY float64
for i := range s.childrenInit {
s.Children[i] = s.childrenInit[i](d)
offsetX, offsetY = s.Children[i].Size()
if s.horizontal {
d.Min.X += offsetX
} else {
d.Min.Y += offsetY
}
}
return &s return &s
} }
} }
@@ -23,29 +43,19 @@ func New(ops ...Option) elements.ElementFunc {
type Stack struct { type Stack struct {
blocks.Block blocks.Block
mouse.NopHandler mouse.NopHandler
horizontal bool horizontal bool
children []elements.ElementFunc childrenInit []elements.InitFunc
Children []elements.Element
} }
func (s *Stack) Draw(image *ebiten.Image) (w, h float64) { func (s *Stack) Draw(image *ebiten.Image) {
s.Block.Draw(image) s.Block.Draw(image)
d := s.ContainerBounds for i := range s.Children {
d.Width, d.Height = s.Block.Size() s.Children[i].Draw(image)
if s.horizontal {
d.Width /= float64(len(s.children))
} else {
d.Height /= float64(len(s.children))
} }
}
var offsetX, offsetY float64
for i := range s.children { func (s *Stack) GetChildren() []elements.Element {
offsetX, offsetY = s.children[i](d).Draw(image) return s.Children
if s.horizontal {
d.Min.X += offsetX
} else {
d.Min.Y += offsetY
}
}
return s.Block.Size()
} }

View File

@@ -5,6 +5,8 @@ import (
"git.vezzani.net/ben/games/common/elements/v1" "git.vezzani.net/ben/games/common/elements/v1"
"git.vezzani.net/ben/games/common/elements/v1/blocks" "git.vezzani.net/ben/games/common/elements/v1/blocks"
"git.vezzani.net/ben/games/common/elements/v1/buttons"
"git.vezzani.net/ben/games/common/elements/v1/mouse"
"git.vezzani.net/ben/games/common/elements/v1/stacks" "git.vezzani.net/ben/games/common/elements/v1/stacks"
"git.vezzani.net/ben/games/common/sprites/v1" "git.vezzani.net/ben/games/common/sprites/v1"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
@@ -20,7 +22,12 @@ var root = stacks.New(
stacks.New( stacks.New(
stacks.BlockOpt(blocks.Name("left")), stacks.BlockOpt(blocks.Name("left")),
stacks.Children( stacks.Children(
blocks.New(blocks.BackgroundColor(colornames.Green)), buttons.New(
buttons.BlockOpt(blocks.BackgroundColor(colornames.Green)),
buttons.OnClick(func(ms mouse.State) {
println("green")
}),
),
blocks.New(blocks.BackgroundColor(colornames.Yellow)), blocks.New(blocks.BackgroundColor(colornames.Yellow)),
)), )),
stacks.New( stacks.New(
@@ -38,15 +45,14 @@ func newEditor() *editor {
} }
type editor struct { type editor struct {
root elements.Element root elements.Element
bounds elements.Bounds bounds elements.Bounds
handleMouse func() bool
} }
//var handleClick = mouse.ClickHandler(root)
func (e *editor) Update() error { func (e *editor) Update() error {
sprites.Update() sprites.Update()
//handleClick() e.handleMouse()
return nil return nil
} }
@@ -62,6 +68,7 @@ func (e *editor) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHei
Height: float64(outsideHeight), Height: float64(outsideHeight),
} }
e.root = root(e.bounds) e.root = root(e.bounds)
e.handleMouse = mouse.Handler(e.root)
} }
return outsideWidth, outsideHeight return outsideWidth, outsideHeight