-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Simplify widget creation
Note
This document is archived as it refers to a design process.
This has now been implemented with the only change that SetWidget
has been named ExtendBaseWidget
and
it is called from within CreateRenderer
in case a struct is used to create a widget instead of it's
constructing function.
In an effort to reduce the code required for a simple widget it is suggested that any new widget must inherit a widget class. Those looking to make minor changes or add interactivity could extend a simple widget, such as widget.Icon
or widget.Label
. For any other widget they would extend a new widget.BaseWidget
which is outlined further down this document.
BaseWidget could also manage the caching of renderers to avoid race conditions around the render cache in a driver.
The result of this would be the following change to complexity of, for example widget.Box
:
--- a/widget/box.go
+++ b/widget/box.go
@@ -12,40 +12,13 @@ import (
// Box widget is a simple list where the child elements are arranged in a single column
// for vertical or a single row for horizontal arrangement
type Box struct {
- baseWidget
+ BaseWidget
background color.Color
Horizontal bool
Children []fyne.CanvasObject
}
-// 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 (b *Box) Resize(size fyne.Size) {
- b.resize(size, b)
-}
-
-// Move the widget to a new position, relative to it's parent.
-// Note this should not be used if the widget is being managed by a Layout within a Container.
-func (b *Box) Move(pos fyne.Position) {
- b.move(pos, b)
-}
-
-// MinSize returns the smallest size this widget can shrink to
-func (b *Box) MinSize() fyne.Size {
- return b.minSize(b)
-}
-
-// Show this widget, if it was previously hidden
-func (b *Box) Show() {
- b.show(b)
-}
-
-// Hide this widget, if it was previously visible
-func (b *Box) Hide() {
- b.hide(b)
-}
-
// ApplyTheme updates this box to match the current theme
func (b *Box) ApplyTheme() {
b.background = theme.BackgroundColor()
@@ -83,7 +56,8 @@ func (b *Box) setBackgroundColor(bg color.Color) {
// NewHBox creates a new horizontally aligned box widget with the specified list of child objects
func NewHBox(children ...fyne.CanvasObject) *Box {
- box := &Box{baseWidget: baseWidget{}, Horizontal: true, Children: children}
+ box := &Box{Horizontal: true, Children: children}
+ box.SetWidget(box)
Renderer(box).Layout(box.MinSize())
return box
@@ -91,7 +65,8 @@ func NewHBox(children ...fyne.CanvasObject) *Box {
// NewVBox creates a new vertically aligned box widget with the specified list of child objects
func NewVBox(children ...fyne.CanvasObject) *Box {
- box := &Box{baseWidget: baseWidget{}, Horizontal: false, Children: children}
+ box := &Box{Horizontal: false, Children: children}
+ box.SetWidget(box)
Renderer(box).Layout(box.MinSize())
return box
This is mostly removal of boilerplate code (yay!) but does require that any widget constructor call SetWidget(self)
so that the inherited object can make appropriate callbacks. This isn't a big impact but it does mean that if a developer had used the &widget.Box{Horizontal: false}
form then they would have to call SetWidget()
additionally.
This provides the additional benefit that for simple extension of existing widgets you could simply use the following code:
type clickableIcon struct {
widget.Icon
}
func (c *clickableIcon) Tapped(_ *fyne.PointEvent) {
// handle tapped
}
func (c *clickableIcon) TappedSecondary(_ *fyne.PointEvent) {
// handle secondary tapped (right click)
}
Any custom code can be contained within the Tapped()
callback and you have created a clickable icon widget.