148 lines
3.6 KiB
Go
148 lines
3.6 KiB
Go
package canvas
|
|
|
|
import (
|
|
"image/color"
|
|
|
|
"github.com/tfriedel6/canvas/backend/backendbase"
|
|
)
|
|
|
|
// LinearGradient is a gradient with any number of
|
|
// stops and any number of colors. The gradient will
|
|
// be drawn such that each point on the gradient
|
|
// will correspond to a straight line
|
|
type LinearGradient struct {
|
|
cv *Canvas
|
|
created bool
|
|
loaded bool
|
|
deleted bool
|
|
opaque bool
|
|
grad backendbase.LinearGradient
|
|
data backendbase.LinearGradientData
|
|
}
|
|
|
|
// RadialGradient is a gradient with any number of
|
|
// stops and any number of colors. The gradient will
|
|
// be drawn such that each point on the gradient
|
|
// will correspond to a circle
|
|
type RadialGradient struct {
|
|
cv *Canvas
|
|
created bool
|
|
loaded bool
|
|
deleted bool
|
|
opaque bool
|
|
grad backendbase.RadialGradient
|
|
data backendbase.RadialGradientData
|
|
}
|
|
|
|
// NewLinearGradient creates a new linear gradient with
|
|
// the coordinates from where to where the gradient
|
|
// will apply on the canvas
|
|
func (cv *Canvas) NewLinearGradient(x0, y0, x1, y1 float64) *LinearGradient {
|
|
return &LinearGradient{
|
|
cv: cv,
|
|
opaque: true,
|
|
data: backendbase.LinearGradientData{
|
|
X0: x0,
|
|
Y0: y0,
|
|
X1: x1,
|
|
Y1: y1,
|
|
Stops: make(backendbase.Gradient, 0, 20),
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewRadialGradient creates a new linear gradient with
|
|
// the coordinates and the radii for two circles. The
|
|
// gradient will apply from the first to the second
|
|
// circle
|
|
func (cv *Canvas) NewRadialGradient(x0, y0, r0, x1, y1, r1 float64) *RadialGradient {
|
|
return &RadialGradient{
|
|
cv: cv,
|
|
opaque: true,
|
|
data: backendbase.RadialGradientData{
|
|
X0: x0,
|
|
Y0: y0,
|
|
X1: x1,
|
|
Y1: y1,
|
|
RadFrom: r0,
|
|
RadTo: r1,
|
|
Stops: make(backendbase.Gradient, 0, 20),
|
|
},
|
|
}
|
|
|
|
}
|
|
|
|
// Delete explicitly deletes the gradient
|
|
func (lg *LinearGradient) Delete() { lg.grad.Delete() }
|
|
|
|
// Delete explicitly deletes the gradient
|
|
func (rg *RadialGradient) Delete() { rg.grad.Delete() }
|
|
|
|
func (lg *LinearGradient) load() {
|
|
if lg.loaded || len(lg.data.Stops) < 1 {
|
|
return
|
|
}
|
|
|
|
if !lg.created {
|
|
lg.grad = lg.cv.b.LoadLinearGradient(&lg.data)
|
|
} else {
|
|
lg.grad.Replace(&lg.data)
|
|
}
|
|
lg.created = true
|
|
lg.loaded = true
|
|
}
|
|
|
|
func (rg *RadialGradient) load() {
|
|
if rg.loaded || len(rg.data.Stops) < 1 {
|
|
return
|
|
}
|
|
|
|
if !rg.created {
|
|
rg.grad = rg.cv.b.LoadRadialGradient(&rg.data)
|
|
} else {
|
|
rg.grad.Replace(&rg.data)
|
|
}
|
|
rg.created = true
|
|
rg.loaded = true
|
|
}
|
|
|
|
// AddColorStop adds a color stop to the gradient. The stops
|
|
// don't have to be added in order, they are sorted into the
|
|
// right place
|
|
func (lg *LinearGradient) AddColorStop(pos float64, stopColor ...interface{}) {
|
|
var c color.RGBA
|
|
lg.data.Stops, c = addColorStop(lg.data.Stops, pos, stopColor...)
|
|
if c.A < 255 {
|
|
lg.opaque = false
|
|
}
|
|
lg.loaded = false
|
|
}
|
|
|
|
// AddColorStop adds a color stop to the gradient. The stops
|
|
// don't have to be added in order, they are sorted into the
|
|
// right place
|
|
func (rg *RadialGradient) AddColorStop(pos float64, stopColor ...interface{}) {
|
|
var c color.RGBA
|
|
rg.data.Stops, c = addColorStop(rg.data.Stops, pos, stopColor...)
|
|
if c.A < 255 {
|
|
rg.opaque = false
|
|
}
|
|
rg.loaded = false
|
|
}
|
|
|
|
func addColorStop(stops backendbase.Gradient, pos float64, stopColor ...interface{}) (backendbase.Gradient, color.RGBA) {
|
|
c, _ := parseColor(stopColor...)
|
|
insert := len(stops)
|
|
for i, stop := range stops {
|
|
if stop.Pos > pos {
|
|
insert = i
|
|
break
|
|
}
|
|
}
|
|
stops = append(stops, backendbase.GradientStop{})
|
|
if insert < len(stops)-1 {
|
|
copy(stops[insert+1:], stops[insert:len(stops)-1])
|
|
}
|
|
stops[insert] = backendbase.GradientStop{Pos: pos, Color: c}
|
|
return stops, c
|
|
}
|