erm/vendor/github.com/lxn/walk/graphicseffects.go
2021-07-30 23:29:20 +01:00

293 lines
7.6 KiB
Go

// Copyright 2017 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package walk
import "math"
var (
borderGlowAlpha = []float64{0.2, 0.1, 0.075, 0.05, 0.075}
InteractionEffect WidgetGraphicsEffect
FocusEffect WidgetGraphicsEffect
)
type WidgetGraphicsEffect interface {
Draw(widget Widget, canvas *Canvas) error
}
type widgetGraphicsEffectBase struct {
color Color
dpi2Bitmap map[int]*Bitmap
}
func (wgeb *widgetGraphicsEffectBase) create(color Color) error {
wgeb.color = color
return nil
}
func (wgeb *widgetGraphicsEffectBase) Dispose() {
if len(wgeb.dpi2Bitmap) == 0 {
return
}
for dpi, bitmap := range wgeb.dpi2Bitmap {
bitmap.Dispose()
delete(wgeb.dpi2Bitmap, dpi)
}
}
func (wgeb *widgetGraphicsEffectBase) bitmapForDPI(dpi int) (*Bitmap, error) {
if wgeb.dpi2Bitmap == nil {
wgeb.dpi2Bitmap = make(map[int]*Bitmap)
} else if bitmap, ok := wgeb.dpi2Bitmap[dpi]; ok {
return bitmap, nil
}
var disposables Disposables
defer disposables.Treat()
bitmap, err := NewBitmapWithTransparentPixelsForDPI(SizeFrom96DPI(Size{12, 12}, dpi), dpi)
if err != nil {
return nil, err
}
disposables.Add(bitmap)
canvas, err := NewCanvasFromImage(bitmap)
if err != nil {
return nil, err
}
defer canvas.Dispose()
for i := 1; i <= 5; i++ {
size := SizeFrom96DPI(Size{i*2 + 2, i*2 + 2}, dpi)
bmp, err := NewBitmapWithTransparentPixelsForDPI(size, dpi)
if err != nil {
return nil, err
}
defer bmp.Dispose()
bmpCanvas, err := NewCanvasFromImage(bmp)
if err != nil {
return nil, err
}
defer bmpCanvas.Dispose()
color := RGB(
byte(math.Min(1.0, float64(wgeb.color.R())/255.0-0.1+0.1*float64(i))*255.0),
byte(math.Min(1.0, float64(wgeb.color.G())/255.0-0.1+0.1*float64(i))*255.0),
byte(math.Min(1.0, float64(wgeb.color.B())/255.0-0.1+0.1*float64(i))*255.0),
)
brush, err := NewSolidColorBrush(color)
if err != nil {
return nil, err
}
defer brush.Dispose()
ellipseSize := SizeFrom96DPI(Size{i * 2, i * 2}, dpi)
if err := bmpCanvas.FillRoundedRectanglePixels(brush, Rectangle{0, 0, size.Width, size.Height}, ellipseSize); err != nil {
return nil, err
}
bmpCanvas.Dispose()
opacity := byte(borderGlowAlpha[i-1] * 255.0)
offset := PointFrom96DPI(Point{5 - i, 5 - i}, dpi)
canvas.DrawBitmapWithOpacityPixels(bmp, Rectangle{offset.X, offset.Y, size.Width, size.Height}, opacity)
}
disposables.Spare()
wgeb.dpi2Bitmap[dpi] = bitmap
return bitmap, nil
}
type BorderGlowEffect struct {
widgetGraphicsEffectBase
}
func NewBorderGlowEffect(color Color) (*BorderGlowEffect, error) {
bge := new(BorderGlowEffect)
if err := bge.create(color); err != nil {
return nil, err
}
return bge, nil
}
func (bge *BorderGlowEffect) Draw(widget Widget, canvas *Canvas) error {
b := widget.BoundsPixels()
dpi := canvas.DPI()
bitmap, err := bge.bitmapForDPI(dpi)
if err != nil {
return err
}
off1 := IntFrom96DPI(1, dpi)
off2 := IntFrom96DPI(2, dpi)
off5 := IntFrom96DPI(5, dpi)
canvas.DrawBitmapPart(bitmap, Rectangle{b.X - off5, b.Y - off5, off5, off5}, Rectangle{0, 0, off5, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X, b.Y - off5, b.Width, off5}, Rectangle{off5 + off1, 0, off1, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y - off5, off5, off5}, Rectangle{off5 + off2, 0, off5, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y, off5, b.Height}, Rectangle{off5 + off2, off5 + off1, off5, off1})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + b.Height, off5, off5}, Rectangle{off5 + off2, off5 + off2, off5, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X, b.Y + b.Height, b.Width, off5}, Rectangle{off5 + off1, off5 + off2, off1, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X - off5, b.Y + b.Height, off5, off5}, Rectangle{0, off5 + off2, off5, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X - off5, b.Y, off5, b.Height}, Rectangle{0, off5 + off1, off5, off1})
return nil
}
type DropShadowEffect struct {
widgetGraphicsEffectBase
}
func NewDropShadowEffect(color Color) (*DropShadowEffect, error) {
dse := new(DropShadowEffect)
if err := dse.create(color); err != nil {
return nil, err
}
return dse, nil
}
func (dse *DropShadowEffect) Draw(widget Widget, canvas *Canvas) error {
b := widget.BoundsPixels()
dpi := canvas.DPI()
bitmap, err := dse.bitmapForDPI(dpi)
if err != nil {
return err
}
off1 := IntFrom96DPI(1, dpi)
off2 := IntFrom96DPI(2, dpi)
off5 := IntFrom96DPI(5, dpi)
off10 := IntFrom96DPI(10, dpi)
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + off10 - off5, off5, off5}, Rectangle{off5 + off2, 0, off5, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + off10, off5, b.Height - off10}, Rectangle{off5 + off2, off5 + off1, off5, off1})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + b.Height, off5, off5}, Rectangle{off5 + off2, off5 + off2, off5, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + off10, b.Y + b.Height, b.Width - off10, off5}, Rectangle{off5 + off1, off5 + off2, off1, off5})
canvas.DrawBitmapPart(bitmap, Rectangle{b.X + off10 - off5, b.Y + b.Height, off5, off5}, Rectangle{0, off5 + off2, off5, off5})
return nil
}
type widgetGraphicsEffectListObserver interface {
onInsertedGraphicsEffect(index int, effect WidgetGraphicsEffect) error
onRemovedGraphicsEffect(index int, effect WidgetGraphicsEffect) error
onClearedGraphicsEffects() error
}
type WidgetGraphicsEffectList struct {
items []WidgetGraphicsEffect
observer widgetGraphicsEffectListObserver
}
func newWidgetGraphicsEffectList(observer widgetGraphicsEffectListObserver) *WidgetGraphicsEffectList {
return &WidgetGraphicsEffectList{observer: observer}
}
func (l *WidgetGraphicsEffectList) Add(effect WidgetGraphicsEffect) error {
if effect == nil {
return newError("effect == nil")
}
return l.Insert(len(l.items), effect)
}
func (l *WidgetGraphicsEffectList) At(index int) WidgetGraphicsEffect {
return l.items[index]
}
func (l *WidgetGraphicsEffectList) Clear() error {
observer := l.observer
oldItems := l.items
l.items = l.items[:0]
if observer != nil {
if err := observer.onClearedGraphicsEffects(); err != nil {
l.items = oldItems
return err
}
}
return nil
}
func (l *WidgetGraphicsEffectList) Index(effect WidgetGraphicsEffect) int {
for i, item := range l.items {
if item == effect {
return i
}
}
return -1
}
func (l *WidgetGraphicsEffectList) Contains(effect WidgetGraphicsEffect) bool {
return l.Index(effect) > -1
}
func (l *WidgetGraphicsEffectList) insertIntoSlice(index int, effect WidgetGraphicsEffect) {
l.items = append(l.items, nil)
copy(l.items[index+1:], l.items[index:])
l.items[index] = effect
}
func (l *WidgetGraphicsEffectList) Insert(index int, effect WidgetGraphicsEffect) error {
observer := l.observer
l.insertIntoSlice(index, effect)
if observer != nil {
if err := observer.onInsertedGraphicsEffect(index, effect); err != nil {
l.items = append(l.items[:index], l.items[index+1:]...)
return err
}
}
return nil
}
func (l *WidgetGraphicsEffectList) Len() int {
return len(l.items)
}
func (l *WidgetGraphicsEffectList) Remove(effect WidgetGraphicsEffect) error {
index := l.Index(effect)
if index == -1 {
return nil
}
return l.RemoveAt(index)
}
func (l *WidgetGraphicsEffectList) RemoveAt(index int) error {
observer := l.observer
item := l.items[index]
l.items = append(l.items[:index], l.items[index+1:]...)
if observer != nil {
if err := observer.onRemovedGraphicsEffect(index, item); err != nil {
l.insertIntoSlice(index, item)
return err
}
}
return nil
}