114 lines
2.7 KiB
Go
114 lines
2.7 KiB
Go
package widgets
|
|
|
|
import (
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
type Aspectable interface {
|
|
fyne.CanvasObject
|
|
Aspect() float32
|
|
}
|
|
|
|
type CaptionedImage struct {
|
|
widget.BaseWidget
|
|
|
|
Content Aspectable
|
|
Caption fyne.CanvasObject
|
|
}
|
|
|
|
var _ fyne.Widget = (*CaptionedImage)(nil)
|
|
|
|
func NewCaptionedImage(content Aspectable, caption fyne.CanvasObject) *CaptionedImage {
|
|
c := &CaptionedImage{Content: content, Caption: caption}
|
|
c.ExtendBaseWidget(c)
|
|
return c
|
|
}
|
|
|
|
func (c *CaptionedImage) CreateRenderer() fyne.WidgetRenderer {
|
|
return &captionedImageRenderer{
|
|
ci: c,
|
|
}
|
|
}
|
|
|
|
type captionedImageRenderer struct {
|
|
ci *CaptionedImage
|
|
}
|
|
|
|
var _ fyne.WidgetRenderer = (*captionedImageRenderer)(nil)
|
|
|
|
func (*captionedImageRenderer) Destroy() {
|
|
// intentionally blank
|
|
}
|
|
|
|
func (c *captionedImageRenderer) Layout(s fyne.Size) {
|
|
content := c.ci.Content
|
|
aspect := content.Aspect()
|
|
caption := c.ci.Caption
|
|
var captionHeight float32
|
|
if caption != nil {
|
|
captionHeight = caption.MinSize().Height
|
|
}
|
|
|
|
// max height that could be allocated to Content
|
|
contentMaxedHeight := s.Height
|
|
if caption != nil {
|
|
contentMaxedHeight -= captionHeight
|
|
}
|
|
|
|
// aspect ratio of Content if it were maxed out
|
|
maxedAspect := s.Width / contentMaxedHeight
|
|
if maxedAspect > aspect {
|
|
// Will use full height, but not full width
|
|
width := contentMaxedHeight * aspect
|
|
content.Resize(fyne.NewSize(width, contentMaxedHeight))
|
|
xStart := (s.Width - width) / 2
|
|
content.Move(fyne.NewPos(xStart, 0))
|
|
if caption != nil {
|
|
caption.Resize(fyne.NewSize(width, captionHeight))
|
|
caption.Move(fyne.NewPos(xStart, contentMaxedHeight))
|
|
}
|
|
return
|
|
}
|
|
|
|
// Content will not use full height
|
|
// Positioning of Content and Caption will be adjusted to center
|
|
contentH := s.Width / aspect
|
|
yStart := (s.Height - contentH - captionHeight) / 2
|
|
content.Resize(fyne.NewSize(s.Width, contentH))
|
|
content.Move(fyne.NewPos(0, yStart))
|
|
if caption != nil {
|
|
caption.Resize(fyne.NewSize(s.Width, captionHeight))
|
|
caption.Move(fyne.NewPos(0, yStart+contentH))
|
|
}
|
|
}
|
|
|
|
func (c *captionedImageRenderer) MinSize() fyne.Size {
|
|
objSize := c.ci.Content.MinSize()
|
|
if c.ci.Caption == nil {
|
|
return objSize
|
|
}
|
|
cptSize := c.ci.Caption.MinSize()
|
|
return fyne.NewSize(
|
|
fyne.Max(objSize.Width, cptSize.Width),
|
|
objSize.Height+cptSize.Height,
|
|
)
|
|
}
|
|
|
|
func (c *captionedImageRenderer) Objects() []fyne.CanvasObject {
|
|
if c.ci.Caption != nil {
|
|
return []fyne.CanvasObject{c.ci.Content, c.ci.Caption}
|
|
}
|
|
return []fyne.CanvasObject{c.ci.Content}
|
|
}
|
|
|
|
func (c *captionedImageRenderer) Refresh() {
|
|
c.ci.Content.Refresh()
|
|
if cap := c.ci.Caption; cap != nil {
|
|
cap.Refresh()
|
|
}
|
|
// aspect may have changed on Content,
|
|
// so we need to re-layout
|
|
c.Layout(c.ci.Size())
|
|
}
|