ough
This commit is contained in:
parent
9e754cdb59
commit
72fc28e223
@ -4,7 +4,6 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/shatter"
|
import "git.tebibyte.media/sashakoshka/tomo/shatter"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
|
||||||
|
|
||||||
var boxCase = tomo.C("tomo", "box")
|
var boxCase = tomo.C("tomo", "box")
|
||||||
|
|
||||||
|
@ -4,9 +4,10 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||||
|
|
||||||
|
var buttonCase = tomo.C("tomo", "button")
|
||||||
|
|
||||||
// Button is a clickable button.
|
// Button is a clickable button.
|
||||||
type Button struct {
|
type Button struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -26,11 +27,11 @@ type Button struct {
|
|||||||
// NewButton creates a new button with the specified label text.
|
// NewButton creates a new button with the specified label text.
|
||||||
func NewButton (text string) (element *Button) {
|
func NewButton (text string) (element *Button) {
|
||||||
element = &Button { showText: true, enabled: true }
|
element = &Button { showText: true, enabled: true }
|
||||||
element.entity = tomo.NewEntity(element).(buttonEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "button")
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal,
|
||||||
|
buttonCase))
|
||||||
element.SetText(text)
|
element.SetText(text)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -44,13 +45,13 @@ func (element *Button) Entity () tomo.Entity {
|
|||||||
func (element *Button) Draw (destination artist.Canvas) {
|
func (element *Button) Draw (destination artist.Canvas) {
|
||||||
state := element.state()
|
state := element.state()
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
pattern := element.theme.Pattern(tomo.PatternButton, state)
|
pattern := element.entity.Theme().Pattern(tomo.PatternButton, state, buttonCase)
|
||||||
|
|
||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
|
|
||||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
foreground := element.entity.Theme().Color(tomo.ColorForeground, state, buttonCase)
|
||||||
sink := element.theme.Sink(tomo.PatternButton)
|
sink := element.entity.Theme().Sink(tomo.PatternButton, buttonCase)
|
||||||
margin := element.theme.Margin(tomo.PatternButton)
|
margin := element.entity.Theme().Margin(tomo.PatternButton, buttonCase)
|
||||||
|
|
||||||
offset := image.Pt (
|
offset := image.Pt (
|
||||||
bounds.Dx() / 2,
|
bounds.Dx() / 2,
|
||||||
@ -65,7 +66,7 @@ func (element *Button) Draw (destination artist.Canvas) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if element.hasIcon {
|
if element.hasIcon {
|
||||||
icon := element.theme.Icon(element.iconId, tomo.IconSizeSmall)
|
icon := element.entity.Theme().Icon(element.iconId, tomo.IconSizeSmall, buttonCase)
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
iconBounds := icon.Bounds()
|
iconBounds := icon.Bounds()
|
||||||
addedWidth := iconBounds.Dx()
|
addedWidth := iconBounds.Dx()
|
||||||
@ -150,21 +151,11 @@ func (element *Button) ShowText (showText bool) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Button) HandleThemeChange () {
|
||||||
func (element *Button) SetTheme (new tomo.Theme) {
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal,
|
||||||
element.updateMinimumSize()
|
buttonCase))
|
||||||
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
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -219,14 +210,14 @@ func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Button) updateMinimumSize () {
|
func (element *Button) updateMinimumSize () {
|
||||||
padding := element.theme.Padding(tomo.PatternButton)
|
padding := element.entity.Theme().Padding(tomo.PatternButton, buttonCase)
|
||||||
margin := element.theme.Margin(tomo.PatternButton)
|
margin := element.entity.Theme().Margin(tomo.PatternButton, buttonCase)
|
||||||
|
|
||||||
textBounds := element.drawer.LayoutBounds()
|
textBounds := element.drawer.LayoutBounds()
|
||||||
minimumSize := textBounds.Sub(textBounds.Min)
|
minimumSize := textBounds.Sub(textBounds.Min)
|
||||||
|
|
||||||
if element.hasIcon {
|
if element.hasIcon {
|
||||||
icon := element.theme.Icon(element.iconId, tomo.IconSizeSmall)
|
icon := element.entity.Theme().Icon(element.iconId, tomo.IconSizeSmall, buttonCase)
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
bounds := icon.Bounds()
|
bounds := icon.Bounds()
|
||||||
if element.showText {
|
if element.showText {
|
||||||
|
@ -2,8 +2,9 @@ package elements
|
|||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
import "git.tebibyte.media/sashakoshka/tomo/artist/artutil"
|
||||||
|
|
||||||
|
var cellCase = tomo.C("tomo", "cell")
|
||||||
|
|
||||||
// Cell is a single-element container that satisfies tomo.Selectable. It
|
// Cell is a single-element container that satisfies tomo.Selectable. It
|
||||||
// provides styling based on whether or not it is selected.
|
// provides styling based on whether or not it is selected.
|
||||||
@ -20,8 +21,7 @@ type Cell struct {
|
|||||||
// method.
|
// method.
|
||||||
func NewCell (child tomo.Element) (element *Cell) {
|
func NewCell (child tomo.Element) (element *Cell) {
|
||||||
element = &Cell { enabled: true }
|
element = &Cell { enabled: true }
|
||||||
element.theme.Case = tomo.C("tomo", "cell")
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.entity = tomo.NewEntity(element).(cellEntity)
|
|
||||||
element.Adopt(child)
|
element.Adopt(child)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -34,11 +34,11 @@ func (element *Cell) Entity () tomo.Entity {
|
|||||||
// Draw causes the element to draw to the specified destination canvas.
|
// Draw causes the element to draw to the specified destination canvas.
|
||||||
func (element *Cell) Draw (destination artist.Canvas) {
|
func (element *Cell) Draw (destination artist.Canvas) {
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
pattern := element.theme.Pattern(tomo.PatternTableCell, element.state())
|
pattern := element.entity.Theme().Pattern(tomo.PatternTableCell, element.state(), cellCase)
|
||||||
if element.child == nil {
|
if element.child == nil {
|
||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
} else {
|
} else {
|
||||||
artist.DrawShatter (
|
artutil.DrawShatter (
|
||||||
destination, pattern, bounds,
|
destination, pattern, bounds,
|
||||||
element.child.Entity().Bounds())
|
element.child.Entity().Bounds())
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ func (element *Cell) Layout () {
|
|||||||
if element.child == nil { return }
|
if element.child == nil { return }
|
||||||
|
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
bounds = element.theme.Padding(tomo.PatternTableCell).Apply(bounds)
|
bounds = element.entity.Theme().Padding(tomo.PatternTableCell, cellCase).Apply(bounds)
|
||||||
|
|
||||||
element.entity.PlaceChild(0, bounds)
|
element.entity.PlaceChild(0, bounds)
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ func (element *Cell) Layout () {
|
|||||||
// DrawBackground draws this element's background pattern to the specified
|
// DrawBackground draws this element's background pattern to the specified
|
||||||
// destination canvas.
|
// destination canvas.
|
||||||
func (element *Cell) DrawBackground (destination artist.Canvas) {
|
func (element *Cell) DrawBackground (destination artist.Canvas) {
|
||||||
element.theme.Pattern(tomo.PatternTableCell, element.state()).
|
element.entity.Theme().Pattern(tomo.PatternTableCell, element.state(), cellCase).
|
||||||
Draw(destination, element.entity.Bounds())
|
Draw(destination, element.entity.Bounds())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,16 +96,6 @@ func (element *Cell) SetEnabled (enabled bool) {
|
|||||||
element.invalidateChild()
|
element.invalidateChild()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets this element's theme.
|
|
||||||
func (element *Cell) SetTheme (theme tomo.Theme) {
|
|
||||||
if theme == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = theme
|
|
||||||
element.updateMinimumSize()
|
|
||||||
element.entity.Invalidate()
|
|
||||||
element.invalidateChild()
|
|
||||||
element.entity.InvalidateLayout()
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnSelectionChange sets a function to be called when this element is selected
|
// OnSelectionChange sets a function to be called when this element is selected
|
||||||
// or unselected.
|
// or unselected.
|
||||||
func (element *Cell) OnSelectionChange (callback func ()) {
|
func (element *Cell) OnSelectionChange (callback func ()) {
|
||||||
@ -116,6 +106,13 @@ func (element *Cell) Selected () bool {
|
|||||||
return element.entity.Selected()
|
return element.entity.Selected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (element *Cell) HandleThemeChange () {
|
||||||
|
element.updateMinimumSize()
|
||||||
|
element.entity.Invalidate()
|
||||||
|
element.invalidateChild()
|
||||||
|
element.entity.InvalidateLayout()
|
||||||
|
}
|
||||||
|
|
||||||
func (element *Cell) HandleSelectionChange () {
|
func (element *Cell) HandleSelectionChange () {
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
element.invalidateChild()
|
element.invalidateChild()
|
||||||
@ -145,7 +142,7 @@ func (element *Cell) updateMinimumSize () {
|
|||||||
width += childWidth
|
width += childWidth
|
||||||
height += childHeight
|
height += childHeight
|
||||||
}
|
}
|
||||||
padding := element.theme.Padding(tomo.PatternTableCell)
|
padding := element.entity.Theme().Padding(tomo.PatternTableCell, cellCase)
|
||||||
width += padding.Horizontal()
|
width += padding.Horizontal()
|
||||||
height += padding.Vertical()
|
height += padding.Vertical()
|
||||||
|
|
||||||
|
@ -4,9 +4,10 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||||
|
|
||||||
|
var checkboxCase = tomo.C("tomo", "checkbox")
|
||||||
|
|
||||||
// Checkbox is a toggle-able checkbox with a label.
|
// Checkbox is a toggle-able checkbox with a label.
|
||||||
type Checkbox struct {
|
type Checkbox struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -23,11 +24,11 @@ type Checkbox struct {
|
|||||||
// NewCheckbox creates a new cbeckbox with the specified label text.
|
// NewCheckbox creates a new cbeckbox with the specified label text.
|
||||||
func NewCheckbox (text string, checked bool) (element *Checkbox) {
|
func NewCheckbox (text string, checked bool) (element *Checkbox) {
|
||||||
element = &Checkbox { checked: checked, enabled: true }
|
element = &Checkbox { checked: checked, enabled: true }
|
||||||
element.entity = tomo.NewEntity(element).(checkboxEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "checkbox")
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal,
|
||||||
|
checkboxCase))
|
||||||
element.SetText(text)
|
element.SetText(text)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -51,11 +52,11 @@ func (element *Checkbox) Draw (destination artist.Canvas) {
|
|||||||
|
|
||||||
element.entity.DrawBackground(destination)
|
element.entity.DrawBackground(destination)
|
||||||
|
|
||||||
pattern := element.theme.Pattern(tomo.PatternButton, state)
|
pattern := element.entity.Theme().Pattern(tomo.PatternButton, state, checkboxCase)
|
||||||
pattern.Draw(destination, boxBounds)
|
pattern.Draw(destination, boxBounds)
|
||||||
|
|
||||||
textBounds := element.drawer.LayoutBounds()
|
textBounds := element.drawer.LayoutBounds()
|
||||||
margin := element.theme.Margin(tomo.PatternBackground)
|
margin := element.entity.Theme().Margin(tomo.PatternBackground, checkboxCase)
|
||||||
offset := bounds.Min.Add(image.Point {
|
offset := bounds.Min.Add(image.Point {
|
||||||
X: bounds.Dy() + margin.X,
|
X: bounds.Dy() + margin.X,
|
||||||
})
|
})
|
||||||
@ -63,7 +64,7 @@ func (element *Checkbox) Draw (destination artist.Canvas) {
|
|||||||
offset.Y -= textBounds.Min.Y
|
offset.Y -= textBounds.Min.Y
|
||||||
offset.X -= textBounds.Min.X
|
offset.X -= textBounds.Min.X
|
||||||
|
|
||||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
foreground := element.entity.Theme().Color(tomo.ColorForeground, state, checkboxCase)
|
||||||
element.drawer.Draw(destination, foreground, offset)
|
element.drawer.Draw(destination, foreground, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,21 +104,11 @@ func (element *Checkbox) SetText (text string) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Checkbox) HandleThemeChange () {
|
||||||
func (element *Checkbox) SetTheme (new tomo.Theme) {
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal,
|
||||||
element.updateMinimumSize()
|
checkboxCase))
|
||||||
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
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -179,7 +170,7 @@ func (element *Checkbox) updateMinimumSize () {
|
|||||||
if element.text == "" {
|
if element.text == "" {
|
||||||
element.entity.SetMinimumSize(textBounds.Dy(), textBounds.Dy())
|
element.entity.SetMinimumSize(textBounds.Dy(), textBounds.Dy())
|
||||||
} else {
|
} else {
|
||||||
margin := element.theme.Margin(tomo.PatternBackground)
|
margin := element.entity.Theme().Margin(tomo.PatternBackground, checkboxCase)
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
textBounds.Dy() + margin.X + textBounds.Dx(),
|
textBounds.Dy() + margin.X + textBounds.Dx(),
|
||||||
textBounds.Dy())
|
textBounds.Dy())
|
||||||
|
@ -7,6 +7,8 @@ import "git.tebibyte.media/sashakoshka/tomo/artist"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||||
|
|
||||||
|
var comboBoxCase = tomo.C("tomo", "comboBox")
|
||||||
|
|
||||||
// Option specifies a ComboBox option. A blank option will display as "(None)".
|
// Option specifies a ComboBox option. A blank option will display as "(None)".
|
||||||
type Option string
|
type Option string
|
||||||
|
|
||||||
@ -36,11 +38,11 @@ type ComboBox struct {
|
|||||||
func NewComboBox (options ...Option) (element *ComboBox) {
|
func NewComboBox (options ...Option) (element *ComboBox) {
|
||||||
if len(options) == 0 { options = []Option { "" } }
|
if len(options) == 0 { options = []Option { "" } }
|
||||||
element = &ComboBox { enabled: true, options: options }
|
element = &ComboBox { enabled: true, options: options }
|
||||||
element.entity = tomo.NewEntity(element).(tomo.FocusableEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "comboBox")
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal,
|
||||||
|
comboBoxCase))
|
||||||
element.Select(options[0])
|
element.Select(options[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -54,14 +56,14 @@ func (element *ComboBox) Entity () tomo.Entity {
|
|||||||
func (element *ComboBox) Draw (destination artist.Canvas) {
|
func (element *ComboBox) Draw (destination artist.Canvas) {
|
||||||
state := element.state()
|
state := element.state()
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
pattern := element.theme.Pattern(tomo.PatternButton, state)
|
pattern := element.entity.Theme().Pattern(tomo.PatternButton, state, comboBoxCase)
|
||||||
|
|
||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
|
|
||||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
foreground := element.entity.Theme().Color(tomo.ColorForeground, state, comboBoxCase)
|
||||||
sink := element.theme.Sink(tomo.PatternButton)
|
sink := element.entity.Theme().Sink(tomo.PatternButton, comboBoxCase)
|
||||||
margin := element.theme.Margin(tomo.PatternButton)
|
margin := element.entity.Theme().Margin(tomo.PatternButton, comboBoxCase)
|
||||||
padding := element.theme.Padding(tomo.PatternButton)
|
padding := element.entity.Theme().Padding(tomo.PatternButton, comboBoxCase)
|
||||||
|
|
||||||
offset := image.Pt(0, bounds.Dy() / 2).Add(bounds.Min)
|
offset := image.Pt(0, bounds.Dy() / 2).Add(bounds.Min)
|
||||||
|
|
||||||
@ -70,7 +72,7 @@ func (element *ComboBox) Draw (destination artist.Canvas) {
|
|||||||
offset.Y -= textBounds.Min.Y
|
offset.Y -= textBounds.Min.Y
|
||||||
offset.X -= textBounds.Min.X
|
offset.X -= textBounds.Min.X
|
||||||
|
|
||||||
icon := element.theme.Icon(tomo.IconExpand, tomo.IconSizeSmall)
|
icon := element.entity.Theme().Icon(tomo.IconExpand, tomo.IconSizeSmall, comboBoxCase)
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
iconBounds := icon.Bounds()
|
iconBounds := icon.Bounds()
|
||||||
addedWidth := iconBounds.Dx() + margin.X
|
addedWidth := iconBounds.Dx() + margin.X
|
||||||
@ -138,21 +140,11 @@ func (element *ComboBox) SetEnabled (enabled bool) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *ComboBox) HandleThemeChange () {
|
||||||
func (element *ComboBox) SetTheme (new tomo.Theme) {
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal,
|
||||||
element.updateMinimumSize()
|
comboBoxCase))
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *ComboBox) SetConfig (new tomo.Config) {
|
|
||||||
if new == element.config.Config { return }
|
|
||||||
element.config.Config = new
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -224,7 +216,7 @@ func (element *ComboBox) dropDown () {
|
|||||||
menu, err := window.NewMenu(element.entity.Bounds())
|
menu, err := window.NewMenu(element.entity.Bounds())
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
|
||||||
cellToOption := make(map[tomo.Selectable] Option)
|
cellToOption := make(map[ability.Selectable] Option)
|
||||||
|
|
||||||
list := NewList()
|
list := NewList()
|
||||||
for _, option := range element.options {
|
for _, option := range element.options {
|
||||||
@ -250,13 +242,13 @@ func (element *ComboBox) dropDown () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ComboBox) updateMinimumSize () {
|
func (element *ComboBox) updateMinimumSize () {
|
||||||
padding := element.theme.Padding(tomo.PatternButton)
|
padding := element.entity.Theme().Padding(tomo.PatternButton, comboBoxCase)
|
||||||
margin := element.theme.Margin(tomo.PatternButton)
|
margin := element.entity.Theme().Margin(tomo.PatternButton, comboBoxCase)
|
||||||
|
|
||||||
textBounds := element.drawer.LayoutBounds()
|
textBounds := element.drawer.LayoutBounds()
|
||||||
minimumSize := textBounds.Sub(textBounds.Min)
|
minimumSize := textBounds.Sub(textBounds.Min)
|
||||||
|
|
||||||
icon := element.theme.Icon(tomo.IconExpand, tomo.IconSizeSmall)
|
icon := element.entity.Theme().Icon(tomo.IconExpand, tomo.IconSizeSmall, comboBoxCase)
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
bounds := icon.Bounds()
|
bounds := icon.Bounds()
|
||||||
minimumSize.Max.X += bounds.Dx()
|
minimumSize.Max.X += bounds.Dx()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package elements
|
package elements
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
|
||||||
|
|
||||||
type scratchEntry struct {
|
type scratchEntry struct {
|
||||||
expand bool
|
expand bool
|
||||||
|
@ -11,6 +11,8 @@ import "git.tebibyte.media/sashakoshka/tomo/shatter"
|
|||||||
// TODO: base on flow implementation of list. also be able to switch to a table
|
// TODO: base on flow implementation of list. also be able to switch to a table
|
||||||
// variant for a more information dense view.
|
// variant for a more information dense view.
|
||||||
|
|
||||||
|
var directoryCase = tomo.C("tomo", "list")
|
||||||
|
|
||||||
type historyEntry struct {
|
type historyEntry struct {
|
||||||
location string
|
location string
|
||||||
filesystem ReadDirStatFS
|
filesystem ReadDirStatFS
|
||||||
@ -42,8 +44,7 @@ func NewDirectory (
|
|||||||
err error,
|
err error,
|
||||||
) {
|
) {
|
||||||
element = &Directory { }
|
element = &Directory { }
|
||||||
element.theme.Case = tomo.C("tomo", "list")
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.entity = tomo.NewEntity(element).(directoryEntity)
|
|
||||||
element.container.entity = element.entity
|
element.container.entity = element.entity
|
||||||
element.minimumSize = element.updateMinimumSize
|
element.minimumSize = element.updateMinimumSize
|
||||||
element.init()
|
element.init()
|
||||||
@ -59,7 +60,7 @@ func (element *Directory) Draw (destination artist.Canvas) {
|
|||||||
|
|
||||||
tiles := shatter.Shatter(element.entity.Bounds(), rocks...)
|
tiles := shatter.Shatter(element.entity.Bounds(), rocks...)
|
||||||
for _, tile := range tiles {
|
for _, tile := range tiles {
|
||||||
element.DrawBackground(canvas.Cut(destination, tile))
|
element.DrawBackground(artist.Cut(destination, tile))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +69,8 @@ func (element *Directory) Layout () {
|
|||||||
element.scroll.Y = element.maxScrollHeight()
|
element.scroll.Y = element.maxScrollHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
margin := element.theme.Margin(tomo.PatternPinboard)
|
margin := element.entity.Theme().Margin(tomo.PatternPinboard, directoryCase)
|
||||||
padding := element.theme.Padding(tomo.PatternPinboard)
|
padding := element.entity.Theme().Padding(tomo.PatternPinboard, directoryCase)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
element.contentBounds = image.Rectangle { }
|
element.contentBounds = image.Rectangle { }
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ func (element *Directory) Layout () {
|
|||||||
if width + dot.X > bounds.Max.X {
|
if width + dot.X > bounds.Max.X {
|
||||||
nextLine()
|
nextLine()
|
||||||
}
|
}
|
||||||
if typedChild, ok := child.(tomo.Flexible); ok {
|
if typedChild, ok := child.(ability.Flexible); ok {
|
||||||
height = typedChild.FlexibleHeightFor(width)
|
height = typedChild.FlexibleHeightFor(width)
|
||||||
}
|
}
|
||||||
if rowHeight < height {
|
if rowHeight < height {
|
||||||
@ -139,7 +140,7 @@ func (element *Directory) HandleChildMouseDown (
|
|||||||
child tomo.Element,
|
child tomo.Element,
|
||||||
) {
|
) {
|
||||||
element.selectNone()
|
element.selectNone()
|
||||||
if child, ok := child.(tomo.Selectable); ok {
|
if child, ok := child.(ability.Selectable); ok {
|
||||||
index := element.entity.IndexOf(child)
|
index := element.entity.IndexOf(child)
|
||||||
element.entity.SelectChild(index, true)
|
element.entity.SelectChild(index, true)
|
||||||
}
|
}
|
||||||
@ -166,7 +167,7 @@ func (element *Directory) ScrollContentBounds () image.Rectangle {
|
|||||||
// ScrollViewportBounds returns the size and position of the element's
|
// ScrollViewportBounds returns the size and position of the element's
|
||||||
// viewport relative to ScrollBounds.
|
// viewport relative to ScrollBounds.
|
||||||
func (element *Directory) ScrollViewportBounds () image.Rectangle {
|
func (element *Directory) ScrollViewportBounds () image.Rectangle {
|
||||||
padding := element.theme.Padding(tomo.PatternPinboard)
|
padding := element.entity.Theme().Padding(tomo.PatternPinboard, directoryCase)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
bounds = bounds.Sub(bounds.Min).Add(element.scroll)
|
bounds = bounds.Sub(bounds.Min).Add(element.scroll)
|
||||||
return bounds
|
return bounds
|
||||||
@ -199,14 +200,11 @@ func (element *Directory) ScrollAxes () (horizontal, vertical bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Directory) DrawBackground (destination artist.Canvas) {
|
func (element *Directory) DrawBackground (destination artist.Canvas) {
|
||||||
element.theme.Pattern(tomo.PatternPinboard, tomo.State { }).
|
element.entity.Theme().Pattern(tomo.PatternPinboard, tomo.State { }, directoryCase).
|
||||||
Draw(destination, element.entity.Bounds())
|
Draw(destination, element.entity.Bounds())
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Directory) HandleThemeChange () {
|
||||||
func (element *Directory) SetTheme (theme tomo.Theme) {
|
|
||||||
if theme == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = theme
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
element.entity.InvalidateLayout()
|
element.entity.InvalidateLayout()
|
||||||
@ -295,7 +293,7 @@ func (element *Directory) selectNone () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Directory) maxScrollHeight () (height int) {
|
func (element *Directory) maxScrollHeight () (height int) {
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, directoryCase)
|
||||||
viewportHeight := element.entity.Bounds().Dy() - padding.Vertical()
|
viewportHeight := element.entity.Bounds().Dy() - padding.Vertical()
|
||||||
height = element.contentBounds.Dy() - viewportHeight
|
height = element.contentBounds.Dy() - viewportHeight
|
||||||
if height < 0 { height = 0 }
|
if height < 0 { height = 0 }
|
||||||
@ -304,7 +302,7 @@ func (element *Directory) maxScrollHeight () (height int) {
|
|||||||
|
|
||||||
|
|
||||||
func (element *Directory) updateMinimumSize () {
|
func (element *Directory) updateMinimumSize () {
|
||||||
padding := element.theme.Padding(tomo.PatternPinboard)
|
padding := element.entity.Theme().Padding(tomo.PatternPinboard, directoryCase)
|
||||||
minimumWidth := 0
|
minimumWidth := 0
|
||||||
for index := 0; index < element.entity.CountChildren(); index ++ {
|
for index := 0; index < element.entity.CountChildren(); index ++ {
|
||||||
width, height := element.entity.ChildMinimumSize(index)
|
width, height := element.entity.ChildMinimumSize(index)
|
||||||
|
@ -6,6 +6,8 @@ import "git.tebibyte.media/sashakoshka/tomo/artist"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/shatter"
|
import "git.tebibyte.media/sashakoshka/tomo/shatter"
|
||||||
|
|
||||||
|
var documentCase = tomo.C("tomo", "document")
|
||||||
|
|
||||||
// Document is a scrollable container capcable of laying out flexible child
|
// Document is a scrollable container capcable of laying out flexible child
|
||||||
// elements. Children can be added either inline (similar to an HTML/CSS inline
|
// elements. Children can be added either inline (similar to an HTML/CSS inline
|
||||||
// element), or expanding (similar to an HTML/CSS block element).
|
// element), or expanding (similar to an HTML/CSS block element).
|
||||||
@ -22,8 +24,7 @@ type Document struct {
|
|||||||
// NewDocument creates a new document container.
|
// NewDocument creates a new document container.
|
||||||
func NewDocument (children ...tomo.Element) (element *Document) {
|
func NewDocument (children ...tomo.Element) (element *Document) {
|
||||||
element = &Document { }
|
element = &Document { }
|
||||||
element.theme.Case = tomo.C("tomo", "document")
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.entity = tomo.NewEntity(element)
|
|
||||||
element.container.entity = element.entity
|
element.container.entity = element.entity
|
||||||
element.minimumSize = element.updateMinimumSize
|
element.minimumSize = element.updateMinimumSize
|
||||||
element.init()
|
element.init()
|
||||||
@ -40,7 +41,7 @@ func (element *Document) Draw (destination artist.Canvas) {
|
|||||||
|
|
||||||
tiles := shatter.Shatter(element.entity.Bounds(), rocks...)
|
tiles := shatter.Shatter(element.entity.Bounds(), rocks...)
|
||||||
for _, tile := range tiles {
|
for _, tile := range tiles {
|
||||||
element.entity.DrawBackground(canvas.Cut(destination, tile))
|
element.entity.DrawBackground(artist.Cut(destination, tile))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,8 +51,8 @@ func (element *Document) Layout () {
|
|||||||
element.scroll.Y = element.maxScrollHeight()
|
element.scroll.Y = element.maxScrollHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
margin := element.theme.Margin(tomo.PatternBackground)
|
margin := element.entity.Theme().Margin(tomo.PatternBackground, documentCase)
|
||||||
padding := element.theme.Padding(tomo.PatternBackground)
|
padding := element.entity.Theme().Padding(tomo.PatternBackground, documentCase)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
element.contentBounds = image.Rectangle { }
|
element.contentBounds = image.Rectangle { }
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ func (element *Document) Layout () {
|
|||||||
if width < bounds.Dx() && entry.expand {
|
if width < bounds.Dx() && entry.expand {
|
||||||
width = bounds.Dx()
|
width = bounds.Dx()
|
||||||
}
|
}
|
||||||
if typedChild, ok := child.(tomo.Flexible); ok {
|
if typedChild, ok := child.(ability.Flexible); ok {
|
||||||
height = typedChild.FlexibleHeightFor(width)
|
height = typedChild.FlexibleHeightFor(width)
|
||||||
}
|
}
|
||||||
if rowHeight < height {
|
if rowHeight < height {
|
||||||
@ -135,10 +136,7 @@ func (element *Document) DrawBackground (destination artist.Canvas) {
|
|||||||
element.entity.DrawBackground(destination)
|
element.entity.DrawBackground(destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Document) HandleThemeChange () {
|
||||||
func (element *Document) SetTheme (theme tomo.Theme) {
|
|
||||||
if theme == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = theme
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
element.entity.InvalidateLayout()
|
element.entity.InvalidateLayout()
|
||||||
@ -152,7 +150,7 @@ func (element *Document) ScrollContentBounds () image.Rectangle {
|
|||||||
// ScrollViewportBounds returns the size and position of the element's
|
// ScrollViewportBounds returns the size and position of the element's
|
||||||
// viewport relative to ScrollBounds.
|
// viewport relative to ScrollBounds.
|
||||||
func (element *Document) ScrollViewportBounds () image.Rectangle {
|
func (element *Document) ScrollViewportBounds () image.Rectangle {
|
||||||
padding := element.theme.Padding(tomo.PatternBackground)
|
padding := element.entity.Theme().Padding(tomo.PatternBackground, documentCase)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
bounds = bounds.Sub(bounds.Min).Add(element.scroll)
|
bounds = bounds.Sub(bounds.Min).Add(element.scroll)
|
||||||
return bounds
|
return bounds
|
||||||
@ -185,7 +183,7 @@ func (element *Document) ScrollAxes () (horizontal, vertical bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Document) maxScrollHeight () (height int) {
|
func (element *Document) maxScrollHeight () (height int) {
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternBackground, documentCase)
|
||||||
viewportHeight := element.entity.Bounds().Dy() - padding.Vertical()
|
viewportHeight := element.entity.Bounds().Dy() - padding.Vertical()
|
||||||
height = element.contentBounds.Dy() - viewportHeight
|
height = element.contentBounds.Dy() - viewportHeight
|
||||||
if height < 0 { height = 0 }
|
if height < 0 { height = 0 }
|
||||||
@ -193,7 +191,7 @@ func (element *Document) maxScrollHeight () (height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Document) updateMinimumSize () {
|
func (element *Document) updateMinimumSize () {
|
||||||
padding := element.theme.Padding(tomo.PatternBackground)
|
padding := element.entity.Theme().Padding(tomo.PatternBackground, documentCase)
|
||||||
minimumWidth := 0
|
minimumWidth := 0
|
||||||
for index := 0; index < element.entity.CountChildren(); index ++ {
|
for index := 0; index < element.entity.CountChildren(); index ++ {
|
||||||
width, height := element.entity.ChildMinimumSize(index)
|
width, height := element.entity.ChildMinimumSize(index)
|
||||||
|
@ -7,6 +7,8 @@ import "git.tebibyte.media/sashakoshka/tomo"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
|
var fileCase = tomo.C("files", "file")
|
||||||
|
|
||||||
// File displays an interactive visual representation of a file within any
|
// File displays an interactive visual representation of a file within any
|
||||||
// file system.
|
// file system.
|
||||||
type File struct {
|
type File struct {
|
||||||
@ -32,8 +34,7 @@ func NewFile (
|
|||||||
err error,
|
err error,
|
||||||
) {
|
) {
|
||||||
element = &File { enabled: true }
|
element = &File { enabled: true }
|
||||||
element.theme.Case = tomo.C("files", "file")
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.entity = tomo.NewEntity(element).(fileEntity)
|
|
||||||
err = element.SetLocation(location, within)
|
err = element.SetLocation(location, within)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -48,9 +49,9 @@ func (element *File) Draw (destination artist.Canvas) {
|
|||||||
// background
|
// background
|
||||||
state := element.state()
|
state := element.state()
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
sink := element.theme.Sink(tomo.PatternButton)
|
sink := element.entity.Theme().Sink(tomo.PatternButton, fileCase)
|
||||||
element.theme.
|
element.entity.Theme().
|
||||||
Pattern(tomo.PatternButton, state).
|
Pattern(tomo.PatternButton, state, fileCase).
|
||||||
Draw(destination, bounds)
|
Draw(destination, bounds)
|
||||||
|
|
||||||
// icon
|
// icon
|
||||||
@ -65,7 +66,7 @@ func (element *File) Draw (destination artist.Canvas) {
|
|||||||
}
|
}
|
||||||
icon.Draw (
|
icon.Draw (
|
||||||
destination,
|
destination,
|
||||||
element.theme.Color(tomo.ColorForeground, state),
|
element.entity.Theme().Color(tomo.ColorForeground, state, fileCase),
|
||||||
bounds.Min.Add(offset))
|
bounds.Min.Add(offset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +175,7 @@ func (element *File) HandleMouseUp (
|
|||||||
if button != input.ButtonLeft { return }
|
if button != input.ButtonLeft { return }
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
within := position.In(element.entity.Bounds())
|
within := position.In(element.entity.Bounds())
|
||||||
if time.Since(element.lastClick) < element.config.DoubleClickDelay() {
|
if time.Since(element.lastClick) < element.entity.Config().DoubleClickDelay() {
|
||||||
if element.Enabled() && within && element.onChoose != nil {
|
if element.Enabled() && within && element.onChoose != nil {
|
||||||
element.onChoose()
|
element.onChoose()
|
||||||
}
|
}
|
||||||
@ -184,17 +185,8 @@ func (element *File) HandleMouseUp (
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *File) HandleThemeChange () {
|
||||||
func (element *File) SetTheme (theme tomo.Theme) {
|
element.updateMinimumSize()
|
||||||
if theme == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = theme
|
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *File) SetConfig (config tomo.Config) {
|
|
||||||
if config == element.config.Config { return }
|
|
||||||
element.config.Config = config
|
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,11 +200,11 @@ func (element *File) state () tomo.State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *File) icon () artist.Icon {
|
func (element *File) icon () artist.Icon {
|
||||||
return element.theme.Icon(element.iconID, tomo.IconSizeLarge)
|
return element.entity.Theme().Icon(element.iconID, tomo.IconSizeLarge, fileCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *File) updateMinimumSize () {
|
func (element *File) updateMinimumSize () {
|
||||||
padding := element.theme.Padding(tomo.PatternButton)
|
padding := element.entity.Theme().Padding(tomo.PatternButton, fileCase)
|
||||||
icon := element.icon()
|
icon := element.icon()
|
||||||
if icon == nil {
|
if icon == nil {
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
|
@ -4,6 +4,8 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
|
var iconCase = tomo.C("tomo", "icon")
|
||||||
|
|
||||||
// Icon is an element capable of displaying a singular icon.
|
// Icon is an element capable of displaying a singular icon.
|
||||||
type Icon struct {
|
type Icon struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -17,8 +19,7 @@ func NewIcon (id tomo.Icon, size tomo.IconSize) (element *Icon) {
|
|||||||
id: id,
|
id: id,
|
||||||
size: size,
|
size: size,
|
||||||
}
|
}
|
||||||
element.entity = tomo.NewEntity(element).(ability.ThemeableEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "icon")
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -37,11 +38,7 @@ func (element *Icon) SetIcon (id tomo.Icon, size tomo.IconSize) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Icon) HandleThemeChange () {
|
||||||
func (element *Icon) SetTheme (new tomo.Theme) {
|
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
if element.entity == nil { return }
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -52,8 +49,8 @@ func (element *Icon) Draw (destination artist.Canvas) {
|
|||||||
|
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
state := tomo.State { }
|
state := tomo.State { }
|
||||||
element.theme.
|
element.entity.Theme().
|
||||||
Pattern(tomo.PatternBackground, state).
|
Pattern(tomo.PatternBackground, state, iconCase).
|
||||||
Draw(destination, bounds)
|
Draw(destination, bounds)
|
||||||
icon := element.icon()
|
icon := element.icon()
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
@ -63,13 +60,13 @@ func (element *Icon) Draw (destination artist.Canvas) {
|
|||||||
(bounds.Dy() - iconBounds.Dy()) / 2)
|
(bounds.Dy() - iconBounds.Dy()) / 2)
|
||||||
icon.Draw (
|
icon.Draw (
|
||||||
destination,
|
destination,
|
||||||
element.theme.Color(tomo.ColorForeground, state),
|
element.entity.Theme().Color(tomo.ColorForeground, state, iconCase),
|
||||||
bounds.Min.Add(offset))
|
bounds.Min.Add(offset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Icon) icon () artist.Icon {
|
func (element *Icon) icon () artist.Icon {
|
||||||
return element.theme.Icon(element.id, element.size)
|
return element.entity.Theme().Icon(element.id, element.size, iconCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Icon) updateMinimumSize () {
|
func (element *Icon) updateMinimumSize () {
|
||||||
|
@ -15,8 +15,8 @@ type Image struct {
|
|||||||
|
|
||||||
// NewImage creates a new image element.
|
// NewImage creates a new image element.
|
||||||
func NewImage (image image.Image) (element *Image) {
|
func NewImage (image image.Image) (element *Image) {
|
||||||
element = &Image { buffer: canvas.FromImage(image) }
|
element = &Image { buffer: artist.FromImage(image) }
|
||||||
element.entity = tomo.NewEntity(element)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
bounds := element.buffer.Bounds()
|
bounds := element.buffer.Bounds()
|
||||||
element.entity.SetMinimumSize(bounds.Dx(), bounds.Dy())
|
element.entity.SetMinimumSize(bounds.Dx(), bounds.Dy())
|
||||||
return
|
return
|
||||||
|
@ -8,6 +8,8 @@ import "git.tebibyte.media/sashakoshka/tomo/input"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||||
|
|
||||||
|
var labelCase = tomo.C("tomo", "label")
|
||||||
|
|
||||||
// Label is a simple text box.
|
// Label is a simple text box.
|
||||||
type Label struct {
|
type Label struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -25,11 +27,10 @@ type Label struct {
|
|||||||
// NewLabel creates a new label.
|
// NewLabel creates a new label.
|
||||||
func NewLabel (text string) (element *Label) {
|
func NewLabel (text string) (element *Label) {
|
||||||
element = &Label { }
|
element = &Label { }
|
||||||
element.theme.Case = tomo.C("tomo", "label")
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.entity = tomo.NewEntity(element)
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal, labelCase))
|
||||||
element.SetText(text)
|
element.SetText(text)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -58,9 +59,9 @@ func (element *Label) Draw (destination artist.Canvas) {
|
|||||||
element.entity.DrawBackground(destination)
|
element.entity.DrawBackground(destination)
|
||||||
|
|
||||||
textBounds := element.drawer.LayoutBounds()
|
textBounds := element.drawer.LayoutBounds()
|
||||||
foreground := element.theme.Color (
|
foreground := element.entity.Theme().Color (
|
||||||
tomo.ColorForeground,
|
tomo.ColorForeground,
|
||||||
tomo.State { })
|
tomo.State { }, labelCase)
|
||||||
element.drawer.Draw(destination, foreground, bounds.Min.Sub(textBounds.Min))
|
element.drawer.Draw(destination, foreground, bounds.Min.Sub(textBounds.Min))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,21 +128,10 @@ func (element *Label) SetAlign (align textdraw.Align) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Label) HandleThemeChange () {
|
||||||
func (element *Label) SetTheme (new tomo.Theme) {
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal, labelCase))
|
||||||
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
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -190,7 +180,7 @@ func (element *Label) updateMinimumSize () {
|
|||||||
if element.wrap {
|
if element.wrap {
|
||||||
em := element.drawer.Em().Round()
|
em := element.drawer.Em().Round()
|
||||||
if em < 1 {
|
if em < 1 {
|
||||||
em = element.theme.Padding(tomo.PatternBackground)[0]
|
em = element.entity.Theme().Padding(tomo.PatternBackground, labelCase)[0]
|
||||||
}
|
}
|
||||||
width, height = em, element.drawer.LineHeight().Round()
|
width, height = em, element.drawer.LineHeight().Round()
|
||||||
element.entity.NotifyFlexibleHeightChange()
|
element.entity.NotifyFlexibleHeightChange()
|
||||||
|
@ -33,7 +33,7 @@ func NewHLerpSlider[T Numeric] (min, max T, value T) (element *LerpSlider[T]) {
|
|||||||
min: min,
|
min: min,
|
||||||
max: max,
|
max: max,
|
||||||
}
|
}
|
||||||
element.entity = tomo.NewEntity(element).(tomo.FocusableEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.construct()
|
element.construct()
|
||||||
element.SetValue(value)
|
element.SetValue(value)
|
||||||
return
|
return
|
||||||
|
@ -4,11 +4,15 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/artist/artutil"
|
||||||
|
|
||||||
type list struct {
|
type list struct {
|
||||||
container
|
container
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
|
|
||||||
|
c tomo.Case
|
||||||
|
|
||||||
enabled bool
|
enabled bool
|
||||||
scroll image.Point
|
scroll image.Point
|
||||||
contentBounds image.Rectangle
|
contentBounds image.Rectangle
|
||||||
@ -32,8 +36,8 @@ type FlowList struct {
|
|||||||
|
|
||||||
func NewList (children ...tomo.Element) (element *List) {
|
func NewList (children ...tomo.Element) (element *List) {
|
||||||
element = &List { }
|
element = &List { }
|
||||||
element.theme.Case = tomo.C("tomo", "list")
|
element.c = tomo.C("tomo", "list")
|
||||||
element.entity = tomo.NewEntity(element)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.container.entity = element.entity
|
element.container.entity = element.entity
|
||||||
element.minimumSize = element.updateMinimumSize
|
element.minimumSize = element.updateMinimumSize
|
||||||
element.init(children...)
|
element.init(children...)
|
||||||
@ -42,8 +46,8 @@ func NewList (children ...tomo.Element) (element *List) {
|
|||||||
|
|
||||||
func NewFlowList (children ...tomo.Element) (element *FlowList) {
|
func NewFlowList (children ...tomo.Element) (element *FlowList) {
|
||||||
element = &FlowList { }
|
element = &FlowList { }
|
||||||
element.theme.Case = tomo.C("tomo", "flowList")
|
element.c = tomo.C("tomo", "flowList")
|
||||||
element.entity = tomo.NewEntity(element).(listEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.container.entity = element.entity
|
element.container.entity = element.entity
|
||||||
element.minimumSize = element.updateMinimumSize
|
element.minimumSize = element.updateMinimumSize
|
||||||
element.init(children...)
|
element.init(children...)
|
||||||
@ -63,8 +67,8 @@ func (element *list) Draw (destination artist.Canvas) {
|
|||||||
rocks[index] = element.entity.Child(index).Entity().Bounds()
|
rocks[index] = element.entity.Child(index).Entity().Bounds()
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern := element.theme.Pattern(tomo.PatternSunken, element.state())
|
pattern := element.entity.Theme().Pattern(tomo.PatternSunken, element.state(), element.c)
|
||||||
artist.DrawShatter(destination, pattern, element.entity.Bounds(), rocks...)
|
artutil.DrawShatter(destination, pattern, element.entity.Bounds(), rocks...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *List) Layout () {
|
func (element *List) Layout () {
|
||||||
@ -72,8 +76,8 @@ func (element *List) Layout () {
|
|||||||
element.scroll.Y = element.maxScrollHeight()
|
element.scroll.Y = element.maxScrollHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
margin := element.theme.Margin(tomo.PatternSunken)
|
margin := element.entity.Theme().Margin(tomo.PatternSunken, element.c)
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, element.c)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
element.contentBounds = image.Rectangle { }
|
element.contentBounds = image.Rectangle { }
|
||||||
|
|
||||||
@ -110,8 +114,8 @@ func (element *FlowList) Layout () {
|
|||||||
element.scroll.Y = element.maxScrollHeight()
|
element.scroll.Y = element.maxScrollHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
margin := element.theme.Margin(tomo.PatternSunken)
|
margin := element.entity.Theme().Margin(tomo.PatternSunken, element.c)
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, element.c)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
element.contentBounds = image.Rectangle { }
|
element.contentBounds = image.Rectangle { }
|
||||||
|
|
||||||
@ -135,7 +139,7 @@ func (element *FlowList) Layout () {
|
|||||||
if width + dot.X > bounds.Max.X {
|
if width + dot.X > bounds.Max.X {
|
||||||
nextLine()
|
nextLine()
|
||||||
}
|
}
|
||||||
if typedChild, ok := child.(tomo.Flexible); ok {
|
if typedChild, ok := child.(ability.Flexible); ok {
|
||||||
height = typedChild.FlexibleHeightFor(width)
|
height = typedChild.FlexibleHeightFor(width)
|
||||||
}
|
}
|
||||||
if rowHeight < height {
|
if rowHeight < height {
|
||||||
@ -162,7 +166,7 @@ func (element *FlowList) Layout () {
|
|||||||
|
|
||||||
func (element *list) Selected () ability.Selectable {
|
func (element *list) Selected () ability.Selectable {
|
||||||
if element.selected == -1 { return nil }
|
if element.selected == -1 { return nil }
|
||||||
child, ok := element.entity.Child(element.selected).(tomo.Selectable)
|
child, ok := element.entity.Child(element.selected).(ability.Selectable)
|
||||||
if !ok { return nil }
|
if !ok { return nil }
|
||||||
return child
|
return child
|
||||||
}
|
}
|
||||||
@ -221,7 +225,7 @@ func (element *list) HandleChildMouseDown (
|
|||||||
) {
|
) {
|
||||||
if !element.enabled { return }
|
if !element.enabled { return }
|
||||||
element.Focus()
|
element.Focus()
|
||||||
if child, ok := child.(tomo.Selectable); ok {
|
if child, ok := child.(ability.Selectable); ok {
|
||||||
element.Select(child)
|
element.Select(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,10 +278,7 @@ func (element *list) DrawBackground (destination artist.Canvas) {
|
|||||||
element.entity.DrawBackground(destination)
|
element.entity.DrawBackground(destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *list) HandleThemeChange () {
|
||||||
func (element *list) SetTheme (theme tomo.Theme) {
|
|
||||||
if theme == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = theme
|
|
||||||
element.minimumSize()
|
element.minimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
element.entity.InvalidateLayout()
|
element.entity.InvalidateLayout()
|
||||||
@ -312,7 +313,7 @@ func (element *list) ScrollContentBounds () image.Rectangle {
|
|||||||
// ScrollViewportBounds returns the size and position of the element's
|
// ScrollViewportBounds returns the size and position of the element's
|
||||||
// viewport relative to ScrollBounds.
|
// viewport relative to ScrollBounds.
|
||||||
func (element *list) ScrollViewportBounds () image.Rectangle {
|
func (element *list) ScrollViewportBounds () image.Rectangle {
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, element.c)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
bounds = bounds.Sub(bounds.Min).Add(element.scroll)
|
bounds = bounds.Sub(bounds.Min).Add(element.scroll)
|
||||||
return bounds
|
return bounds
|
||||||
@ -364,7 +365,7 @@ func (element *list) selectNone () {
|
|||||||
func (element *list) scrollToSelected () {
|
func (element *list) scrollToSelected () {
|
||||||
if element.selected < 0 { return }
|
if element.selected < 0 { return }
|
||||||
target := element.entity.Child(element.selected).Entity().Bounds()
|
target := element.entity.Child(element.selected).Entity().Bounds()
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, element.c)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
if target.Min.Y < bounds.Min.Y {
|
if target.Min.Y < bounds.Min.Y {
|
||||||
element.scroll.Y -= bounds.Min.Y - target.Min.Y
|
element.scroll.Y -= bounds.Min.Y - target.Min.Y
|
||||||
@ -385,7 +386,7 @@ func (element *list) state () tomo.State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *list) maxScrollHeight () (height int) {
|
func (element *list) maxScrollHeight () (height int) {
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, element.c)
|
||||||
viewportHeight := element.entity.Bounds().Dy() - padding.Vertical()
|
viewportHeight := element.entity.Bounds().Dy() - padding.Vertical()
|
||||||
height = element.contentBounds.Dy() - viewportHeight
|
height = element.contentBounds.Dy() - viewportHeight
|
||||||
if height < 0 { height = 0 }
|
if height < 0 { height = 0 }
|
||||||
@ -393,8 +394,8 @@ func (element *list) maxScrollHeight () (height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *List) updateMinimumSize () {
|
func (element *List) updateMinimumSize () {
|
||||||
margin := element.theme.Margin(tomo.PatternSunken)
|
margin := element.entity.Theme().Margin(tomo.PatternSunken, element.c)
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, element.c)
|
||||||
|
|
||||||
width := 0
|
width := 0
|
||||||
height := 0
|
height := 0
|
||||||
@ -427,7 +428,7 @@ func (element *List) updateMinimumSize () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *FlowList) updateMinimumSize () {
|
func (element *FlowList) updateMinimumSize () {
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, element.c)
|
||||||
minimumWidth := 0
|
minimumWidth := 0
|
||||||
for index := 0; index < element.entity.CountChildren(); index ++ {
|
for index := 0; index < element.entity.CountChildren(); index ++ {
|
||||||
width, height := element.entity.ChildMinimumSize(index)
|
width, height := element.entity.ChildMinimumSize(index)
|
||||||
|
@ -4,6 +4,8 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
|
var progressBarCase = tomo.C("tomo", "progressBar")
|
||||||
|
|
||||||
// ProgressBar displays a visual indication of how far along a task is.
|
// ProgressBar displays a visual indication of how far along a task is.
|
||||||
type ProgressBar struct {
|
type ProgressBar struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -16,8 +18,7 @@ func NewProgressBar (progress float64) (element *ProgressBar) {
|
|||||||
if progress < 0 { progress = 0 }
|
if progress < 0 { progress = 0 }
|
||||||
if progress > 1 { progress = 1 }
|
if progress > 1 { progress = 1 }
|
||||||
element = &ProgressBar { progress: progress }
|
element = &ProgressBar { progress: progress }
|
||||||
element.entity = tomo.NewEntity(element)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "progressBar")
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -31,15 +32,15 @@ func (element *ProgressBar) Entity () tomo.Entity {
|
|||||||
func (element *ProgressBar) Draw (destination artist.Canvas) {
|
func (element *ProgressBar) Draw (destination artist.Canvas) {
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
|
|
||||||
pattern := element.theme.Pattern(tomo.PatternSunken, tomo.State { })
|
pattern := element.entity.Theme().Pattern(tomo.PatternSunken, tomo.State { }, progressBarCase)
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, progressBarCase)
|
||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
bounds = padding.Apply(bounds)
|
bounds = padding.Apply(bounds)
|
||||||
meterBounds := image.Rect (
|
meterBounds := image.Rect (
|
||||||
bounds.Min.X, bounds.Min.Y,
|
bounds.Min.X, bounds.Min.Y,
|
||||||
bounds.Min.X + int(float64(bounds.Dx()) * element.progress),
|
bounds.Min.X + int(float64(bounds.Dx()) * element.progress),
|
||||||
bounds.Max.Y)
|
bounds.Max.Y)
|
||||||
mercury := element.theme.Pattern(tomo.PatternMercury, tomo.State { })
|
mercury := element.entity.Theme().Pattern(tomo.PatternMercury, tomo.State { }, progressBarCase)
|
||||||
mercury.Draw(destination, meterBounds)
|
mercury.Draw(destination, meterBounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,17 +53,14 @@ func (element *ProgressBar) SetProgress (progress float64) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *ProgressBar) HandleThemeChange () {
|
||||||
func (element *ProgressBar) SetTheme (new tomo.Theme) {
|
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ProgressBar) updateMinimumSize() {
|
func (element *ProgressBar) updateMinimumSize() {
|
||||||
padding := element.theme.Padding(tomo.PatternSunken)
|
padding := element.entity.Theme().Padding(tomo.PatternSunken, progressBarCase)
|
||||||
innerPadding := element.theme.Padding(tomo.PatternMercury)
|
innerPadding := element.entity.Theme().Padding(tomo.PatternMercury, progressBarCase)
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
padding.Horizontal() + innerPadding.Horizontal(),
|
padding.Horizontal() + innerPadding.Horizontal(),
|
||||||
padding.Vertical() + innerPadding.Vertical())
|
padding.Vertical() + innerPadding.Vertical())
|
||||||
|
@ -6,6 +6,8 @@ import "git.tebibyte.media/sashakoshka/tomo/input"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
|
|
||||||
|
var scrollCase = tomo.C("tomo", "scroll")
|
||||||
|
|
||||||
// ScrollMode specifies which sides of a Scroll have scroll bars.
|
// ScrollMode specifies which sides of a Scroll have scroll bars.
|
||||||
type ScrollMode int; const (
|
type ScrollMode int; const (
|
||||||
ScrollNeither ScrollMode = 0
|
ScrollNeither ScrollMode = 0
|
||||||
@ -33,8 +35,7 @@ type Scroll struct {
|
|||||||
// NewScroll creates a new scroll element.
|
// NewScroll creates a new scroll element.
|
||||||
func NewScroll (mode ScrollMode, child ability.Scrollable) (element *Scroll) {
|
func NewScroll (mode ScrollMode, child ability.Scrollable) (element *Scroll) {
|
||||||
element = &Scroll { }
|
element = &Scroll { }
|
||||||
element.theme.Case = tomo.C("tomo", "scroll")
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.entity = tomo.NewEntity(element).(scrollEntity)
|
|
||||||
|
|
||||||
if mode.Includes(ScrollHorizontal) {
|
if mode.Includes(ScrollHorizontal) {
|
||||||
element.horizontal = NewHScrollBar()
|
element.horizontal = NewHScrollBar()
|
||||||
@ -82,8 +83,8 @@ func (element *Scroll) Draw (destination artist.Canvas) {
|
|||||||
bounds.Max.X - element.vertical.Entity().Bounds().Dx(),
|
bounds.Max.X - element.vertical.Entity().Bounds().Dx(),
|
||||||
bounds.Max.Y - element.horizontal.Entity().Bounds().Dy())
|
bounds.Max.Y - element.horizontal.Entity().Bounds().Dy())
|
||||||
state := tomo.State { }
|
state := tomo.State { }
|
||||||
deadArea := element.theme.Pattern(tomo.PatternDead, state)
|
deadArea := element.entity.Theme().Pattern(tomo.PatternDead, state, scrollCase)
|
||||||
deadArea.Draw(canvas.Cut(destination, bounds), bounds)
|
deadArea.Draw(artist.Cut(destination, bounds), bounds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,20 +186,12 @@ func (element *Scroll) HandleScroll (
|
|||||||
element.scrollChildBy(int(deltaX), int(deltaY))
|
element.scrollChildBy(int(deltaX), int(deltaY))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Scroll) HandleThemeChange () {
|
||||||
func (element *Scroll) SetTheme (theme tomo.Theme) {
|
|
||||||
if theme == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = theme
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
element.entity.InvalidateLayout()
|
element.entity.InvalidateLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *Scroll) SetConfig (config tomo.Config) {
|
|
||||||
element.config.Config = config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Scroll) updateMinimumSize () {
|
func (element *Scroll) updateMinimumSize () {
|
||||||
var width, height int
|
var width, height int
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
|
||||||
|
|
||||||
// ScrollBar is an element similar to Slider, but it has special behavior that
|
// ScrollBar is an element similar to Slider, but it has special behavior that
|
||||||
// makes it well suited for controlling the viewport position on one axis of a
|
// makes it well suited for controlling the viewport position on one axis of a
|
||||||
@ -20,6 +19,8 @@ import "git.tebibyte.media/sashakoshka/tomo/ability"
|
|||||||
type ScrollBar struct {
|
type ScrollBar struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
|
|
||||||
|
c tomo.Case
|
||||||
|
|
||||||
vertical bool
|
vertical bool
|
||||||
enabled bool
|
enabled bool
|
||||||
dragging bool
|
dragging bool
|
||||||
@ -39,8 +40,8 @@ func NewVScrollBar () (element *ScrollBar) {
|
|||||||
vertical: true,
|
vertical: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
element.theme.Case = tomo.C("tomo", "scrollBarVertical")
|
element.c = tomo.C("tomo", "scrollBarVertical")
|
||||||
element.entity = tomo.NewEntity(element).(scrollBarEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -50,8 +51,8 @@ func NewHScrollBar () (element *ScrollBar) {
|
|||||||
element = &ScrollBar {
|
element = &ScrollBar {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
element.theme.Case = tomo.C("tomo", "scrollBarHorizontal")
|
element.c = tomo.C("tomo", "scrollBarHorizontal")
|
||||||
element.entity = tomo.NewEntity(element).(tomo.Entity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -70,10 +71,10 @@ func (element *ScrollBar) Draw (destination artist.Canvas) {
|
|||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Pressed: element.dragging,
|
Pressed: element.dragging,
|
||||||
}
|
}
|
||||||
element.theme.Pattern(tomo.PatternGutter, state).Draw (
|
element.entity.Theme().Pattern(tomo.PatternGutter, state, element.c).Draw (
|
||||||
destination,
|
destination,
|
||||||
bounds)
|
bounds)
|
||||||
element.theme.Pattern(tomo.PatternHandle, state).Draw (
|
element.entity.Theme().Pattern(tomo.PatternHandle, state, element.c).Draw (
|
||||||
destination,
|
destination,
|
||||||
element.bar)
|
element.bar)
|
||||||
}
|
}
|
||||||
@ -83,7 +84,7 @@ func (element *ScrollBar) HandleMouseDown (
|
|||||||
button input.Button,
|
button input.Button,
|
||||||
modifiers input.Modifiers,
|
modifiers input.Modifiers,
|
||||||
) {
|
) {
|
||||||
velocity := element.config.ScrollVelocity()
|
velocity := element.entity.Config().ScrollVelocity()
|
||||||
|
|
||||||
if position.In(element.bar) {
|
if position.In(element.bar) {
|
||||||
// the mouse is pressed down within the bar's handle
|
// the mouse is pressed down within the bar's handle
|
||||||
@ -185,17 +186,7 @@ func (element *ScrollBar) OnScroll (callback func (viewport image.Point)) {
|
|||||||
element.onScroll = callback
|
element.onScroll = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *ScrollBar) HandleThemeChange () {
|
||||||
func (element *ScrollBar) SetTheme (new tomo.Theme) {
|
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *ScrollBar) SetConfig (new tomo.Config) {
|
|
||||||
if new == element.config.Config { return }
|
|
||||||
element.config.Config = new
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -263,7 +254,7 @@ func (element *ScrollBar) recalculate () {
|
|||||||
|
|
||||||
func (element *ScrollBar) recalculateVertical () {
|
func (element *ScrollBar) recalculateVertical () {
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
padding := element.theme.Padding(tomo.PatternGutter)
|
padding := element.entity.Theme().Padding(tomo.PatternGutter, element.c)
|
||||||
element.track = padding.Apply(bounds)
|
element.track = padding.Apply(bounds)
|
||||||
|
|
||||||
contentBounds := element.contentBounds
|
contentBounds := element.contentBounds
|
||||||
@ -290,7 +281,7 @@ func (element *ScrollBar) recalculateVertical () {
|
|||||||
|
|
||||||
func (element *ScrollBar) recalculateHorizontal () {
|
func (element *ScrollBar) recalculateHorizontal () {
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
padding := element.theme.Padding(tomo.PatternGutter)
|
padding := element.entity.Theme().Padding(tomo.PatternGutter, element.c)
|
||||||
element.track = padding.Apply(bounds)
|
element.track = padding.Apply(bounds)
|
||||||
|
|
||||||
contentBounds := element.contentBounds
|
contentBounds := element.contentBounds
|
||||||
@ -316,8 +307,8 @@ func (element *ScrollBar) recalculateHorizontal () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollBar) updateMinimumSize () {
|
func (element *ScrollBar) updateMinimumSize () {
|
||||||
gutterPadding := element.theme.Padding(tomo.PatternGutter)
|
gutterPadding := element.entity.Theme().Padding(tomo.PatternGutter, element.c)
|
||||||
handlePadding := element.theme.Padding(tomo.PatternHandle)
|
handlePadding := element.entity.Theme().Padding(tomo.PatternHandle, element.c)
|
||||||
if element.vertical {
|
if element.vertical {
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
gutterPadding.Horizontal() + handlePadding.Horizontal(),
|
gutterPadding.Horizontal() + handlePadding.Horizontal(),
|
||||||
|
@ -4,7 +4,6 @@ import "image"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
|
||||||
|
|
||||||
// Slider is a slider control with a floating point value between zero and one.
|
// Slider is a slider control with a floating point value between zero and one.
|
||||||
type Slider struct {
|
type Slider struct {
|
||||||
@ -22,12 +21,16 @@ func NewVSlider (value float64) (element *Slider) {
|
|||||||
func NewHSlider (value float64) (element *Slider) {
|
func NewHSlider (value float64) (element *Slider) {
|
||||||
element = &Slider { }
|
element = &Slider { }
|
||||||
element.value = value
|
element.value = value
|
||||||
element.entity = tomo.NewEntity(element)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.construct()
|
element.construct()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type slider struct {
|
type slider struct {
|
||||||
|
entity tomo.Entity
|
||||||
|
|
||||||
|
c tomo.Case
|
||||||
|
|
||||||
value float64
|
value float64
|
||||||
vertical bool
|
vertical bool
|
||||||
dragging bool
|
dragging bool
|
||||||
@ -43,9 +46,9 @@ type slider struct {
|
|||||||
func (element *slider) construct () {
|
func (element *slider) construct () {
|
||||||
element.enabled = true
|
element.enabled = true
|
||||||
if element.vertical {
|
if element.vertical {
|
||||||
element.theme.Case = tomo.C("tomo", "sliderVertical")
|
element.c = tomo.C("tomo", "sliderVertical")
|
||||||
} else {
|
} else {
|
||||||
element.theme.Case = tomo.C("tomo", "sliderHorizontal")
|
element.c = tomo.C("tomo", "sliderHorizontal")
|
||||||
}
|
}
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
}
|
}
|
||||||
@ -58,7 +61,7 @@ func (element *slider) Entity () tomo.Entity {
|
|||||||
// Draw causes the element to draw to the specified destination canvas.
|
// Draw causes the element to draw to the specified destination canvas.
|
||||||
func (element *slider) Draw (destination artist.Canvas) {
|
func (element *slider) Draw (destination artist.Canvas) {
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
element.track = element.theme.Padding(tomo.PatternGutter).Apply(bounds)
|
element.track = element.entity.Theme().Padding(tomo.PatternGutter, element.c).Apply(bounds)
|
||||||
if element.vertical {
|
if element.vertical {
|
||||||
barSize := element.track.Dx()
|
barSize := element.track.Dx()
|
||||||
element.bar = image.Rect(0, 0, barSize, barSize).Add(element.track.Min)
|
element.bar = image.Rect(0, 0, barSize, barSize).Add(element.track.Min)
|
||||||
@ -80,8 +83,8 @@ func (element *slider) Draw (destination artist.Canvas) {
|
|||||||
Focused: element.entity.Focused(),
|
Focused: element.entity.Focused(),
|
||||||
Pressed: element.dragging,
|
Pressed: element.dragging,
|
||||||
}
|
}
|
||||||
element.theme.Pattern(tomo.PatternGutter, state).Draw(destination, bounds)
|
element.entity.Theme().Pattern(tomo.PatternGutter, state, element.c).Draw(destination, bounds)
|
||||||
element.theme.Pattern(tomo.PatternHandle, state).Draw(destination, element.bar)
|
element.entity.Theme().Pattern(tomo.PatternHandle, state, element.c).Draw(destination, element.bar)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus gives this element input focus.
|
// Focus gives this element input focus.
|
||||||
@ -205,21 +208,12 @@ func (element *slider) OnRelease (callback func ()) {
|
|||||||
element.onRelease = callback
|
element.onRelease = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *slider) HandleThemeChange () {
|
||||||
func (element *slider) SetTheme (new tomo.Theme) {
|
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *slider) SetConfig (new tomo.Config) {
|
|
||||||
if new == element.config.Config { return }
|
|
||||||
element.config.Config = new
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (element *slider) changeValue (delta float64) {
|
func (element *slider) changeValue (delta float64) {
|
||||||
element.value += delta
|
element.value += delta
|
||||||
if element.value < 0 {
|
if element.value < 0 {
|
||||||
@ -252,8 +246,8 @@ func (element *slider) valueFor (x, y int) (value float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *slider) updateMinimumSize () {
|
func (element *slider) updateMinimumSize () {
|
||||||
gutterPadding := element.theme.Padding(tomo.PatternGutter)
|
gutterPadding := element.entity.Theme().Padding(tomo.PatternGutter, element.c)
|
||||||
handlePadding := element.theme.Padding(tomo.PatternHandle)
|
handlePadding := element.entity.Theme().Padding(tomo.PatternHandle, element.c)
|
||||||
if element.vertical {
|
if element.vertical {
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
gutterPadding.Horizontal() + handlePadding.Horizontal(),
|
gutterPadding.Horizontal() + handlePadding.Horizontal(),
|
||||||
|
@ -3,6 +3,8 @@ package elements
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
|
var spacerCase = tomo.C("tomo", "spacer")
|
||||||
|
|
||||||
// Spacer can be used to put space between two elements..
|
// Spacer can be used to put space between two elements..
|
||||||
type Spacer struct {
|
type Spacer struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -12,8 +14,7 @@ type Spacer struct {
|
|||||||
// NewSpacer creates a new spacer.
|
// NewSpacer creates a new spacer.
|
||||||
func NewSpacer () (element *Spacer) {
|
func NewSpacer () (element *Spacer) {
|
||||||
element = &Spacer { }
|
element = &Spacer { }
|
||||||
element.entity = tomo.NewEntity(element).(spacerEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "spacer")
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -35,14 +36,14 @@ func (element *Spacer) Draw (destination artist.Canvas) {
|
|||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
|
|
||||||
if element.line {
|
if element.line {
|
||||||
pattern := element.theme.Pattern (
|
pattern := element.entity.Theme().Pattern (
|
||||||
tomo.PatternLine,
|
tomo.PatternLine,
|
||||||
tomo.State { })
|
tomo.State { }, spacerCase)
|
||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
} else {
|
} else {
|
||||||
pattern := element.theme.Pattern (
|
pattern := element.entity.Theme().Pattern (
|
||||||
tomo.PatternBackground,
|
tomo.PatternBackground,
|
||||||
tomo.State { })
|
tomo.State { }, spacerCase)
|
||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,23 +56,13 @@ func (element *Spacer) SetLine (line bool) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Spacer) HandleThemeChange () {
|
||||||
func (element *Spacer) SetTheme (new tomo.Theme) {
|
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *Spacer) SetConfig (new tomo.Config) {
|
|
||||||
if new == element.config.Config { return }
|
|
||||||
element.config.Config = new
|
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Spacer) updateMinimumSize () {
|
func (element *Spacer) updateMinimumSize () {
|
||||||
if element.line {
|
if element.line {
|
||||||
padding := element.theme.Padding(tomo.PatternLine)
|
padding := element.entity.Theme().Padding(tomo.PatternLine, spacerCase)
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
padding.Horizontal(),
|
padding.Horizontal(),
|
||||||
padding.Vertical())
|
padding.Vertical())
|
||||||
|
@ -6,6 +6,8 @@ import "git.tebibyte.media/sashakoshka/tomo/input"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||||
|
|
||||||
|
var switchCase = tomo.C("tomo", "switch")
|
||||||
|
|
||||||
// Switch is a toggle-able on/off switch with an optional label. It is
|
// Switch is a toggle-able on/off switch with an optional label. It is
|
||||||
// functionally identical to Checkbox, but plays a different semantic role.
|
// functionally identical to Checkbox, but plays a different semantic role.
|
||||||
type Switch struct {
|
type Switch struct {
|
||||||
@ -27,11 +29,10 @@ func NewSwitch (text string, on bool) (element *Switch) {
|
|||||||
text: text,
|
text: text,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
element.entity = tomo.NewEntity(element).(checkboxEntity)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "switch")
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal, switchCase))
|
||||||
element.drawer.SetText([]rune(text))
|
element.drawer.SetText([]rune(text))
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
return
|
return
|
||||||
@ -71,24 +72,24 @@ func (element *Switch) Draw (destination artist.Canvas) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gutterPattern := element.theme.Pattern (
|
gutterPattern := element.entity.Theme().Pattern (
|
||||||
tomo.PatternGutter, state)
|
tomo.PatternGutter, state, switchCase)
|
||||||
gutterPattern.Draw(destination, gutterBounds)
|
gutterPattern.Draw(destination, gutterBounds)
|
||||||
|
|
||||||
handlePattern := element.theme.Pattern (
|
handlePattern := element.entity.Theme().Pattern (
|
||||||
tomo.PatternHandle, state)
|
tomo.PatternHandle, state, switchCase)
|
||||||
handlePattern.Draw(destination, handleBounds)
|
handlePattern.Draw(destination, handleBounds)
|
||||||
|
|
||||||
textBounds := element.drawer.LayoutBounds()
|
textBounds := element.drawer.LayoutBounds()
|
||||||
offset := bounds.Min.Add(image.Point {
|
offset := bounds.Min.Add(image.Point {
|
||||||
X: bounds.Dy() * 2 +
|
X: bounds.Dy() * 2 +
|
||||||
element.theme.Margin(tomo.PatternBackground).X,
|
element.entity.Theme().Margin(tomo.PatternBackground, switchCase).X,
|
||||||
})
|
})
|
||||||
|
|
||||||
offset.Y -= textBounds.Min.Y
|
offset.Y -= textBounds.Min.Y
|
||||||
offset.X -= textBounds.Min.X
|
offset.X -= textBounds.Min.X
|
||||||
|
|
||||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
foreground := element.entity.Theme().Color(tomo.ColorForeground, state, switchCase)
|
||||||
element.drawer.Draw(destination, foreground, offset)
|
element.drawer.Draw(destination, foreground, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,21 +182,10 @@ func (element *Switch) SetText (text string) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *Switch) HandleThemeChange () {
|
||||||
func (element *Switch) SetTheme (new tomo.Theme) {
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal, switchCase))
|
||||||
element.updateMinimumSize()
|
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *Switch) SetConfig (new tomo.Config) {
|
|
||||||
if new == element.config.Config { return }
|
|
||||||
element.config.Config = new
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -209,7 +199,7 @@ func (element *Switch) updateMinimumSize () {
|
|||||||
} else {
|
} else {
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
lineHeight * 2 +
|
lineHeight * 2 +
|
||||||
element.theme.Margin(tomo.PatternBackground).X +
|
element.entity.Theme().Margin(tomo.PatternBackground, switchCase).X +
|
||||||
textBounds.Dx(),
|
textBounds.Dx(),
|
||||||
lineHeight)
|
lineHeight)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import "git.tebibyte.media/sashakoshka/tomo/textmanip"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/fixedutil"
|
import "git.tebibyte.media/sashakoshka/tomo/fixedutil"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist/shapes"
|
import "git.tebibyte.media/sashakoshka/tomo/artist/shapes"
|
||||||
|
|
||||||
|
var textBoxCase = tomo.C("tomo", "textBox")
|
||||||
|
|
||||||
// TextBox is a single-line text input.
|
// TextBox is a single-line text input.
|
||||||
type TextBox struct {
|
type TextBox struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -38,15 +40,14 @@ type TextBox struct {
|
|||||||
// text.
|
// text.
|
||||||
func NewTextBox (placeholder, value string) (element *TextBox) {
|
func NewTextBox (placeholder, value string) (element *TextBox) {
|
||||||
element = &TextBox { enabled: true }
|
element = &TextBox { enabled: true }
|
||||||
element.theme.Case = tomo.C("tomo", "textBox")
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.entity = tomo.NewEntity(element).(textBoxEntity)
|
|
||||||
element.placeholder = placeholder
|
element.placeholder = placeholder
|
||||||
element.placeholderDrawer.SetFace (element.theme.FontFace (
|
element.placeholderDrawer.SetFace (element.entity.Theme().FontFace (
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal, textBoxCase))
|
||||||
element.valueDrawer.SetFace (element.theme.FontFace (
|
element.valueDrawer.SetFace (element.entity.Theme().FontFace (
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal, textBoxCase))
|
||||||
element.placeholderDrawer.SetText([]rune(placeholder))
|
element.placeholderDrawer.SetText([]rune(placeholder))
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.SetValue(value)
|
element.SetValue(value)
|
||||||
@ -63,15 +64,15 @@ func (element *TextBox) Draw (destination artist.Canvas) {
|
|||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
|
|
||||||
state := element.state()
|
state := element.state()
|
||||||
pattern := element.theme.Pattern(tomo.PatternInput, state)
|
pattern := element.entity.Theme().Pattern(tomo.PatternInput, state, textBoxCase)
|
||||||
padding := element.theme.Padding(tomo.PatternInput)
|
padding := element.entity.Theme().Padding(tomo.PatternInput, textBoxCase)
|
||||||
innerCanvas := canvas.Cut(destination, padding.Apply(bounds))
|
innerCanvas := artist.Cut(destination, padding.Apply(bounds))
|
||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
offset := element.textOffset()
|
offset := element.textOffset()
|
||||||
|
|
||||||
if element.entity.Focused() && !element.dot.Empty() {
|
if element.entity.Focused() && !element.dot.Empty() {
|
||||||
// draw selection bounds
|
// draw selection bounds
|
||||||
accent := element.theme.Color(tomo.ColorAccent, state)
|
accent := element.entity.Theme().Color(tomo.ColorAccent, state, textBoxCase)
|
||||||
canon := element.dot.Canon()
|
canon := element.dot.Canon()
|
||||||
foff := fixedutil.Pt(offset)
|
foff := fixedutil.Pt(offset)
|
||||||
start := element.valueDrawer.PositionAt(canon.Start).Add(foff)
|
start := element.valueDrawer.PositionAt(canon.Start).Add(foff)
|
||||||
@ -89,9 +90,9 @@ func (element *TextBox) Draw (destination artist.Canvas) {
|
|||||||
if len(element.text) == 0 {
|
if len(element.text) == 0 {
|
||||||
// draw placeholder
|
// draw placeholder
|
||||||
textBounds := element.placeholderDrawer.LayoutBounds()
|
textBounds := element.placeholderDrawer.LayoutBounds()
|
||||||
foreground := element.theme.Color (
|
foreground := element.entity.Theme().Color (
|
||||||
tomo.ColorForeground,
|
tomo.ColorForeground,
|
||||||
tomo.State { Disabled: true })
|
tomo.State { Disabled: true }, textBoxCase)
|
||||||
element.placeholderDrawer.Draw (
|
element.placeholderDrawer.Draw (
|
||||||
innerCanvas,
|
innerCanvas,
|
||||||
foreground,
|
foreground,
|
||||||
@ -99,7 +100,7 @@ func (element *TextBox) Draw (destination artist.Canvas) {
|
|||||||
} else {
|
} else {
|
||||||
// draw input value
|
// draw input value
|
||||||
textBounds := element.valueDrawer.LayoutBounds()
|
textBounds := element.valueDrawer.LayoutBounds()
|
||||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
foreground := element.entity.Theme().Color(tomo.ColorForeground, state, textBoxCase)
|
||||||
element.valueDrawer.Draw (
|
element.valueDrawer.Draw (
|
||||||
innerCanvas,
|
innerCanvas,
|
||||||
foreground,
|
foreground,
|
||||||
@ -108,7 +109,7 @@ func (element *TextBox) Draw (destination artist.Canvas) {
|
|||||||
|
|
||||||
if element.entity.Focused() && element.dot.Empty() {
|
if element.entity.Focused() && element.dot.Empty() {
|
||||||
// draw cursor
|
// draw cursor
|
||||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
foreground := element.entity.Theme().Color(tomo.ColorForeground, state, textBoxCase)
|
||||||
cursorPosition := fixedutil.RoundPt (
|
cursorPosition := fixedutil.RoundPt (
|
||||||
element.valueDrawer.PositionAt(element.dot.End))
|
element.valueDrawer.PositionAt(element.dot.End))
|
||||||
shapes.ColorLine (
|
shapes.ColorLine (
|
||||||
@ -144,7 +145,7 @@ func (element *TextBox) HandleMouseDown (
|
|||||||
runeIndex := element.atPosition(position)
|
runeIndex := element.atPosition(position)
|
||||||
if runeIndex == -1 { return }
|
if runeIndex == -1 { return }
|
||||||
|
|
||||||
if time.Since(element.lastClick) < element.config.DoubleClickDelay() {
|
if time.Since(element.lastClick) < element.entity.Config().DoubleClickDelay() {
|
||||||
element.dragging = 2
|
element.dragging = 2
|
||||||
element.dot = textmanip.WordAround(element.text, runeIndex)
|
element.dot = textmanip.WordAround(element.text, runeIndex)
|
||||||
} else {
|
} else {
|
||||||
@ -202,7 +203,7 @@ func (element *TextBox) HandleMotion (position image.Point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) textOffset () image.Point {
|
func (element *TextBox) textOffset () image.Point {
|
||||||
padding := element.theme.Padding(tomo.PatternInput)
|
padding := element.entity.Theme().Padding(tomo.PatternInput, textBoxCase)
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
innerBounds := padding.Apply(bounds)
|
innerBounds := padding.Apply(bounds)
|
||||||
textHeight := element.valueDrawer.LineHeight().Round()
|
textHeight := element.valueDrawer.LineHeight().Round()
|
||||||
@ -464,27 +465,17 @@ func (element *TextBox) ScrollAxes () (horizontal, vertical bool) {
|
|||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *TextBox) HandleThemeChange () {
|
||||||
func (element *TextBox) SetTheme (new tomo.Theme) {
|
face := element.entity.Theme().FontFace (
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
face := element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal)
|
tomo.FontSizeNormal,
|
||||||
|
textBoxCase)
|
||||||
element.placeholderDrawer.SetFace(face)
|
element.placeholderDrawer.SetFace(face)
|
||||||
element.valueDrawer.SetFace(face)
|
element.valueDrawer.SetFace(face)
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *TextBox) SetConfig (new tomo.Config) {
|
|
||||||
if new == element.config.Config { return }
|
|
||||||
element.config.Config = new
|
|
||||||
element.updateMinimumSize()
|
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *TextBox) contextMenu (position image.Point) {
|
func (element *TextBox) contextMenu (position image.Point) {
|
||||||
window := element.entity.Window()
|
window := element.entity.Window()
|
||||||
menu, err := window.NewMenu(image.Rectangle { position, position })
|
menu, err := window.NewMenu(image.Rectangle { position, position })
|
||||||
@ -528,12 +519,12 @@ func (element *TextBox) runOnChange () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) scrollViewportWidth () (width int) {
|
func (element *TextBox) scrollViewportWidth () (width int) {
|
||||||
padding := element.theme.Padding(tomo.PatternInput)
|
padding := element.entity.Theme().Padding(tomo.PatternInput, textBoxCase)
|
||||||
return padding.Apply(element.entity.Bounds()).Dx()
|
return padding.Apply(element.entity.Bounds()).Dx()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) scrollToCursor () {
|
func (element *TextBox) scrollToCursor () {
|
||||||
padding := element.theme.Padding(tomo.PatternInput)
|
padding := element.entity.Theme().Padding(tomo.PatternInput, textBoxCase)
|
||||||
bounds := padding.Apply(element.entity.Bounds())
|
bounds := padding.Apply(element.entity.Bounds())
|
||||||
bounds = bounds.Sub(bounds.Min)
|
bounds = bounds.Sub(bounds.Min)
|
||||||
bounds.Max.X -= element.valueDrawer.Em().Round()
|
bounds.Max.X -= element.valueDrawer.Em().Round()
|
||||||
@ -556,7 +547,7 @@ func (element *TextBox) scrollToCursor () {
|
|||||||
|
|
||||||
func (element *TextBox) updateMinimumSize () {
|
func (element *TextBox) updateMinimumSize () {
|
||||||
textBounds := element.placeholderDrawer.LayoutBounds()
|
textBounds := element.placeholderDrawer.LayoutBounds()
|
||||||
padding := element.theme.Padding(tomo.PatternInput)
|
padding := element.entity.Theme().Padding(tomo.PatternInput, textBoxCase)
|
||||||
element.entity.SetMinimumSize (
|
element.entity.SetMinimumSize (
|
||||||
padding.Horizontal() + textBounds.Dx(),
|
padding.Horizontal() + textBounds.Dx(),
|
||||||
padding.Vertical() +
|
padding.Vertical() +
|
||||||
|
@ -6,6 +6,8 @@ import "git.tebibyte.media/sashakoshka/tomo/input"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||||
|
|
||||||
|
var toggleButtonCase = tomo.C("tomo", "toggleButton")
|
||||||
|
|
||||||
// ToggleButton is a togglable button.
|
// ToggleButton is a togglable button.
|
||||||
type ToggleButton struct {
|
type ToggleButton struct {
|
||||||
entity tomo.Entity
|
entity tomo.Entity
|
||||||
@ -30,11 +32,11 @@ func NewToggleButton (text string, on bool) (element *ToggleButton) {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
on: on,
|
on: on,
|
||||||
}
|
}
|
||||||
element.entity = tomo.NewEntity(element)
|
element.entity = tomo.GetBackend().NewEntity(element)
|
||||||
element.theme.Case = tomo.C("tomo", "toggleButton")
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal,
|
||||||
|
toggleButtonCase))
|
||||||
element.SetText(text)
|
element.SetText(text)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -48,10 +50,10 @@ func (element *ToggleButton) Entity () tomo.Entity {
|
|||||||
func (element *ToggleButton) Draw (destination artist.Canvas) {
|
func (element *ToggleButton) Draw (destination artist.Canvas) {
|
||||||
state := element.state()
|
state := element.state()
|
||||||
bounds := element.entity.Bounds()
|
bounds := element.entity.Bounds()
|
||||||
pattern := element.theme.Pattern(tomo.PatternButton, state)
|
pattern := element.entity.Theme().Pattern(tomo.PatternButton, state, toggleButtonCase)
|
||||||
|
|
||||||
lampPattern := element.theme.Pattern(tomo.PatternLamp, state)
|
lampPattern := element.entity.Theme().Pattern(tomo.PatternLamp, state, toggleButtonCase)
|
||||||
lampPadding := element.theme.Padding(tomo.PatternLamp).Horizontal()
|
lampPadding := element.entity.Theme().Padding(tomo.PatternLamp, toggleButtonCase).Horizontal()
|
||||||
lampBounds := bounds
|
lampBounds := bounds
|
||||||
lampBounds.Max.X = lampBounds.Min.X + lampPadding
|
lampBounds.Max.X = lampBounds.Min.X + lampPadding
|
||||||
bounds.Min.X += lampPadding
|
bounds.Min.X += lampPadding
|
||||||
@ -59,9 +61,9 @@ func (element *ToggleButton) Draw (destination artist.Canvas) {
|
|||||||
pattern.Draw(destination, bounds)
|
pattern.Draw(destination, bounds)
|
||||||
lampPattern.Draw(destination, lampBounds)
|
lampPattern.Draw(destination, lampBounds)
|
||||||
|
|
||||||
foreground := element.theme.Color(tomo.ColorForeground, state)
|
foreground := element.entity.Theme().Color(tomo.ColorForeground, state, toggleButtonCase)
|
||||||
sink := element.theme.Sink(tomo.PatternButton)
|
sink := element.entity.Theme().Sink(tomo.PatternButton, toggleButtonCase)
|
||||||
margin := element.theme.Margin(tomo.PatternButton)
|
margin := element.entity.Theme().Margin(tomo.PatternButton, toggleButtonCase)
|
||||||
|
|
||||||
offset := image.Pt (
|
offset := image.Pt (
|
||||||
bounds.Dx() / 2,
|
bounds.Dx() / 2,
|
||||||
@ -76,7 +78,7 @@ func (element *ToggleButton) Draw (destination artist.Canvas) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if element.hasIcon {
|
if element.hasIcon {
|
||||||
icon := element.theme.Icon(element.iconId, tomo.IconSizeSmall)
|
icon := element.entity.Theme().Icon(element.iconId, tomo.IconSizeSmall, toggleButtonCase)
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
iconBounds := icon.Bounds()
|
iconBounds := icon.Bounds()
|
||||||
addedWidth := iconBounds.Dx()
|
addedWidth := iconBounds.Dx()
|
||||||
@ -166,21 +168,10 @@ func (element *ToggleButton) ShowText (showText bool) {
|
|||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the element's theme.
|
func (element *ToggleButton) HandleThemeChange () {
|
||||||
func (element *ToggleButton) SetTheme (new tomo.Theme) {
|
element.drawer.SetFace (element.entity.Theme().FontFace (
|
||||||
if new == element.theme.Theme { return }
|
|
||||||
element.theme.Theme = new
|
|
||||||
element.drawer.SetFace (element.theme.FontFace (
|
|
||||||
tomo.FontStyleRegular,
|
tomo.FontStyleRegular,
|
||||||
tomo.FontSizeNormal))
|
tomo.FontSizeNormal, toggleButtonCase))
|
||||||
element.updateMinimumSize()
|
|
||||||
element.entity.Invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig sets the element's configuration.
|
|
||||||
func (element *ToggleButton) SetConfig (new tomo.Config) {
|
|
||||||
if new == element.config.Config { return }
|
|
||||||
element.config.Config = new
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
}
|
}
|
||||||
@ -239,15 +230,15 @@ func (element *ToggleButton) HandleKeyUp(key input.Key, modifiers input.Modifier
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ToggleButton) updateMinimumSize () {
|
func (element *ToggleButton) updateMinimumSize () {
|
||||||
padding := element.theme.Padding(tomo.PatternButton)
|
padding := element.entity.Theme().Padding(tomo.PatternButton, toggleButtonCase)
|
||||||
margin := element.theme.Margin(tomo.PatternButton)
|
margin := element.entity.Theme().Margin(tomo.PatternButton, toggleButtonCase)
|
||||||
lampPadding := element.theme.Padding(tomo.PatternLamp)
|
lampPadding := element.entity.Theme().Padding(tomo.PatternLamp, toggleButtonCase)
|
||||||
|
|
||||||
textBounds := element.drawer.LayoutBounds()
|
textBounds := element.drawer.LayoutBounds()
|
||||||
minimumSize := textBounds.Sub(textBounds.Min)
|
minimumSize := textBounds.Sub(textBounds.Min)
|
||||||
|
|
||||||
if element.hasIcon {
|
if element.hasIcon {
|
||||||
icon := element.theme.Icon(element.iconId, tomo.IconSizeSmall)
|
icon := element.entity.Theme().Icon(element.iconId, tomo.IconSizeSmall, toggleButtonCase)
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
bounds := icon.Bounds()
|
bounds := icon.Bounds()
|
||||||
if element.showText {
|
if element.showText {
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/nasin"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
|
|
||||||
|
|
||||||
func main () {
|
func main () {
|
||||||
tomo.Run(run)
|
nasin.Run(Application { })
|
||||||
}
|
}
|
||||||
|
|
||||||
func run () {
|
type Application struct { }
|
||||||
window, _ := tomo.NewWindow(tomo.Bounds(0, 0, 128, 128))
|
|
||||||
|
func (Application) Init () error {
|
||||||
|
window, err := nasin.NewWindow(tomo.Bounds(0, 0, 128, 128))
|
||||||
|
if err != nil { return err }
|
||||||
window.SetTitle("vertical stack")
|
window.SetTitle("vertical stack")
|
||||||
|
|
||||||
container := elements.NewVBox(elements.SpaceBoth)
|
container := elements.NewVBox(elements.SpaceBoth)
|
||||||
@ -25,13 +28,15 @@ func run () {
|
|||||||
container.Adopt(okButton)
|
container.Adopt(okButton)
|
||||||
okButton.Focus()
|
okButton.Focus()
|
||||||
})
|
})
|
||||||
okButton.OnClick(tomo.Stop)
|
okButton.OnClick(nasin.Stop)
|
||||||
|
|
||||||
container.AdoptExpand(label)
|
container.AdoptExpand(label)
|
||||||
container.Adopt(button, okButton)
|
container.Adopt(button, okButton)
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
okButton.Focus()
|
okButton.Focus()
|
||||||
window.OnClose(tomo.Stop)
|
window.OnClose(nasin.Stop)
|
||||||
window.Show()
|
window.Show()
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import "git.tebibyte.media/sashakoshka/tomo/artist"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
|
|
||||||
type entity struct {
|
type entity struct {
|
||||||
|
backend *backend
|
||||||
window *window
|
window *window
|
||||||
parent *entity
|
parent *entity
|
||||||
children []*entity
|
children []*entity
|
||||||
@ -21,7 +22,7 @@ type entity struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (backend *backend) NewEntity (owner tomo.Element) tomo.Entity {
|
func (backend *backend) NewEntity (owner tomo.Element) tomo.Entity {
|
||||||
entity := &entity { element: owner }
|
entity := &entity { element: owner, backend: backend }
|
||||||
entity.InvalidateLayout()
|
entity.InvalidateLayout()
|
||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
@ -162,7 +163,7 @@ func (entity *entity) DrawBackground (destination artist.Canvas) {
|
|||||||
if entity.parent != nil {
|
if entity.parent != nil {
|
||||||
entity.parent.element.(ability.Container).DrawBackground(destination)
|
entity.parent.element.(ability.Container).DrawBackground(destination)
|
||||||
} else if entity.window != nil {
|
} else if entity.window != nil {
|
||||||
entity.window.system.theme.Pattern (
|
entity.backend.theme.Pattern (
|
||||||
tomo.PatternBackground,
|
tomo.PatternBackground,
|
||||||
tomo.State { },
|
tomo.State { },
|
||||||
tomo.C("tomo", "window")).Draw (
|
tomo.C("tomo", "window")).Draw (
|
||||||
@ -292,11 +293,11 @@ func (entity *entity) NotifyScrollBoundsChange () {
|
|||||||
// ----------- ThemeableEntity ----------- //
|
// ----------- ThemeableEntity ----------- //
|
||||||
|
|
||||||
func (entity *entity) Theme () tomo.Theme {
|
func (entity *entity) Theme () tomo.Theme {
|
||||||
return entity.window.theme
|
return entity.backend.theme
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------- ConfigurableEntity ----------- //
|
// ----------- ConfigurableEntity ----------- //
|
||||||
|
|
||||||
func (entity *entity) Config () tomo.Config {
|
func (entity *entity) Config () tomo.Config {
|
||||||
return entity.window.config
|
return entity.backend.config
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package x
|
package x
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
import defaultTheme "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
|
||||||
import defaultConfig "git.tebibyte.media/sashakoshka/tomo/default/config"
|
|
||||||
|
|
||||||
type entitySet map[*entity] struct { }
|
type entitySet map[*entity] struct { }
|
||||||
|
|
||||||
@ -26,10 +23,7 @@ type system struct {
|
|||||||
child *entity
|
child *entity
|
||||||
focused *entity
|
focused *entity
|
||||||
canvas artist.BasicCanvas
|
canvas artist.BasicCanvas
|
||||||
|
|
||||||
theme tomo.Theme
|
|
||||||
config tomo.Config
|
|
||||||
|
|
||||||
invalidateIgnore bool
|
invalidateIgnore bool
|
||||||
drawingInvalid entitySet
|
drawingInvalid entitySet
|
||||||
anyLayoutInvalid bool
|
anyLayoutInvalid bool
|
||||||
@ -43,12 +37,7 @@ func (system *system) initialize () {
|
|||||||
system.drawingInvalid = make(entitySet)
|
system.drawingInvalid = make(entitySet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (system *system) setTheme (theme tomo.Theme) {
|
func (system *system) handleThemeChange () {
|
||||||
if theme == nil {
|
|
||||||
system.theme = defaultTheme.Default { }
|
|
||||||
} else {
|
|
||||||
system.theme = theme
|
|
||||||
}
|
|
||||||
system.propagate (func (entity *entity) bool {
|
system.propagate (func (entity *entity) bool {
|
||||||
if child, ok := system.child.element.(ability.Themeable); ok {
|
if child, ok := system.child.element.(ability.Themeable); ok {
|
||||||
child.HandleThemeChange()
|
child.HandleThemeChange()
|
||||||
@ -57,12 +46,7 @@ func (system *system) setTheme (theme tomo.Theme) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (system *system) setConfig (config tomo.Config) {
|
func (system *system) handleConfigChange () {
|
||||||
if config == nil {
|
|
||||||
system.config = defaultConfig.Default { }
|
|
||||||
} else {
|
|
||||||
system.config = config
|
|
||||||
}
|
|
||||||
system.propagate (func (entity *entity) bool {
|
system.propagate (func (entity *entity) bool {
|
||||||
if child, ok := system.child.element.(ability.Configurable); ok {
|
if child, ok := system.child.element.(ability.Configurable); ok {
|
||||||
child.HandleConfigChange()
|
child.HandleConfigChange()
|
||||||
|
@ -120,9 +120,6 @@ func (backend *backend) newWindow (
|
|||||||
Connect(backend.connection, window.xWindow.Id)
|
Connect(backend.connection, window.xWindow.Id)
|
||||||
xevent.SelectionRequestFun(window.handleSelectionRequest).
|
xevent.SelectionRequestFun(window.handleSelectionRequest).
|
||||||
Connect(backend.connection, window.xWindow.Id)
|
Connect(backend.connection, window.xWindow.Id)
|
||||||
|
|
||||||
window.setTheme(backend.theme)
|
|
||||||
window.setConfig(backend.config)
|
|
||||||
|
|
||||||
window.metrics.bounds = bounds
|
window.metrics.bounds = bounds
|
||||||
window.setMinimumSize(8, 8)
|
window.setMinimumSize(8, 8)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package x
|
package x
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
|
import defaultTheme "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||||
|
import defaultConfig "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||||
|
|
||||||
import "github.com/jezek/xgbutil"
|
import "github.com/jezek/xgbutil"
|
||||||
import "github.com/jezek/xgb/xproto"
|
import "github.com/jezek/xgb/xproto"
|
||||||
@ -96,17 +98,26 @@ func (backend *backend) Do (callback func ()) {
|
|||||||
|
|
||||||
func (backend *backend) SetTheme (theme tomo.Theme) {
|
func (backend *backend) SetTheme (theme tomo.Theme) {
|
||||||
backend.assert()
|
backend.assert()
|
||||||
backend.theme = theme
|
if theme == nil {
|
||||||
|
backend.theme = defaultTheme.Default { }
|
||||||
|
} else {
|
||||||
|
backend.theme = theme
|
||||||
|
}
|
||||||
for _, window := range backend.windows {
|
for _, window := range backend.windows {
|
||||||
window.setTheme(theme)
|
window.handleThemeChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *backend) SetConfig (config tomo.Config) {
|
func (backend *backend) SetConfig (config tomo.Config) {
|
||||||
backend.assert()
|
backend.assert()
|
||||||
|
if config == nil {
|
||||||
|
backend.config = defaultConfig.Default { }
|
||||||
|
} else {
|
||||||
|
backend.config = config
|
||||||
|
}
|
||||||
backend.config = config
|
backend.config = config
|
||||||
for _, window := range backend.windows {
|
for _, window := range backend.windows {
|
||||||
window.setConfig(config)
|
window.handleConfigChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user