240 lines
5.2 KiB
Go
240 lines
5.2 KiB
Go
package uiwidget
|
|
|
|
import (
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/data/binding"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
type ScoreDisplayResources struct {
|
|
Empty fyne.Resource
|
|
Digits [10]fyne.Resource
|
|
}
|
|
|
|
func NewScoreDisplayResources(
|
|
empty fyne.Resource,
|
|
digits [10]fyne.Resource,
|
|
) *ScoreDisplayResources {
|
|
return &ScoreDisplayResources{
|
|
Empty: empty,
|
|
Digits: digits,
|
|
}
|
|
}
|
|
|
|
type ScoreDisplay struct {
|
|
widget.BaseWidget
|
|
|
|
Score int
|
|
|
|
scoreBinding binding.Int
|
|
numDigits int
|
|
digits []*canvas.Image
|
|
resources *ScoreDisplayResources
|
|
layout *ScoreDisplayLayout
|
|
cont *fyne.Container
|
|
relSize *fyne.Size
|
|
fixedSize *fyne.Size
|
|
}
|
|
|
|
func NewScoreDisplay(
|
|
score int,
|
|
numDigits int,
|
|
resources *ScoreDisplayResources,
|
|
relSize *fyne.Size,
|
|
fizedSize *fyne.Size,
|
|
) *ScoreDisplay {
|
|
sd := new(ScoreDisplay)
|
|
sd.Score = score
|
|
sd.numDigits = numDigits
|
|
sd.resources = resources
|
|
sd.digits = make([]*canvas.Image, numDigits)
|
|
for i := 0; i < numDigits; i++ {
|
|
sd.digits[i] = canvas.NewImageFromResource(resources.Empty)
|
|
}
|
|
sd.relSize = relSize
|
|
sd.fixedSize = fizedSize
|
|
sd.ExtendBaseWidget(sd)
|
|
sd.updateScore()
|
|
return sd
|
|
}
|
|
|
|
func NewScoreDisplayWithData(
|
|
scoreBinding binding.Int,
|
|
numDigits int,
|
|
resources *ScoreDisplayResources,
|
|
relSize *fyne.Size,
|
|
fixedSize *fyne.Size,
|
|
) *ScoreDisplay {
|
|
sd := new(ScoreDisplay)
|
|
sd.scoreBinding = scoreBinding
|
|
sd.numDigits = numDigits
|
|
sd.resources = resources
|
|
sd.digits = make([]*canvas.Image, numDigits)
|
|
for i := 0; i < numDigits; i++ {
|
|
sd.digits[i] = canvas.NewImageFromResource(resources.Empty)
|
|
}
|
|
sd.relSize = relSize
|
|
sd.fixedSize = fixedSize
|
|
sd.ExtendBaseWidget(sd)
|
|
sd.scoreBinding.AddListener(sd)
|
|
return sd
|
|
}
|
|
|
|
func (sd *ScoreDisplay) CreateRenderer() fyne.WidgetRenderer {
|
|
sd.layout = NewScoreDisplayLayout(sd.relSize, sd.fixedSize)
|
|
sd.cont = container.New(sd.layout)
|
|
for i := sd.numDigits; i > 0; i-- {
|
|
digit := sd.digits[i-1]
|
|
sd.cont.Add(digit)
|
|
}
|
|
|
|
return widget.NewSimpleRenderer(sd.cont)
|
|
}
|
|
|
|
func (sd *ScoreDisplay) Refresh() {
|
|
sd.updateScore()
|
|
sd.BaseWidget.Refresh()
|
|
}
|
|
|
|
func (sd *ScoreDisplay) Resize(size fyne.Size) {
|
|
if sd.fixedSize != nil {
|
|
sd.fixedSize = &size
|
|
}
|
|
}
|
|
|
|
func (sd *ScoreDisplay) Size() fyne.Size {
|
|
if sd.layout == nil {
|
|
if sd.fixedSize != nil {
|
|
return *sd.fixedSize
|
|
} else if sd.relSize != nil {
|
|
canvas := fyne.CurrentApp().Driver().AllWindows()[0].Canvas()
|
|
if canvas == nil {
|
|
return fyne.NewSize(0, 0)
|
|
}
|
|
size := fyne.NewSize(
|
|
canvas.Size().Width*sd.relSize.Width,
|
|
canvas.Size().Height*sd.relSize.Height,
|
|
)
|
|
return size
|
|
} else {
|
|
return fyne.NewSize(0, 0)
|
|
}
|
|
|
|
}
|
|
return sd.layout.CurrentSize()
|
|
}
|
|
|
|
func (sd *ScoreDisplay) MinSize() fyne.Size {
|
|
return sd.Size()
|
|
}
|
|
|
|
func (sd *ScoreDisplay) DataChanged() {
|
|
var err error
|
|
|
|
sd.Score, err = sd.scoreBinding.Get()
|
|
if err != nil {
|
|
return
|
|
}
|
|
sd.Refresh()
|
|
}
|
|
|
|
func (sd *ScoreDisplay) updateScore() {
|
|
aspect := float32(0)
|
|
score := sd.Score
|
|
for i := 0; i < sd.numDigits; i++ {
|
|
digit := score % 10
|
|
score /= 10
|
|
if i != 0 && digit == 0 && score == 0 {
|
|
sd.digits[i].Resource = sd.resources.Empty
|
|
} else {
|
|
sd.digits[i].Resource = sd.resources.Digits[digit]
|
|
}
|
|
sd.digits[i].ScaleMode = canvas.ImageScaleSmooth
|
|
sd.digits[i].FillMode = canvas.ImageFillContain
|
|
sd.digits[i].Resize(fyne.NewSize(200, 300))
|
|
aspect += sd.digits[i].Aspect()
|
|
}
|
|
if sd.layout != nil {
|
|
sd.layout.setAspect(aspect)
|
|
}
|
|
}
|
|
|
|
type ScoreDisplayLayout struct {
|
|
canvas fyne.Canvas
|
|
relSize *fyne.Size
|
|
fixedSize *fyne.Size
|
|
aspect float32
|
|
currentSize fyne.Size
|
|
}
|
|
|
|
func NewScoreDisplayLayout(relSize *fyne.Size, fixedSize *fyne.Size) *ScoreDisplayLayout {
|
|
return &ScoreDisplayLayout{
|
|
relSize: relSize,
|
|
fixedSize: fixedSize,
|
|
aspect: float32(0),
|
|
}
|
|
}
|
|
|
|
func (sdl *ScoreDisplayLayout) setAspect(a float32) {
|
|
sdl.aspect = a
|
|
}
|
|
|
|
func (sdl *ScoreDisplayLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {
|
|
if sdl.fixedSize != nil {
|
|
return *sdl.fixedSize
|
|
}
|
|
return sdl.calculateSize(objects)
|
|
}
|
|
|
|
func (sdl *ScoreDisplayLayout) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) {
|
|
size := sdl.calculateSize(objects)
|
|
sdl.currentSize = size
|
|
|
|
numObjects := len(objects)
|
|
objSize := fyne.NewSize(
|
|
size.Width/float32(numObjects),
|
|
size.Height)
|
|
|
|
pos := fyne.NewPos(0, 0)
|
|
for _, o := range objects {
|
|
o.Resize(objSize)
|
|
o.Move(pos)
|
|
pos = pos.Add(fyne.NewPos(objSize.Width, 0))
|
|
}
|
|
}
|
|
|
|
func (sdl *ScoreDisplayLayout) CurrentSize() fyne.Size {
|
|
return sdl.currentSize
|
|
}
|
|
|
|
func (sdl *ScoreDisplayLayout) calculateSize(objects []fyne.CanvasObject) fyne.Size {
|
|
size := fyne.NewSize(0, 0)
|
|
if sdl.relSize != nil {
|
|
if sdl.canvas == nil && len(objects) > 0 {
|
|
sdl.canvas = fyne.CurrentApp().Driver().CanvasForObject(objects[0])
|
|
}
|
|
if sdl.canvas != nil {
|
|
size = fyne.NewSize(
|
|
sdl.canvas.Size().Width*sdl.relSize.Width,
|
|
sdl.canvas.Size().Height*sdl.relSize.Height,
|
|
)
|
|
}
|
|
} else if sdl.fixedSize != nil {
|
|
size = *sdl.fixedSize
|
|
sdl.currentSize = size
|
|
}
|
|
|
|
if sdl.aspect > 0 {
|
|
curAspect := size.Width / size.Height
|
|
if curAspect > sdl.aspect {
|
|
size.Width = size.Height * sdl.aspect
|
|
} else {
|
|
size.Height = size.Width / sdl.aspect
|
|
}
|
|
sdl.currentSize = size
|
|
}
|
|
return size
|
|
}
|