2023-01-28 23:49:01 -07:00
|
|
|
package theme
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
|
|
|
|
2023-01-29 23:30:13 -07:00
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-28 23:49:01 -07:00
|
|
|
// PatternState lists parameters which can change the appearance of some
|
|
|
|
// patterns. For example, passing a PatternState with Selected set to true may
|
|
|
|
// result in a pattern that has a colored border within it.
|
|
|
|
type PatternState struct {
|
2023-01-29 23:30:13 -07:00
|
|
|
Case
|
|
|
|
|
2023-01-28 23:49:01 -07:00
|
|
|
// 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
|
|
|
|
// switch is toggled on. This is only necessary if the element in
|
|
|
|
// question is capable of being toggled.
|
|
|
|
On bool
|
|
|
|
|
2023-01-30 15:01:47 -07:00
|
|
|
// Focused should be set to true if the element that is using this
|
|
|
|
// pattern is currently focused.
|
|
|
|
Focused bool
|
2023-01-28 23:49:01 -07:00
|
|
|
|
|
|
|
// Pressed should be set to true if the element that is using this
|
|
|
|
// pattern is being pressed down by the mouse. This is only necessary if
|
|
|
|
// the element in question processes mouse button events.
|
|
|
|
Pressed bool
|
|
|
|
|
|
|
|
// Disabled should be set to true if the element that is using this
|
|
|
|
// pattern is locked and cannot be interacted with. Disabled variations
|
|
|
|
// of patterns are typically flattened and greyed-out.
|
|
|
|
Disabled bool
|
|
|
|
|
|
|
|
// Invalid should be set to true if th element that is using this
|
|
|
|
// pattern wants to warn the user of an invalid interaction or data
|
|
|
|
// entry. Invalid variations typically have some sort of reddish tint
|
|
|
|
// or outline.
|
|
|
|
Invalid bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inset represents an inset amount for all four sides of a rectangle. The top
|
|
|
|
// side is at index zero, the right at index one, the bottom at index two, and
|
|
|
|
// the left at index three. These values may be negative.
|
|
|
|
type Inset [4]int
|
|
|
|
|
|
|
|
// Apply returns the given rectangle, shrunk on all four sides by the given
|
|
|
|
// inset. If a measurment of the inset is negative, that side will instead be
|
|
|
|
// expanded outward. If the rectangle's dimensions cannot be reduced any
|
|
|
|
// further, an empty rectangle near its center will be returned.
|
|
|
|
func (inset Inset) Apply (bigger image.Rectangle) (smaller image.Rectangle) {
|
|
|
|
smaller = bigger
|
2023-01-30 00:22:16 -07:00
|
|
|
if smaller.Dx() < inset[3] + inset[1] {
|
2023-01-28 23:49:01 -07:00
|
|
|
smaller.Min.X = (smaller.Min.X + smaller.Max.X) / 2
|
|
|
|
smaller.Max.X = smaller.Min.X
|
|
|
|
} else {
|
|
|
|
smaller.Min.X += inset[3]
|
|
|
|
smaller.Max.X -= inset[1]
|
|
|
|
}
|
|
|
|
|
2023-01-30 00:22:16 -07:00
|
|
|
if smaller.Dy() < inset[0] + inset[2] {
|
2023-01-28 23:49:01 -07:00
|
|
|
smaller.Min.Y = (smaller.Min.Y + smaller.Max.Y) / 2
|
|
|
|
smaller.Max.Y = smaller.Min.Y
|
|
|
|
} else {
|
|
|
|
smaller.Min.Y += inset[0]
|
|
|
|
smaller.Max.Y -= inset[2]
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inverse returns a negated version of the inset.
|
|
|
|
func (inset Inset) Inverse () (prime Inset) {
|
|
|
|
return Inset {
|
|
|
|
inset[0] * -1,
|
|
|
|
inset[1] * -1,
|
|
|
|
inset[2] * -1,
|
|
|
|
inset[3] * -1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AccentPattern returns the accent pattern, which is usually just a solid
|
|
|
|
// color.
|
|
|
|
func AccentPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
return accentPattern, Inset { }
|
|
|
|
}
|
|
|
|
|
|
|
|
// BackgroundPattern returns the main background pattern.
|
|
|
|
func BackgroundPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
return backgroundPattern, Inset { }
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeadPattern returns a pattern that can be used to mark an area or gap that
|
|
|
|
// serves no purpose, but still needs aesthetic structure.
|
|
|
|
func DeadPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
return deadPattern, Inset { }
|
|
|
|
}
|
|
|
|
|
|
|
|
// ForegroundPattern returns the color text should be.
|
|
|
|
func ForegroundPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
if state.Disabled {
|
|
|
|
return weakForegroundPattern, Inset { }
|
|
|
|
} else {
|
|
|
|
return foregroundPattern, Inset { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// InputPattern returns a background pattern for any input field that can be
|
|
|
|
// edited by typing with the keyboard.
|
|
|
|
func InputPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
if state.Disabled {
|
|
|
|
return disabledInputPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.Focused {
|
2023-01-28 23:49:01 -07:00
|
|
|
return selectedInputPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
|
|
|
return inputPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListPattern returns a background pattern for a list of things.
|
|
|
|
func ListPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.Focused {
|
2023-01-30 15:57:24 -07:00
|
|
|
pattern = focusedListPattern
|
|
|
|
inset = Inset { 2, 1, 2, 1 }
|
2023-01-28 23:49:01 -07:00
|
|
|
} else {
|
2023-01-30 15:57:24 -07:00
|
|
|
pattern = listPattern
|
|
|
|
inset = Inset { 2, 1, 1, 1 }
|
2023-01-28 23:49:01 -07:00
|
|
|
}
|
2023-01-30 15:57:24 -07:00
|
|
|
return
|
2023-01-28 23:49:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// ItemPattern returns a background pattern for a list item.
|
|
|
|
func ItemPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.Focused {
|
|
|
|
if state.On {
|
2023-01-30 15:57:24 -07:00
|
|
|
pattern = focusedOnListEntryPattern
|
2023-01-30 15:01:47 -07:00
|
|
|
} else {
|
2023-01-30 15:57:24 -07:00
|
|
|
pattern = focusedListEntryPattern
|
2023-01-30 15:01:47 -07:00
|
|
|
}
|
2023-01-28 23:49:01 -07:00
|
|
|
} else {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.On {
|
2023-01-30 15:57:24 -07:00
|
|
|
pattern = onListEntryPattern
|
2023-01-30 15:01:47 -07:00
|
|
|
} else {
|
2023-01-30 15:57:24 -07:00
|
|
|
pattern = listEntryPattern
|
2023-01-30 15:01:47 -07:00
|
|
|
}
|
2023-01-28 23:49:01 -07:00
|
|
|
}
|
2023-01-30 15:57:24 -07:00
|
|
|
inset = Inset { 4, 6, 4, 6 }
|
|
|
|
return
|
2023-01-28 23:49:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// ButtonPattern returns a pattern to be displayed on buttons.
|
|
|
|
func ButtonPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
if state.Disabled {
|
|
|
|
return disabledButtonPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
|
|
|
if state.Pressed {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.Focused {
|
2023-01-28 23:49:01 -07:00
|
|
|
return pressedSelectedButtonPattern, Inset {
|
|
|
|
2, 0, 0, 2 }
|
|
|
|
} else {
|
|
|
|
return pressedButtonPattern, Inset { 2, 0, 0, 2 }
|
|
|
|
}
|
|
|
|
} else {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.Focused {
|
2023-01-28 23:49:01 -07:00
|
|
|
return selectedButtonPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
|
|
|
return buttonPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GutterPattern returns a pattern to be used to mark a track along which
|
|
|
|
// something slides.
|
|
|
|
func GutterPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
if state.Disabled {
|
|
|
|
return disabledScrollGutterPattern, Inset { 0, 0, 0, 0 }
|
|
|
|
} else {
|
|
|
|
return scrollGutterPattern, Inset { 0, 0, 0, 0 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// HandlePattern returns a pattern to be displayed on a grab handle that slides
|
|
|
|
// along a gutter.
|
|
|
|
func HandlePattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
if state.Disabled {
|
|
|
|
return disabledScrollBarPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.Focused {
|
2023-01-28 23:49:01 -07:00
|
|
|
if state.Pressed {
|
|
|
|
return pressedSelectedScrollBarPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
|
|
|
return selectedScrollBarPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if state.Pressed {
|
|
|
|
return pressedScrollBarPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
|
|
|
return scrollBarPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SunkenPattern returns a general purpose pattern that is sunken/engraved into
|
|
|
|
// the background.
|
|
|
|
func SunkenPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
return sunkenPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
}
|
|
|
|
|
|
|
|
// RaisedPattern returns a general purpose pattern that is raised up out of the
|
|
|
|
// background.
|
|
|
|
func RaisedPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
2023-01-30 15:01:47 -07:00
|
|
|
if state.Focused {
|
2023-01-28 23:49:01 -07:00
|
|
|
return selectedRaisedPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
} else {
|
|
|
|
return raisedPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PinboardPattern returns a textured backdrop pattern. Anything drawn within it
|
|
|
|
// should have its own background pattern.
|
|
|
|
func PinboardPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|
|
|
return texturedSunkenPattern, Inset { 1, 1, 1, 1 }
|
|
|
|
}
|