226 lines
6.5 KiB
Go
226 lines
6.5 KiB
Go
package tomo
|
|
|
|
import "fmt"
|
|
import "image"
|
|
import "image/color"
|
|
|
|
// Side represents one side of a rectangle.
|
|
type Side int; const (
|
|
SideTop Side = iota
|
|
SideRight
|
|
SideBottom
|
|
SideLeft
|
|
)
|
|
|
|
func (side Side) String () string {
|
|
switch side {
|
|
case SideTop: return "SideTop"
|
|
case SideRight: return "SideRight"
|
|
case SideBottom: return "SideBottom"
|
|
case SideLeft: return "SideLeft"
|
|
default: return fmt.Sprintf("Side(%d)", side)
|
|
}
|
|
}
|
|
|
|
// Inset represents a rectangle inset that can have a different value for each
|
|
// side.
|
|
type Inset [4]int
|
|
|
|
// I allows you to create an inset in a CSS-ish way:
|
|
//
|
|
// - One argument: all sides are set to this value
|
|
// - Two arguments: the top and bottom sides are set to the first value, and
|
|
// the left and right sides are set to the second value.
|
|
// - Three arguments: the top side is set by the first value, the left and
|
|
// right sides are set by the second vaue, and the bottom side is set by the
|
|
// third value.
|
|
// - Four arguments: each value corresponds to a side.
|
|
//
|
|
// This function will panic if an argument count that isn't one of these is
|
|
// given.
|
|
func I (sides ...int) Inset {
|
|
switch len(sides) {
|
|
case 1: return Inset { sides[0], sides[0], sides[0], sides[0] }
|
|
case 2: return Inset { sides[0], sides[1], sides[0], sides[1] }
|
|
case 3: return Inset { sides[0], sides[1], sides[2], sides[1] }
|
|
case 4: return Inset { sides[0], sides[1], sides[2], sides[3] }
|
|
default: panic("I: illegal argument count.")
|
|
}
|
|
}
|
|
|
|
func (inset Inset) String () string {
|
|
return fmt.Sprintf("%d %d %d %d", inset[0], inset[1], inset[2], inset[3])
|
|
}
|
|
|
|
// Apply returns the given image.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
|
|
if smaller.Dx() < inset[3] + inset[1] {
|
|
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]
|
|
}
|
|
|
|
if smaller.Dy() < inset[0] + inset[2] {
|
|
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,
|
|
}
|
|
}
|
|
|
|
// Horizontal returns the sum of SideRight and SideLeft.
|
|
func (inset Inset) Horizontal () int {
|
|
return inset[SideRight] + inset[SideLeft]
|
|
}
|
|
|
|
// Vertical returns the sum of SideTop and SideBottom.
|
|
func (inset Inset) Vertical () int {
|
|
return inset[SideTop] + inset[SideBottom]
|
|
}
|
|
|
|
// Border represents a single border of a Box.
|
|
type Border struct {
|
|
Width Inset
|
|
Color [4]color.Color
|
|
}
|
|
|
|
func (border Border) String () string {
|
|
return fmt.Sprintf("%v %v %v %v / %v",
|
|
border.Color[0], border.Color[1], border.Color[2], border.Color[3],
|
|
border.Width)
|
|
}
|
|
|
|
// Align lists basic alignment types.
|
|
type Align int; const (
|
|
AlignStart Align = iota // similar to left-aligned text
|
|
AlignMiddle // similar to center-aligned text
|
|
AlignEnd // similar to right-aligned text
|
|
AlignEven // similar to justified text
|
|
)
|
|
|
|
func (align Align) String () string {
|
|
switch align {
|
|
case AlignStart: return "AlignStart"
|
|
case AlignMiddle: return "AlignMiddle"
|
|
case AlignEnd: return "AlignEnd"
|
|
case AlignEven: return "AlignEven"
|
|
default: return fmt.Sprintf("Align(%d)", align)
|
|
}
|
|
}
|
|
|
|
// TextureMode lists texture rendering modes.
|
|
type TextureMode int; const (
|
|
TextureModeTile TextureMode = iota
|
|
TextureModeCenter
|
|
|
|
// TODO more modes: fit, fill, and stretch
|
|
// Of course canvas will need to have a concept of this.
|
|
)
|
|
|
|
func (mode TextureMode) String () string {
|
|
switch mode {
|
|
case TextureModeTile: return "TextureModeTile"
|
|
case TextureModeCenter: return "TextureModeCenter"
|
|
default: return fmt.Sprintf("TextureMode(%d)", mode)
|
|
}
|
|
}
|
|
|
|
// Face represents a typeface.
|
|
type Face struct {
|
|
// Font specifies the font name. This should be searched for in a list
|
|
// of installed fonts.
|
|
Font string
|
|
// Size is the point size of the face.
|
|
Size float64
|
|
// Weight is the weight of the face. If zero, it should be interpreted
|
|
// as normal (equivalent to 400).
|
|
Weight int
|
|
// Italic is how italicized the face is. It ranges from 0 to 1. It is
|
|
// different from Slant in that it may alter the design of the glyphs
|
|
// instead of simply skewing them.
|
|
Italic float64
|
|
// Slant is how slanted the face is. It ranges from 0 to 1. It is
|
|
// different from Italic in that it simply skews the glyphs without
|
|
// altering their design.
|
|
Slant float64
|
|
}
|
|
|
|
func (face Face) String () string {
|
|
return fmt.Sprintf (
|
|
"%s %fpt W%d I%f S%f",
|
|
face.Font, face.Size, face.Weight, face.Italic, face.Slant)
|
|
}
|
|
|
|
// Role describes the role of an Object.
|
|
type Role struct {
|
|
// Package is an optional namespace field. If specified, it should be
|
|
// the package name or module name the object is from.
|
|
Package string
|
|
|
|
// Object specifies what type of Object it is. For example:
|
|
// - TextInput
|
|
// - Table
|
|
// - Label
|
|
// - Dial
|
|
// This should correspond directly to the type name of the Object.
|
|
Object string
|
|
}
|
|
|
|
// String satisfies the fmt.Stringer interface. It follows the format of:
|
|
// Package.Object
|
|
func (r Role) String () string {
|
|
return fmt.Sprintf("%s.%s", r.Package, r.Object)
|
|
}
|
|
|
|
// R is a convenience constructor for Role.
|
|
func R (pack, object string) Role {
|
|
return Role { Package: pack, Object: object }
|
|
}
|
|
|
|
// Color represents a color ID.
|
|
type Color int; const (
|
|
ColorBackground Color = iota
|
|
ColorForeground
|
|
ColorRaised
|
|
ColorSunken
|
|
ColorAccent
|
|
)
|
|
|
|
func (id Color) String () string {
|
|
switch id {
|
|
case ColorBackground: return "ColorBackground"
|
|
case ColorForeground: return "ColorForeground"
|
|
case ColorRaised: return "ColorRaised"
|
|
case ColorSunken: return "ColorSunken"
|
|
case ColorAccent: return "ColorAccent"
|
|
default: return fmt.Sprintf("Color(%d)", id)
|
|
}
|
|
}
|
|
|
|
// RGBA satisfies the color.Color interface. The result of this method may be
|
|
// rendered invalid if the visual style changes, so it is often necessary to
|
|
// subscribe to the StyleChange event in order to get new RGBA values when this
|
|
// happens.
|
|
func (id Color) RGBA () (r, g, b, a uint32) {
|
|
assertBackend()
|
|
return backend.ColorRGBA(id)
|
|
}
|