This repository has been archived on 2023-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
tomo-old/theme/default.go

268 lines
8.0 KiB
Go
Raw Normal View History

2023-02-02 22:57:18 -07:00
package theme
import "image"
2023-02-27 10:48:44 -07:00
import "bytes"
import _ "embed"
import _ "image/png"
2023-02-26 20:20:17 -07:00
import "image/color"
2023-02-02 22:57:18 -07:00
import "golang.org/x/image/font"
2023-03-04 14:18:43 -07:00
import "git.tebibyte.media/sashakoshka/tomo/data"
2023-02-02 22:57:18 -07:00
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
2023-02-02 22:57:18 -07:00
import "git.tebibyte.media/sashakoshka/tomo/defaultfont"
import "git.tebibyte.media/sashakoshka/tomo/artist/patterns"
2023-02-02 22:57:18 -07:00
2023-02-27 10:48:44 -07:00
//go:embed assets/wintergreen.png
var defaultAtlasBytes []byte
var defaultAtlas canvas.Canvas
2023-02-28 17:00:34 -07:00
var defaultTextures [14][9]artist.Pattern
2023-03-04 20:07:59 -07:00
//go:embed assets/wintergreen-icons-small.png
var defaultIconsSmallAtlasBytes []byte
var defaultIconsSmall [640]binaryIcon
2023-02-27 10:48:44 -07:00
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)
}
}
2023-03-04 20:07:59 -07:00
type binaryIcon struct {
data []bool
stride int
}
func (icon binaryIcon) Draw (destination canvas.Canvas, color color.RGBA, at image.Point) {
bounds := icon.Bounds().Add(at).Intersect(destination.Bounds())
point := image.Point { }
data, stride := destination.Buffer()
for point.Y = bounds.Min.Y; point.Y < bounds.Max.Y; point.Y ++ {
for point.X = bounds.Min.X; point.X < bounds.Max.X; point.X ++ {
srcPoint := point.Sub(at)
srcIndex := srcPoint.X + srcPoint.Y * icon.stride
dstIndex := point.X + point.Y * stride
if icon.data[srcIndex] {
data[dstIndex] = color
}
}}
}
func (icon binaryIcon) Bounds () image.Rectangle {
return image.Rect(0, 0, icon.stride, len(icon.data) / icon.stride)
}
func binaryIconFrom (source image.Image, clip image.Rectangle) (icon binaryIcon) {
bounds := source.Bounds().Intersect(clip)
if bounds.Empty() { return }
icon.stride = bounds.Dx()
icon.data = make([]bool, bounds.Dx() * bounds.Dy())
point := image.Point { }
dstIndex := 0
for point.Y = bounds.Min.Y; point.Y < bounds.Max.Y; point.Y ++ {
for point.X = bounds.Min.X; point.X < bounds.Max.X; point.X ++ {
r, g, b, a := source.At(point.X, point.Y).RGBA()
if a > 0x8000 && (r + g + b) / 3 < 0x8000 {
icon.data[dstIndex] = true
}
dstIndex ++
}}
return
}
2023-02-27 10:48:44 -07:00
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 })
2023-02-27 10:48:44 -07:00
// 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 })
2023-02-27 10:48:44 -07:00
// PatternInput
atlasCol(5, artist.Inset { 4, 4, 4, 4 })
// PatternGutter
atlasCol(6, artist.Inset { 7, 7, 7, 7 })
2023-02-27 10:48:44 -07:00
// PatternHandle
2023-03-01 11:06:34 -07:00
atlasCol(7, artist.Inset { 3, 3, 3, 3 })
// PatternLine
atlasCol(8, artist.Inset { 1, 1, 1, 1 })
2023-02-28 17:00:34 -07:00
// PatternMercury
atlasCol(13, artist.Inset { 2, 2, 2, 2 })
// PatternButton: basic.checkbox
atlasCol(9, artist.Inset { 3, 3, 3, 3 })
// PatternRaised: basic.listEntry
atlasCol(10, artist.Inset { 3, 3, 3, 3 })
// PatternRaised: fun.flatKey
atlasCol(11, artist.Inset { 3, 3, 5, 3 })
// PatternRaised: fun.sharpKey
atlasCol(12, artist.Inset { 3, 3, 4, 3 })
2023-03-04 20:07:59 -07:00
// set up small icons
defaultIconsSmallAtlasImage, _, _ := image.Decode (
bytes.NewReader(defaultIconsSmallAtlasBytes))
bounds := defaultIconsSmallAtlasImage.Bounds()
point := image.Point { }
iconIndex := 0
for point.Y = bounds.Min.Y; point.Y < bounds.Max.Y; point.Y += 16 {
for point.X = bounds.Min.X; point.X < bounds.Max.X; point.X += 16 {
defaultIconsSmall[iconIndex] = binaryIconFrom (
defaultIconsSmallAtlasImage,
image.Rect(0, 0, 16, 16).Add(point))
iconIndex ++
}}
2023-02-27 10:48:44 -07:00
}
2023-02-02 22:57:18 -07:00
// Default is the default theme.
type Default struct { }
// FontFace returns the default font face.
func (Default) FontFace (style FontStyle, size FontSize, c Case) font.Face {
switch style {
case FontStyleBold:
return defaultfont.FaceBold
case FontStyleItalic:
return defaultfont.FaceItalic
case FontStyleBoldItalic:
return defaultfont.FaceBoldItalic
default:
return defaultfont.FaceRegular
}
}
// Icon returns an icon from the default set corresponding to the given name.
2023-03-04 20:07:59 -07:00
func (Default) Icon (id Icon, size IconSize, c Case) artist.Icon {
if size == IconSizeLarge {
// TODO
return nil
} else {
if id < 0 || int(id) >= len(defaultIconsSmall) {
return nil
} else {
return defaultIconsSmall[id]
}
}
2023-02-02 22:57:18 -07:00
}
2023-03-04 14:18:43 -07:00
// MimeIcon returns an icon from the default set corresponding to the given mime.
// type.
2023-03-04 18:48:46 -07:00
func (Default) MimeIcon (data.Mime, IconSize, Case) artist.Icon {
2023-03-04 14:18:43 -07:00
// TODO
return nil
}
2023-02-02 22:57:18 -07:00
// Pattern returns a pattern from the default theme corresponding to the given
// pattern ID.
2023-02-26 20:20:17 -07:00
func (Default) Pattern (id Pattern, state State, c Case) artist.Pattern {
2023-02-27 10:48:44 -07:00
offset := 0; switch {
case state.Disabled: offset = 1
case state.Pressed && state.On: offset = 4
2023-02-27 10:48:44 -07:00
case state.Focused && state.On: offset = 7
case state.Invalid && state.On: offset = 8
case state.On: offset = 2
case state.Pressed: offset = 3
case state.Focused: offset = 5
case state.Invalid: offset = 6
2023-02-27 10:48:44 -07:00
}
2023-02-26 20:20:17 -07:00
switch id {
2023-02-27 10:48:44 -07:00
case PatternBackground: return patterns.Uhex(0xaaaaaaFF)
case PatternDead: return defaultTextures[0][offset]
case PatternRaised:
if c == C("basic", "listEntry") {
return defaultTextures[10][offset]
} else {
return defaultTextures[1][offset]
}
2023-02-27 10:48:44 -07:00
case PatternSunken: return defaultTextures[2][offset]
case PatternPinboard: return defaultTextures[3][offset]
case PatternButton:
switch c {
case C("basic", "checkbox"): return defaultTextures[9][offset]
case C("fun", "flatKey"): return defaultTextures[11][offset]
case C("fun", "sharpKey"): return defaultTextures[12][offset]
default: return defaultTextures[4][offset]
}
2023-02-27 10:48:44 -07:00
case PatternInput: return defaultTextures[5][offset]
case PatternGutter: return defaultTextures[6][offset]
case PatternHandle: return defaultTextures[7][offset]
case PatternLine: return defaultTextures[8][offset]
2023-02-28 17:00:34 -07:00
case PatternMercury: return defaultTextures[13][offset]
2023-02-27 10:48:44 -07:00
default: return patterns.Uhex(0xFF00FFFF)
2023-02-02 22:57:18 -07:00
}
}
2023-02-26 20:20:17 -07:00
func (Default) Color (id Color, state State, c Case) color.RGBA {
2023-02-27 10:48:44 -07:00
if state.Disabled {
return artist.Hex(0x444444FF)
} else {
switch id {
case ColorAccent: return artist.Hex(0x408090FF)
case ColorForeground: return artist.Hex(0x000000FF)
default: return artist.Hex(0x888888FF)
}
2023-02-26 20:20:17 -07:00
}
}
// Padding returns the default padding value for the given pattern.
2023-02-27 15:00:28 -07:00
func (Default) Padding (id Pattern, c Case) artist.Inset {
switch id {
case PatternRaised:
if c == C("basic", "listEntry") {
return artist.Inset { 4, 8, 4, 8 }
} else {
return artist.Inset { 8, 8, 8, 8 }
}
2023-02-27 15:00:28 -07:00
case PatternSunken:
if c == C("basic", "list") {
return artist.Inset { 4, 0, 3, 0 }
2023-02-28 17:00:34 -07:00
} else if c == C("basic", "progressBar") {
return artist.Inset { 2, 1, 1, 2 }
} else {
return artist.Inset { 8, 8, 8, 8 }
}
case PatternPinboard:
if c == C("fun", "piano") {
2023-02-27 15:00:28 -07:00
return artist.Inset { 2, 2, 2, 2 }
} else {
return artist.Inset { 8, 8, 8, 8 }
}
case PatternGutter: return artist.Inset { }
case PatternLine: return artist.Inset { 1, 1, 1, 1 }
2023-02-28 17:00:34 -07:00
case PatternMercury: return artist.Inset { 5, 5, 5, 5 }
2023-02-27 15:00:28 -07:00
default: return artist.Inset { 8, 8, 8, 8 }
}
}
2023-02-09 09:38:01 -07:00
// Margin returns the default margin value for the given pattern.
func (Default) Margin (id Pattern, c Case) image.Point {
2023-02-27 10:48:44 -07:00
return image.Pt(8, 8)
2023-02-02 22:57:18 -07:00
}
// Hints returns rendering optimization hints for a particular pattern.
// These are optional, but following them may result in improved
// performance.
func (Default) Hints (pattern Pattern, c Case) (hints Hints) {
return
}
2023-02-02 22:57:18 -07:00
// Sink returns the default sink vector for the given pattern.
func (Default) Sink (pattern Pattern, c Case) image.Point {
return image.Point { 1, 1 }
}