Added a case specifier to the theme API
This will allow themes to pull off some cool dirty tricks without screwing anything up
This commit is contained in:
parent
2c55824920
commit
174beba79f
@ -6,6 +6,8 @@ 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
|
||||||
@ -114,7 +116,7 @@ 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 { })
|
_, inset := theme.ButtonPattern(theme.PatternState { Case: buttonCase })
|
||||||
minimumSize := inset.Inverse().Apply(textBounds).Inset(-theme.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 () {
|
if element.core.HasImage () {
|
||||||
@ -127,6 +129,7 @@ func (element *Button) draw () {
|
|||||||
bounds := element.core.Bounds()
|
bounds := element.core.Bounds()
|
||||||
|
|
||||||
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
||||||
|
Case: buttonCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Selected: element.Selected(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
@ -148,6 +151,7 @@ func (element *Button) draw () {
|
|||||||
offset.X -= textBounds.Min.X
|
offset.X -= textBounds.Min.X
|
||||||
|
|
||||||
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
||||||
|
Case: buttonCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
})
|
})
|
||||||
element.drawer.Draw(element.core, foreground, offset)
|
element.drawer.Draw(element.core, foreground, offset)
|
||||||
|
@ -6,6 +6,8 @@ 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
|
||||||
@ -140,10 +142,13 @@ func (element *Checkbox) draw () {
|
|||||||
bounds := element.core.Bounds()
|
bounds := element.core.Bounds()
|
||||||
boxBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy())
|
boxBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy())
|
||||||
|
|
||||||
backgroundPattern, _ := theme.BackgroundPattern(theme.PatternState { })
|
backgroundPattern, _ := theme.BackgroundPattern(theme.PatternState {
|
||||||
|
Case: checkboxCase,
|
||||||
|
})
|
||||||
artist.FillRectangle ( element.core, backgroundPattern, bounds)
|
artist.FillRectangle ( element.core, backgroundPattern, bounds)
|
||||||
|
|
||||||
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
||||||
|
Case: checkboxCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Selected: element.Selected(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
@ -159,6 +164,7 @@ func (element *Checkbox) draw () {
|
|||||||
offset.X -= textBounds.Min.X
|
offset.X -= textBounds.Min.X
|
||||||
|
|
||||||
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
||||||
|
Case: checkboxCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
})
|
})
|
||||||
element.drawer.Draw(element.core, foreground, offset)
|
element.drawer.Draw(element.core, foreground, offset)
|
||||||
|
@ -6,6 +6,8 @@ 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 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 {
|
||||||
@ -473,7 +475,9 @@ func (element *Container) recalculate () {
|
|||||||
func (element *Container) draw () {
|
func (element *Container) draw () {
|
||||||
bounds := element.core.Bounds()
|
bounds := element.core.Bounds()
|
||||||
|
|
||||||
pattern, _ := theme.BackgroundPattern(theme.PatternState { })
|
pattern, _ := theme.BackgroundPattern (theme.PatternState {
|
||||||
|
Case: containerCase,
|
||||||
|
})
|
||||||
artist.FillRectangle(element.core, pattern, bounds)
|
artist.FillRectangle(element.core, pattern, bounds)
|
||||||
|
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
|
@ -5,6 +5,8 @@ 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
|
||||||
@ -108,12 +110,16 @@ func (element *Label) updateMinimumSize () {
|
|||||||
func (element *Label) draw () {
|
func (element *Label) draw () {
|
||||||
bounds := element.core.Bounds()
|
bounds := element.core.Bounds()
|
||||||
|
|
||||||
pattern, _ := theme.BackgroundPattern(theme.PatternState { })
|
pattern, _ := theme.BackgroundPattern(theme.PatternState {
|
||||||
|
Case: labelCase,
|
||||||
|
})
|
||||||
artist.FillRectangle(element.core, pattern, bounds)
|
artist.FillRectangle(element.core, pattern, bounds)
|
||||||
|
|
||||||
textBounds := element.drawer.LayoutBounds()
|
textBounds := element.drawer.LayoutBounds()
|
||||||
|
|
||||||
foreground, _ := theme.ForegroundPattern (theme.PatternState { })
|
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
||||||
|
Case: labelCase,
|
||||||
|
})
|
||||||
element.drawer.Draw (element.core, foreground, image.Point {
|
element.drawer.Draw (element.core, foreground, image.Point {
|
||||||
X: 0 - textBounds.Min.X,
|
X: 0 - textBounds.Min.X,
|
||||||
Y: 0 - textBounds.Min.Y,
|
Y: 0 - textBounds.Min.Y,
|
||||||
|
@ -7,6 +7,8 @@ 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 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
|
||||||
@ -164,7 +166,9 @@ 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 := theme.ListPattern(theme.PatternState {
|
||||||
|
Case: listCase,
|
||||||
|
})
|
||||||
return element.Bounds().Dy() - inset[0] - inset[2]
|
return element.Bounds().Dy() - inset[0] - inset[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +334,9 @@ 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 := theme.ListPattern(theme.PatternState {
|
||||||
|
Case: listCase,
|
||||||
|
})
|
||||||
entry.Collapse(element.forcedMinimumWidth - inset[3] - inset[1])
|
entry.Collapse(element.forcedMinimumWidth - inset[3] - inset[1])
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
@ -357,7 +363,9 @@ func (element *List) updateMinimumSize () {
|
|||||||
minimumHeight = element.contentHeight
|
minimumHeight = element.contentHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
_, inset := theme.ListPattern(theme.PatternState { })
|
_, inset := theme.ListPattern(theme.PatternState {
|
||||||
|
Case: listCase,
|
||||||
|
})
|
||||||
minimumWidth += inset[1] + inset[3]
|
minimumWidth += inset[1] + inset[3]
|
||||||
minimumHeight += inset[0] + inset[2]
|
minimumHeight += inset[0] + inset[2]
|
||||||
|
|
||||||
@ -368,6 +376,7 @@ func (element *List) draw () {
|
|||||||
bounds := element.Bounds()
|
bounds := element.Bounds()
|
||||||
|
|
||||||
pattern, inset := theme.ListPattern(theme.PatternState {
|
pattern, inset := theme.ListPattern(theme.PatternState {
|
||||||
|
Case: listCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Selected: element.Selected(),
|
||||||
})
|
})
|
||||||
@ -386,6 +395,7 @@ func (element *List) draw () {
|
|||||||
|
|
||||||
if element.selectedEntry == index {
|
if element.selectedEntry == index {
|
||||||
pattern, _ := theme.ItemPattern(theme.PatternState {
|
pattern, _ := theme.ItemPattern(theme.PatternState {
|
||||||
|
Case: listEntryCase,
|
||||||
On: true,
|
On: true,
|
||||||
})
|
})
|
||||||
artist.FillRectangle (
|
artist.FillRectangle (
|
||||||
|
@ -5,6 +5,8 @@ import "git.tebibyte.media/sashakoshka/tomo"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
|
var listEntryCase = theme.C("basic", "listEntry")
|
||||||
|
|
||||||
// ListEntry is an item that can be added to a list.
|
// ListEntry is an item that can be added to a list.
|
||||||
type ListEntry struct {
|
type ListEntry struct {
|
||||||
drawer artist.TextDrawer
|
drawer artist.TextDrawer
|
||||||
@ -41,7 +43,8 @@ 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 := theme.ItemPattern(theme.PatternState {
|
||||||
|
})
|
||||||
entry.bounds.Max.Y += inset[0] + inset[2]
|
entry.bounds.Max.Y += inset[0] + inset[2]
|
||||||
|
|
||||||
entry.textPoint =
|
entry.textPoint =
|
||||||
@ -56,7 +59,9 @@ func (entry *ListEntry) Draw (
|
|||||||
) (
|
) (
|
||||||
updatedRegion image.Rectangle,
|
updatedRegion image.Rectangle,
|
||||||
) {
|
) {
|
||||||
foreground, _ := theme.ForegroundPattern (theme.PatternState { })
|
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
||||||
|
Case: listEntryCase,
|
||||||
|
})
|
||||||
return entry.drawer.Draw (
|
return entry.drawer.Draw (
|
||||||
destination,
|
destination,
|
||||||
foreground,
|
foreground,
|
||||||
|
@ -6,6 +6,10 @@ 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 scrollContainerCase = theme.C("basic", "scrollContainer")
|
||||||
|
var scrollBarHorizontalCase = theme.C("basic", "scrollBarHorizontal")
|
||||||
|
var scrollBarVerticalCase = theme.C("basic", "scrollBarVertical")
|
||||||
|
|
||||||
// ScrollContainer is a container that is capable of holding a scrollable
|
// ScrollContainer is a container that is capable of holding a scrollable
|
||||||
// element.
|
// element.
|
||||||
type ScrollContainer struct {
|
type ScrollContainer struct {
|
||||||
@ -273,12 +277,24 @@ func (element *ScrollContainer) clearChildEventHandlers (child tomo.Scrollable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) recalculate () {
|
func (element *ScrollContainer) recalculate () {
|
||||||
_, gutterInset := theme.GutterPattern(theme.PatternState { })
|
_, gutterInsetHorizontal := theme.GutterPattern(theme.PatternState {
|
||||||
|
Case: scrollBarHorizontalCase,
|
||||||
|
})
|
||||||
|
_, gutterInsetVertical := theme.GutterPattern(theme.PatternState {
|
||||||
|
Case: scrollBarHorizontalCase,
|
||||||
|
})
|
||||||
|
|
||||||
horizontal := &element.horizontal
|
horizontal := &element.horizontal
|
||||||
vertical := &element.vertical
|
vertical := &element.vertical
|
||||||
bounds := element.Bounds()
|
bounds := element.Bounds()
|
||||||
thickness := theme.HandleWidth() + gutterInset[3] + gutterInset[1]
|
thicknessHorizontal :=
|
||||||
|
theme.HandleWidth() +
|
||||||
|
gutterInsetHorizontal[3] +
|
||||||
|
gutterInsetHorizontal[1]
|
||||||
|
thicknessVertical :=
|
||||||
|
theme.HandleWidth() +
|
||||||
|
gutterInsetVertical[3] +
|
||||||
|
gutterInsetVertical[1]
|
||||||
|
|
||||||
// calculate child size
|
// calculate child size
|
||||||
element.childWidth = bounds.Dx()
|
element.childWidth = bounds.Dx()
|
||||||
@ -292,24 +308,24 @@ func (element *ScrollContainer) recalculate () {
|
|||||||
|
|
||||||
// if enabled, give substance to the gutters
|
// if enabled, give substance to the gutters
|
||||||
if horizontal.exists {
|
if horizontal.exists {
|
||||||
horizontal.gutter.Min.Y = bounds.Max.Y - thickness
|
horizontal.gutter.Min.Y = bounds.Max.Y - thicknessHorizontal
|
||||||
horizontal.gutter.Max.X = bounds.Max.X
|
horizontal.gutter.Max.X = bounds.Max.X
|
||||||
horizontal.gutter.Max.Y = bounds.Max.Y
|
horizontal.gutter.Max.Y = bounds.Max.Y
|
||||||
if vertical.exists {
|
if vertical.exists {
|
||||||
horizontal.gutter.Max.X -= thickness
|
horizontal.gutter.Max.X -= thicknessVertical
|
||||||
}
|
}
|
||||||
element.childHeight -= thickness
|
element.childHeight -= thicknessHorizontal
|
||||||
horizontal.track = gutterInset.Apply(horizontal.gutter)
|
horizontal.track = gutterInsetHorizontal.Apply(horizontal.gutter)
|
||||||
}
|
}
|
||||||
if vertical.exists {
|
if vertical.exists {
|
||||||
vertical.gutter.Min.X = bounds.Max.X - thickness
|
vertical.gutter.Min.X = bounds.Max.X - thicknessVertical
|
||||||
vertical.gutter.Max.X = bounds.Max.X
|
vertical.gutter.Max.X = bounds.Max.X
|
||||||
vertical.gutter.Max.Y = bounds.Max.Y
|
vertical.gutter.Max.Y = bounds.Max.Y
|
||||||
if horizontal.exists {
|
if horizontal.exists {
|
||||||
vertical.gutter.Max.Y -= thickness
|
vertical.gutter.Max.Y -= thicknessHorizontal
|
||||||
}
|
}
|
||||||
element.childWidth -= thickness
|
element.childWidth -= thicknessVertical
|
||||||
vertical.track = gutterInset.Apply(vertical.gutter)
|
vertical.track = gutterInsetVertical.Apply(vertical.gutter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if enabled, calculate the positions of the bars
|
// if enabled, calculate the positions of the bars
|
||||||
@ -351,7 +367,9 @@ func (element *ScrollContainer) recalculate () {
|
|||||||
|
|
||||||
func (element *ScrollContainer) draw () {
|
func (element *ScrollContainer) draw () {
|
||||||
artist.Paste(element.core, element.child, image.Point { })
|
artist.Paste(element.core, element.child, image.Point { })
|
||||||
deadPattern, _ := theme.DeadPattern(theme.PatternState { })
|
deadPattern, _ := theme.DeadPattern(theme.PatternState {
|
||||||
|
Case: scrollContainerCase,
|
||||||
|
})
|
||||||
artist.FillRectangle (
|
artist.FillRectangle (
|
||||||
element, deadPattern,
|
element, deadPattern,
|
||||||
image.Rect (
|
image.Rect (
|
||||||
@ -365,11 +383,13 @@ func (element *ScrollContainer) draw () {
|
|||||||
|
|
||||||
func (element *ScrollContainer) drawHorizontalBar () {
|
func (element *ScrollContainer) drawHorizontalBar () {
|
||||||
gutterPattern, _ := theme.GutterPattern (theme.PatternState {
|
gutterPattern, _ := theme.GutterPattern (theme.PatternState {
|
||||||
|
Case: scrollBarHorizontalCase,
|
||||||
Disabled: !element.horizontal.enabled,
|
Disabled: !element.horizontal.enabled,
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element, gutterPattern, element.horizontal.gutter)
|
artist.FillRectangle(element, gutterPattern, element.horizontal.gutter)
|
||||||
|
|
||||||
handlePattern, _ := theme.HandlePattern (theme.PatternState {
|
handlePattern, _ := theme.HandlePattern (theme.PatternState {
|
||||||
|
Case: scrollBarHorizontalCase,
|
||||||
Disabled: !element.horizontal.enabled,
|
Disabled: !element.horizontal.enabled,
|
||||||
Pressed: element.horizontal.dragging,
|
Pressed: element.horizontal.dragging,
|
||||||
})
|
})
|
||||||
@ -378,11 +398,13 @@ func (element *ScrollContainer) drawHorizontalBar () {
|
|||||||
|
|
||||||
func (element *ScrollContainer) drawVerticalBar () {
|
func (element *ScrollContainer) drawVerticalBar () {
|
||||||
gutterPattern, _ := theme.GutterPattern (theme.PatternState {
|
gutterPattern, _ := theme.GutterPattern (theme.PatternState {
|
||||||
|
Case: scrollBarVerticalCase,
|
||||||
Disabled: !element.vertical.enabled,
|
Disabled: !element.vertical.enabled,
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element, gutterPattern, element.vertical.gutter)
|
artist.FillRectangle(element, gutterPattern, element.vertical.gutter)
|
||||||
|
|
||||||
handlePattern, _ := theme.HandlePattern (theme.PatternState {
|
handlePattern, _ := theme.HandlePattern (theme.PatternState {
|
||||||
|
Case: scrollBarVerticalCase,
|
||||||
Disabled: !element.vertical.enabled,
|
Disabled: !element.vertical.enabled,
|
||||||
Pressed: element.vertical.dragging,
|
Pressed: element.vertical.dragging,
|
||||||
})
|
})
|
||||||
@ -408,11 +430,24 @@ func (element *ScrollContainer) dragVerticalBar (mousePosition image.Point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) updateMinimumSize () {
|
func (element *ScrollContainer) updateMinimumSize () {
|
||||||
_, gutterInset := theme.GutterPattern(theme.PatternState { })
|
_, gutterInsetHorizontal := theme.GutterPattern(theme.PatternState {
|
||||||
thickness := theme.HandleWidth() + gutterInset[3] + gutterInset[1]
|
Case: scrollBarHorizontalCase,
|
||||||
|
})
|
||||||
|
_, gutterInsetVertical := theme.GutterPattern(theme.PatternState {
|
||||||
|
Case: scrollBarHorizontalCase,
|
||||||
|
})
|
||||||
|
|
||||||
|
thicknessHorizontal :=
|
||||||
|
theme.HandleWidth() +
|
||||||
|
gutterInsetHorizontal[3] +
|
||||||
|
gutterInsetHorizontal[1]
|
||||||
|
thicknessVertical :=
|
||||||
|
theme.HandleWidth() +
|
||||||
|
gutterInsetVertical[3] +
|
||||||
|
gutterInsetVertical[1]
|
||||||
|
|
||||||
width := thickness
|
width := thicknessHorizontal
|
||||||
height := thickness
|
height := thicknessVertical
|
||||||
if element.child != nil {
|
if element.child != nil {
|
||||||
childWidth, childHeight := element.child.MinimumSize()
|
childWidth, childHeight := element.child.MinimumSize()
|
||||||
width += childWidth
|
width += childWidth
|
||||||
|
@ -4,6 +4,8 @@ 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 spacerCase = theme.C("basic", "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 {
|
||||||
*core.Core
|
*core.Core
|
||||||
@ -43,11 +45,13 @@ func (element *Spacer) draw () {
|
|||||||
|
|
||||||
if element.line {
|
if element.line {
|
||||||
pattern, _ := theme.ForegroundPattern(theme.PatternState {
|
pattern, _ := theme.ForegroundPattern(theme.PatternState {
|
||||||
|
Case: spacerCase,
|
||||||
Disabled: true,
|
Disabled: true,
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element.core, pattern, bounds)
|
artist.FillRectangle(element.core, pattern, bounds)
|
||||||
} else {
|
} else {
|
||||||
pattern, _ := theme.BackgroundPattern(theme.PatternState {
|
pattern, _ := theme.BackgroundPattern(theme.PatternState {
|
||||||
|
Case: spacerCase,
|
||||||
Disabled: true,
|
Disabled: true,
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element.core, pattern, bounds)
|
artist.FillRectangle(element.core, pattern, bounds)
|
||||||
|
@ -6,6 +6,8 @@ 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 switchCase = theme.C("basic", "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 {
|
||||||
@ -147,7 +149,9 @@ func (element *Switch) draw () {
|
|||||||
bounds := element.core.Bounds()
|
bounds := element.core.Bounds()
|
||||||
handleBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy())
|
handleBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy())
|
||||||
gutterBounds := image.Rect(0, 0, bounds.Dy() * 2, bounds.Dy())
|
gutterBounds := image.Rect(0, 0, bounds.Dy() * 2, bounds.Dy())
|
||||||
backgroundPattern, _ := theme.BackgroundPattern(theme.PatternState { })
|
backgroundPattern, _ := theme.BackgroundPattern(theme.PatternState {
|
||||||
|
Case: switchCase,
|
||||||
|
})
|
||||||
artist.FillRectangle ( element.core, backgroundPattern, bounds)
|
artist.FillRectangle ( element.core, backgroundPattern, bounds)
|
||||||
|
|
||||||
if element.checked {
|
if element.checked {
|
||||||
@ -165,6 +169,7 @@ func (element *Switch) draw () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gutterPattern, _ := theme.GutterPattern(theme.PatternState {
|
gutterPattern, _ := theme.GutterPattern(theme.PatternState {
|
||||||
|
Case: switchCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Selected: element.Selected(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
@ -172,6 +177,7 @@ func (element *Switch) draw () {
|
|||||||
artist.FillRectangle(element.core, gutterPattern, gutterBounds)
|
artist.FillRectangle(element.core, gutterPattern, gutterBounds)
|
||||||
|
|
||||||
handlePattern, _ := theme.HandlePattern(theme.PatternState {
|
handlePattern, _ := theme.HandlePattern(theme.PatternState {
|
||||||
|
Case: switchCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Selected: element.Selected(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
@ -187,6 +193,7 @@ func (element *Switch) draw () {
|
|||||||
offset.X -= textBounds.Min.X
|
offset.X -= textBounds.Min.X
|
||||||
|
|
||||||
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
||||||
|
Case: switchCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
})
|
})
|
||||||
element.drawer.Draw(element.core, foreground, offset)
|
element.drawer.Draw(element.core, foreground, offset)
|
||||||
|
@ -7,6 +7,8 @@ import "git.tebibyte.media/sashakoshka/tomo/artist"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/textmanip"
|
import "git.tebibyte.media/sashakoshka/tomo/textmanip"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
|
|
||||||
|
var textBoxCase = theme.C("basic", "textBox")
|
||||||
|
|
||||||
// TextBox is a single-line text input.
|
// TextBox is a single-line text input.
|
||||||
type TextBox struct {
|
type TextBox struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
@ -237,7 +239,9 @@ func (element *TextBox) OnScrollBoundsChange (callback func ()) {
|
|||||||
|
|
||||||
func (element *TextBox) updateMinimumSize () {
|
func (element *TextBox) updateMinimumSize () {
|
||||||
textBounds := element.placeholderDrawer.LayoutBounds()
|
textBounds := element.placeholderDrawer.LayoutBounds()
|
||||||
_, inset := theme.InputPattern(theme.PatternState { })
|
_, inset := theme.InputPattern(theme.PatternState {
|
||||||
|
Case: textBoxCase,
|
||||||
|
})
|
||||||
element.core.SetMinimumSize (
|
element.core.SetMinimumSize (
|
||||||
textBounds.Dx() +
|
textBounds.Dx() +
|
||||||
theme.Padding() * 2 + inset[3] + inset[1],
|
theme.Padding() * 2 + inset[3] + inset[1],
|
||||||
@ -273,6 +277,7 @@ func (element *TextBox) draw () {
|
|||||||
|
|
||||||
// FIXME: take index into account
|
// FIXME: take index into account
|
||||||
pattern, inset := theme.InputPattern(theme.PatternState {
|
pattern, inset := theme.InputPattern(theme.PatternState {
|
||||||
|
Case: textBoxCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Selected: element.Selected(),
|
||||||
})
|
})
|
||||||
@ -286,6 +291,7 @@ func (element *TextBox) draw () {
|
|||||||
Y: theme.Padding() + inset[0],
|
Y: theme.Padding() + inset[0],
|
||||||
}
|
}
|
||||||
foreground, _ := theme.ForegroundPattern(theme.PatternState {
|
foreground, _ := theme.ForegroundPattern(theme.PatternState {
|
||||||
|
Case: textBoxCase,
|
||||||
Disabled: true,
|
Disabled: true,
|
||||||
})
|
})
|
||||||
element.placeholderDrawer.Draw (
|
element.placeholderDrawer.Draw (
|
||||||
@ -300,6 +306,7 @@ func (element *TextBox) draw () {
|
|||||||
Y: theme.Padding() + inset[0],
|
Y: theme.Padding() + inset[0],
|
||||||
}
|
}
|
||||||
foreground, _ := theme.ForegroundPattern(theme.PatternState {
|
foreground, _ := theme.ForegroundPattern(theme.PatternState {
|
||||||
|
Case: textBoxCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
})
|
})
|
||||||
element.valueDrawer.Draw (
|
element.valueDrawer.Draw (
|
||||||
@ -311,7 +318,9 @@ func (element *TextBox) draw () {
|
|||||||
// cursor
|
// cursor
|
||||||
cursorPosition := element.valueDrawer.PositionOf (
|
cursorPosition := element.valueDrawer.PositionOf (
|
||||||
element.cursor)
|
element.cursor)
|
||||||
foreground, _ := theme.ForegroundPattern(theme.PatternState { })
|
foreground, _ := theme.ForegroundPattern(theme.PatternState {
|
||||||
|
Case: textBoxCase,
|
||||||
|
})
|
||||||
artist.Line (
|
artist.Line (
|
||||||
element.core,
|
element.core,
|
||||||
foreground, 1,
|
foreground, 1,
|
||||||
|
@ -7,6 +7,8 @@ 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 clockCase = theme.C("fun", "clock")
|
||||||
|
|
||||||
// AnalogClock can display the time of day in an analog format.
|
// AnalogClock can display the time of day in an analog format.
|
||||||
type AnalogClock struct {
|
type AnalogClock struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
@ -41,13 +43,19 @@ func (element *AnalogClock) SetTime (newTime time.Time) {
|
|||||||
func (element *AnalogClock) draw () {
|
func (element *AnalogClock) draw () {
|
||||||
bounds := element.core.Bounds()
|
bounds := element.core.Bounds()
|
||||||
|
|
||||||
pattern, inset := theme.SunkenPattern(theme.PatternState { })
|
pattern, inset := theme.SunkenPattern(theme.PatternState {
|
||||||
|
Case: clockCase,
|
||||||
|
})
|
||||||
artist.FillRectangle(element, pattern, bounds)
|
artist.FillRectangle(element, pattern, bounds)
|
||||||
|
|
||||||
bounds = inset.Apply(bounds)
|
bounds = inset.Apply(bounds)
|
||||||
|
|
||||||
foreground, _ := theme.ForegroundPattern(theme.PatternState { })
|
foreground, _ := theme.ForegroundPattern(theme.PatternState {
|
||||||
accent, _ := theme.AccentPattern(theme.PatternState { })
|
Case: clockCase,
|
||||||
|
})
|
||||||
|
accent, _ := theme.AccentPattern(theme.PatternState {
|
||||||
|
Case: clockCase,
|
||||||
|
})
|
||||||
|
|
||||||
for hour := 0; hour < 12; hour ++ {
|
for hour := 0; hour < 12; hour ++ {
|
||||||
element.radialLine (
|
element.radialLine (
|
||||||
|
@ -3,10 +3,28 @@ package theme
|
|||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
|
// Case sepecifies what kind of element is using a pattern. It contains a
|
||||||
|
// namespace parameter and an element parameter. The element parameter does not
|
||||||
|
// necissarily need to match an element name, but if it can, it should. Both
|
||||||
|
// parameters should be written in camel case. Themes can change their styling
|
||||||
|
// based on this parameter for fine-grained control over the look and feel of
|
||||||
|
// specific elements.
|
||||||
|
type Case struct { Namespace, Element string }
|
||||||
|
|
||||||
|
// C can be used as shorthand to generate a case struct as used in PatternState.
|
||||||
|
func C (namespace, element string) (c Case) {
|
||||||
|
return Case {
|
||||||
|
Namespace: namespace,
|
||||||
|
Element: element,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PatternState lists parameters which can change the appearance of some
|
// PatternState lists parameters which can change the appearance of some
|
||||||
// patterns. For example, passing a PatternState with Selected set to true may
|
// patterns. For example, passing a PatternState with Selected set to true may
|
||||||
// result in a pattern that has a colored border within it.
|
// result in a pattern that has a colored border within it.
|
||||||
type PatternState struct {
|
type PatternState struct {
|
||||||
|
Case
|
||||||
|
|
||||||
// On should be set to true if the element that is using this pattern is
|
// On should be set to true if the element that is using this pattern is
|
||||||
// in some sort of "on" state, such as if a checkbox is checked or a
|
// in some sort of "on" state, such as if a checkbox is checked or a
|
||||||
// switch is toggled on. This is only necessary if the element in
|
// switch is toggled on. This is only necessary if the element in
|
||||||
|
Reference in New Issue
Block a user