doodle/render/interface.go
Noah Petherbridge 11df6cbda9 Move most properties from Button to parent Widget
These properties will be globally useful to all sorts of Widgets and
have been moved from the Button up into the Common widget, and its
interface extended to configure these:
* Padding int32
* Background color
* Foreground color
* Border size, color and style (default solid; raised; sunken)
* Outline size and color

The button adjusts its border style from "raised" to "sunken" for
MouseDown events and its Background color for MouseOver events. Other
widgets such as Labels and Frames will be able to have borders, paddings
and outlines too, but they will be off by default.
2018-07-25 21:24:37 -07:00

199 lines
3.8 KiB
Go

package render
import (
"fmt"
"math"
"git.kirsle.net/apps/doodle/events"
)
// Engine is the interface for the rendering engine, keeping SDL-specific stuff
// far away from the core of Doodle.
type Engine interface {
Setup() error
// Poll for events like keypresses and mouse clicks.
Poll() (*events.State, error)
GetTicks() uint32
// Present presents the current state to the screen.
Present() error
// Clear the full canvas and set this color.
Clear(Color)
DrawPoint(Color, Point)
DrawLine(Color, Point, Point)
DrawRect(Color, Rect)
DrawBox(Color, Rect)
DrawText(Text, Point) error
ComputeTextRect(Text) (Rect, error)
// Delay for a moment using the render engine's delay method,
// implemented by sdl.Delay(uint32)
Delay(uint32)
// Tasks that the Setup function should defer until tear-down.
Teardown()
Loop() error // maybe?
}
// Color holds an RGBA color value.
type Color struct {
Red uint8
Green uint8
Blue uint8
Alpha uint8
}
// RGBA creates a new Color.
func RGBA(r, g, b, a uint8) Color {
return Color{
Red: r,
Green: g,
Blue: b,
Alpha: a,
}
}
func (c Color) String() string {
return fmt.Sprintf(
"Color<#%02x%02x%02x>",
c.Red, c.Green, c.Blue,
)
}
// Add a relative color value to the color.
func (c Color) Add(r, g, b, a int32) Color {
var (
R = int32(c.Red) + r
G = int32(c.Green) + g
B = int32(c.Blue) + b
A = int32(c.Alpha) + a
)
cap8 := func(v int32) uint8 {
if v > 255 {
v = 255
} else if v < 0 {
v = 0
}
return uint8(v)
}
return Color{
Red: cap8(R),
Green: cap8(G),
Blue: cap8(B),
Alpha: cap8(A),
}
}
// Point holds an X,Y coordinate value.
type Point struct {
X int32
Y int32
}
// NewPoint makes a new Point at an X,Y coordinate.
func NewPoint(x, y int32) Point {
return Point{
X: x,
Y: y,
}
}
func (p Point) String() string {
return fmt.Sprintf("Point<%d,%d>", p.X, p.Y)
}
// Rect has a coordinate and a width and height.
type Rect struct {
X int32
Y int32
W int32
H int32
}
func (r Rect) String() string {
return fmt.Sprintf("Rect<%d,%d,%d,%d>",
r.X, r.Y, r.W, r.H,
)
}
// Text holds information for drawing text.
type Text struct {
Text string
Size int
Color Color
Stroke Color // Stroke color (if not zero)
Shadow Color // Drop shadow color (if not zero)
}
func (t Text) String() string {
return fmt.Sprintf("Text<%s>", t.Text)
}
// Common color names.
var (
Invisible = Color{}
White = RGBA(255, 255, 255, 255)
Grey = RGBA(153, 153, 153, 255)
Black = RGBA(0, 0, 0, 255)
SkyBlue = RGBA(0, 153, 255, 255)
Blue = RGBA(0, 0, 255, 255)
DarkBlue = RGBA(0, 0, 153, 255)
Red = RGBA(255, 0, 0, 255)
DarkRed = RGBA(153, 0, 0, 255)
Green = RGBA(0, 255, 0, 255)
DarkGreen = RGBA(0, 153, 0, 255)
Cyan = RGBA(0, 255, 255, 255)
DarkCyan = RGBA(0, 153, 153, 255)
Yellow = RGBA(255, 255, 0, 255)
DarkYellow = RGBA(153, 153, 0, 255)
Magenta = RGBA(255, 0, 255, 255)
Purple = RGBA(153, 0, 153, 255)
Pink = RGBA(255, 153, 255, 255)
)
// IterLine is a generator that returns the X,Y coordinates to draw a line.
// https://en.wikipedia.org/wiki/Digital_differential_analyzer_(graphics_algorithm)
func IterLine(x1, y1, x2, y2 int32) chan Point {
generator := make(chan Point)
go func() {
var (
dx = float64(x2 - x1)
dy = float64(y2 - y1)
)
var step float64
if math.Abs(dx) >= math.Abs(dy) {
step = math.Abs(dx)
} else {
step = math.Abs(dy)
}
dx = dx / step
dy = dy / step
x := float64(x1)
y := float64(y1)
for i := 0; i <= int(step); i++ {
generator <- Point{
X: int32(x),
Y: int32(y),
}
x += dx
y += dy
}
close(generator)
}()
return generator
}
// IterLine2 works with two Points rather than four coordinates.
func IterLine2(p1 Point, p2 Point) chan Point {
return IterLine(p1.X, p1.Y, p2.X, p2.Y)
}