data-oriented-patterns #9
@ -44,9 +44,7 @@ func (pattern Border) Draw (destination canvas.Canvas, clip image.Rectangle) {
|
|||||||
srcSections := nonasect(pattern.Bounds(), pattern.Inset)
|
srcSections := nonasect(pattern.Bounds(), pattern.Inset)
|
||||||
srcTextures := [9]Texture { }
|
srcTextures := [9]Texture { }
|
||||||
for index, section := range srcSections {
|
for index, section := range srcSections {
|
||||||
srcTextures[index] = Texture {
|
srcTextures[index].Canvas = canvas.Cut(pattern, section)
|
||||||
Canvas: canvas.Cut(pattern, section),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dstSections := nonasect(destination.Bounds(), pattern.Inset)
|
dstSections := nonasect(destination.Bounds(), pattern.Inset)
|
||||||
|
@ -12,7 +12,8 @@ type Texture struct {
|
|||||||
// Draw tiles the pattern's canvas within the clipping bounds. The minimum
|
// Draw tiles the pattern's canvas within the clipping bounds. The minimum
|
||||||
// points of the pattern's canvas and the destination canvas will be lined up.
|
// points of the pattern's canvas and the destination canvas will be lined up.
|
||||||
func (pattern Texture) Draw (destination canvas.Canvas, clip image.Rectangle) {
|
func (pattern Texture) Draw (destination canvas.Canvas, clip image.Rectangle) {
|
||||||
bounds := clip.Canon().Intersect(destination.Bounds())
|
realBounds := destination.Bounds()
|
||||||
|
bounds := clip.Canon().Intersect(realBounds)
|
||||||
if bounds.Empty() { return }
|
if bounds.Empty() { return }
|
||||||
|
|
||||||
dstData, dstStride := destination.Buffer()
|
dstData, dstStride := destination.Buffer()
|
||||||
@ -23,8 +24,8 @@ func (pattern Texture) Draw (destination canvas.Canvas, clip image.Rectangle) {
|
|||||||
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
||||||
dstIndex := x + y * dstStride
|
dstIndex := x + y * dstStride
|
||||||
srcIndex :=
|
srcIndex :=
|
||||||
wrap(x - bounds.Min.X, srcBounds.Min.X, srcBounds.Max.X) +
|
wrap(x - realBounds.Min.X, srcBounds.Min.X, srcBounds.Max.X) +
|
||||||
wrap(x - bounds.Min.Y, srcBounds.Min.Y, srcBounds.Max.Y) * srcStride
|
wrap(y - realBounds.Min.Y, srcBounds.Min.Y, srcBounds.Max.Y) * srcStride
|
||||||
dstData[dstIndex] = srcData[srcIndex]
|
dstData[dstIndex] = srcData[srcIndex]
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ func (element *TextBox) HandleMouseMove (x, y int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) atPosition (position image.Point) int {
|
func (element *TextBox) atPosition (position image.Point) int {
|
||||||
padding := element.theme.Padding(theme.PatternSunken)
|
padding := element.theme.Padding(theme.PatternInput)
|
||||||
offset := element.Bounds().Min.Add (image.Pt (
|
offset := element.Bounds().Min.Add (image.Pt (
|
||||||
padding[artist.SideLeft] - element.scroll,
|
padding[artist.SideLeft] - element.scroll,
|
||||||
padding[artist.SideTop]))
|
padding[artist.SideTop]))
|
||||||
@ -253,7 +253,7 @@ func (element *TextBox) ScrollViewportBounds () (bounds image.Rectangle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) scrollViewportWidth () (width int) {
|
func (element *TextBox) scrollViewportWidth () (width int) {
|
||||||
padding := element.theme.Padding(theme.PatternSunken)
|
padding := element.theme.Padding(theme.PatternInput)
|
||||||
return padding.Apply(element.Bounds()).Dx()
|
return padding.Apply(element.Bounds()).Dx()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ func (element *TextBox) runOnChange () {
|
|||||||
func (element *TextBox) scrollToCursor () {
|
func (element *TextBox) scrollToCursor () {
|
||||||
if !element.core.HasImage() { return }
|
if !element.core.HasImage() { return }
|
||||||
|
|
||||||
padding := element.theme.Padding(theme.PatternSunken)
|
padding := element.theme.Padding(theme.PatternInput)
|
||||||
bounds := padding.Apply(element.Bounds())
|
bounds := padding.Apply(element.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()
|
||||||
@ -333,7 +333,7 @@ func (element *TextBox) SetConfig (new config.Config) {
|
|||||||
|
|
||||||
func (element *TextBox) updateMinimumSize () {
|
func (element *TextBox) updateMinimumSize () {
|
||||||
textBounds := element.placeholderDrawer.LayoutBounds()
|
textBounds := element.placeholderDrawer.LayoutBounds()
|
||||||
padding := element.theme.Padding(theme.PatternSunken)
|
padding := element.theme.Padding(theme.PatternInput)
|
||||||
element.core.SetMinimumSize (
|
element.core.SetMinimumSize (
|
||||||
padding.Horizontal() + textBounds.Dx(),
|
padding.Horizontal() + textBounds.Dx(),
|
||||||
padding.Vertical() +
|
padding.Vertical() +
|
||||||
@ -354,8 +354,8 @@ func (element *TextBox) draw () {
|
|||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Focused: element.Focused(),
|
Focused: element.Focused(),
|
||||||
}
|
}
|
||||||
pattern := element.theme.Pattern(theme.PatternSunken, state)
|
pattern := element.theme.Pattern(theme.PatternInput, state)
|
||||||
padding := element.theme.Padding(theme.PatternSunken)
|
padding := element.theme.Padding(theme.PatternInput)
|
||||||
innerCanvas := canvas.Cut(element.core, padding.Apply(bounds))
|
innerCanvas := canvas.Cut(element.core, padding.Apply(bounds))
|
||||||
pattern.Draw(element.core, bounds)
|
pattern.Draw(element.core, bounds)
|
||||||
|
|
||||||
|
BIN
theme/assets/wintergreen.png
Normal file
BIN
theme/assets/wintergreen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@ -1,6 +1,9 @@
|
|||||||
package theme
|
package theme
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
|
import "bytes"
|
||||||
|
import _ "embed"
|
||||||
|
import _ "image/png"
|
||||||
import "image/color"
|
import "image/color"
|
||||||
import "golang.org/x/image/font"
|
import "golang.org/x/image/font"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
@ -8,6 +11,47 @@ import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/defaultfont"
|
import "git.tebibyte.media/sashakoshka/tomo/defaultfont"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist/patterns"
|
import "git.tebibyte.media/sashakoshka/tomo/artist/patterns"
|
||||||
|
|
||||||
|
//go:embed assets/wintergreen.png
|
||||||
|
var defaultAtlasBytes []byte
|
||||||
|
var defaultAtlas canvas.Canvas
|
||||||
|
var defaultTextures [8][10]artist.Pattern
|
||||||
|
|
||||||
|
func atlasCell (col, row int, border artist.Inset) {
|
||||||
|
bounds := image.Rect(0, 0, 16, 16).Add(image.Pt(col, row).Mul(16))
|
||||||
|
defaultTextures[col][row] = patterns.Border {
|
||||||
|
Canvas: canvas.Cut(defaultAtlas, bounds),
|
||||||
|
Inset: border,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func atlasCol (col int, border artist.Inset) {
|
||||||
|
for index, _ := range defaultTextures[col] {
|
||||||
|
atlasCell(col, index, border)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init () {
|
||||||
|
defaultAtlasImage, _, _ := image.Decode(bytes.NewReader(defaultAtlasBytes))
|
||||||
|
defaultAtlas = canvas.FromImage(defaultAtlasImage)
|
||||||
|
|
||||||
|
// PatternDead
|
||||||
|
atlasCol(0, artist.Inset { })
|
||||||
|
// PatternRaised
|
||||||
|
atlasCol(1, artist.Inset { 6, 6, 6, 6 })
|
||||||
|
// PatternSunken
|
||||||
|
atlasCol(2, artist.Inset { 4, 4, 4, 4 })
|
||||||
|
// PatternPinboard
|
||||||
|
atlasCol(3, artist.Inset { 2, 2, 2, 2 })
|
||||||
|
// PatternButton
|
||||||
|
atlasCol(4, artist.Inset { 6, 6, 6, 6 })
|
||||||
|
// PatternInput
|
||||||
|
atlasCol(5, artist.Inset { 4, 4, 4, 4 })
|
||||||
|
// PatternGutter
|
||||||
|
atlasCol(6, artist.Inset { 4, 4, 4, 4 })
|
||||||
|
// PatternHandle
|
||||||
|
atlasCol(7, artist.Inset { 6, 6, 6, 6 })
|
||||||
|
}
|
||||||
|
|
||||||
// Default is the default theme.
|
// Default is the default theme.
|
||||||
type Default struct { }
|
type Default struct { }
|
||||||
|
|
||||||
@ -34,36 +78,52 @@ func (Default) Icon (string, IconSize, Case) canvas.Image {
|
|||||||
// Pattern returns a pattern from the default theme corresponding to the given
|
// Pattern returns a pattern from the default theme corresponding to the given
|
||||||
// pattern ID.
|
// pattern ID.
|
||||||
func (Default) Pattern (id Pattern, state State, c Case) artist.Pattern {
|
func (Default) Pattern (id Pattern, state State, c Case) artist.Pattern {
|
||||||
|
offset := 0; switch {
|
||||||
|
case state.Disabled: offset = 1
|
||||||
|
case state.Focused && state.Pressed: offset = 6
|
||||||
|
case state.Focused && state.On: offset = 7
|
||||||
|
case state.Invalid && state.Pressed: offset = 8
|
||||||
|
case state.Invalid && state.On: offset = 9
|
||||||
|
case state.Invalid: offset = 5
|
||||||
|
case state.Focused: offset = 4
|
||||||
|
case state.Pressed: offset = 2
|
||||||
|
case state.On: offset = 3
|
||||||
|
}
|
||||||
|
|
||||||
switch id {
|
switch id {
|
||||||
case PatternBackground: return patterns.Uhex(0x000000FF)
|
case PatternBackground: return patterns.Uhex(0xaaaaaaFF)
|
||||||
// case PatternDead:
|
case PatternDead: return defaultTextures[0][offset]
|
||||||
// case PatternRaised:
|
case PatternRaised: return defaultTextures[1][offset]
|
||||||
// case PatternSunken:
|
case PatternSunken: return defaultTextures[2][offset]
|
||||||
// case PatternPinboard:
|
case PatternPinboard: return defaultTextures[3][offset]
|
||||||
// case PatternButton:
|
case PatternButton: return defaultTextures[4][offset]
|
||||||
// case PatternInput:
|
case PatternInput: return defaultTextures[5][offset]
|
||||||
// case PatternGutter:
|
case PatternGutter: return defaultTextures[6][offset]
|
||||||
// case PatternHandle:
|
case PatternHandle: return defaultTextures[7][offset]
|
||||||
default: return patterns.Uhex(0x888888FF)
|
default: return patterns.Uhex(0xFF00FFFF)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Default) Color (id Color, state State, c Case) color.RGBA {
|
func (Default) Color (id Color, state State, c Case) color.RGBA {
|
||||||
switch id {
|
if state.Disabled {
|
||||||
case ColorAccent: return artist.Hex(0xFF8800FF)
|
return artist.Hex(0x444444FF)
|
||||||
case ColorForeground: return artist.Hex(0xFFFFFFFF)
|
} else {
|
||||||
default: return artist.Hex(0x888888FF)
|
switch id {
|
||||||
|
case ColorAccent: return artist.Hex(0x408090FF)
|
||||||
|
case ColorForeground: return artist.Hex(0x000000FF)
|
||||||
|
default: return artist.Hex(0x888888FF)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Padding returns the default padding value for the given pattern.
|
// Padding returns the default padding value for the given pattern.
|
||||||
func (Default) Padding (pattern Pattern, c Case) artist.Inset {
|
func (Default) Padding (pattern Pattern, c Case) artist.Inset {
|
||||||
return artist.Inset { 4, 4, 4, 4}
|
return artist.Inset { 8, 8, 8, 8 }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Margin returns the default margin value for the given pattern.
|
// Margin returns the default margin value for the given pattern.
|
||||||
func (Default) Margin (id Pattern, c Case) image.Point {
|
func (Default) Margin (id Pattern, c Case) image.Point {
|
||||||
return image.Pt(4, 4)
|
return image.Pt(8, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hints returns rendering optimization hints for a particular pattern.
|
// Hints returns rendering optimization hints for a particular pattern.
|
||||||
|
Reference in New Issue
Block a user