adam-gui/vendor/fyne.io/fyne/v2/internal/widget/base.go

177 lines
3.7 KiB
Go
Raw Normal View History

2024-04-29 19:13:50 +02:00
package widget
import (
"sync"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/internal/cache"
)
// Base provides a helper that handles basic widget behaviours.
type Base struct {
hidden bool
position fyne.Position
size fyne.Size
impl fyne.Widget
propertyLock sync.RWMutex
}
// ExtendBaseWidget is used by an extending widget to make use of BaseWidget functionality.
func (w *Base) ExtendBaseWidget(wid fyne.Widget) {
impl := w.super()
if impl != nil {
return
}
w.propertyLock.Lock()
defer w.propertyLock.Unlock()
w.impl = wid
}
// Size gets the current size of this widget.
func (w *Base) Size() fyne.Size {
w.propertyLock.RLock()
defer w.propertyLock.RUnlock()
return w.size
}
// Resize sets a new size for a widget.
// Note this should not be used if the widget is being managed by a Layout within a Container.
func (w *Base) Resize(size fyne.Size) {
w.propertyLock.RLock()
baseSize := w.size
impl := w.impl
w.propertyLock.RUnlock()
if baseSize == size {
return
}
w.propertyLock.Lock()
w.size = size
w.propertyLock.Unlock()
if impl == nil {
return
}
cache.Renderer(impl).Layout(size)
}
// Position gets the current position of this widget, relative to its parent.
func (w *Base) Position() fyne.Position {
w.propertyLock.RLock()
defer w.propertyLock.RUnlock()
return w.position
}
// Move the widget to a new position, relative to its parent.
// Note this should not be used if the widget is being managed by a Layout within a Container.
func (w *Base) Move(pos fyne.Position) {
w.propertyLock.Lock()
w.position = pos
w.propertyLock.Unlock()
Repaint(w.super())
}
// MinSize for the widget - it should never be resized below this value.
func (w *Base) MinSize() fyne.Size {
impl := w.super()
r := cache.Renderer(impl)
if r == nil {
return fyne.NewSize(0, 0)
}
return r.MinSize()
}
// Visible returns whether or not this widget should be visible.
// Note that this may not mean it is currently visible if a parent has been hidden.
func (w *Base) Visible() bool {
w.propertyLock.RLock()
defer w.propertyLock.RUnlock()
return !w.hidden
}
// Show this widget so it becomes visible
func (w *Base) Show() {
if w.Visible() {
return
}
w.setFieldsAndRefresh(func() {
w.hidden = false
})
}
// Hide this widget so it is no longer visible
func (w *Base) Hide() {
if !w.Visible() {
return
}
w.propertyLock.Lock()
w.hidden = true
impl := w.impl
w.propertyLock.Unlock()
if impl == nil {
return
}
canvas.Refresh(impl)
}
// Refresh causes this widget to be redrawn in it's current state
func (w *Base) Refresh() {
impl := w.super()
if impl == nil {
return
}
render := cache.Renderer(impl)
render.Refresh()
}
// setFieldsAndRefresh helps to make changes to a widget that should be followed by a refresh.
// This method is a guaranteed thread-safe way of directly manipulating widget fields.
func (w *Base) setFieldsAndRefresh(f func()) {
w.propertyLock.Lock()
f()
impl := w.impl
w.propertyLock.Unlock()
if impl == nil {
return
}
impl.Refresh()
}
// super will return the actual object that this represents.
// If extended then this is the extending widget, otherwise it is nil.
func (w *Base) super() fyne.Widget {
w.propertyLock.RLock()
impl := w.impl
w.propertyLock.RUnlock()
return impl
}
// Repaint instructs the containing canvas to redraw, even if nothing changed.
// This method is a duplicate of what is in `canvas/canvas.go` to avoid a dependency loop or public API.
func Repaint(obj fyne.CanvasObject) {
if fyne.CurrentApp() == nil || fyne.CurrentApp().Driver() == nil {
return
}
c := fyne.CurrentApp().Driver().CanvasForObject(obj)
if c != nil {
if paint, ok := c.(interface{ SetDirty() }); ok {
paint.SetDirty()
}
}
}