add CaptionedImage widget
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
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 {
|
||||
// Content will use full height, but not full width
|
||||
contentW := contentMaxedHeight * aspect
|
||||
content.Resize(fyne.NewSize(contentW, contentMaxedHeight))
|
||||
contentX := (s.Width - contentW) / 2
|
||||
content.Move(fyne.NewPos(contentX, 0))
|
||||
if caption != nil {
|
||||
caption.Resize(fyne.NewSize(s.Width, captionHeight))
|
||||
caption.Move(fyne.NewPos(0, 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())
|
||||
}
|
||||
Reference in New Issue
Block a user