From 5f47a811aac6bd18c2076c7196554ad8bac0cd57 Mon Sep 17 00:00:00 2001 From: Ben Vezzani Date: Sun, 31 Aug 2025 21:15:18 -0400 Subject: [PATCH] cleaning up the component system just a bit more... --- common/elements/v1/blocks/block.go | 37 ++++---------- common/elements/v1/blocks/options.go | 12 ++++- common/elements/v1/buttons/button.go | 24 +++++---- common/elements/v1/buttons/options.go | 7 ++- common/elements/v1/config.go | 15 ++++++ common/elements/v1/element.go | 25 +++++++++- common/elements/v1/stacks/options.go | 8 ++- common/elements/v1/stacks/stack.go | 70 +++++++++------------------ tools/component_test/editor.go | 26 +++++----- 9 files changed, 114 insertions(+), 110 deletions(-) create mode 100644 common/elements/v1/config.go diff --git a/common/elements/v1/blocks/block.go b/common/elements/v1/blocks/block.go index ed092c8..cbfd734 100644 --- a/common/elements/v1/blocks/block.go +++ b/common/elements/v1/blocks/block.go @@ -10,44 +10,31 @@ import ( "github.com/hajimehoshi/ebiten/v2/vector" ) -func New(ops ...OptFunc) elements.InitFunc { - return func() elements.Element { - b := Block{} - for i := range ops { - ops[i](&b) - } - return &b +func New(ops ...OptFunc) elements.Element { + b := Block{} + for i := range ops { + ops[i](&b) } + return &b } type Block struct { - anchor elements.Point + elements.Core + backgroundColor *color.Color mouse.NopHandler width, height int name string } -func (b *Block) SetAnchor(a elements.Point) { - d := b.anchor.Delta(a) - for i := range b.Children() { - b.Children()[i].SetAnchor(b.Children()[i].Anchor().Add(d)) - } - b.anchor = a -} - func (b *Block) Bounds() elements.Bounds { return elements.Bounds{ - Min: b.anchor, + Min: b.Anchor(), Width: b.width, Height: b.height, } } -func (b *Block) Anchor() elements.Point { - return b.anchor -} - func (b *Block) Size() (w, h int) { return b.width, b.height } @@ -57,8 +44,8 @@ func (b *Block) Draw(image *ebiten.Image) { if b.backgroundColor != nil { vector.DrawFilledRect( image, - float32(b.anchor.X), - float32(b.anchor.Y), + float32(b.Anchor().X), + float32(b.Anchor().Y), float32(bnd.Width), float32(bnd.Height), *b.backgroundColor, @@ -67,7 +54,3 @@ func (b *Block) Draw(image *ebiten.Image) { } return } - -func (b *Block) Children() []elements.Element { - return nil -} diff --git a/common/elements/v1/blocks/options.go b/common/elements/v1/blocks/options.go index 2816e8a..9644f5f 100644 --- a/common/elements/v1/blocks/options.go +++ b/common/elements/v1/blocks/options.go @@ -1,9 +1,19 @@ package blocks -import "image/color" +import ( + "image/color" + + "git.vezzani.net/ben/games/common/elements/v1" +) type OptFunc func(*Block) +func Core(f elements.OptFunc) OptFunc { + return func(b *Block) { + f(&b.Core) + } +} + func Size(w, h int) OptFunc { return func(b *Block) { b.width, b.height = w, h diff --git a/common/elements/v1/buttons/button.go b/common/elements/v1/buttons/button.go index ba5a2c5..54c459d 100644 --- a/common/elements/v1/buttons/button.go +++ b/common/elements/v1/buttons/button.go @@ -13,19 +13,17 @@ import ( "golang.org/x/image/font" ) -func New(ops ...OptFunc) elements.InitFunc { - return func() elements.Element { - b := Button{ - Block: blocks.Block{}, - font: ux.FontFace, - color: ux.FontColor, - } - for op := range ops { - ops[op](&b) - } - - return &b +func New(ops ...OptFunc) elements.Element { + b := Button{ + Block: blocks.Block{}, + font: ux.FontFace, + color: ux.FontColor, } + for op := range ops { + ops[op](&b) + } + + return &b } type Button struct { @@ -67,7 +65,7 @@ func (b *Button) HandleMouseEvent(ms mouse.State) bool { if !bnd.Contains(ms.Point()) { return false } - + switch { case b.onClick != nil && (ms.RightClicked || ms.LeftClicked): b.onClick(ms) diff --git a/common/elements/v1/buttons/options.go b/common/elements/v1/buttons/options.go index ccf81ae..afcde1c 100644 --- a/common/elements/v1/buttons/options.go +++ b/common/elements/v1/buttons/options.go @@ -3,14 +3,17 @@ package buttons import ( "image/color" + "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" ) type OptFunc func(button *Button) -type Option interface { - OptFunc | blocks.OptFunc +func Core(f elements.OptFunc) OptFunc { + return func(b *Button) { + f(&b.Core) + } } func OnClick(f func(ms mouse.State)) OptFunc { diff --git a/common/elements/v1/config.go b/common/elements/v1/config.go new file mode 100644 index 0000000..193596e --- /dev/null +++ b/common/elements/v1/config.go @@ -0,0 +1,15 @@ +package elements + +type OptFunc func(*Core) + +func Children(children ...Element) OptFunc { + return func(c *Core) { + c.children = children + } +} + +func Name(name string) OptFunc { + return func(s *Core) { + s.name = name + } +} diff --git a/common/elements/v1/element.go b/common/elements/v1/element.go index 234c7b7..3f33463 100644 --- a/common/elements/v1/element.go +++ b/common/elements/v1/element.go @@ -4,8 +4,6 @@ import ( "github.com/hajimehoshi/ebiten/v2" ) -type InitFunc func() Element - type Element interface { Draw(*ebiten.Image) SetAnchor(Point) @@ -40,3 +38,26 @@ type Bounds struct { 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 } + +type Core struct { + anchor Point + children []Element + + name string // For debugging +} + +func (c *Core) Anchor() Point { + return c.anchor +} + +func (c *Core) SetAnchor(a Point) { + d := c.Anchor().Delta(a) + for _, ch := range c.Children() { + ch.SetAnchor(ch.Anchor().Add(d)) + } + c.anchor = a +} + +func (c *Core) Children() []Element { + return c.children +} diff --git a/common/elements/v1/stacks/options.go b/common/elements/v1/stacks/options.go index af50647..cefb6c9 100644 --- a/common/elements/v1/stacks/options.go +++ b/common/elements/v1/stacks/options.go @@ -1,14 +1,12 @@ package stacks -import ( - "git.vezzani.net/ben/games/common/elements/v1" -) +import "git.vezzani.net/ben/games/common/elements/v1" type OptFunc func(*Stack) -func Children(children ...elements.InitFunc) OptFunc { +func Core(f elements.OptFunc) OptFunc { return func(s *Stack) { - s.childrenInit = children + f(&s.Core) } } diff --git a/common/elements/v1/stacks/stack.go b/common/elements/v1/stacks/stack.go index 9bf2562..d4792af 100644 --- a/common/elements/v1/stacks/stack.go +++ b/common/elements/v1/stacks/stack.go @@ -7,55 +7,37 @@ import ( "github.com/hajimehoshi/ebiten/v2" ) -func New(ops ...OptFunc) elements.InitFunc { - return func() elements.Element { - s := Stack{} - for op := range ops { - ops[op](&s) - } - - s.children = make([]elements.Element, len(s.childrenInit)) - var cw, ch int - anchor := s.anchor - for i := range s.childrenInit { - s.children[i] = s.childrenInit[i]() - s.children[i].SetAnchor(anchor) - cw, ch = s.children[i].Size() - if s.horizontal { - anchor.X += cw - } else { - anchor.Y += ch - } - } - - return &s +func New(ops ...OptFunc) elements.Element { + s := Stack{} + for op := range ops { + ops[op](&s) } + + var cw, ch int + anchor := s.Anchor() + for _, c := range s.Children() { + c.SetAnchor(anchor) + cw, ch = c.Size() + if s.horizontal { + anchor.X += cw + } else { + anchor.Y += ch + } + } + + return &s } type Stack struct { + elements.Core mouse.NopHandler - anchor elements.Point - horizontal bool - childrenInit []elements.InitFunc - children []elements.Element -} - -func (s *Stack) SetAnchor(a elements.Point) { - d := s.anchor.Delta(a) - for i := range s.Children() { - s.Children()[i].SetAnchor(s.Children()[i].Anchor().Add(d)) - } - s.anchor = a -} - -func (s *Stack) Anchor() elements.Point { - return s.anchor + horizontal bool } func (s *Stack) Size() (w, h int) { var cw, ch int - for i := range s.children { - cw, ch = s.children[i].Size() + for _, c := range s.Children() { + cw, ch = c.Size() if s.horizontal { w += cw if h < ch { @@ -73,11 +55,7 @@ func (s *Stack) Size() (w, h int) { } func (s *Stack) Draw(image *ebiten.Image) { - for i := range s.children { - s.children[i].Draw(image) + for _, c := range s.Children() { + c.Draw(image) } } - -func (s *Stack) Children() []elements.Element { - return s.children -} diff --git a/tools/component_test/editor.go b/tools/component_test/editor.go index daeee5c..35faa44 100644 --- a/tools/component_test/editor.go +++ b/tools/component_test/editor.go @@ -14,12 +14,12 @@ import ( var root = stacks.New( stacks.Horizontal(), - //stacks.BlockOpt(blocks.BackgroundColor(color.White)), - //stacks.BlockOpt(blocks.Name("parent")), - stacks.Children( + //stacks.Core(blocks.BackgroundColor(color.White)), + stacks.Core(elements.Name("parent")), + stacks.Core(elements.Children( stacks.New( - //stacks.BlockOpt(blocks.Name("left")), - stacks.Children( + stacks.Core(elements.Name("left")), + stacks.Core(elements.Children( buttons.New( buttons.BlockOpt(blocks.Size(100, 100)), buttons.Label("hello"), @@ -32,11 +32,11 @@ var root = stacks.New( blocks.Size(100, 100), blocks.BackgroundColor(colornames.Yellow), ), - ), + )), ), stacks.New( - //stacks.BlockOpt(blocks.Name("right")), - stacks.Children( + stacks.Core(elements.Name("right")), + stacks.Core(elements.Children( blocks.New( blocks.Size(100, 100), blocks.BackgroundColor(colornames.Blue), @@ -45,9 +45,9 @@ var root = stacks.New( blocks.Size(100, 100), blocks.BackgroundColor(colornames.Red), ), - ), + )), ), - ), + )), ) func newEditor() *editor { @@ -55,7 +55,6 @@ func newEditor() *editor { } type editor struct { - root elements.Element bounds elements.Bounds handleMouse func() bool } @@ -67,7 +66,7 @@ func (e *editor) Update() error { } func (e *editor) Draw(screen *ebiten.Image) { - e.root.Draw(screen) + root.Draw(screen) } func (e *editor) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { @@ -77,8 +76,7 @@ func (e *editor) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHei Width: outsideWidth, Height: outsideHeight, } - e.root = root() - e.handleMouse = mouse.Handler(e.root) + e.handleMouse = mouse.Handler(root) } return outsideWidth, outsideHeight