Half-done migration of basic elements

This commit is contained in:
Sasha Koshka 2023-02-07 11:27:59 -05:00
parent 0bdbaa39ca
commit 3998d842b1
8 changed files with 214 additions and 128 deletions

View File

@ -6,8 +6,6 @@ import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core" import "git.tebibyte.media/sashakoshka/tomo/elements/core"
var buttonCase = theme.C("basic", "button")
// Button is a clickable button. // Button is a clickable button.
type Button struct { type Button struct {
*core.Core *core.Core
@ -25,19 +23,27 @@ 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 { } element = &Button { }
element.Core, element.core = core.NewCore(element.draw) element.Core, element.core = core.NewCore (
element.draw,
element.redo,
element.redo,
theme.C("basic", "button"))
element.FocusableCore, element.FocusableCore,
element.focusableControl = core.NewFocusableCore (func () { element.focusableControl = core.NewFocusableCore(element.redo)
if element.core.HasImage () {
element.draw()
element.core.DamageAll()
}
})
element.drawer.SetFace(theme.FontFaceRegular())
element.SetText(text) element.SetText(text)
return return
} }
func (element *Button) redo () {
element.drawer.SetFace (
element.core.FontFace(theme.FontStyleRegular,
theme.FontSizeNormal))
if element.core.HasImage () {
element.draw()
element.core.DamageAll()
}
}
func (element *Button) HandleMouseDown (x, y int, button input.Button) { func (element *Button) HandleMouseDown (x, y int, button input.Button) {
if !element.Enabled() { return } if !element.Enabled() { return }
if !element.Focused() { element.Focus() } if !element.Focused() { element.Focus() }
@ -83,10 +89,7 @@ func (element *Button) HandleKeyDown (key input.Key, modifiers input.Modifiers)
func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) { func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) {
if key == input.KeyEnter && element.pressed { if key == input.KeyEnter && element.pressed {
element.pressed = false element.pressed = false
if element.core.HasImage() { element.redo()
element.draw()
element.core.DamageAll()
}
if !element.Enabled() { return } if !element.Enabled() { return }
if element.onClick != nil { if element.onClick != nil {
element.onClick() element.onClick()
@ -111,33 +114,28 @@ func (element *Button) SetText (text string) {
element.text = text element.text = text
element.drawer.SetText([]rune(text)) element.drawer.SetText([]rune(text))
textBounds := element.drawer.LayoutBounds() textBounds := element.drawer.LayoutBounds()
_, inset := theme.ButtonPattern(theme.PatternState { Case: buttonCase }) minimumSize := textBounds.Inset(-element.core.Config().Padding())
minimumSize := inset.Inverse().Apply(textBounds).Inset(-theme.Padding())
element.core.SetMinimumSize(minimumSize.Dx(), minimumSize.Dy()) element.core.SetMinimumSize(minimumSize.Dx(), minimumSize.Dy())
if element.core.HasImage () { element.redo()
element.draw()
element.core.DamageAll()
}
} }
func (element *Button) draw () { func (element *Button) draw () {
bounds := element.Bounds() bounds := element.Bounds()
pattern, inset := theme.ButtonPattern(theme.PatternState { state := theme.PatternState {
Case: buttonCase,
Disabled: !element.Enabled(), Disabled: !element.Enabled(),
Focused: element.Focused(), Focused: element.Focused(),
Pressed: element.pressed, Pressed: element.pressed,
}) }
pattern := element.core.Pattern(theme.PatternButton, state)
artist.FillRectangle(element, pattern, bounds) artist.FillRectangle(element, pattern, bounds)
innerBounds := inset.Apply(bounds)
textBounds := element.drawer.LayoutBounds() textBounds := element.drawer.LayoutBounds()
offset := image.Point { offset := image.Point {
X: innerBounds.Min.X + (innerBounds.Dx() - textBounds.Dx()) / 2, X: bounds.Min.X + (bounds.Dx() - textBounds.Dx()) / 2,
Y: innerBounds.Min.Y + (innerBounds.Dy() - textBounds.Dy()) / 2, Y: bounds.Min.Y + (bounds.Dy() - textBounds.Dy()) / 2,
} }
// account for the fact that the bounding rectangle will be shifted over // account for the fact that the bounding rectangle will be shifted over
@ -145,9 +143,6 @@ func (element *Button) draw () {
offset.Y -= textBounds.Min.Y offset.Y -= textBounds.Min.Y
offset.X -= textBounds.Min.X offset.X -= textBounds.Min.X
foreground, _ := theme.ForegroundPattern (theme.PatternState { foreground := element.core.Pattern(theme.PatternForeground, state)
Case: buttonCase,
Disabled: !element.Enabled(),
})
element.drawer.Draw(element, foreground, offset) element.drawer.Draw(element, foreground, offset)
} }

View File

@ -6,8 +6,6 @@ import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core" import "git.tebibyte.media/sashakoshka/tomo/elements/core"
var checkboxCase = theme.C("basic", "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 {
*core.Core *core.Core
@ -26,19 +24,27 @@ 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 } element = &Checkbox { checked: checked }
element.Core, element.core = core.NewCore(element.draw) element.Core, element.core = core.NewCore (
element.draw,
element.redo,
element.redo,
theme.C("basic", "checkbox"))
element.FocusableCore, element.FocusableCore,
element.focusableControl = core.NewFocusableCore (func () { element.focusableControl = core.NewFocusableCore(element.redo)
if element.core.HasImage () {
element.draw()
element.core.DamageAll()
}
})
element.drawer.SetFace(theme.FontFaceRegular())
element.SetText(text) element.SetText(text)
return return
} }
func (element *Checkbox) redo () {
element.drawer.SetFace (
element.core.FontFace(theme.FontStyleRegular,
theme.FontSizeNormal))
if element.core.HasImage () {
element.draw()
element.core.DamageAll()
}
}
func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) { func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) {
if !element.Enabled() { return } if !element.Enabled() { return }
element.Focus() element.Focus()
@ -122,7 +128,7 @@ func (element *Checkbox) SetText (text string) {
element.core.SetMinimumSize(textBounds.Dy(), textBounds.Dy()) element.core.SetMinimumSize(textBounds.Dy(), textBounds.Dy())
} else { } else {
element.core.SetMinimumSize ( element.core.SetMinimumSize (
textBounds.Dy() + theme.Padding() + textBounds.Dx(), textBounds.Dy() + element.core.Config().Padding() + textBounds.Dx(),
textBounds.Dy()) textBounds.Dy())
} }
@ -136,35 +142,27 @@ func (element *Checkbox) draw () {
bounds := element.Bounds() bounds := element.Bounds()
boxBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy()).Add(bounds.Min) boxBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy()).Add(bounds.Min)
backgroundPattern, _ := theme.BackgroundPattern(theme.PatternState { state := theme.PatternState {
Case: checkboxCase,
})
artist.FillRectangle(element, backgroundPattern, bounds)
pattern, inset := theme.ButtonPattern(theme.PatternState {
Case: checkboxCase,
Disabled: !element.Enabled(), Disabled: !element.Enabled(),
Focused: element.Focused(), Focused: element.Focused(),
Pressed: element.pressed, Pressed: element.pressed,
}) On: element.checked,
}
backgroundPattern := element.core.Pattern(theme.PatternBackground, state)
artist.FillRectangle(element, backgroundPattern, bounds)
pattern := element.core.Pattern (theme.PatternButton, state)
artist.FillRectangle(element, pattern, boxBounds) artist.FillRectangle(element, pattern, boxBounds)
textBounds := element.drawer.LayoutBounds() textBounds := element.drawer.LayoutBounds()
offset := bounds.Min.Add(image.Point { offset := bounds.Min.Add(image.Point {
X: bounds.Dy() + theme.Padding(), X: bounds.Dy() + element.core.Config().Padding(),
}) })
offset.Y -= textBounds.Min.Y offset.Y -= textBounds.Min.Y
offset.X -= textBounds.Min.X offset.X -= textBounds.Min.X
foreground, _ := theme.ForegroundPattern (theme.PatternState { foreground := element.core.Pattern(theme.PatternForeground, state)
Case: checkboxCase,
Disabled: !element.Enabled(),
})
element.drawer.Draw(element, foreground, offset) element.drawer.Draw(element, foreground, offset)
if element.checked {
checkBounds := inset.Apply(boxBounds).Inset(2)
artist.FillRectangle(element, foreground, checkBounds)
}
} }

