Basic elements now conform to the new API (largely untested)

This commit is contained in:
Sasha Koshka 2023-01-19 16:49:34 -05:00
parent 8a72e8bf01
commit c813463bb4
8 changed files with 187 additions and 78 deletions

View File

@ -14,10 +14,13 @@ type Button struct {
pressed bool
enabled bool
selected bool
onClick func ()
text string
drawer artist.TextDrawer
onClick func ()
onSelectionRequest func () (granted bool)
onSelectionMotionRequest func (tomo.SelectionDirection) (granted bool)
}
// NewButton creates a new button with the specified label text.
@ -41,7 +44,7 @@ func (element *Button) HandleMouseDown (x, y int, button tomo.Button) {
element.pressed = true
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -50,7 +53,7 @@ func (element *Button) HandleMouseUp (x, y int, button tomo.Button) {
element.pressed = false
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
within := image.Point { x, y }.
@ -63,7 +66,7 @@ func (element *Button) HandleMouseUp (x, y int, button tomo.Button) {
}
func (element *Button) HandleMouseMove (x, y int) { }
func (element *Button) HandleScroll (x, y int, deltaX, deltaY float64) { }
func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *Button) HandleKeyDown (
key tomo.Key,
@ -75,7 +78,7 @@ func (element *Button) HandleKeyDown (
element.pressed = true
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
}
@ -85,7 +88,7 @@ func (element *Button) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) {
element.pressed = false
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
if !element.enabled { return }
if element.onClick != nil {
@ -100,7 +103,9 @@ func (element *Button) Selected () (selected bool) {
func (element *Button) Select () {
if !element.enabled { return }
element.core.RequestSelection()
if element.onSelectionRequest != nil {
element.onSelectionRequest()
}
}
func (element *Button) HandleSelection (
@ -117,7 +122,7 @@ func (element *Button) HandleSelection (
element.selected = true
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
return true
}
@ -126,10 +131,20 @@ func (element *Button) HandleDeselection () {
element.selected = false
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
func (element *Button) OnSelectionRequest (callback func () (granted bool)) {
element.onSelectionRequest = callback
}
func (element *Button) OnSelectionMotionRequest (
callback func (direction tomo.SelectionDirection) (granted bool),
) {
element.onSelectionMotionRequest = callback
}
// OnClick sets the function to be called when the button is clicked.
func (element *Button) OnClick (callback func ()) {
element.onClick = callback
@ -141,7 +156,7 @@ func (element *Button) SetEnabled (enabled bool) {
element.enabled = enabled
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -157,7 +172,7 @@ func (element *Button) SetText (text string) {
theme.Padding() * 2 + textBounds.Dy())
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}

View File

@ -15,10 +15,13 @@ type Checkbox struct {
checked bool
enabled bool
selected bool
onClick func ()
text string
drawer artist.TextDrawer
onClick func ()
onSelectionRequest func () (granted bool)
onSelectionMotionRequest func (tomo.SelectionDirection) (granted bool)
}
// NewCheckbox creates a new cbeckbox with the specified label text.
@ -41,7 +44,7 @@ func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) {
element.pressed = true
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -57,7 +60,7 @@ func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) {
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
if within && element.onClick != nil {
element.onClick()
@ -76,7 +79,7 @@ func (element *Checkbox) HandleKeyDown (
element.pressed = true
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
}
@ -87,7 +90,7 @@ func (element *Checkbox) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
element.checked = !element.checked
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
if element.onClick != nil {
element.onClick()
@ -102,7 +105,10 @@ func (element *Checkbox) Selected () (selected bool) {
// Select requests that this element be selected.
func (element *Checkbox) Select () {
element.core.RequestSelection()
if !element.enabled { return }
if element.onSelectionRequest != nil {
element.onSelectionRequest()
}
}
func (element *Checkbox) HandleSelection (
@ -119,7 +125,7 @@ func (element *Checkbox) HandleSelection (
element.selected = true
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
return true
}
@ -128,10 +134,20 @@ func (element *Checkbox) HandleDeselection () {
element.selected = false
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
func (element *Checkbox) OnSelectionRequest (callback func () (granted bool)) {
element.onSelectionRequest = callback
}
func (element *Checkbox) OnSelectionMotionRequest (
callback func (direction tomo.SelectionDirection) (granted bool),
) {
element.onSelectionMotionRequest = callback
}
// OnClick sets the function to be called when the checkbox is toggled.
func (element *Checkbox) OnClick (callback func ()) {
element.onClick = callback
@ -148,7 +164,7 @@ func (element *Checkbox) SetEnabled (enabled bool) {
element.enabled = enabled
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -164,7 +180,7 @@ func (element *Checkbox) SetText (text string) {
textBounds.Dy())
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}

View File

@ -19,6 +19,10 @@ type Container struct {
selected bool
selectable bool
flexible bool
onSelectionRequest func () (granted bool)
onSelectionMotionRequest func (tomo.SelectionDirection) (granted bool)
onFlexibleHeightChange func ()
}
// NewContainer creates a new container.
@ -35,7 +39,7 @@ func (element *Container) SetLayout (layout tomo.Layout) {
if element.core.HasImage() {
element.recalculate()
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -43,38 +47,40 @@ func (element *Container) SetLayout (layout tomo.Layout) {
// the element will expand (instead of contract to its minimum size), in
// whatever way is defined by the current layout.
func (element *Container) Adopt (child tomo.Element, expand bool) {
child.SetParentHooks (tomo.ParentHooks {
Draw: func (region tomo.Canvas) {
element.drawChildRegion(child, region)
},
MinimumSizeChange: func (int, int) {
element.updateMinimumSize()
},
FlexibleHeightChange: element.updateMinimumSize,
SelectionRequest: func () (granted bool) {
child, selectable := child.(tomo.Selectable)
if !selectable { return }
return element.childSelectionRequestCallback(child)
},
SelectionMotionRequest: func (
direction tomo.SelectionDirection,
) (
granted bool,
) {
return element.core.RequestSelectionMotion(direction)
},
// set event handlers
child.OnDamage (func (region tomo.Canvas) {
element.drawChildRegion(child, region)
})
child.OnMinimumSizeChange(element.updateMinimumSize)
if child0, ok := child.(tomo.Flexible); ok {
child0.OnFlexibleHeightChange(element.updateMinimumSize)
}
if child0, ok := child.(tomo.Selectable); ok {
child0.OnSelectionRequest (func () (granted bool) {
return element.childSelectionRequestCallback(child0)
})
}
if child0, ok := child.(tomo.Selectable); ok {
child0.OnSelectionMotionRequest (
func (direction tomo.SelectionDirection) (granted bool) {
if element.onSelectionMotionRequest == nil { return }
return element.onSelectionMotionRequest(direction)
})
}
// add child
element.children = append (element.children, tomo.LayoutEntry {
Element: child,
Expand: expand,
})
// refresh stale data
element.updateMinimumSize()
element.reflectChildProperties()
if element.core.HasImage() && !element.warping {
element.recalculate()
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -97,7 +103,7 @@ func (element *Container) Warp (callback func ()) {
if element.core.HasImage() {
element.recalculate()
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -106,7 +112,7 @@ func (element *Container) Warp (callback func ()) {
func (element *Container) Disown (child tomo.Element) {
for index, entry := range element.children {
if entry.Element == child {
entry.SetParentHooks(tomo.ParentHooks { })
element.clearChildEventHandlers(entry.Element)
element.children = append (
element.children[:index],
element.children[index + 1:]...)
@ -119,7 +125,22 @@ func (element *Container) Disown (child tomo.Element) {
if element.core.HasImage() && !element.warping {
element.recalculate()
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
func (element *Container) clearChildEventHandlers (child tomo.Element) {
child.OnDamage(nil)
child.OnMinimumSizeChange(nil)
if child0, ok := child.(tomo.Selectable); ok {
child0.OnSelectionRequest(nil)
child0.OnSelectionMotionRequest(nil)
if child0.Selected() {
child0.HandleDeselection()
}
}
if child0, ok := child.(tomo.Flexible); ok {
child0.OnFlexibleHeightChange(nil)
}
}
@ -132,7 +153,7 @@ func (element *Container) DisownAll () {
if element.core.HasImage() && !element.warping {
element.recalculate()
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -213,7 +234,7 @@ func (element *Container) HandleScroll (x, y int, deltaX, deltaY float64) {
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget)
if !handlesMouse { return }
childPosition := element.childPosition(child)
child.HandleScroll(x - childPosition.X, y - childPosition.Y, deltaX, deltaY)
child.HandleMouseScroll(x - childPosition.X, y - childPosition.Y, deltaX, deltaY)
}
func (element *Container) HandleKeyDown (
@ -245,7 +266,9 @@ func (element *Container) Selected () (selected bool) {
}
func (element *Container) Select () {
element.core.RequestSelection()
if element.onSelectionRequest != nil {
element.onSelectionRequest()
}
}
func (element *Container) HandleSelection (direction tomo.SelectionDirection) (ok bool) {
@ -300,10 +323,14 @@ func (element *Container) HandleSelection (direction tomo.SelectionDirection) (o
return false
}
func (element *Container) MinimumHeightFor (width int) (height int) {
func (element *Container) FlexibleHeightFor (width int) (height int) {
return element.layout.MinimumHeightFor(element.children, width)
}
func (element *Container) OnFlexibleHeightChange (callback func ()) {
element.onFlexibleHeightChange = callback
}
func (element *Container) HandleDeselection () {
element.selected = false
element.forSelected (func (child tomo.Selectable) bool {
@ -312,6 +339,16 @@ func (element *Container) HandleDeselection () {
})
}
func (element *Container) OnSelectionRequest (callback func () (granted bool)) {
element.onSelectionRequest = callback
}
func (element *Container) OnSelectionMotionRequest (
callback func (direction tomo.SelectionDirection) (granted bool),
) {
element.onSelectionMotionRequest = callback
}
func (element *Container) forSelected (callback func (child tomo.Selectable) bool) {
for _, entry := range element.children {
child, selectable := entry.Element.(tomo.Selectable)
@ -379,7 +416,7 @@ func (element *Container) childSelectionRequestCallback (
) (
granted bool,
) {
if element.core.RequestSelection() {
if element.onSelectionRequest != nil && element.onSelectionRequest() {
element.forSelected (func (child tomo.Selectable) bool {
child.HandleDeselection()
return true
@ -422,7 +459,7 @@ func (element *Container) drawChildRegion (child tomo.Element, region tomo.Canva
for _, entry := range element.children {
if entry.Element == child {
artist.Paste(element.core, region, entry.Position)
element.core.PushRegion (
element.core.DamageRegion (
region.Bounds().Add(entry.Position))
break
}

View File

@ -13,6 +13,8 @@ type Label struct {
wrap bool
text string
drawer artist.TextDrawer
onFlexibleHeightChange func ()
}
// NewLabel creates a new label. If wrap is set to true, the text inside will be
@ -38,9 +40,9 @@ func (element *Label) Resize (width, height int) {
return
}
// MinimumHeightFor returns the reccomended height for this element based on the
// given width in order to allow the text to wrap properly.
func (element *Label) MinimumHeightFor (width int) (height int) {
// FlexibleHeightFor returns the reccomended height for this element based on
// the given width in order to allow the text to wrap properly.
func (element *Label) FlexibleHeightFor (width int) (height int) {
if element.wrap {
return element.drawer.ReccomendedHeightFor(width)
} else {
@ -49,6 +51,12 @@ func (element *Label) MinimumHeightFor (width int) (height int) {
}
}
// OnFlexibleHeightChange sets a function to be called when the parameters
// affecting this element's flexible height are changed.
func (element *Label) OnFlexibleHeightChange (callback func ()) {
element.onFlexibleHeightChange = callback
}
// SetText sets the label's text.
func (element *Label) SetText (text string) {
if element.text == text { return }
@ -59,7 +67,7 @@ func (element *Label) SetText (text string) {
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -78,7 +86,7 @@ func (element *Label) SetWrap (wrap bool) {
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -88,7 +96,9 @@ func (element *Label) updateMinimumSize () {
if em < 1 { em = theme.Padding() }
element.core.SetMinimumSize (
em, element.drawer.LineHeight().Round())
element.core.NotifyFlexibleHeightChange()
if element.onFlexibleHeightChange != nil {
element.onFlexibleHeightChange()
}
} else {
bounds := element.drawer.LayoutBounds()
element.core.SetMinimumSize(bounds.Dx(), bounds.Dy())

View File

@ -34,7 +34,7 @@ func (element *ProgressBar) SetProgress (progress float64) {
element.progress = progress
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}

View File

@ -23,6 +23,8 @@ type ScrollContainer struct {
enabled bool
bounds image.Rectangle
}
// TODO event handlers
}
// NewScrollContainer creates a new scroll container with the specified scroll
@ -52,23 +54,18 @@ func (element *ScrollContainer) Resize (width, height int) {
func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
// disown previous child if it exists
if element.child != nil {
element.child.SetParentHooks (tomo.ParentHooks { })
if previousChild, ok := element.child.(tomo.Selectable); ok {
if previousChild.Selected() {
previousChild.HandleDeselection()
}
}
element.clearChildEventHandlers(child)
}
// adopt new child
element.child = child
if child != nil {
child.SetParentHooks (tomo.ParentHooks {
// child.SetParentHooks (tomo.ParentHooks {
// Draw: window.childDrawCallback,
// MinimumSizeChange: window.childMinimumSizeChangeCallback,
// FlexibleHeightChange: window.resizeChildToFit,
// SelectionRequest: window.childSelectionRequestCallback,
})
// })
// TODO: somehow inform the core that we do not in fact want to
// redraw the element.
@ -84,6 +81,21 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
}
}
func (element *ScrollContainer) clearChildEventHandlers (child tomo.Element) {
child.OnDamage(nil)
child.OnMinimumSizeChange(nil)
if child0, ok := child.(tomo.Selectable); ok {
child0.OnSelectionRequest(nil)
child0.OnSelectionMotionRequest(nil)
if child0.Selected() {
child0.HandleDeselection()
}
}
if child0, ok := child.(tomo.Flexible); ok {
child0.OnFlexibleHeightChange(nil)
}
}
func (element *ScrollContainer) recalculate () {
horizontal := &element.horizontal
vertical := &element.vertical

View File

@ -34,7 +34,7 @@ func (element *Spacer) SetLine (line bool) {
element.line = line
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}

View File

@ -25,6 +25,9 @@ type TextBox struct {
onKeyDown func (tomo.Key, tomo.Modifiers, bool) (bool)
onChange func ()
onSelectionRequest func () (granted bool)
onSelectionMotionRequest func (tomo.SelectionDirection) (granted bool)
onScrollBoundsChange func ()
}
// NewTextBox creates a new text box with the specified placeholder text, and
@ -119,7 +122,7 @@ func (element *TextBox) HandleKeyDown (
if altered && element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -130,7 +133,9 @@ func (element *TextBox) Selected () (selected bool) {
}
func (element *TextBox) Select () {
element.core.RequestSelection()
if element.onSelectionRequest != nil {
element.onSelectionRequest()
}
}
func (element *TextBox) HandleSelection (
@ -147,7 +152,7 @@ func (element *TextBox) HandleSelection (
element.selected = true
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
return true
}
@ -156,16 +161,26 @@ func (element *TextBox) HandleDeselection () {
element.selected = false
if element.core.HasImage() {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
func (element *TextBox) OnSelectionRequest (callback func () (granted bool)) {
element.onSelectionRequest = callback
}
func (element *TextBox) OnSelectionMotionRequest (
callback func (direction tomo.SelectionDirection) (granted bool),
) {
element.onSelectionMotionRequest = callback
}
func (element *TextBox) SetEnabled (enabled bool) {
if element.enabled == enabled { return }
element.enabled = enabled
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -178,7 +193,7 @@ func (element *TextBox) SetPlaceholder (placeholder string) {
element.updateMinimumSize()
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -195,7 +210,7 @@ func (element *TextBox) SetValue (text string) {
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
}
@ -246,9 +261,11 @@ func (element *TextBox) ScrollTo (position image.Point) {
if element.core.HasImage () {
element.draw()
element.core.PushAll()
element.core.DamageAll()
}
if element.onScrollBoundsChange != nil {
element.onScrollBoundsChange()
}
element.core.NotifyContentBoundsChange()
}
// ScrollAxes returns the supported axes for scrolling.
@ -286,7 +303,9 @@ func (element *TextBox) scrollToCursor () {
element.scroll -= minX - cursorPosition.X
if element.scroll < 0 { element.scroll = 0 }
}
element.core.NotifyContentBoundsChange()
if element.onScrollBoundsChange != nil {
element.onScrollBoundsChange()
}
}
func (element *TextBox) draw () {