adam-gui/vendor/fyne.io/fyne/v2/internal/widget/shadow.go
2024-04-29 19:13:50 +02:00

190 lines
4.8 KiB
Go

package widget
import (
"image/color"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
)
var _ fyne.Widget = (*Shadow)(nil)
// Shadow is a widget that renders a shadow.
type Shadow struct {
Base
level ElevationLevel
typ ShadowType
}
// ElevationLevel is the level of elevation of the shadow casting object.
type ElevationLevel int
// ElevationLevel constants inspired by:
// https://storage.googleapis.com/spec-host/mio-staging%2Fmio-design%2F1584058305895%2Fassets%2F0B6xUSjjSulxceF9udnA4Sk5tdU0%2Fbaselineelevation-chart.png
const (
BaseLevel ElevationLevel = 0
CardLevel ElevationLevel = 1
ButtonLevel ElevationLevel = 2
MenuLevel ElevationLevel = 4
PopUpLevel ElevationLevel = 8
SubmergedContentLevel ElevationLevel = 8
DialogLevel ElevationLevel = 24
)
// ShadowType specifies the type of the shadow.
type ShadowType int
// ShadowType constants
const (
ShadowAround ShadowType = iota
ShadowLeft
ShadowRight
ShadowBottom
ShadowTop
)
// NewShadow create a new Shadow.
func NewShadow(typ ShadowType, level ElevationLevel) *Shadow {
s := &Shadow{typ: typ, level: level}
s.ExtendBaseWidget(s)
return s
}
// CreateRenderer returns a new renderer for the shadow.
//
// Implements: fyne.Widget
func (s *Shadow) CreateRenderer() fyne.WidgetRenderer {
r := &shadowRenderer{s: s}
r.createShadows()
return r
}
type shadowRenderer struct {
BaseRenderer
b, l, r, t *canvas.LinearGradient
bl, br, tl, tr *canvas.RadialGradient
minSize fyne.Size
s *Shadow
}
func (r *shadowRenderer) Layout(size fyne.Size) {
depth := float32(r.s.level)
if r.tl != nil {
r.tl.Resize(fyne.NewSize(depth, depth))
r.tl.Move(fyne.NewPos(-depth, -depth))
}
if r.t != nil {
r.t.Resize(fyne.NewSize(size.Width, depth))
r.t.Move(fyne.NewPos(0, -depth))
}
if r.tr != nil {
r.tr.Resize(fyne.NewSize(depth, depth))
r.tr.Move(fyne.NewPos(size.Width, -depth))
}
if r.r != nil {
r.r.Resize(fyne.NewSize(depth, size.Height))
r.r.Move(fyne.NewPos(size.Width, 0))
}
if r.br != nil {
r.br.Resize(fyne.NewSize(depth, depth))
r.br.Move(fyne.NewPos(size.Width, size.Height))
}
if r.b != nil {
r.b.Resize(fyne.NewSize(size.Width, depth))
r.b.Move(fyne.NewPos(0, size.Height))
}
if r.bl != nil {
r.bl.Resize(fyne.NewSize(depth, depth))
r.bl.Move(fyne.NewPos(-depth, size.Height))
}
if r.l != nil {
r.l.Resize(fyne.NewSize(depth, size.Height))
r.l.Move(fyne.NewPos(-depth, 0))
}
}
func (r *shadowRenderer) MinSize() fyne.Size {
return r.minSize
}
func (r *shadowRenderer) Refresh() {
r.refreshShadows()
r.Layout(r.s.Size())
canvas.Refresh(r.s)
}
func (r *shadowRenderer) createShadows() {
switch r.s.typ {
case ShadowLeft:
r.l = canvas.NewHorizontalGradient(color.Transparent, theme.ShadowColor())
r.SetObjects([]fyne.CanvasObject{r.l})
case ShadowRight:
r.r = canvas.NewHorizontalGradient(theme.ShadowColor(), color.Transparent)
r.SetObjects([]fyne.CanvasObject{r.r})
case ShadowBottom:
r.b = canvas.NewVerticalGradient(theme.ShadowColor(), color.Transparent)
r.SetObjects([]fyne.CanvasObject{r.b})
case ShadowTop:
r.t = canvas.NewVerticalGradient(color.Transparent, theme.ShadowColor())
r.SetObjects([]fyne.CanvasObject{r.t})
case ShadowAround:
r.tl = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent)
r.tl.CenterOffsetX = 0.5
r.tl.CenterOffsetY = 0.5
r.t = canvas.NewVerticalGradient(color.Transparent, theme.ShadowColor())
r.tr = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent)
r.tr.CenterOffsetX = -0.5
r.tr.CenterOffsetY = 0.5
r.r = canvas.NewHorizontalGradient(theme.ShadowColor(), color.Transparent)
r.br = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent)
r.br.CenterOffsetX = -0.5
r.br.CenterOffsetY = -0.5
r.b = canvas.NewVerticalGradient(theme.ShadowColor(), color.Transparent)
r.bl = canvas.NewRadialGradient(theme.ShadowColor(), color.Transparent)
r.bl.CenterOffsetX = 0.5
r.bl.CenterOffsetY = -0.5
r.l = canvas.NewHorizontalGradient(color.Transparent, theme.ShadowColor())
r.SetObjects([]fyne.CanvasObject{r.tl, r.t, r.tr, r.r, r.br, r.b, r.bl, r.l})
}
}
func (r *shadowRenderer) refreshShadows() {
updateShadowEnd(r.l)
updateShadowStart(r.r)
updateShadowStart(r.b)
updateShadowEnd(r.t)
updateShadowRadial(r.tl)
updateShadowRadial(r.tr)
updateShadowRadial(r.bl)
updateShadowRadial(r.br)
}
func updateShadowEnd(g *canvas.LinearGradient) {
if g == nil {
return
}
g.EndColor = theme.ShadowColor()
g.Refresh()
}
func updateShadowRadial(g *canvas.RadialGradient) {
if g == nil {
return
}
g.StartColor = theme.ShadowColor()
g.Refresh()
}
func updateShadowStart(g *canvas.LinearGradient) {
if g == nil {
return
}
g.StartColor = theme.ShadowColor()
g.Refresh()
}