Implement defining screens in yaml

This commit is contained in:
Maarten Heremans
2024-04-03 16:07:24 +02:00
parent b9d2b680bc
commit c848c2332f
15 changed files with 1204 additions and 334 deletions

View File

@ -9,45 +9,85 @@ import (
"fyne.io/fyne/v2/container"
)
// The constants for the Containers
//
// Available yaml options for all containers:
// - id: The ID for exporting the container to code
// - decorators: The decorators to wrap the container into
// - hidden: Wether the container is hidden or not
type Container string
const (
// HScroll Container
//
// Available yaml options:
// - content: The content of the container
HScroll Container = "HScroll"
Scroll Container = "Scroll"
// Scroll Container
//
// Available yaml options:
// - content: The content of the container
Scroll Container = "Scroll"
// VScroll Container
//
// Available yaml options:
// - content: The content of the container
VScroll Container = "VScroll"
)
func (cnt Container) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
// Build builds the container and decorator for the given Container and Element,
// using the provided ScreenHandler to fetch functions, data bindings, etc.
//
// Parameters:
// - e *Element - the element to build the container for
// - s ScreenHandler - the screen handler for the container
//
// Returns the CanvasObject for the widget, the CanvasObject for the decorator
// I fno decorators are specified, the widget and decorator will be the same.
func (cnt Container) Build(
e *Element,
s ScreenHandler,
) (
container fyne.CanvasObject,
decorator fyne.CanvasObject,
err error,
) {
switch cnt {
case HScroll:
c, err = cnt.buildHScrollContainer(e, s)
container, err = cnt.buildHScrollContainer(e, s)
case Scroll:
c, err = cnt.buildScrollContainer(e, s)
container, err = cnt.buildScrollContainer(e, s)
case VScroll:
c, err = cnt.buildVScrollContainer(e, s)
container, err = cnt.buildVScrollContainer(e, s)
default:
err = errors.New("invalid container")
}
if err != nil {
return
}
if e.Decorators != nil {
decorator = container
if e.Decorators != nil {
for _, dec := range e.Decorators {
switch dec {
case "Border":
c = uiwidget.NewWidgetBorder(c)
decorator = uiwidget.NewWidgetBorder(decorator)
}
}
}
if e.Hidden {
c.Hide()
decorator.Hide()
}
return
}
func (ctn Container) buildHScrollContainer(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (ctn Container) buildHScrollContainer(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
if e.Content == nil {
err = errors.New("HScroll: no content defined")
return
@ -62,7 +102,10 @@ func (ctn Container) buildHScrollContainer(e *Element, s ScreenHandler) (c fyne.
return
}
func (ctn Container) buildScrollContainer(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (ctn Container) buildScrollContainer(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
if e.Content == nil {
err = errors.New("Scroll: no content defined")
return
@ -77,7 +120,10 @@ func (ctn Container) buildScrollContainer(e *Element, s ScreenHandler) (c fyne.C
return
}
func (ctn Container) buildVScrollContainer(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (ctn Container) buildVScrollContainer(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
if e.Content == nil {
err = errors.New("VScroll: no content defined")
return

View File

@ -7,11 +7,13 @@ import (
"fyne.io/fyne/v2"
)
// Size represents the yaml description of a ui size
type Size struct {
Width float32 `yaml:"width"`
Height float32 `yaml:"height"`
}
// Element represents the yaml description of a ui element
type Element struct {
ID string `yaml:"id"`
@ -57,6 +59,12 @@ type Element struct {
Time *string `yaml:"time"`
TimeFormat *string `yaml:"timeFormat"`
// Entry Properties
MultiLine bool `yaml:"multiLine"`
Placeholder string `yaml:"placeholder"`
PlaceholderLocalized bool `yaml:"placeholderLocalized"`
Validator string `yaml:"validator"`
// List Properties
ItemTemplate string `yaml:"itemTemplate"`
ItemRenderer string `yaml:"itemRenderer"`
@ -70,38 +78,44 @@ type Element struct {
FixVertical bool `yaml:"fixVertical"`
// Handlers
OnClicked string `yaml:"onClicked"`
OnUpClicked string `yaml:"onUpClicked"`
OnDownClicked string `yaml:"onDownClicked"`
OnChanged string `yaml:"onChanged"`
OnSelected string `yaml:"onSelected"`
OnUnselected string `yaml:"onUnselected"`
OnDateSelected string `yaml:"onDateSelected"`
OnClicked string `yaml:"onClicked"`
OnUpClicked string `yaml:"onUpClicked"`
OnDownClicked string `yaml:"onDownClicked"`
OnChanged string `yaml:"onChanged"`
OnSelected string `yaml:"onSelected"`
OnUnselected string `yaml:"onUnselected"`
OnDateSelected string `yaml:"onDateSelected"`
OnValidationChanged string `yaml:"onValidationChanged"`
}
// BuildUI generates the UI for the Element.
//
// It takes a ScreenHandler parameter and returns a fyne.CanvasObject and an error.
func (e *Element) BuildUI(s ScreenHandler) (obj fyne.CanvasObject, err error) {
var baseObject fyne.CanvasObject
defer func() {
if e.ID != "" && obj != nil {
s.RegisterElement(e.ID, obj)
if e.ID != "" && baseObject != nil {
s.RegisterElement(e.ID, baseObject, obj)
}
}()
if e.Container != "" {
if obj, err = e.Container.Build(e, s); err != nil {
if baseObject, obj, err = e.Container.Build(e, s); err != nil {
err = fmt.Errorf("failed to build container element: %w", err)
return
}
return
}
if e.Layout != "" {
if obj, err = e.Layout.Build(e, s); err != nil {
if baseObject, obj, err = e.Layout.Build(e, s); err != nil {
err = fmt.Errorf("failed to build layout element: %w", err)
return
}
return
}
if e.Widget != "" {
if obj, err = e.Widget.Build(e, s); err != nil {
if baseObject, obj, err = e.Widget.Build(e, s); err != nil {
err = fmt.Errorf("failed to build widget element: %w", err)
return
}
@ -115,4 +129,7 @@ func (e *Element) localize(s ScreenHandler) {
if e.Localized {
e.Text = i18n.T(s.GetLocalizer(), e.Text)
}
if e.PlaceholderLocalized {
e.Placeholder = i18n.T(s.GetLocalizer(), e.Placeholder)
}
}

View File

@ -11,34 +11,101 @@ import (
"fyne.io/fyne/v2/layout"
)
// The constants for the Layouts
//
// Available yaml options for all layouts:
// - id: The ID for exporting the layout to code
// - decorators: The decorators to wrap the layout into
// - hidden: Wether the layout is hidden or not
type Layout string
const (
Border Layout = "Border"
Form Layout = "Form"
Grid Layout = "Grid"
HBox Layout = "HBox"
// Border Layout
//
// Available yaml options
// - top: The top pane (contains 1 widget)
// - bottom: The bottom pane (contains 1 widget)
// - left: The left pane (contains 1 widget)
// - right: The right pane (contains 1 widget)
// - center: The center pane (contains multiple widgets)
Border Layout = "Border"
// Form Layout
//
// Available yaml options
// - children: The children of the form
// - label: The label of the form element
// - field: The field of the form element
Form Layout = "Form"
// Grid Layout
//
// Available yaml options
// - columns: The number of columns (GridWithColumns)
// - rows: The number of rows (GridWithRows)
// - rowColumns: The number of rows and columns (AdaptiveGrid)
// - elementSize: The size of the elements (GridWrap)
// - children: The children of the grid
Grid Layout = "Grid"
// HBox Layout
//
// Available yaml options
// - children: The children of the HBox
HBox Layout = "HBox"
// MinSize Layout
//
// Available yaml options
// - minSize: The minimum size of the layout
// - children: The children of the MinSize
MinSize Layout = "MinSize"
Stack Layout = "Stack"
VBox Layout = "VBox"
// Stack Layout
//
// Available yaml options
// - children: The children of the Stack
Stack Layout = "Stack"
// VBox Layout
//
// Available yaml options
// - children: The children of the VBox
VBox Layout = "VBox"
)
func (l Layout) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
// Build builds the layout based on the given Layout and Element
// using the provided ScreenHandler to fetch functions, data bindings, etc.
//
// Parameters:
// - e: The Element to build the Layout for
// - s: The ScreenHandler to use to fetch functions, data bindings, etc.
// Returns the CanvasObject for the Layout, the CanvasObject for the decorator
// and an error if any.
// If no decorators are specified, the widget and decorator will be the same.
func (l Layout) Build(
e *Element,
s ScreenHandler,
) (
layout fyne.CanvasObject,
decorator fyne.CanvasObject,
err error,
) {
switch l {
case Border:
c, err = l.buildBorderLayout(e, s)
layout, err = l.buildBorderLayout(e, s)
case Form:
c, err = l.buildFormLayout(e, s)
layout, err = l.buildFormLayout(e, s)
case Grid:
c, err = l.buildGridLayout(e, s)
layout, err = l.buildGridLayout(e, s)
case HBox:
c, err = l.buildHBoxLayout(e, s)
layout, err = l.buildHBoxLayout(e, s)
case MinSize:
c, err = l.buildMinSizeLayout(e, s)
layout, err = l.buildMinSizeLayout(e, s)
case Stack:
c, err = l.buildStackLayout(e, s)
layout, err = l.buildStackLayout(e, s)
case VBox:
c, err = l.buildVBoxLayout(e, s)
layout, err = l.buildVBoxLayout(e, s)
default:
err = errors.New("invalid layout")
}
@ -46,22 +113,26 @@ func (l Layout) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err err
return
}
decorator = layout
if e.Decorators != nil {
for _, dec := range e.Decorators {
switch dec {
case "Border":
c = uiwidget.NewWidgetBorder(c)
decorator = uiwidget.NewWidgetBorder(decorator)
}
}
}
if e.Hidden {
c.Hide()
decorator.Hide()
}
return
}
func (l Layout) buildBorderLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
func (l Layout) buildBorderLayout(
e *Element,
s ScreenHandler,
) (c *fyne.Container, err error) {
var top, left, right, bottom fyne.CanvasObject
var center []fyne.CanvasObject
@ -109,7 +180,10 @@ func (l Layout) buildBorderLayout(e *Element, s ScreenHandler) (c *fyne.Containe
return
}
func (l Layout) buildFormLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
func (l Layout) buildFormLayout(
e *Element,
s ScreenHandler,
) (c *fyne.Container, err error) {
children := make([]fyne.CanvasObject, 0, len(e.Children)*2)
for _, child := range e.Children {
if child.Label == nil {
@ -149,7 +223,10 @@ func (l Layout) buildFormLayout(e *Element, s ScreenHandler) (c *fyne.Container,
return
}
func (l Layout) buildGridLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
func (l Layout) buildGridLayout(
e *Element,
s ScreenHandler,
) (c *fyne.Container, err error) {
children := make([]fyne.CanvasObject, 0, len(e.Children))
for _, child := range e.Children {
var obj fyne.CanvasObject
@ -179,7 +256,10 @@ func (l Layout) buildGridLayout(e *Element, s ScreenHandler) (c *fyne.Container,
return
}
func (l Layout) buildHBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
func (l Layout) buildHBoxLayout(
e *Element,
s ScreenHandler,
) (c *fyne.Container, err error) {
children := make([]fyne.CanvasObject, 0, len(e.Children))
for _, child := range e.Children {
var obj fyne.CanvasObject
@ -193,7 +273,10 @@ func (l Layout) buildHBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container,
return
}
func (l Layout) buildMinSizeLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
func (l Layout) buildMinSizeLayout(
e *Element,
s ScreenHandler,
) (c *fyne.Container, err error) {
children := make([]fyne.CanvasObject, 0, len(e.Children))
for _, child := range e.Children {
var obj fyne.CanvasObject
@ -216,7 +299,10 @@ func (l Layout) buildMinSizeLayout(e *Element, s ScreenHandler) (c *fyne.Contain
return
}
func (l Layout) buildStackLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
func (l Layout) buildStackLayout(
e *Element,
s ScreenHandler,
) (c *fyne.Container, err error) {
children := make([]fyne.CanvasObject, 0, len(e.Children))
for _, child := range e.Children {
var obj fyne.CanvasObject
@ -230,7 +316,10 @@ func (l Layout) buildStackLayout(e *Element, s ScreenHandler) (c *fyne.Container
return
}
func (l Layout) buildVBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
func (l Layout) buildVBoxLayout(
e *Element,
s ScreenHandler,
) (c *fyne.Container, err error) {
children := make([]fyne.CanvasObject, 0, len(e.Children))
for _, child := range e.Children {
var obj fyne.CanvasObject

View File

@ -5,15 +5,19 @@ import (
"fyne.io/fyne/v2/widget"
)
// ListItemTemplate is a template for a list item.
// It implements the fyne.CanvasObject interface and TemplateScreenHandler
type ListItemTemplate struct {
fyne.CanvasObject
*TemplateScreenHandler
}
// CreateRenderer implements the fyne.CanvasObject interface
func (i *ListItemTemplate) CreateRenderer() fyne.WidgetRenderer {
return widget.NewSimpleRenderer(i.CanvasObject)
}
// NewListItemTemplate creates a new ListItemTemplate
func NewListItemTemplate(
obj fyne.CanvasObject,
screenHandler *TemplateScreenHandler,

View File

@ -16,22 +16,39 @@ import (
"gopkg.in/yaml.v2"
)
type ListItemTemplateFn func() fyne.CanvasObject
type ListDataItemRendererFn func(binding.DataItem, fyne.CanvasObject)
type ListItemRendererFn func(int, fyne.CanvasObject)
type ListLengthFn func() int
type ListItemHandlerFn func(widget.ListItemID)
type ClickHandlerFn func()
type CheckHandlerFn func(bool)
type DateSelectedHandlerFn func(time.Time)
type ValidationChangedHandlerFn func(error)
type UIElement struct {
Object fyne.CanvasObject
Decorator fyne.CanvasObject
}
type ScreenHandler interface {
RegisterElement(string, fyne.CanvasObject)
RegisterElement(string, fyne.CanvasObject, fyne.CanvasObject)
GetLocalizer() *i18n.Localizer
GetIcon(string) fyne.Resource
GetBinding(string) binding.DataItem
GetListItemTemplate(string) func() fyne.CanvasObject
GetListDataItemRenderer(string) func(binding.DataItem, fyne.CanvasObject)
GetListItemRenderer(string) func(int, fyne.CanvasObject)
GetListLength(string) func() int
GetValidator(string) fyne.StringValidator
GetListItemTemplate(string) ListItemTemplateFn
GetListDataItemRenderer(string) ListDataItemRendererFn
GetListItemRenderer(string) ListItemRendererFn
GetListLength(string) ListLengthFn
GetOnSelectedHandler(string) func(widget.ListItemID)
GetOnUnselectedHandler(string) func(widget.ListItemID)
GetClickedHandler(string) func()
GetCheckChangedHandler(string) func(bool)
GetDateSelectedHandler(string) func(time.Time)
GetOnListItemSelectedHandler(string) ListItemHandlerFn
GetOnListItemUnselectedHandler(string) ListItemHandlerFn
GetOnClickedHandler(string) ClickHandlerFn
GetOnCheckChangedHandler(string) CheckHandlerFn
GetOnDateSelectedHandler(string) DateSelectedHandlerFn
GetOnValidationChangedHandler(string) ValidationChangedHandlerFn
}
type Screen struct {
@ -79,7 +96,7 @@ func NewTemplate(
handler *TemplateScreenHandler,
err error,
) {
handler = NewDummyScreenHandler(localizer)
handler = NewTemplateScreenHandler(localizer)
scr, err = New(filesystem, name, handler)
return
}
@ -94,21 +111,27 @@ func (s *Screen) Initialize() (obj fyne.CanvasObject, err error) {
type TemplateScreenHandler struct {
localizer *i18n.Localizer
elementsMap map[string]fyne.CanvasObject
elementsMap map[string]*UIElement
}
func NewDummyScreenHandler(localizer *i18n.Localizer) *TemplateScreenHandler {
func NewTemplateScreenHandler(
localizer *i18n.Localizer,
) *TemplateScreenHandler {
return &TemplateScreenHandler{
localizer: localizer,
elementsMap: make(map[string]fyne.CanvasObject),
elementsMap: make(map[string]*UIElement),
}
}
func (d *TemplateScreenHandler) RegisterElement(name string, element fyne.CanvasObject) {
d.elementsMap[name] = element
func (d *TemplateScreenHandler) RegisterElement(
name string,
element fyne.CanvasObject,
decorator fyne.CanvasObject,
) {
d.elementsMap[name] = &UIElement{element, decorator}
}
func (d *TemplateScreenHandler) GetElement(name string) fyne.CanvasObject {
func (d *TemplateScreenHandler) GetElement(name string) *UIElement {
elem, ok := d.elementsMap[name]
if !ok {
return nil
@ -132,38 +155,46 @@ func (*TemplateScreenHandler) GetBinding(string) binding.DataItem {
return nil
}
func (*TemplateScreenHandler) GetListItemTemplate(string) func() fyne.CanvasObject {
func (*TemplateScreenHandler) GetValidator(string) fyne.StringValidator {
return nil
}
func (*TemplateScreenHandler) GetListItemTemplate(string) ListItemTemplateFn {
return func() fyne.CanvasObject { return nil }
}
func (*TemplateScreenHandler) GetListDataItemRenderer(string) func(binding.DataItem, fyne.CanvasObject) {
func (*TemplateScreenHandler) GetListDataItemRenderer(string) ListDataItemRendererFn {
return func(binding.DataItem, fyne.CanvasObject) {}
}
func (*TemplateScreenHandler) GetListItemRenderer(string) func(int, fyne.CanvasObject) {
func (*TemplateScreenHandler) GetListItemRenderer(string) ListItemRendererFn {
return func(int, fyne.CanvasObject) {}
}
func (*TemplateScreenHandler) GetListLength(string) func() int {
func (*TemplateScreenHandler) GetListLength(string) ListLengthFn {
return func() int { return 0 }
}
func (*TemplateScreenHandler) GetOnSelectedHandler(string) func(widget.ListItemID) {
func (*TemplateScreenHandler) GetOnListItemSelectedHandler(string) ListItemHandlerFn {
return func(widget.ListItemID) {}
}
func (*TemplateScreenHandler) GetOnUnselectedHandler(string) func(widget.ListItemID) {
func (*TemplateScreenHandler) GetOnListItemUnselectedHandler(string) ListItemHandlerFn {
return func(widget.ListItemID) {}
}
func (*TemplateScreenHandler) GetClickedHandler(string) func() {
func (*TemplateScreenHandler) GetOnClickedHandler(string) ClickHandlerFn {
return func() {}
}
func (*TemplateScreenHandler) GetCheckChangedHandler(string) func(bool) {
func (*TemplateScreenHandler) GetOnCheckChangedHandler(string) CheckHandlerFn {
return func(bool) {}
}
func (*TemplateScreenHandler) GetDateSelectedHandler(string) func(time.Time) {
func (*TemplateScreenHandler) GetOnDateSelectedHandler(string) DateSelectedHandlerFn {
return func(time.Time) {}
}
func (*TemplateScreenHandler) GetOnValidationChangedHandler(string) ValidationChangedHandlerFn {
return func(error) {}
}

View File

@ -13,47 +13,216 @@ import (
xwidget "fyne.io/x/fyne/widget"
)
// The constants for the Widgets
//
// Available yaml options for all widgets:
// - id: The ID for exporting the widget to code
// - decorators: The decorators to wrap the widget into
// - hidden: Wether the widget is hidden or not
type Widget string
const (
Button Widget = "Button"
Calendar Widget = "Calendar"
Check Widget = "Check"
H1 Widget = "H1"
H2 Widget = "H2"
H3 Widget = "H3"
H4 Widget = "H4"
H5 Widget = "H5"
H6 Widget = "H6"
Label Widget = "Label"
List Widget = "List"
Separator Widget = "Separator"
Spacer Widget = "Spacer"
// Button Widget
//
// Available yaml options:
// - text: The text for the button
// - localized: If the text represents a localization key
// - icon: The icon for the button
// - disabled: Wether the button is disabled or not
// - options: Additional options for the button
// - alignment: The alignment of the button
// - iconPlacement: The icon placement of the button
// - importance: The importance of the button
// - onclicked: The function to call when the button is clicked
Button Widget = "Button"
// Calendar Widget
//
// Available yaml options:
// - time: The current time to use for the calendar
// - timeFormat: The format to use to interpret the time field (default time.DateOnly)
// - onDateSelected: The function to call when a date is selected
Calendar Widget = "Calendar"
// Checkbox Widget
//
// Available yaml options:
// - text: The text for the checkbox
// - localized: If the text represents a localization key
// - binding: The databinding for the checkbox
// - checked: The checked state of the checkbox
// - disabled: Wether the button is disabled or not
// - onChanged: The function to call when the checkbox is changed
Check Widget = "Check"
// Entry Widget
//
// Available yaml options:
// - text: The text for the entry
// - localized: If the text represents a localization key
// - binding: The databinding for the entry
// - placeholder: The placeholder for the entry
// - placeholderLocalized: If the placeholder represents a localization key
// - multiLine: If the entry is multiline
// - disabled: Wether the button is disabled or not
// - validator: The validator for the entry
// - onValidationChanged: The function to call when the validation changes
Entry Widget = "Entry"
// H1 Widget
//
// Available yaml options:
// - text: The text for the H1
// - localized: If the text represents a localization key
// - binding: The databinding for the H1
// - options: The options for the H1
// - wrapping: The wrapping option for the H1
// - truncation: The truncation option for the H1
H1 Widget = "H1"
// H2 Widget
//
// Available yaml options:
// - text: The text for the H2
// - localized: If the text represents a localization key
// - binding: The databinding for the H2
// - options: The options for the H2
// - wrapping: The wrapping option for the H2
// - truncation: The truncation option for the H2
H2 Widget = "H2"
// H3 Widget
//
// Available yaml options:
// - text: The text for the H3
// - localized: If the text represents a localization key
// - binding: The databinding for the H3
// - options: The options for the H3
// - wrapping: The wrapping option for the H3
// - truncation: The truncation option for the H3
H3 Widget = "H3"
// H4 Widget
//
// Available yaml options:
// - text: The text for the H4
// - localized: If the text represents a localization key
// - binding: The databinding for the H4
// - options: The options for the H4
// - wrapping: The wrapping option for the H4
// - truncation: The truncation option for the H4
H4 Widget = "H4"
// H5 Widget
//
// Available yaml options:
// - text: The text for the H5
// - localized: If the text represents a localization key
// - binding: The databinding for the H5
// - options: The options for the H5
// - wrapping: The wrapping option for the H5
// - truncation: The truncation option for the H5
H5 Widget = "H5"
// H6 Widget
//
// Available yaml options:
// - text: The text for the H6
// - localized: If the text represents a localization key
// - binding: The databinding for the H6
// - options: The options for the H6
// - wrapping: The wrapping option for the H6
// - truncation: The truncation option for the H6
H6 Widget = "H6"
// Icon Widget
//
// Available yaml options:
// - icon: The icon for the icon
Icon Widget = "Icon"
// Label Widget
//
// Available yaml options:
// - text: The text for the label
// - localized: If the text represents a localization key
// - binding: The databinding for the label
// - options: The options for the label
// - allignment: The alignment option for the label
// - wrapping: The wrapping option for the label
// - textStyle: The text style option for the label
// - truncation: The truncation option for the label
Label Widget = "Label"
// List Widget
//
// Available yaml options:
// - binding: The databinding for the list
// - listLength: The length of the list
// - itemTemplate: The item template for the list
// - itemRenderer: The item renderer for the list
// - onSelect: The on select function for the list
// - onUnselect: The on unselect function for the list
List Widget = "List"
// Separator Widget
Separator Widget = "Separator"
// Spacer Widget
Spacer Widget = "Spacer"
// UpDownLabel Widget
//
// Available yaml options:
// - binding: The databinding for the up down label
// - onUpClicked: The on up clicked function for the up down label
// - onDownClicked: The on down clicked function for the up down label
UpDownLabel Widget = "UpDownLabel"
)
func (w Widget) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
// Build builds a fyne.CanvasObject for the given Widget and Element,
// using the provided ScreenHandler to fetch functions, data bindings, etc.
//
// Arguments:
// - e: The Element to build the Widget for.
// - s: The ScreenHandler to use to fetch functions, data bindings, etc.
//
// Returns the CanvasObject for the widget, the CanvasObject for the decorator,
// and an error if any.
// If no decorators are specified, the widget and decorator will be the same.
func (w Widget) Build(
e *Element,
s ScreenHandler,
) (
widget fyne.CanvasObject,
decorator fyne.CanvasObject,
err error,
) {
e.localize(s)
switch w {
case Button:
c, err = w.buildButtonWidget(e, s)
widget, err = w.buildButtonWidget(e, s)
case Calendar:
c, err = w.buildCalendarWidget(e, s)
widget, err = w.buildCalendarWidget(e, s)
case Check:
c, err = w.buildCheckWidget(e, s)
widget, err = w.buildCheckWidget(e, s)
case Entry:
widget, err = w.buildEntryWidget(e, s)
case H1, H2, H3, H4, H5, H6:
c, err = w.buildHeaderLabelWidget(e, s)
widget, err = w.buildHeaderLabelWidget(e, s)
case Icon:
widget, err = w.buildIconWidget(e, s)
case Label:
c, err = w.buildLabelWidget(e, s)
widget, err = w.buildLabelWidget(e, s)
case List:
c, err = w.buildListWidget(e, s)
widget, err = w.buildListWidget(e, s)
case Separator:
c, err = w.buildSeparatorWidget(e, s)
widget, err = w.buildSeparatorWidget(e, s)
case Spacer:
c, err = w.buildSpacerWidget(e, s)
widget, err = w.buildSpacerWidget(e, s)
case UpDownLabel:
c, err = w.buildUpDownLabelWidget(e, s)
widget, err = w.buildUpDownLabelWidget(e, s)
default:
err = errors.New("invalid widget")
}
@ -61,28 +230,32 @@ func (w Widget) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err err
return
}
decorator = widget
if e.Decorators != nil {
for _, dec := range e.Decorators {
switch dec {
case "Border":
c = uiwidget.NewWidgetBorder(c)
decorator = uiwidget.NewWidgetBorder(decorator)
}
}
}
if e.Hidden {
c.Hide()
decorator.Hide()
}
return
}
func (w Widget) buildButtonWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildButtonWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
var btn *widget.Button
if e.Icon != "" {
btn = widget.NewButtonWithIcon(
e.Text, s.GetIcon(e.Icon), s.GetClickedHandler(e.OnClicked))
e.Text, s.GetIcon(e.Icon), s.GetOnClickedHandler(e.OnClicked))
} else {
btn = widget.NewButton(e.Text, s.GetClickedHandler(e.OnClicked))
btn = widget.NewButton(e.Text, s.GetOnClickedHandler(e.OnClicked))
}
for opt, val := range e.Options {
@ -103,7 +276,10 @@ func (w Widget) buildButtonWidget(e *Element, s ScreenHandler) (c fyne.CanvasObj
return
}
func (w Widget) buildCalendarWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildCalendarWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
t := time.Now()
if e.Time != nil {
timeFormat := time.DateOnly
@ -116,18 +292,21 @@ func (w Widget) buildCalendarWidget(e *Element, s ScreenHandler) (c fyne.CanvasO
}
}
c = xwidget.NewCalendar(t, s.GetDateSelectedHandler(e.OnDateSelected))
c = xwidget.NewCalendar(t, s.GetOnDateSelectedHandler(e.OnDateSelected))
return
}
func (w Widget) buildCheckWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildCheckWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
var chk *widget.Check
if e.Binding != "" {
chk = widget.NewCheckWithData(
e.Text, s.GetBinding(e.Binding).(binding.Bool))
} else {
chk = widget.NewCheck(
e.Text, s.GetCheckChangedHandler(e.OnChanged))
e.Text, s.GetOnCheckChangedHandler(e.OnChanged))
chk.SetChecked(e.Checked)
}
@ -138,7 +317,40 @@ func (w Widget) buildCheckWidget(e *Element, s ScreenHandler) (c fyne.CanvasObje
return
}
func (w Widget) buildHeaderLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildEntryWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
var ent *widget.Entry
if e.MultiLine {
ent = widget.NewMultiLineEntry()
} else {
ent = widget.NewEntry()
}
if e.Binding != "" {
ent.Bind(s.GetBinding(e.Binding).(binding.String))
} else {
ent.Text = e.Text
}
ent.PlaceHolder = e.Placeholder
if e.Validator != "" {
ent.Validator = s.GetValidator(e.Validator)
}
if e.OnValidationChanged != "" {
ent.SetOnValidationChanged(s.GetOnValidationChangedHandler(e.OnValidationChanged))
}
if e.Disabled {
ent.Disable()
}
c = ent
return
}
func (w Widget) buildHeaderLabelWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
var rt *widget.RichText
level := 1
@ -174,7 +386,18 @@ func (w Widget) buildHeaderLabelWidget(e *Element, s ScreenHandler) (c fyne.Canv
return
}
func (w Widget) buildLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildIconWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
c = widget.NewIcon(s.GetIcon(e.Icon))
return
}
func (w Widget) buildLabelWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
var lbl *widget.Label
if e.Binding != "" {
@ -201,7 +424,10 @@ func (w Widget) buildLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObje
return
}
func (w Widget) buildListWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildListWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
var lst *widget.List
if e.Binding != "" {
@ -217,22 +443,28 @@ func (w Widget) buildListWidget(e *Element, s ScreenHandler) (c fyne.CanvasObjec
}
if e.OnSelected != "" {
lst.OnSelected = s.GetOnSelectedHandler(e.OnSelected)
lst.OnSelected = s.GetOnListItemSelectedHandler(e.OnSelected)
}
if e.OnUnselected != "" {
lst.OnUnselected = s.GetOnUnselectedHandler(e.OnUnselected)
lst.OnUnselected = s.GetOnListItemUnselectedHandler(e.OnUnselected)
}
c = lst
return
}
func (w Widget) buildSeparatorWidget(_ *Element, _ ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildSeparatorWidget(
_ *Element,
_ ScreenHandler,
) (c fyne.CanvasObject, err error) {
sep := widget.NewSeparator()
c = sep
return
}
func (w Widget) buildSpacerWidget(e *Element, _ ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildSpacerWidget(
e *Element,
_ ScreenHandler,
) (c fyne.CanvasObject, err error) {
spc := &layout.Spacer{
FixHorizontal: e.FixHorizontal,
FixVertical: e.FixVertical,
@ -241,11 +473,14 @@ func (w Widget) buildSpacerWidget(e *Element, _ ScreenHandler) (c fyne.CanvasObj
return
}
func (w Widget) buildUpDownLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
func (w Widget) buildUpDownLabelWidget(
e *Element,
s ScreenHandler,
) (c fyne.CanvasObject, err error) {
btn := uiwidget.NewUpDownLabelWithData(
s.GetBinding(e.Binding).(binding.String),
s.GetClickedHandler(e.OnUpClicked),
s.GetClickedHandler(e.OnDownClicked))
s.GetOnClickedHandler(e.OnUpClicked),
s.GetOnClickedHandler(e.OnDownClicked))
c = btn
return
}