View File

@ -9,8 +9,6 @@ import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements" import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/core" import "git.tebibyte.media/sashakoshka/tomo/elements/core"
var containerCase = theme.C("basic", "container")
// Container is an element capable of containg other elements, and arranging // Container is an element capable of containg other elements, and arranging
// them in a layout. // them in a layout.
type Container struct { type Container struct {
@ -33,7 +31,11 @@ type Container struct {
// NewContainer creates a new container. // NewContainer creates a new container.
func NewContainer (layout layouts.Layout) (element *Container) { func NewContainer (layout layouts.Layout) (element *Container) {
element = &Container { } element = &Container { }
element.Core, element.core = core.NewCore(element.redoAll) element.Core, element.core = core.NewCore (
element.redoAll,
element.handleConfigChange,
element.handleThemeChange,
theme.C("basic", "container"))
element.SetLayout(layout) element.SetLayout(layout)
return return
} }
@ -205,9 +207,7 @@ func (element *Container) redoAll () {
// draw a background // draw a background
bounds := element.Bounds() bounds := element.Bounds()
pattern, _ := theme.BackgroundPattern (theme.PatternState { pattern := element.core.Pattern (theme.PatternBackground, theme.PatternState { })
Case: containerCase,
})
artist.FillRectangle(element, pattern, bounds) artist.FillRectangle(element, pattern, bounds)
// cut our canvas up and give peices to child elements // cut our canvas up and give peices to child elements
@ -216,6 +216,24 @@ func (element *Container) redoAll () {
} }
} }
func (element *Container) handleConfigChange () {
for _, child := range element.children {
if child0, ok := child.Element.(elements.Configurable); ok {
child0.SetConfig(element.core.Config())
}
}
element.redoAll()
}
func (element *Container) handleThemeChange () {
for _, child := range element.children {
if child0, ok := child.Element.(elements.Themeable); ok {
child0.SetTheme(element.core.Theme())
}
}
element.redoAll()
}
func (element *Container) HandleMouseDown (x, y int, button input.Button) { func (element *Container) HandleMouseDown (x, y int, button input.Button) {
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget) child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget)
if !handlesMouse { return } if !handlesMouse { return }
@ -266,7 +284,7 @@ func (element *Container) HandleKeyUp (key input.Key, modifiers input.Modifiers)
func (element *Container) FlexibleHeightFor (width int) (height int) { func (element *Container) FlexibleHeightFor (width int) (height int) {
return element.layout.FlexibleHeightFor ( return element.layout.FlexibleHeightFor (
element.children, element.children,
theme.Margin(), width) element.core.Config().Margin(), width)
} }
func (element *Container) OnFlexibleHeightChange (callback func ()) { func (element *Container) OnFlexibleHeightChange (callback func ()) {
@ -469,15 +487,15 @@ func (element *Container) childFocusRequestCallback (
func (element *Container) updateMinimumSize () { func (element *Container) updateMinimumSize () {
width, height := element.layout.MinimumSize ( width, height := element.layout.MinimumSize (
element.children, theme.Margin()) element.children, element.core.Config().Margin())
if element.flexible { if element.flexible {
height = element.layout.FlexibleHeightFor ( height = element.layout.FlexibleHeightFor (
element.children, theme.Margin(), width) element.children, element.core.Config().Margin(), width)
} }
element.core.SetMinimumSize(width, height) element.core.SetMinimumSize(width, height)
} }
func (element *Container) recalculate () { func (element *Container) recalculate () {
element.layout.Arrange ( element.layout.Arrange (
element.children, theme.Margin(), element.Bounds()) element.children, element.core.Config().Margin(), element.Bounds())
} }

View File

@ -4,8 +4,6 @@ import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core" import "git.tebibyte.media/sashakoshka/tomo/elements/core"
var labelCase = theme.C("basic", "label")
// Label is a simple text box. // Label is a simple text box.
type Label struct { type Label struct {
*core.Core *core.Core
@ -22,14 +20,35 @@ type Label struct {
// wrapped. // wrapped.
func NewLabel (text string, wrap bool) (element *Label) { func NewLabel (text string, wrap bool) (element *Label) {
element = &Label { } element = &Label { }
element.Core, element.core = core.NewCore(element.handleResize) element.Core, element.core = core.NewCore (
face := theme.FontFaceRegular() element.handleResize,
element.redo,
element.redo,
theme.C("basic", "label"))
face := element.core.FontFace (
theme.FontStyleRegular,
theme.FontSizeNormal)
element.drawer.SetFace(face) element.drawer.SetFace(face)
element.SetWrap(wrap) element.SetWrap(wrap)
element.SetText(text) element.SetText(text)
return return
} }
func (element *Label) redo () {
face := element.core.FontFace (
theme.FontStyleRegular,
theme.FontSizeNormal)
element.drawer.SetFace(face)
element.updateMinimumSize()
bounds := element.Bounds()
if element.wrap {
element.drawer.SetMaxWidth(bounds.Dx())
element.drawer.SetMaxHeight(bounds.Dy())
}
element.draw()
element.core.DamageAll()
}
func (element *Label) handleResize () { func (element *Label) handleResize () {
bounds := element.Bounds() bounds := element.Bounds()
if element.wrap { if element.wrap {
@ -93,7 +112,7 @@ func (element *Label) SetWrap (wrap bool) {
func (element *Label) updateMinimumSize () { func (element *Label) updateMinimumSize () {
if element.wrap { if element.wrap {
em := element.drawer.Em().Round() em := element.drawer.Em().Round()
if em < 1 { em = theme.Padding() } if em < 1 { em = element.core.Config().Padding() }
element.core.SetMinimumSize ( element.core.SetMinimumSize (
em, element.drawer.LineHeight().Round()) em, element.drawer.LineHeight().Round())
if element.onFlexibleHeightChange != nil { if element.onFlexibleHeightChange != nil {
@ -108,15 +127,15 @@ func (element *Label) updateMinimumSize () {
func (element *Label) draw () { func (element *Label) draw () {
bounds := element.Bounds() bounds := element.Bounds()
pattern, _ := theme.BackgroundPattern(theme.PatternState { pattern := element.core.Pattern (
Case: labelCase, theme.PatternBackground,
}) theme.PatternState { })
artist.FillRectangle(element, pattern, bounds) artist.FillRectangle(element, pattern, bounds)
textBounds := element.drawer.LayoutBounds() textBounds := element.drawer.LayoutBounds()
foreground, _ := theme.ForegroundPattern (theme.PatternState { foreground := element.core.Pattern (
Case: labelCase, theme.PatternForeground,
}) theme.PatternState { })
element.drawer.Draw (element, foreground, bounds.Min.Sub(textBounds.Min)) element.drawer.Draw (element, foreground, bounds.Min.Sub(textBounds.Min))
} }

View File

@ -8,8 +8,6 @@ import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core" import "git.tebibyte.media/sashakoshka/tomo/elements/core"
var listCase = theme.C("basic", "list")
// List is an element that contains several objects that a user can select. // List is an element that contains several objects that a user can select.
type List struct { type List struct {
*core.Core *core.Core
@ -34,7 +32,11 @@ type List struct {
// NewList creates a new list element with the specified entries. // NewList creates a new list element with the specified entries.
func NewList (entries ...ListEntry) (element *List) { func NewList (entries ...ListEntry) (element *List) {
element = &List { selectedEntry: -1 } element = &List { selectedEntry: -1 }
element.Core, element.core = core.NewCore(element.handleResize) element.Core, element.core = core.NewCore (
element.handleResize,
element.redo,
element.redo,
theme.C("basic", "list"))
element.FocusableCore, element.FocusableCore,
element.focusableControl = core.NewFocusableCore (func () { element.focusableControl = core.NewFocusableCore (func () {
if element.core.HasImage () { if element.core.HasImage () {
@ -63,6 +65,36 @@ func (element *List) handleResize () {
} }
} }
func (element *List) handleConfigChange () {
for index, entry := range element.entries {
entry.SetConfig(element.core.Config())
element.entries[index] = entry
}
element.redo()
}
func (element *List) handleThemeChange () {
for index, entry := range element.entries {
entry.SetConfig(element.core.Config())
element.entries[index] = entry
}
element.redo()
}
func (element *List) redo () {
for index, entry := range element.entries {
element.entries[index] = element.resizeEntryToFit(entry)
}
if element.core.HasImage() {
element.draw()
element.core.DamageAll()
}
if element.onScrollBoundsChange != nil {
element.onScrollBoundsChange()
}
}
// Collapse forces a minimum width and height upon the list. If a zero value is // Collapse forces a minimum width and height upon the list. If a zero value is
// given for a dimension, its minimum will be determined by the list's content. // given for a dimension, its minimum will be determined by the list's content.
// If the list's height goes beyond the forced size, it will need to be accessed // If the list's height goes beyond the forced size, it will need to be accessed
@ -164,9 +196,7 @@ func (element *List) ScrollAxes () (horizontal, vertical bool) {
} }
func (element *List) scrollViewportHeight () (height int) { func (element *List) scrollViewportHeight () (height int) {
_, inset := theme.ListPattern(theme.PatternState { inset := element.core.Inset(theme.PatternSunken)
Case: listCase,
})
return element.Bounds().Dy() - inset[0] - inset[2] return element.Bounds().Dy() - inset[0] - inset[2]
} }
@ -198,6 +228,8 @@ func (element *List) CountEntries () (count int) {
func (element *List) Append (entry ListEntry) { func (element *List) Append (entry ListEntry) {
// append // append
entry.Collapse(element.forcedMinimumWidth) entry.Collapse(element.forcedMinimumWidth)
entry.SetTheme(element.core.Theme())
entry.SetConfig(element.core.Config())
element.entries = append(element.entries, entry) element.entries = append(element.entries, entry)
// recalculate, redraw, notify // recalculate, redraw, notify
@ -290,7 +322,7 @@ func (element *List) Replace (index int, entry ListEntry) {
} }
func (element *List) selectUnderMouse (x, y int) (updated bool) { func (element *List) selectUnderMouse (x, y int) (updated bool) {
_, inset := theme.ListPattern(theme.PatternState { }) inset := element.core.Inset(theme.PatternSunken)
bounds := inset.Apply(element.Bounds()) bounds := inset.Apply(element.Bounds())
mousePoint := image.Pt(x, y) mousePoint := image.Pt(x, y)
dot := image.Pt ( dot := image.Pt (
@ -332,9 +364,7 @@ func (element *List) changeSelectionBy (delta int) (updated bool) {
} }
func (element *List) resizeEntryToFit (entry ListEntry) (resized ListEntry) { func (element *List) resizeEntryToFit (entry ListEntry) (resized ListEntry) {
_, inset := theme.ListPattern(theme.PatternState { inset := element.core.Inset(theme.PatternSunken)
Case: listCase,
})
entry.Collapse(element.forcedMinimumWidth - inset[3] - inset[1]) entry.Collapse(element.forcedMinimumWidth - inset[3] - inset[1])
return entry return entry
} }
@ -361,9 +391,7 @@ func (element *List) updateMinimumSize () {
minimumHeight = element.contentHeight minimumHeight = element.contentHeight
} }
_, inset := theme.ListPattern(theme.PatternState { inset := element.core.Inset(theme.PatternSunken)
Case: listCase,
})
minimumHeight += inset[0] + inset[2] minimumHeight += inset[0] + inset[2]
element.core.SetMinimumSize(minimumWidth, minimumHeight) element.core.SetMinimumSize(minimumWidth, minimumHeight)
@ -372,8 +400,8 @@ func (element *List) updateMinimumSize () {
func (element *List) draw () { func (element *List) draw () {
bounds := element.Bounds() bounds := element.Bounds()
pattern, inset := theme.ListPattern(theme.PatternState { inset := element.core.Inset(theme.PatternSunken)
Case: listCase, pattern := element.core.Pattern (theme.PatternSunken, theme.PatternState {
Disabled: !element.Enabled(), Disabled: !element.Enabled(),
Focused: element.Focused(), Focused: element.Focused(),
}) })

View File

@ -2,6 +2,7 @@ package basicElements
import "image" import "image"
import "git.tebibyte.media/sashakoshka/tomo/theme" import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config"
import "git.tebibyte.media/sashakoshka/tomo/canvas" import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/artist"
@ -15,6 +16,8 @@ type ListEntry struct {
text string text string
forcedMinimumWidth int forcedMinimumWidth int
onSelect func () onSelect func ()
theme theme.Theme
config config.Config
} }
func NewListEntry (text string, onSelect func ()) (entry ListEntry) { func NewListEntry (text string, onSelect func ()) (entry ListEntry) {
@ -23,7 +26,6 @@ func NewListEntry (text string, onSelect func ()) (entry ListEntry) {
onSelect: onSelect, onSelect: onSelect,
} }
entry.drawer.SetText([]rune(text)) entry.drawer.SetText([]rune(text))
entry.drawer.SetFace(theme.FontFaceRegular())
entry.updateBounds() entry.updateBounds()
return return
} }
@ -34,6 +36,19 @@ func (entry *ListEntry) Collapse (width int) {
entry.updateBounds() entry.updateBounds()
} }
func (entry *ListEntry) SetTheme (new theme.Theme) {
entry.theme = new
entry.drawer.SetFace (entry.theme.FontFace (
theme.FontStyleRegular,
theme.FontSizeNormal,
listEntryCase))
entry.updateBounds()
}
func (entry *ListEntry) SetConfig (config config.Config) {
entry.config = config
}
func (entry *ListEntry) updateBounds () { func (entry *ListEntry) updateBounds () {
entry.bounds = image.Rectangle { } entry.bounds = image.Rectangle { }
entry.bounds.Max.Y = entry.drawer.LineHeight().Round() entry.bounds.Max.Y = entry.drawer.LineHeight().Round()
@ -43,8 +58,7 @@ func (entry *ListEntry) updateBounds () {
entry.bounds.Max.X = entry.drawer.LayoutBounds().Dx() entry.bounds.Max.X = entry.drawer.LayoutBounds().Dx()
} }
_, inset := theme.ItemPattern(theme.PatternState { inset := entry.theme.Inset(theme.PatternRaised, listEntryCase)
})
entry.bounds.Max.Y += inset[0] + inset[2] entry.bounds.Max.Y += inset[0] + inset[2]
entry.textPoint = entry.textPoint =
@ -60,20 +74,16 @@ func (entry *ListEntry) Draw (
) ( ) (
updatedRegion image.Rectangle, updatedRegion image.Rectangle,
) { ) {
pattern, _ := theme.ItemPattern(theme.PatternState { state := theme.PatternState {
Case: listEntryCase,
Focused: focused, Focused: focused,
On: on, On: on,
}) }
pattern := entry.theme.Pattern (theme.PatternRaised, listEntryCase, state)
artist.FillRectangle ( artist.FillRectangle (
destination, destination,
pattern, pattern,
entry.Bounds().Add(offset)) entry.Bounds().Add(offset))
foreground, _ := theme.ForegroundPattern (theme.PatternState { foreground := entry.theme.Pattern (theme.PatternForeground, listEntryCase, state)
Case: listEntryCase,
Focused: focused,
On: on,
})
return entry.drawer.Draw ( return entry.drawer.Draw (
destination, destination,
foreground, foreground,

View File

@ -16,11 +16,24 @@ type ProgressBar struct {
// level. // level.
func NewProgressBar (progress float64) (element *ProgressBar) { func NewProgressBar (progress float64) (element *ProgressBar) {
element = &ProgressBar { progress: progress } element = &ProgressBar { progress: progress }
element.Core, element.core = core.NewCore(element.draw) element.Core, element.core = core.NewCore (
element.core.SetMinimumSize(theme.Padding() * 2, theme.Padding() * 2) element.draw,
element.redo,
element.redo,
theme.C("basic", "progressBar"))
return return
} }
func (element *ProgressBar) redo () {
element.core.SetMinimumSize (
element.core.Config().Padding() * 2,
element.core.Config().Padding() * 2)
if element.core.HasImage() {
element.draw()
element.core.DamageAll()
}
}
// SetProgress sets the progress level of the bar. // SetProgress sets the progress level of the bar.
func (element *ProgressBar) SetProgress (progress float64) { func (element *ProgressBar) SetProgress (progress float64) {
if progress == element.progress { return } if progress == element.progress { return }
@ -34,13 +47,18 @@ func (element *ProgressBar) SetProgress (progress float64) {
func (element *ProgressBar) draw () { func (element *ProgressBar) draw () {
bounds := element.Bounds() bounds := element.Bounds()
pattern, inset := theme.SunkenPattern(theme.PatternState { }) pattern := element.core.Pattern (
theme.PatternSunken,
theme.PatternState { })
inset := element.core.Inset(theme.PatternSunken)
artist.FillRectangle(element, pattern, bounds) artist.FillRectangle(element, pattern, bounds)
bounds = inset.Apply(bounds) bounds = inset.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)
accent, _ := theme.AccentPattern(theme.PatternState { }) accent := element.core.Pattern (
theme.PatternSunken,
theme.PatternState { })
artist.FillRectangle(element, accent, meterBounds) artist.FillRectangle(element, accent, meterBounds)
} }

View File

@ -22,27 +22,27 @@ type Core struct {
theme theme.Theme theme theme.Theme
c theme.Case c theme.Case
drawSizeChange func () handleSizeChange func ()
onConfigChange func () handleConfigChange func ()
onThemeChange func () handleThemeChange func ()
onMinimumSizeChange func () onMinimumSizeChange func ()
onDamage func (region canvas.Canvas) onDamage func (region canvas.Canvas)
} }
// NewCore creates a new element core and its corresponding control. // NewCore creates a new element core and its corresponding control.
func NewCore ( func NewCore (
drawSizeChange func (), handleSizeChange func (),
onConfigChange func (), handleConfigChange func (),
onThemeChange func (), handleThemeChange func (),
c theme.Case, c theme.Case,
) ( ) (
core *Core, core *Core,
control CoreControl, control CoreControl,
) { ) {
core = &Core { core = &Core {
drawSizeChange: drawSizeChange, handleSizeChange: handleSizeChange,
onConfigChange: onConfigChange, handleConfigChange: handleConfigChange,
onThemeChange: onThemeChange, handleThemeChange: handleThemeChange,
c: c, c: c,
} }
control = CoreControl { core: core } control = CoreControl { core: core }
@ -88,8 +88,8 @@ func (core *Core) MinimumSize () (width, height int) {
// overridden. // overridden.
func (core *Core) DrawTo (canvas canvas.Canvas) { func (core *Core) DrawTo (canvas canvas.Canvas) {
core.canvas = canvas core.canvas = canvas
if core.drawSizeChange != nil { if core.handleSizeChange != nil {
core.drawSizeChange() core.handleSizeChange()
} }
} }
@ -109,8 +109,8 @@ func (core *Core) OnMinimumSizeChange (callback func ()) {
// to be overridden. // to be overridden.
func (core *Core) SetConfig (config config.Config) { func (core *Core) SetConfig (config config.Config) {
core.config = config core.config = config
if core.onConfigChange != nil { if core.handleConfigChange != nil {
core.onConfigChange() core.handleConfigChange()
} }
} }
@ -118,8 +118,8 @@ func (core *Core) SetConfig (config config.Config) {
// to be overridden. // to be overridden.
func (core *Core) SetTheme (theme theme.Theme) { func (core *Core) SetTheme (theme theme.Theme) {
core.theme = theme core.theme = theme
if core.onThemeChange != nil { if core.handleThemeChange != nil {
core.onThemeChange() core.handleThemeChange()
} }
} }