From b1fd021120c7f3b38d04da0dbcc308f6c50427ca Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Tue, 10 Jan 2023 11:51:46 -0500 Subject: [PATCH] dasjkhkljashdkjsha --- elements/basic/button.go | 6 +- elements/basic/label.go | 4 -- elements/basic/test.go | 4 -- elements/core/core.go | 13 ++++ elements/layouts/vertical.go | 126 ++++++++++++++++++++++++++++++++++- iterator/iterator.go | 30 ++++++++- tomo.go | 12 ++++ 7 files changed, 178 insertions(+), 17 deletions(-) diff --git a/elements/basic/button.go b/elements/basic/button.go index 328976a..75364b1 100644 --- a/elements/basic/button.go +++ b/elements/basic/button.go @@ -23,6 +23,7 @@ func NewButton (text string) (element *Button) { element = &Button { enabled: true } element.Core, element.core = core.NewCore(element) element.drawer.SetFace(theme.FontFaceRegular()) + element.core.SetSelectable(true) element.SetText(text) return } @@ -112,10 +113,6 @@ func (element *Button) AdvanceSelection (direction int) (ok bool) { return } -func (element *Button) Selectable () (selectable bool) { - return element.enabled -} - func (element *Button) Select () { element.core.Select() } @@ -123,6 +120,7 @@ func (element *Button) Select () { func (element *Button) SetEnabled (enabled bool) { if element.enabled == enabled { return } element.enabled = enabled + element.core.SetSelectable(enabled) if element.core.HasImage () { element.draw() element.core.PushAll() diff --git a/elements/basic/label.go b/elements/basic/label.go index 8500d69..01728ab 100644 --- a/elements/basic/label.go +++ b/elements/basic/label.go @@ -53,10 +53,6 @@ func (element *Label) SetText (text string) { } } -func (element *Label) Selectable () (selectable bool) { - return -} - func (element *Label) AdvanceSelection (direction int) (ok bool) { return } diff --git a/elements/basic/test.go b/elements/basic/test.go index 6a45e76..50d1940 100644 --- a/elements/basic/test.go +++ b/elements/basic/test.go @@ -48,10 +48,6 @@ func (element *Test) Handle (event tomo.Event) { return } -func (element *Test) Selectable () (selectable bool) { - return -} - func (element *Test) AdvanceSelection (direction int) (ok bool) { return } diff --git a/elements/core/core.go b/elements/core/core.go index 6828824..028935a 100644 --- a/elements/core/core.go +++ b/elements/core/core.go @@ -15,6 +15,7 @@ type Core struct { minimumHeight int } + selectable bool hooks tomo.ParentHooks } @@ -50,6 +51,10 @@ func (core *Core) SetParentHooks (hooks tomo.ParentHooks) { core.hooks = hooks } +func (core Core) Selectable () (selectable bool) { + return core.selectable +} + func (core Core) MinimumSize () (width, height int) { return core.metrics.minimumWidth, core.metrics.minimumHeight } @@ -86,6 +91,14 @@ func (control *CoreControl) AllocateCanvas (width, height int) { control.RGBA = core.canvas } +func (control CoreControl) SetSelectable (selectable bool) { + changed := control.core.selectable != selectable + control.core.selectable = selectable + if changed { + control.core.hooks.RunSelectabilityChange(selectable) + } +} + func (control CoreControl) SetMinimumSize (width, height int) { core := control.core if width != core.metrics.minimumWidth || diff --git a/elements/layouts/vertical.go b/elements/layouts/vertical.go index c196dbb..4b53fdf 100644 --- a/elements/layouts/vertical.go +++ b/elements/layouts/vertical.go @@ -1,14 +1,136 @@ package layouts import "git.tebibyte.media/sashakoshka/tomo" -import "git.tebibyte.media/sashakoshka/tomo/artist" +import "git.tebibyte.media/sashakoshka/tomo/theme" +// import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/elements/core" +type verticalEntry struct { + y int + minHeight int + element tomo.Element +} + // Vertical lays its children out vertically. It can contain any number of // children. When an child is added to the layout, it can either be set to // contract to its minimum height or expand to fill the remaining space (space // that is not taken up by other children or padding is divided equally among // these). Child elements will all have the same width. type Vertical struct { - + *core.Core + core core.CoreControl + + gap, pad bool + children []verticalEntry + selectable bool +} + +// NewVertical creates a new vertical layout. If gap is set to true, a gap will +// be placed between each child element. If pad is set to true, padding will be +// be placed around the inside of this element's border. Usually, you will want +// these to be true. +func NewVertical (gap, pad bool) (element *Vertical) { + element = &Vertical { } + element.Core, element.core = core.NewCore(element) + element.gap = gap + element.pad = pad + element.recalculate() + return +} + +// SetPad sets whether or not padding will be placed around the inside of this +// element's border. +func (element *Vertical) SetPad (pad bool) { + changed := element.pad != pad + element.pad = pad + if changed { element.recalculate() } +} + +// SetGap sets whether or not a gap will be placed in between child elements. +func (element *Vertical) SetGap (gap bool) { + changed := element.gap != gap + element.gap = gap + if changed { element.recalculate() } +} + +// Adopt adds a child element to the vertical layout. If expand is set to true, +// the element will be expanded to fill a portion of the remaining space in the +// layout. +func (element *Vertical) Adopt (child tomo.Element, expand bool) { + _, minHeight := child.MinimumSize() + child.SetParentHooks (tomo.ParentHooks { + // TODO + }) + element.children = append (element.children, verticalEntry { + element: child, + minHeight: minHeight, + }) + if child.Selectable() { element.core.SetSelectable(true) } + + element.recalculate() +} + +// Disown removes the given child from the layout if it is contained within it. +func (element *Vertical) Disown (child tomo.Element) { + for index, entry := range element.children { + if entry.element == child { + entry.element.SetParentHooks(tomo.ParentHooks { }) + element.children = append ( + element.children[:index], + element.children[index + 1:]...) + break + } + } + + selectable := false + for _, entry := range element.children { + if entry.element.Selectable() { selectable = true } + } + element.core.SetSelectable(selectable) +} + +// Children returns a slice containing this element's children. +func (element *Vertical) Children () (children []tomo.Element) { + children = make([]tomo.Element, len(element.children)) + for index, entry := range element.children { + children[index] = entry.element + } + return +} + +// CountChildren returns the amount of children contained within this element. +func (element *Vertical) CountChildren () (count int) { + return len(element.children) +} + +// Child returns the child at the specified index. If the index is out of +// bounds, this method will return nil. +func (element *Vertical) Child (index int) (child tomo.Element) { + if index < 0 || index > len(element.children) { return } + return element.children[index].element +} + +func (element *Vertical) Handle (event tomo.Event) { + switch event.(type) { + case tomo.EventResize: + element.recalculate() + // TODO: + + // TODO: + } + return +} + +func (element *Vertical) AdvanceSelection (direction int) (ok bool) { + // TODO: + return +} + +func (element *Vertical) recalculate () { + var x, y int + if element.pad { + x += theme.Padding() + y += theme.Padding() + } + // TODO } diff --git a/iterator/iterator.go b/iterator/iterator.go index 9ffbba8..d8d9a96 100644 --- a/iterator/iterator.go +++ b/iterator/iterator.go @@ -1,6 +1,30 @@ package iterator -type Iterator[ELEMENT_TYPE any] interface { - Length() int - Next() ELEMENT_TYPE +type Iterator[ELEMENT_TYPE any] struct { + index int + slice []ELEMENT_TYPE +} + +func New[ELEMENT_TYPE any] ( + slice []ELEMENT_TYPE, +) ( + iterator Iterator[ELEMENT_TYPE], +) { + iterator.slice = slice + return +} + +func (iterator *Iterator[ELEMENT_TYPE]) Length () (length int) { + return len(iterator.slice) +} + +func (iterator *Iterator[ELEMENT_TYPE]) Next () (element ELEMENT_TYPE) { + if !iterator.MoreLeft() { return } + element = iterator.slice[iterator.index] + iterator.index ++ + return +} + +func (iterator *Iterator[ELEMENT_TYPE]) MoreLeft () (moreLeft bool) { + return iterator.index < len(iterator.slice) } diff --git a/tomo.go b/tomo.go index 990d228..3aaf5bd 100644 --- a/tomo.go +++ b/tomo.go @@ -37,6 +37,10 @@ type ParentHooks struct { // event. MinimumSizeChange func (width, height int) + // SelectabilityChange is called when the chid element becomes + // selectable or non-selectable. + SelectabilityChange func (selectable bool) + // SelectionRequest is called when the child element element wants // itself to be selected. If the parent element chooses to grant the // request, it must send the child element a selection event. @@ -66,6 +70,14 @@ func (hooks ParentHooks) RunSelectionRequest () { } } +// RunSelectabilityChange runs the SelectionRequest hook if it is not nil. If it +// is nil, it does nothing. +func (hooks ParentHooks) RunSelectabilityChange (selectable bool) { + if hooks.SelectabilityChange != nil { + hooks.SelectabilityChange(selectable) + } +} + // Element represents a basic on-screen object. type Element interface { // Element must implement the Image interface. Elements should start out