Migrated over some elements
This commit is contained in:
parent
4c6f1f80e7
commit
68128c94d8
@ -1,24 +1,19 @@
|
||||
package elements
|
||||
|
||||
import "image"
|
||||
// import "runtime/debug"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
// import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||
// import "git.tebibyte.media/sashakoshka/tomo/shatter"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
|
||||
// Button is a clickable button.
|
||||
type Button struct {
|
||||
*core.Core
|
||||
*core.FocusableCore
|
||||
core core.CoreControl
|
||||
focusableControl core.FocusableCoreControl
|
||||
entity tomo.FocusableEntity
|
||||
drawer textdraw.Drawer
|
||||
|
||||
enabled bool
|
||||
pressed bool
|
||||
text string
|
||||
|
||||
@ -36,9 +31,6 @@ type Button struct {
|
||||
func NewButton (text string) (element *Button) {
|
||||
element = &Button { showText: true }
|
||||
element.theme.Case = tomo.C("tomo", "button")
|
||||
element.Core, element.core = core.NewCore(element, element.drawAll)
|
||||
element.FocusableCore,
|
||||
element.focusableControl = core.NewFocusableCore(element.core, element.drawAndPush)
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
@ -46,42 +38,11 @@ func NewButton (text string) (element *Button) {
|
||||
return
|
||||
}
|
||||
|
||||
func (element *Button) HandleMouseDown (x, y int, button input.Button) {
|
||||
if !element.Enabled() { return }
|
||||
if !element.Focused() { element.Focus() }
|
||||
if button != input.ButtonLeft { return }
|
||||
element.pressed = true
|
||||
element.drawAndPush()
|
||||
}
|
||||
|
||||
func (element *Button) HandleMouseUp (x, y int, button input.Button) {
|
||||
if button != input.ButtonLeft { return }
|
||||
element.pressed = false
|
||||
within := image.Point { x, y }.
|
||||
In(element.Bounds())
|
||||
if element.Enabled() && within && element.onClick != nil {
|
||||
element.onClick()
|
||||
}
|
||||
element.drawAndPush()
|
||||
}
|
||||
|
||||
func (element *Button) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||
if !element.Enabled() { return }
|
||||
if key == input.KeyEnter {
|
||||
element.pressed = true
|
||||
element.drawAndPush()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) {
|
||||
if key == input.KeyEnter && element.pressed {
|
||||
element.pressed = false
|
||||
element.drawAndPush()
|
||||
if !element.Enabled() { return }
|
||||
if element.onClick != nil {
|
||||
element.onClick()
|
||||
}
|
||||
}
|
||||
// Bind binds this element to an entity.
|
||||
func (element *Button) Bind (entity tomo.Entity) {
|
||||
if entity == nil { element.entity = nil; return }
|
||||
element.entity = entity.(tomo.FocusableEntity)
|
||||
element.updateMinimumSize()
|
||||
}
|
||||
|
||||
// OnClick sets the function to be called when the button is clicked.
|
||||
@ -89,19 +50,33 @@ func (element *Button) OnClick (callback func ()) {
|
||||
element.onClick = callback
|
||||
}
|
||||
|
||||
// Focus gives this element input focus.
|
||||
func (element *Button) Focus () {
|
||||
if element.entity == nil { return }
|
||||
if !element.entity.Focused() { element.entity.Focus() }
|
||||
}
|
||||
|
||||
// Enabled returns whether this button is enabled or not.
|
||||
func (element *Button) Enabled () bool {
|
||||
return element.enabled
|
||||
}
|
||||
|
||||
// SetEnabled sets whether this button can be clicked or not.
|
||||
func (element *Button) SetEnabled (enabled bool) {
|
||||
element.focusableControl.SetEnabled(enabled)
|
||||
if element.enabled == enabled { return }
|
||||
element.enabled = enabled
|
||||
if element.entity == nil { return }
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetText sets the button's label text.
|
||||
func (element *Button) SetText (text string) {
|
||||
if element.text == text { return }
|
||||
|
||||
element.text = text
|
||||
element.drawer.SetText([]rune(text))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.drawAndPush()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetIcon sets the icon of the button. Passing theme.IconNone removes the
|
||||
@ -109,23 +84,22 @@ func (element *Button) SetText (text string) {
|
||||
func (element *Button) SetIcon (id tomo.Icon) {
|
||||
if id == tomo.IconNone {
|
||||
element.hasIcon = false
|
||||
element.updateMinimumSize()
|
||||
element.drawAndPush()
|
||||
} else {
|
||||
if element.hasIcon && element.iconId == id { return }
|
||||
element.hasIcon = true
|
||||
element.iconId = id
|
||||
}
|
||||
element.updateMinimumSize()
|
||||
element.drawAndPush()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// ShowText sets whether or not the button's text will be displayed.
|
||||
func (element *Button) ShowText (showText bool) {
|
||||
if element.showText == showText { return }
|
||||
element.showText = showText
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.drawAndPush()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetTheme sets the element's theme.
|
||||
@ -135,74 +109,30 @@ func (element *Button) SetTheme (new tomo.Theme) {
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.drawAndPush()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetConfig sets the element's configuration.
|
||||
func (element *Button) SetConfig (new tomo.Config) {
|
||||
if new == element.config.Config { return }
|
||||
element.config.Config = new
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.drawAndPush()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
func (element *Button) updateMinimumSize () {
|
||||
padding := element.theme.Padding(tomo.PatternButton)
|
||||
margin := element.theme.Margin(tomo.PatternButton)
|
||||
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
minimumSize := textBounds.Sub(textBounds.Min)
|
||||
// Draw causes the element to draw to the specified destination canvas.
|
||||
func (element *Button) Draw (destination canvas.Canvas) {
|
||||
if element.entity == nil { return }
|
||||
|
||||
if element.hasIcon {
|
||||
icon := element.theme.Icon(element.iconId, tomo.IconSizeSmall)
|
||||
if icon != nil {
|
||||
bounds := icon.Bounds()
|
||||
if element.showText {
|
||||
minimumSize.Max.X += bounds.Dx()
|
||||
minimumSize.Max.X += margin.X
|
||||
} else {
|
||||
minimumSize.Max.X = bounds.Dx()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minimumSize = padding.Inverse().Apply(minimumSize)
|
||||
element.core.SetMinimumSize(minimumSize.Dx(), minimumSize.Dy())
|
||||
}
|
||||
|
||||
func (element *Button) state () tomo.State {
|
||||
return tomo.State {
|
||||
Disabled: !element.Enabled(),
|
||||
Focused: element.Focused(),
|
||||
Pressed: element.pressed,
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Button) drawAndPush () {
|
||||
if element.core.HasImage () {
|
||||
element.drawAll()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Button) drawAll () {
|
||||
element.drawBackground()
|
||||
element.drawText()
|
||||
}
|
||||
|
||||
func (element *Button) drawBackground () []image.Rectangle {
|
||||
state := element.state()
|
||||
bounds := element.Bounds()
|
||||
bounds := element.entity.Bounds()
|
||||
pattern := element.theme.Pattern(tomo.PatternButton, state)
|
||||
|
||||
pattern.Draw(element.core, bounds)
|
||||
return []image.Rectangle { bounds }
|
||||
}
|
||||
|
||||
func (element *Button) drawText () {
|
||||
state := element.state()
|
||||
bounds := element.Bounds()
|
||||
pattern.Draw(destination, bounds)
|
||||
|
||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
||||
sink := element.theme.Sink(tomo.PatternButton)
|
||||
margin := element.theme.Margin(tomo.PatternButton)
|
||||
@ -240,7 +170,7 @@ func (element *Button) drawText () {
|
||||
}
|
||||
offset.X += addedWidth / 2
|
||||
|
||||
icon.Draw(element.core, foreground, iconOffset)
|
||||
icon.Draw(destination, foreground, iconOffset)
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,6 +178,84 @@ func (element *Button) drawText () {
|
||||
if element.pressed {
|
||||
offset = offset.Add(sink)
|
||||
}
|
||||
element.drawer.Draw(element.core, foreground, offset)
|
||||
element.drawer.Draw(destination, foreground, offset)
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Button) HandleFocusChange () {
|
||||
if element.entity == nil { return }
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
func (element *Button) HandleMouseDown (x, y int, button input.Button) {
|
||||
if element.entity == nil { return }
|
||||
if !element.Enabled() { return }
|
||||
element.Focus()
|
||||
if button != input.ButtonLeft { return }
|
||||
element.pressed = true
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
func (element *Button) HandleMouseUp (x, y int, button input.Button) {
|
||||
if element.entity == nil { return }
|
||||
if button != input.ButtonLeft { return }
|
||||
element.pressed = false
|
||||
within := image.Point { x, y }.In(element.entity.Bounds())
|
||||
if element.Enabled() && within && element.onClick != nil {
|
||||
element.onClick()
|
||||
}
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
func (element *Button) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||
if element.entity == nil { return }
|
||||
if !element.Enabled() { return }
|
||||
if key == input.KeyEnter {
|
||||
element.pressed = true
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) {
|
||||
if element.entity == nil { return }
|
||||
if key == input.KeyEnter && element.pressed {
|
||||
element.pressed = false
|
||||
element.entity.Invalidate()
|
||||
if !element.Enabled() { return }
|
||||
if element.onClick != nil {
|
||||
element.onClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Button) updateMinimumSize () {
|
||||
padding := element.theme.Padding(tomo.PatternButton)
|
||||
margin := element.theme.Margin(tomo.PatternButton)
|
||||
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
minimumSize := textBounds.Sub(textBounds.Min)
|
||||
|
||||
if element.hasIcon {
|
||||
icon := element.theme.Icon(element.iconId, tomo.IconSizeSmall)
|
||||
if icon != nil {
|
||||
bounds := icon.Bounds()
|
||||
if element.showText {
|
||||
minimumSize.Max.X += bounds.Dx()
|
||||
minimumSize.Max.X += margin.X
|
||||
} else {
|
||||
minimumSize.Max.X = bounds.Dx()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minimumSize = padding.Inverse().Apply(minimumSize)
|
||||
element.entity.SetMinimumSize(minimumSize.Dx(), minimumSize.Dy())
|
||||
}
|
||||
|
||||
func (element *Button) state () tomo.State {
|
||||
return tomo.State {
|
||||
Disabled: !element.Enabled(),
|
||||
Focused: element.entity.Focused(),
|
||||
Pressed: element.pressed,
|
||||
}
|
||||
}
|
||||
|
@ -3,19 +3,17 @@ package elements
|
||||
import "image"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// Checkbox is a toggle-able checkbox with a label.
|
||||
type Checkbox struct {
|
||||
*core.Core
|
||||
*core.FocusableCore
|
||||
core core.CoreControl
|
||||
focusableControl core.FocusableCoreControl
|
||||
entity tomo.FocusableEntity
|
||||
drawer textdraw.Drawer
|
||||
|
||||
enabled bool
|
||||
pressed bool
|
||||
checked bool
|
||||
text string
|
||||
@ -30,9 +28,6 @@ type Checkbox struct {
|
||||
func NewCheckbox (text string, checked bool) (element *Checkbox) {
|
||||
element = &Checkbox { checked: checked }
|
||||
element.theme.Case = tomo.C("tomo", "checkbox")
|
||||
element.Core, element.core = core.NewCore(element, element.draw)
|
||||
element.FocusableCore,
|
||||
element.focusableControl = core.NewFocusableCore(element.core, element.redo)
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
@ -40,57 +35,11 @@ func NewCheckbox (text string, checked bool) (element *Checkbox) {
|
||||
return
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) {
|
||||
if !element.Enabled() { return }
|
||||
element.Focus()
|
||||
element.pressed = true
|
||||
if element.core.HasImage() {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleMouseUp (x, y int, button input.Button) {
|
||||
if button != input.ButtonLeft || !element.pressed { return }
|
||||
|
||||
element.pressed = false
|
||||
within := image.Point { x, y }.
|
||||
In(element.Bounds())
|
||||
if within {
|
||||
element.checked = !element.checked
|
||||
}
|
||||
|
||||
if element.core.HasImage() {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
if within && element.onToggle != nil {
|
||||
element.onToggle()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||
if key == input.KeyEnter {
|
||||
element.pressed = true
|
||||
if element.core.HasImage() {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
|
||||
if key == input.KeyEnter && element.pressed {
|
||||
element.pressed = false
|
||||
element.checked = !element.checked
|
||||
if element.core.HasImage() {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
if element.onToggle != nil {
|
||||
element.onToggle()
|
||||
}
|
||||
}
|
||||
// Bind binds this element to an entity.
|
||||
func (element *Checkbox) Bind (entity tomo.Entity) {
|
||||
if entity == nil { element.entity = nil; return }
|
||||
element.entity = entity.(tomo.FocusableEntity)
|
||||
element.updateMinimumSize()
|
||||
}
|
||||
|
||||
// OnToggle sets the function to be called when the checkbox is toggled.
|
||||
@ -103,23 +52,33 @@ func (element *Checkbox) Value () (checked bool) {
|
||||
return element.checked
|
||||
}
|
||||
|
||||
// Focus gives this element input focus.
|
||||
func (element *Checkbox) Focus () {
|
||||
if element.entity == nil { return }
|
||||
if !element.entity.Focused() { element.entity.Focus() }
|
||||
}
|
||||
|
||||
// Enabled returns whether this checkbox is enabled or not.
|
||||
func (element *Checkbox) Enabled () bool {
|
||||
return element.enabled
|
||||
}
|
||||
|
||||
// SetEnabled sets whether this checkbox can be toggled or not.
|
||||
func (element *Checkbox) SetEnabled (enabled bool) {
|
||||
element.focusableControl.SetEnabled(enabled)
|
||||
if element.enabled == enabled { return }
|
||||
element.enabled = enabled
|
||||
if element.entity == nil { return }
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetText sets the checkbox's label text.
|
||||
func (element *Checkbox) SetText (text string) {
|
||||
if element.text == text { return }
|
||||
|
||||
element.text = text
|
||||
element.drawer.SetText([]rune(text))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetTheme sets the element's theme.
|
||||
@ -129,53 +88,38 @@ func (element *Checkbox) SetTheme (new tomo.Theme) {
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.redo()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetConfig sets the element's configuration.
|
||||
func (element *Checkbox) SetConfig (new tomo.Config) {
|
||||
if new == element.config.Config { return }
|
||||
element.config.Config = new
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.redo()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
func (element *Checkbox) updateMinimumSize () {
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
if element.text == "" {
|
||||
element.core.SetMinimumSize(textBounds.Dy(), textBounds.Dy())
|
||||
} else {
|
||||
margin := element.theme.Margin(tomo.PatternBackground)
|
||||
element.core.SetMinimumSize (
|
||||
textBounds.Dy() + margin.X + textBounds.Dx(),
|
||||
textBounds.Dy())
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) redo () {
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) draw () {
|
||||
bounds := element.Bounds()
|
||||
// Draw causes the element to draw to the specified destination canvas.
|
||||
func (element *Checkbox) Draw (destination canvas.Canvas) {
|
||||
if element.entity == nil { return }
|
||||
|
||||
bounds := element.entity.Bounds()
|
||||
boxBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy()).Add(bounds.Min)
|
||||
|
||||
state := tomo.State {
|
||||
Disabled: !element.Enabled(),
|
||||
Focused: element.Focused(),
|
||||
Focused: element.entity.Focused(),
|
||||
Pressed: element.pressed,
|
||||
On: element.checked,
|
||||
}
|
||||
|
||||
element.core.DrawBackground (
|
||||
element.theme.Pattern(tomo.PatternBackground, state))
|
||||
element.entity.DrawBackground(destination, bounds)
|
||||
|
||||
pattern := element.theme.Pattern(tomo.PatternButton, state)
|
||||
pattern.Draw(element.core, boxBounds)
|
||||
pattern.Draw(destination, boxBounds)
|
||||
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
margin := element.theme.Margin(tomo.PatternBackground)
|
||||
@ -187,5 +131,61 @@ func (element *Checkbox) draw () {
|
||||
offset.X -= textBounds.Min.X
|
||||
|
||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
||||
element.drawer.Draw(element.core, foreground, offset)
|
||||
element.drawer.Draw(destination, foreground, offset)
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) {
|
||||
if element.entity == nil { return }
|
||||
if !element.Enabled() { return }
|
||||
element.Focus()
|
||||
element.pressed = true
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleMouseUp (x, y int, button input.Button) {
|
||||
if element.entity == nil { return }
|
||||
if button != input.ButtonLeft || !element.pressed { return }
|
||||
|
||||
element.pressed = false
|
||||
within := image.Point { x, y }.In(element.entity.Bounds())
|
||||
if within {
|
||||
element.checked = !element.checked
|
||||
}
|
||||
|
||||
element.entity.Invalidate()
|
||||
if within && element.onToggle != nil {
|
||||
element.onToggle()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||
if element.entity == nil { return }
|
||||
if key == input.KeyEnter {
|
||||
element.pressed = true
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
|
||||
if element.entity == nil { return }
|
||||
if key == input.KeyEnter && element.pressed {
|
||||
element.pressed = false
|
||||
element.checked = !element.checked
|
||||
element.entity.Invalidate()
|
||||
if element.onToggle != nil {
|
||||
element.onToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Checkbox) updateMinimumSize () {
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
if element.text == "" {
|
||||
element.entity.SetMinimumSize(textBounds.Dy(), textBounds.Dy())
|
||||
} else {
|
||||
margin := element.theme.Margin(tomo.PatternBackground)
|
||||
element.entity.SetMinimumSize (
|
||||
textBounds.Dy() + margin.X + textBounds.Dx(),
|
||||
textBounds.Dy())
|
||||
}
|
||||
}
|
||||
|
@ -2,47 +2,72 @@ package elements
|
||||
|
||||
import "image"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
|
||||
// Icon is an element capable of displaying a singular icon.
|
||||
type Icon struct {
|
||||
*core.Core
|
||||
core core.CoreControl
|
||||
theme theme.Wrapped
|
||||
id tomo.Icon
|
||||
size tomo.IconSize
|
||||
entity tomo.Entity
|
||||
theme theme.Wrapped
|
||||
id tomo.Icon
|
||||
size tomo.IconSize
|
||||
}
|
||||
|
||||
// Icon creates a new icon element.
|
||||
func NewIcon (id tomo.Icon, size tomo.IconSize) (element *Icon) {
|
||||
element = &Icon {
|
||||
id: id,
|
||||
size: size,
|
||||
}
|
||||
element.theme.Case = tomo.C("tomo", "icon")
|
||||
element.Core, element.core = core.NewCore(element, element.draw)
|
||||
element.updateMinimumSize()
|
||||
return
|
||||
}
|
||||
|
||||
// Bind binds this element to an entity.
|
||||
func (element *Icon) Bind (entity tomo.Entity) {
|
||||
if entity == nil { element.entity = nil; return }
|
||||
element.entity = entity
|
||||
element.updateMinimumSize()
|
||||
}
|
||||
|
||||
// SetIcon sets the element's icon.
|
||||
func (element *Icon) SetIcon (id tomo.Icon, size tomo.IconSize) {
|
||||
element.id = id
|
||||
element.size = size
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
if element.core.HasImage() {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetTheme sets the element's theme.
|
||||
func (element *Icon) SetTheme (new tomo.Theme) {
|
||||
if new == element.theme.Theme { return }
|
||||
element.theme.Theme = new
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
if element.core.HasImage() {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// Draw causes the element to draw to the specified destination canvas.
|
||||
func (element *Icon) Draw (destination canvas.Canvas) {
|
||||
if element.entity == nil { return }
|
||||
|
||||
bounds := element.entity.Bounds()
|
||||
state := tomo.State { }
|
||||
element.theme.
|
||||
Pattern(tomo.PatternBackground, state).
|
||||
Draw(destination, bounds)
|
||||
icon := element.icon()
|
||||
if icon != nil {
|
||||
iconBounds := icon.Bounds()
|
||||
offset := image.Pt (
|
||||
(bounds.Dx() - iconBounds.Dx()) / 2,
|
||||
(bounds.Dy() - iconBounds.Dy()) / 2)
|
||||
icon.Draw (
|
||||
destination,
|
||||
element.theme.Color(tomo.ColorForeground, state),
|
||||
bounds.Min.Add(offset))
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,28 +78,9 @@ func (element *Icon) icon () artist.Icon {
|
||||
func (element *Icon) updateMinimumSize () {
|
||||
icon := element.icon()
|
||||
if icon == nil {
|
||||
element.core.SetMinimumSize(0, 0)
|
||||
element.entity.SetMinimumSize(0, 0)
|
||||
} else {
|
||||
bounds := icon.Bounds()
|
||||
element.core.SetMinimumSize(bounds.Dx(), bounds.Dy())
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Icon) draw () {
|
||||
bounds := element.Bounds()
|
||||
state := tomo.State { }
|
||||
element.theme.
|
||||
Pattern(tomo.PatternBackground, state).
|
||||
Draw(element.core, bounds)
|
||||
icon := element.icon()
|
||||
if icon != nil {
|
||||
iconBounds := icon.Bounds()
|
||||
offset := image.Pt (
|
||||
(bounds.Dx() - iconBounds.Dx()) / 2,
|
||||
(bounds.Dy() - iconBounds.Dy()) / 2)
|
||||
icon.Draw (
|
||||
element.core,
|
||||
element.theme.Color(tomo.ColorForeground, state),
|
||||
bounds.Min.Add(offset))
|
||||
element.entity.SetMinimumSize(bounds.Dx(), bounds.Dy())
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,35 @@
|
||||
package elements
|
||||
|
||||
import "image"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/artist/patterns"
|
||||
|
||||
// TODO: this element is lame need to make it better
|
||||
|
||||
// Image is an element capable of displaying an image.
|
||||
type Image struct {
|
||||
*core.Core
|
||||
core core.CoreControl
|
||||
entity tomo.Entity
|
||||
buffer canvas.Canvas
|
||||
}
|
||||
|
||||
// NewImage creates a new image element.
|
||||
func NewImage (image image.Image) (element *Image) {
|
||||
element = &Image { buffer: canvas.FromImage(image) }
|
||||
element.Core, element.core = core.NewCore(element, element.draw)
|
||||
bounds := image.Bounds()
|
||||
element.core.SetMinimumSize(bounds.Dx(), bounds.Dy())
|
||||
return
|
||||
}
|
||||
|
||||
func (element *Image) draw () {
|
||||
(patterns.Texture { Canvas: element.buffer }).
|
||||
Draw(element.core, element.Bounds())
|
||||
// Bind binds this element to an entity.
|
||||
func (element *Image) Bind (entity tomo.Entity) {
|
||||
if entity == nil { element.entity = nil; return }
|
||||
element.entity = entity
|
||||
bounds := element.buffer.Bounds()
|
||||
element.entity.SetMinimumSize(bounds.Dx(), bounds.Dy())
|
||||
}
|
||||
|
||||
// Draw causes the element to draw to the specified destination canvas.
|
||||
func (element *Image) Draw (destination canvas.Canvas) {
|
||||
if element.entity == nil { return }
|
||||
(patterns.Texture { Canvas: element.buffer }).
|
||||
Draw(destination, element.entity.Bounds())
|
||||
}
|
||||
|
@ -2,16 +2,15 @@ package elements
|
||||
|
||||
import "golang.org/x/image/math/fixed"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// Label is a simple text box.
|
||||
type Label struct {
|
||||
*core.Core
|
||||
core core.CoreControl
|
||||
|
||||
entity tomo.FlexibleEntity
|
||||
|
||||
align textdraw.Align
|
||||
wrap bool
|
||||
text string
|
||||
@ -19,11 +18,10 @@ type Label struct {
|
||||
|
||||
forcedColumns int
|
||||
forcedRows int
|
||||
minHeight int
|
||||
|
||||
config config.Wrapped
|
||||
theme theme.Wrapped
|
||||
|
||||
onFlexibleHeightChange func ()
|
||||
}
|
||||
|
||||
// NewLabel creates a new label. If wrap is set to true, the text inside will be
|
||||
@ -31,7 +29,6 @@ type Label struct {
|
||||
func NewLabel (text string, wrap bool) (element *Label) {
|
||||
element = &Label { }
|
||||
element.theme.Case = tomo.C("tomo", "label")
|
||||
element.Core, element.core = core.NewCore(element, element.handleResize)
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
@ -40,29 +37,11 @@ func NewLabel (text string, wrap bool) (element *Label) {
|
||||
return
|
||||
}
|
||||
|
||||
func (element *Label) redo () {
|
||||
face := element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal)
|
||||
element.drawer.SetFace(face)
|
||||
// Bind binds this element to an entity.
|
||||
func (element *Label) Bind (entity tomo.Entity) {
|
||||
if entity == nil { element.entity = nil; return }
|
||||
element.entity = entity.(tomo.FlexibleEntity)
|
||||
element.updateMinimumSize()
|
||||
bounds := element.Bounds()
|
||||
if element.wrap {
|
||||
element.drawer.SetMaxWidth(bounds.Dx())
|
||||
element.drawer.SetMaxHeight(bounds.Dy())
|
||||
}
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
|
||||
func (element *Label) handleResize () {
|
||||
bounds := element.Bounds()
|
||||
if element.wrap {
|
||||
element.drawer.SetMaxWidth(bounds.Dx())
|
||||
element.drawer.SetMaxHeight(bounds.Dy())
|
||||
}
|
||||
element.draw()
|
||||
return
|
||||
}
|
||||
|
||||
// EmCollapse forces a minimum width and height upon the label. The width is
|
||||
@ -73,6 +52,7 @@ func (element *Label) handleResize () {
|
||||
func (element *Label) EmCollapse (columns int, rows int) {
|
||||
element.forcedColumns = columns
|
||||
element.forcedRows = rows
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
}
|
||||
|
||||
@ -82,29 +62,19 @@ func (element *Label) FlexibleHeightFor (width int) (height int) {
|
||||
if element.wrap {
|
||||
return element.drawer.ReccomendedHeightFor(width)
|
||||
} else {
|
||||
_, height = element.MinimumSize()
|
||||
return
|
||||
return element.minHeight
|
||||
}
|
||||
}
|
||||
|
||||
// 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 }
|
||||
|
||||
element.text = text
|
||||
element.drawer.SetText([]rune(text))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetWrap sets wether or not the label's text wraps. If the text is set to
|
||||
@ -118,26 +88,19 @@ func (element *Label) SetWrap (wrap bool) {
|
||||
element.drawer.SetMaxHeight(0)
|
||||
}
|
||||
element.wrap = wrap
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetAlign sets the alignment method of the label.
|
||||
func (element *Label) SetAlign (align textdraw.Align) {
|
||||
if align == element.align { return }
|
||||
|
||||
element.align = align
|
||||
element.drawer.SetAlign(align)
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetTheme sets the element's theme.
|
||||
@ -147,24 +110,38 @@ func (element *Label) SetTheme (new tomo.Theme) {
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetConfig sets the element's configuration.
|
||||
func (element *Label) SetConfig (new tomo.Config) {
|
||||
if new == element.config.Config { return }
|
||||
element.config.Config = new
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// Draw causes the element to draw to the specified destination canvas.
|
||||
func (element *Label) Draw (destination canvas.Canvas) {
|
||||
if element.entity == nil { return }
|
||||
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
bounds := element.entity. Bounds()
|
||||
|
||||
if element.wrap {
|
||||
element.drawer.SetMaxWidth(bounds.Dx())
|
||||
element.drawer.SetMaxHeight(bounds.Dy())
|
||||
}
|
||||
|
||||
element.entity.DrawBackground(destination, bounds)
|
||||
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
foreground := element.theme.Color (
|
||||
tomo.ColorForeground,
|
||||
tomo.State { })
|
||||
element.drawer.Draw(destination, foreground, bounds.Min.Sub(textBounds.Min))
|
||||
}
|
||||
|
||||
func (element *Label) updateMinimumSize () {
|
||||
@ -176,9 +153,8 @@ func (element *Label) updateMinimumSize () {
|
||||
em = element.theme.Padding(tomo.PatternBackground)[0]
|
||||
}
|
||||
width, height = em, element.drawer.LineHeight().Round()
|
||||
if element.onFlexibleHeightChange != nil {
|
||||
element.onFlexibleHeightChange()
|
||||
}
|
||||
// FIXME we shoudl not have to pass in the element here
|
||||
element.entity.NotifyFlexibleHeightChange(element)
|
||||
} else {
|
||||
bounds := element.drawer.LayoutBounds()
|
||||
width, height = bounds.Dx(), bounds.Dy()
|
||||
@ -196,18 +172,6 @@ func (element *Label) updateMinimumSize () {
|
||||
Mul(fixed.I(element.forcedRows)).Floor()
|
||||
}
|
||||
|
||||
element.core.SetMinimumSize(width, height)
|
||||
}
|
||||
|
||||
func (element *Label) draw () {
|
||||
element.core.DrawBackground (
|
||||
element.theme.Pattern(tomo.PatternBackground, tomo.State { }))
|
||||
|
||||
bounds := element.Bounds()
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
|
||||
foreground := element.theme.Color (
|
||||
tomo.ColorForeground,
|
||||
tomo.State { })
|
||||
element.drawer.Draw(element.core, foreground, bounds.Min.Sub(textBounds.Min))
|
||||
element.minHeight = height
|
||||
element.entity.SetMinimumSize(width, height)
|
||||
}
|
||||
|
177
elements/notdone/label.go
Normal file
177
elements/notdone/label.go
Normal file
@ -0,0 +1,177 @@
|
||||
package elements
|
||||
|
||||
import "golang.org/x/image/math/fixed"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// Label is a simple text box.
|
||||
type Label struct {
|
||||
entity tomo.FlexibleEntity
|
||||
|
||||
align textdraw.Align
|
||||
wrap bool
|
||||
text string
|
||||
drawer textdraw.Drawer
|
||||
|
||||
forcedColumns int
|
||||
forcedRows int
|
||||
minHeight int
|
||||
|
||||
config config.Wrapped
|
||||
theme theme.Wrapped
|
||||
}
|
||||
|
||||
// NewLabel creates a new label. If wrap is set to true, the text inside will be
|
||||
// wrapped.
|
||||
func NewLabel (text string, wrap bool) (element *Label) {
|
||||
element = &Label { }
|
||||
element.theme.Case = tomo.C("tomo", "label")
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
element.SetWrap(wrap)
|
||||
element.SetText(text)
|
||||
return
|
||||
}
|
||||
|
||||
// Bind binds this element to an entity.
|
||||
func (element *Label) Bind (entity tomo.Entity) {
|
||||
element.entity = entity.(tomo.FlexibleEntity)
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
}
|
||||
|
||||
// EmCollapse forces a minimum width and height upon the label. The width is
|
||||
// measured in emspaces, and the height is measured in lines. If a zero value is
|
||||
// given for a dimension, its minimum will be determined by the label's content.
|
||||
// If the label's content is greater than these dimensions, it will be truncated
|
||||
// to fit.
|
||||
func (element *Label) EmCollapse (columns int, rows int) {
|
||||
element.forcedColumns = columns
|
||||
element.forcedRows = rows
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return element.minHeight
|
||||
}
|
||||
}
|
||||
|
||||
// SetText sets the label's text.
|
||||
func (element *Label) SetText (text string) {
|
||||
if element.text == text { return }
|
||||
|
||||
element.text = text
|
||||
element.drawer.SetText([]rune(text))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetWrap sets wether or not the label's text wraps. If the text is set to
|
||||
// wrap, the element will have a minimum size of a single character and
|
||||
// automatically wrap its text. If the text is set to not wrap, the element will
|
||||
// have a minimum size that fits its text.
|
||||
func (element *Label) SetWrap (wrap bool) {
|
||||
if wrap == element.wrap { return }
|
||||
if !wrap {
|
||||
element.drawer.SetMaxWidth(0)
|
||||
element.drawer.SetMaxHeight(0)
|
||||
}
|
||||
element.wrap = wrap
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetAlign sets the alignment method of the label.
|
||||
func (element *Label) SetAlign (align textdraw.Align) {
|
||||
if align == element.align { return }
|
||||
element.align = align
|
||||
element.drawer.SetAlign(align)
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetTheme sets the element's theme.
|
||||
func (element *Label) SetTheme (new tomo.Theme) {
|
||||
if new == element.theme.Theme { return }
|
||||
element.theme.Theme = new
|
||||
element.drawer.SetFace (element.theme.FontFace (
|
||||
tomo.FontStyleRegular,
|
||||
tomo.FontSizeNormal))
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetConfig sets the element's configuration.
|
||||
func (element *Label) SetConfig (new tomo.Config) {
|
||||
if new == element.config.Config { return }
|
||||
element.config.Config = new
|
||||
if element.entity == nil { return }
|
||||
element.updateMinimumSize()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// Draw causes the element to draw to the specified destination canvas.
|
||||
func (element *Label) Draw (destination canvas.Canvas) {
|
||||
if element.entity == nil { return }
|
||||
|
||||
bounds := element.entity. Bounds()
|
||||
|
||||
if element.wrap {
|
||||
element.drawer.SetMaxWidth(bounds.Dx())
|
||||
element.drawer.SetMaxHeight(bounds.Dy())
|
||||
}
|
||||
|
||||
element.entity.DrawBackground(destination, bounds)
|
||||
|
||||
textBounds := element.drawer.LayoutBounds()
|
||||
foreground := element.theme.Color (
|
||||
tomo.ColorForeground,
|
||||
tomo.State { })
|
||||
element.drawer.Draw(destination, foreground, bounds.Min.Sub(textBounds.Min))
|
||||
}
|
||||
|
||||
func (element *Label) updateMinimumSize () {
|
||||
var width, height int
|
||||
|
||||
if element.wrap {
|
||||
em := element.drawer.Em().Round()
|
||||
if em < 1 {
|
||||
em = element.theme.Padding(tomo.PatternBackground)[0]
|
||||
}
|
||||
width, height = em, element.drawer.LineHeight().Round()
|
||||
// FIXME we shoudl not have to pass in the element here
|
||||
element.entity.NotifyFlexibleHeightChange(element)
|
||||
} else {
|
||||
bounds := element.drawer.LayoutBounds()
|
||||
width, height = bounds.Dx(), bounds.Dy()
|
||||
}
|
||||
|
||||
if element.forcedColumns > 0 {
|
||||
width =
|
||||
element.drawer.Em().
|
||||
Mul(fixed.I(element.forcedColumns)).Floor()
|
||||
}
|
||||
|
||||
if element.forcedRows > 0 {
|
||||
height =
|
||||
element.drawer.LineHeight().
|
||||
Mul(fixed.I(element.forcedRows)).Floor()
|
||||
}
|
||||
|
||||
element.minHeight = height
|
||||
element.entity.SetMinimumSize(width, height)
|
||||
}
|
@ -6,17 +6,18 @@ import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
type listEntity interface {
|
||||
tomo.FlexibleEntity
|
||||
tomo.ContainerEntity
|
||||
tomo.ScrollableEntity
|
||||
}
|
||||
|
||||
// List is an element that contains several objects that a user can select.
|
||||
type List struct {
|
||||
*core.Core
|
||||
*core.FocusableCore
|
||||
core core.CoreControl
|
||||
focusableControl core.FocusableCoreControl
|
||||
|
||||
entity listEntity
|
||||
pressed bool
|
||||
|
||||
contentHeight int
|
||||
@ -25,7 +26,6 @@ type List struct {
|
||||
|
||||
selectedEntry int
|
||||
scroll int
|
||||
entries []ListEntry
|
||||
|
||||
config config.Wrapped
|
||||
theme theme.Wrapped
|
||||
@ -38,36 +38,14 @@ type List struct {
|
||||
func NewList (entries ...ListEntry) (element *List) {
|
||||
element = &List { selectedEntry: -1 }
|
||||
element.theme.Case = tomo.C("tomo", "list")
|
||||
element.Core, element.core = core.NewCore(element, element.handleResize)
|
||||
element.FocusableCore,
|
||||
element.focusableControl = core.NewFocusableCore (element.core, func () {
|
||||
if element.core.HasImage () {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
})
|
||||
|
||||
element.entries = make([]ListEntry, len(entries))
|
||||
for index, entry := range entries {
|
||||
element.entries[index] = entry
|
||||
}
|
||||
|
||||
element.updateMinimumSize()
|
||||
return
|
||||
}
|
||||
|
||||
func (element *List) handleResize () {
|
||||
for index, entry := range element.entries {
|
||||
element.entries[index] = element.resizeEntryToFit(entry)
|
||||
}
|
||||
|
||||
if element.scroll > element.maxScrollHeight() {
|
||||
element.scroll = element.maxScrollHeight()
|
||||
}
|
||||
element.draw()
|
||||
element.scrollBoundsChange()
|
||||
}
|
||||
|
||||
// SetTheme sets the element's theme.
|
||||
func (element *List) SetTheme (new tomo.Theme) {
|
||||
if new == element.theme.Theme { return }
|
||||
@ -77,7 +55,7 @@ func (element *List) SetTheme (new tomo.Theme) {
|
||||
element.entries[index] = entry
|
||||
}
|
||||
element.updateMinimumSize()
|
||||
element.redo()
|
||||
element.entity.Invalidate()
|
||||
}
|
||||
|
||||
// SetConfig sets the element's configuration.
|
||||
@ -92,18 +70,6 @@ func (element *List) SetConfig (new tomo.Config) {
|
||||
element.redo()
|
||||
}
|
||||
|
||||
func (element *List) redo () {
|
||||
for index, entry := range element.entries {
|
||||
element.entries[index] = element.resizeEntryToFit(entry)
|
||||
}
|
||||
|
||||
if element.core.HasImage() {
|
||||
element.draw()
|
||||
element.core.DamageAll()
|
||||
}
|
||||
element.scrollBoundsChange()
|
||||
}
|
||||
|
||||
// Collapse forces a minimum width and height upon the list. If a zero value is
|
||||
// given for a dimension, its minimum will be determined by the list's content.
|
||||
// If the list's height goes beyond the forced size, it will need to be accessed
|
||||
@ -213,19 +179,6 @@ func (element *List) ScrollAxes () (horizontal, vertical bool) {
|
||||
return false, true
|
||||
}
|
||||
|
||||
func (element *List) scrollViewportHeight () (height int) {
|
||||
padding := element.theme.Padding(tomo.PatternSunken)
|
||||
return element.Bounds().Dy() - padding[0] - padding[2]
|
||||
}
|
||||
|
||||
func (element *List) maxScrollHeight () (height int) {
|
||||
height =
|
||||
element.contentHeight -
|
||||
element.scrollViewportHeight()
|
||||
if height < 0 { height = 0 }
|
||||
return
|
||||
}
|
||||
|
||||
// OnNoEntrySelected sets a function to be called when the user chooses to
|
||||
// deselect the current selected entry by clicking on empty space within the
|
||||
// list or by pressing the escape key.
|
||||
@ -443,7 +396,32 @@ func (element *List) scrollBoundsChange () {
|
||||
}
|
||||
}
|
||||
|
||||
func (element *List) draw () {
|
||||
func (element *List) scrollViewportHeight () (height int) {
|
||||
padding := element.theme.Padding(tomo.PatternSunken)
|
||||
return element.Bounds().Dy() - padding[0] - padding[2]
|
||||
}
|
||||
|
||||
func (element *List) maxScrollHeight () (height int) {
|
||||
height =
|
||||
element.contentHeight -
|
||||
element.scrollViewportHeight()
|
||||
if height < 0 { height = 0 }
|
||||
return
|
||||
}
|
||||
|
||||
func (element *List) Layout () {
|
||||
for index, entry := range element.entries {
|
||||
element.entries[index] = element.resizeEntryToFit(entry)
|
||||
}
|
||||
|
||||
if element.scroll > element.maxScrollHeight() {
|
||||
element.scroll = element.maxScrollHeight()
|
||||
}
|
||||
element.draw()
|
||||
element.scrollBoundsChange()
|
||||
}
|
||||
|
||||
func (element *List) Draw (destination canvas.Canvas) {
|
||||
bounds := element.Bounds()
|
||||
padding := element.theme.Padding(tomo.PatternSunken)
|
||||
innerBounds := padding.Apply(bounds)
|
@ -2,14 +2,11 @@ package elements
|
||||
|
||||
import "image"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// ProgressBar displays a visual indication of how far along a task is.
|
||||
type ProgressBar struct {
|
||||
*core.Core
|
||||
core core.CoreControl
|
||||
progress float64
|
||||
|
||||
config config.Wrapped
|
@ -3,7 +3,6 @@ package elements
|
||||
import "image"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
@ -19,9 +18,6 @@ import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
// Typically, you wont't want to use a ScrollBar by itself. A ScrollContainer is
|
||||
// better for most cases.
|
||||
type ScrollBar struct {
|
||||
*core.Core
|
||||
core core.CoreControl
|
||||
|
||||
vertical bool
|
||||
enabled bool
|
||||
dragging bool
|
@ -3,17 +3,11 @@ package elements
|
||||
import "image"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// Slider is a slider control with a floating point value between zero and one.
|
||||
type Slider struct {
|
||||
*core.Core
|
||||
*core.FocusableCore
|
||||
core core.CoreControl
|
||||
focusableControl core.FocusableCoreControl
|
||||
|
||||
value float64
|
||||
vertical bool
|
||||
dragging bool
|
@ -1,14 +1,11 @@
|
||||
package elements
|
||||
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// Spacer can be used to put space between two elements..
|
||||
type Spacer struct {
|
||||
*core.Core
|
||||
core core.CoreControl
|
||||
line bool
|
||||
|
||||
config config.Wrapped
|
@ -4,17 +4,12 @@ import "image"
|
||||
import "git.tebibyte.media/sashakoshka/tomo"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// Switch is a toggle-able on/off switch with an optional label. It is
|
||||
// functionally identical to Checkbox, but plays a different semantic role.
|
||||
type Switch struct {
|
||||
*core.Core
|
||||
*core.FocusableCore
|
||||
core core.CoreControl
|
||||
focusableControl core.FocusableCoreControl
|
||||
drawer textdraw.Drawer
|
||||
|
||||
pressed bool
|
@ -12,17 +12,11 @@ import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/textmanip"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/fixedutil"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/artist/shapes"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||
|
||||
// TextBox is a single-line text input.
|
||||
type TextBox struct {
|
||||
*core.Core
|
||||
*core.FocusableCore
|
||||
core core.CoreControl
|
||||
focusableControl core.FocusableCoreControl
|
||||
|
||||
lastClick time.Time
|
||||
dragging int
|
||||
dot textmanip.Dot
|
Reference in New Issue
Block a user