holy crap click handling works too

This commit was merged in pull request #5.
This commit is contained in:
2025-08-29 22:58:06 -04:00
parent 4829fbb5c7
commit 430259475b
9 changed files with 173 additions and 119 deletions

View File

@@ -9,7 +9,7 @@ import (
"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 {
b := Block{
ContainerBounds: d,
@@ -41,8 +41,8 @@ func (b *Block) Size() (w, h float64) {
return
}
func (b *Block) Draw(image *ebiten.Image) (w, h float64) {
w, h = b.Size()
func (b *Block) Draw(image *ebiten.Image) {
w, h := b.Size()
if b.backgroundColor != nil {
vector.DrawFilledRect(
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
import (
"git.vezzani.net/ben/games/common/elements/v1/mouse"
"github.com/hajimehoshi/ebiten/v2"
)
type ElementFunc func(Bounds) Element
type Clickable interface {
}
type Mouseable interface {
}
type InitFunc func(Bounds) Element
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 {
@@ -27,3 +20,7 @@ type Bounds struct {
Min Point
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
import (
"git.vezzani.net/ben/games/common/elements/v1"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
)
@@ -11,6 +12,14 @@ func (n NopHandler) HandleMouseEvent(s State) bool {
return false
}
type ChildrenProvider interface {
GetChildren() []elements.Element
}
type EventHandler interface {
HandleMouseEvent(s State) bool
}
type State struct {
X, Y int
LeftDown, RightDown bool
@@ -19,13 +28,30 @@ type State struct {
Clicked bool
}
//func ClickHandler(e elements.Element) func() bool {
// newState := StateBuilder()
// return func() bool {
// _ = newState()
// if
// }
//}
func Handler(e elements.Element) func() bool {
newState := StateBuilder()
ms := newState()
return func() bool {
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 {
prevState := State{}
@@ -57,6 +83,8 @@ func StateBuilder() func() State {
state.LeftChanged = state.LeftDown != prevState.LeftDown
state.RightChanged = state.RightDown != prevState.RightDown
state.LeftClicked = state.LeftChanged && state.LeftDown
state.RightClicked = state.RightChanged && state.RightDown
prevState = 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) {
s.children = children
s.childrenInit = children
}
}

View File

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

View File

@@ -5,6 +5,8 @@ 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/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/sprites/v1"
"github.com/hajimehoshi/ebiten/v2"
@@ -20,7 +22,12 @@ var root = stacks.New(
stacks.New(
stacks.BlockOpt(blocks.Name("left")),
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)),
)),
stacks.New(
@@ -38,15 +45,14 @@ func newEditor() *editor {
}
type editor struct {
root elements.Element
bounds elements.Bounds
root elements.Element
bounds elements.Bounds
handleMouse func() bool
}
//var handleClick = mouse.ClickHandler(root)
func (e *editor) Update() error {
sprites.Update()
//handleClick()
e.handleMouse()
return nil
}
@@ -62,6 +68,7 @@ func (e *editor) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHei
Height: float64(outsideHeight),
}
e.root = root(e.bounds)
e.handleMouse = mouse.Handler(e.root)
}
return outsideWidth, outsideHeight