diff --git a/elements/basic/container.go b/elements/basic/container.go index e130c62..1e48bcf 100644 --- a/elements/basic/container.go +++ b/elements/basic/container.go @@ -1,5 +1,6 @@ package basic +import "image" import "git.tebibyte.media/sashakoshka/tomo" import "git.tebibyte.media/sashakoshka/tomo/theme" import "git.tebibyte.media/sashakoshka/tomo/artist" @@ -12,6 +13,8 @@ type Container struct { layout tomo.Layout children []tomo.LayoutEntry selectable bool + + drags [10]tomo.Element } func NewContainer (layout tomo.Layout) (element *Container) { @@ -24,23 +27,36 @@ func NewContainer (layout tomo.Layout) (element *Container) { func (element *Container) SetLayout (layout tomo.Layout) { element.layout = layout element.recalculate() + if element.core.HasImage() { + element.draw() + element.core.PushAll() + } } func (element *Container) Adopt (child tomo.Element, expand bool) { child.SetParentHooks (tomo.ParentHooks { - MinimumSizeChange: - func (int, int) { element.updateMinimumSize() }, - SelectabilityChange: - func (bool) { element.updateSelectable() }, + MinimumSizeChange: func (int, int) { + element.updateMinimumSize() + }, + SelectabilityChange: func (bool) { + element.updateSelectable() + }, + Draw: func (region tomo.Image) { + element.drawChildRegion(child, region) + }, }) element.children = append (element.children, tomo.LayoutEntry { Element: child, + Expand: expand, }) element.updateMinimumSize() element.updateSelectable() element.recalculate() - if element.core.HasImage() { element.draw() } + if element.core.HasImage() { + element.draw() + element.core.PushAll() + } } // Disown removes the given child from the container if it is contained within @@ -59,7 +75,10 @@ func (element *Container) Disown (child tomo.Element) { element.updateMinimumSize() element.updateSelectable() element.recalculate() - if element.core.HasImage() { element.draw() } + if element.core.HasImage() { + element.draw() + element.core.PushAll() + } } // Children returns a slice containing this element's children. @@ -83,6 +102,28 @@ func (element *Container) Child (index int) (child tomo.Element) { return element.children[index].Element } +// ChildAt returns the child that contains the specified x and y coordinates. If +// there are no children at the coordinates, this method will return nil. +func (element *Container) ChildAt (point image.Point) (child tomo.Element) { + for _, entry := range element.children { + if point.In(entry.Bounds().Add(entry.Position)) { + child = entry.Element + } + } + return +} + +func (element *Container) childPosition (child tomo.Element) (position image.Point) { + for _, entry := range element.children { + if entry.Element == child { + position = entry.Position + break + } + } + + return +} + func (element *Container) Handle (event tomo.Event) { switch event.(type) { case tomo.EventResize: @@ -92,8 +133,43 @@ func (element *Container) Handle (event tomo.Event) { resizeEvent.Height) element.recalculate() element.draw() - - // TODO: + + case tomo.EventMouseDown: + mouseDownEvent := event.(tomo.EventMouseDown) + child := element.ChildAt (image.Pt ( + mouseDownEvent.X, + mouseDownEvent.Y)) + if child == nil { break } + element.drags[mouseDownEvent.Button] = child + childPosition := element.childPosition(child) + child.Handle (tomo.EventMouseDown { + Button: mouseDownEvent.Button, + X: mouseDownEvent.X - childPosition.X, + Y: mouseDownEvent.Y - childPosition.Y, + }) + + case tomo.EventMouseUp: + mouseUpEvent := event.(tomo.EventMouseUp) + child := element.drags[mouseUpEvent.Button] + if child == nil { break } + element.drags[mouseUpEvent.Button] = nil + childPosition := element.childPosition(child) + child.Handle (tomo.EventMouseUp { + Button: mouseUpEvent.Button, + X: mouseUpEvent.X - childPosition.X, + Y: mouseUpEvent.Y - childPosition.Y, + }) + + case tomo.EventMouseMove: + mouseMoveEvent := event.(tomo.EventMouseMove) + for _, child := range element.drags { + if child == nil { continue } + childPosition := element.childPosition(child) + child.Handle (tomo.EventMouseMove { + X: mouseMoveEvent.X - childPosition.X, + Y: mouseMoveEvent.Y - childPosition.Y, + }) + } } return } @@ -129,8 +205,18 @@ func (element *Container) draw () { nil, 0, bounds) - // TODO for _, entry := range element.children { artist.Paste(element.core, entry, entry.Position) } } + +func (element *Container) drawChildRegion (child tomo.Element, region tomo.Image) { + for _, entry := range element.children { + if entry.Element == child { + artist.Paste(element.core, region, entry.Position) + element.core.PushRegion ( + region.Bounds().Add(entry.Position)) + break + } + } +} diff --git a/elements/basic/test.go b/elements/basic/test.go index 50d1940..133510a 100644 --- a/elements/basic/test.go +++ b/elements/basic/test.go @@ -10,6 +10,9 @@ import "git.tebibyte.media/sashakoshka/tomo/elements/core" type Test struct { *core.Core core core.CoreControl + drawing bool + color tomo.Image + lastMousePos image.Point } // NewTest creates a new test element. @@ -17,6 +20,7 @@ func NewTest () (element *Test) { element = &Test { } element.Core, element.core = core.NewCore(element) element.core.SetMinimumSize(32, 32) + element.color = artist.NewUniform(color.Black) return } @@ -43,7 +47,33 @@ func (element *Test) Handle (event tomo.Event) { image.Pt(0, resizeEvent.Height), image.Pt(resizeEvent.Width, 0)) - default: + case tomo.EventMouseDown: + element.drawing = true + mouseDownEvent := event.(tomo.EventMouseDown) + element.lastMousePos = image.Pt ( + mouseDownEvent.X, + mouseDownEvent.Y) + + case tomo.EventMouseUp: + element.drawing = false + mouseUpEvent := event.(tomo.EventMouseUp) + mousePos := image.Pt ( + mouseUpEvent.X, + mouseUpEvent.Y) + element.core.PushRegion (artist.Line ( + element.core, element.color, 1, + element.lastMousePos, mousePos)) + element.lastMousePos = mousePos + + case tomo.EventMouseMove: + mouseMoveEvent := event.(tomo.EventMouseMove) + mousePos := image.Pt ( + mouseMoveEvent.X, + mouseMoveEvent.Y) + element.core.PushRegion (artist.Line ( + element.core, element.color, 1, + element.lastMousePos, mousePos)) + element.lastMousePos = mousePos } return } diff --git a/elements/layouts/vertical.go b/elements/layouts/vertical.go index 2ebc7a8..c61b99b 100644 --- a/elements/layouts/vertical.go +++ b/elements/layouts/vertical.go @@ -33,6 +33,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, width, height int) { } else { _, entryMinHeight := entry.MinimumSize() freeSpace -= entryMinHeight + freeSpace -= theme.Padding() } } expandingElementHeight := 0 diff --git a/examples/verticalLayout/main.go b/examples/verticalLayout/main.go index dd7d152..546013f 100644 --- a/examples/verticalLayout/main.go +++ b/examples/verticalLayout/main.go @@ -16,18 +16,22 @@ func run () { container := basic.NewContainer(layouts.Vertical { true, true }) window.Adopt(container) - label := basic.NewLabel("it is a label hehe") - button := basic.NewButton("press me") + label := basic.NewLabel("it is a label hehe") + button := basic.NewButton("drawing pad") + okButton := basic.NewButton("OK") button.OnClick (func () { - label.SetText ( - "woah, this button changes the label text! since the " + - "size of this text box has changed, the window " + - "should expand (unless you resized it already).") + container.Disown(label) + container.Disown(button) + container.Disown(okButton) + container.Adopt(basic.NewLabel("Draw here:"), false) + container.Adopt(basic.NewTest(), true) + container.Adopt(okButton, false) }) + okButton.OnClick(tomo.Stop) container.Adopt(label, true) - container.Adopt(basic.NewButton("yeah"), false) container.Adopt(button, false) + container.Adopt(okButton, false) window.OnClose(tomo.Stop) window.Show()