Implement defining screens in yaml
This commit is contained in:
parent
b9d2b680bc
commit
c848c2332f
63
baseview.go
63
baseview.go
@ -1,12 +1,10 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"time"
|
||||
"embed"
|
||||
|
||||
"bitbucket.org/hevanto/ui/screen"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/google/uuid"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
)
|
||||
@ -26,35 +24,8 @@ type BaseView struct {
|
||||
// Root CanvasObject of the view
|
||||
CanvasObject fyne.CanvasObject
|
||||
|
||||
// The screen definition
|
||||
screenDefinition *screen.Screen
|
||||
|
||||
// ----------- ScreenHandler -------------//
|
||||
|
||||
// Localizer to translate screen labels
|
||||
localizer *i18n.Localizer
|
||||
|
||||
// Map of screen elements that got an id assigned
|
||||
screenElementMap map[string]fyne.CanvasObject
|
||||
|
||||
// Map of list item template
|
||||
listItemTemplates map[string]func() fyne.CanvasObject
|
||||
|
||||
// Map of list data item renderers
|
||||
listDataItemRenderers map[string]func(binding.DataItem, fyne.CanvasObject)
|
||||
|
||||
// Map of list item renderers
|
||||
listItemRenderers map[string]func(int, fyne.CanvasObject)
|
||||
|
||||
// Map of list length functions
|
||||
listLenghts map[string]func() int
|
||||
|
||||
// Handlers
|
||||
onSelectedHandlers map[string]func(widget.ListItemID)
|
||||
onUnselectedHandlers map[string]func(widget.ListItemID)
|
||||
onClickedHandlers map[string]func()
|
||||
onCheckChangedHandlers map[string]func(bool)
|
||||
onDateSelectedHandlers map[string]func(time.Time)
|
||||
*ScreenHandler
|
||||
}
|
||||
|
||||
// NewBaseView creates a new baseview
|
||||
@ -80,6 +51,28 @@ func NewBaseView(
|
||||
return v
|
||||
}
|
||||
|
||||
func NewBaseViewWithScreen(
|
||||
concreteView View,
|
||||
controller Controller,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
) *BaseView {
|
||||
v := NewBaseView(concreteView, controller)
|
||||
|
||||
var err error
|
||||
v.ScreenHandler, err = NewScreenHandler(
|
||||
filesystem,
|
||||
screenName,
|
||||
controller,
|
||||
localizer)
|
||||
if err != nil {
|
||||
LogWindowError(v, LoadScreen, err)
|
||||
return nil
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// ID returns tie id of the view
|
||||
func (v BaseView) ID() string {
|
||||
return v.id
|
||||
@ -106,8 +99,8 @@ func (v *BaseView) Initialize() fyne.CanvasObject {
|
||||
if err := v.Ctrl.Initialize(); err != nil {
|
||||
LogWindowError(v, Initialize, err)
|
||||
}
|
||||
if v.screenDefinition != nil {
|
||||
obj, err := v.screenDefinition.Initialize()
|
||||
if v.ScreenHandler != nil && v.ScreenDefinition() != nil {
|
||||
obj, err := v.ScreenDefinition().Initialize()
|
||||
if err != nil {
|
||||
LogWindowError(v, Initialize, err)
|
||||
return nil
|
||||
@ -133,3 +126,7 @@ func (v *BaseView) OnShow() {
|
||||
func (v *BaseView) OnHide() {
|
||||
LogWindowEvent(v, OnHide)
|
||||
}
|
||||
|
||||
func (v *BaseView) GetBinding(bindingName string) binding.DataItem {
|
||||
return v.Ctrl.GetBinding(bindingName)
|
||||
}
|
||||
|
@ -1,177 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/hevanto/ui/screen"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
)
|
||||
|
||||
func NewBaseViewWithScreen(
|
||||
concreteView View,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
controller Controller,
|
||||
) *BaseView {
|
||||
v := NewBaseView(concreteView, controller)
|
||||
def, err := screen.New(filesystem, screenName, v)
|
||||
if err != nil {
|
||||
LogWindowError(v, LoadScreen, err)
|
||||
return nil
|
||||
}
|
||||
v.screenDefinition = def
|
||||
v.localizer = localizer
|
||||
v.screenElementMap = make(map[string]fyne.CanvasObject)
|
||||
v.listItemTemplates = make(map[string]func() fyne.CanvasObject)
|
||||
v.listDataItemRenderers = make(map[string]func(binding.DataItem, fyne.CanvasObject))
|
||||
v.listItemRenderers = make(map[string]func(int, fyne.CanvasObject))
|
||||
v.listLenghts = make(map[string]func() int)
|
||||
v.onSelectedHandlers = make(map[string]func(widget.ListItemID))
|
||||
v.onUnselectedHandlers = make(map[string]func(widget.ListItemID))
|
||||
v.onClickedHandlers = make(map[string]func())
|
||||
v.onCheckChangedHandlers = make(map[string]func(bool))
|
||||
v.onDateSelectedHandlers = make(map[string]func(time.Time))
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterElement(id string, elem fyne.CanvasObject) {
|
||||
v.screenElementMap[id] = elem
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterListItemTemplate(name string, fn func() fyne.CanvasObject) {
|
||||
v.listItemTemplates[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterListDataItemRenderer(name string, fn func(binding.DataItem, fyne.CanvasObject)) {
|
||||
v.listDataItemRenderers[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterListItemRenderer(name string, fn func(int, fyne.CanvasObject)) {
|
||||
v.listItemRenderers[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterListLength(name string, fn func() int) {
|
||||
v.listLenghts[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterOnSelectedHandler(name string, fn func(widget.ListItemID)) {
|
||||
v.onSelectedHandlers[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterOnUnselectedHandler(name string, fn func(widget.ListItemID)) {
|
||||
v.onUnselectedHandlers[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterOnClickHandler(name string, fn func()) {
|
||||
v.onClickedHandlers[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterOnCheckChangedHandler(name string, fn func(bool)) {
|
||||
v.onCheckChangedHandlers[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) RegisterOnDateSelectedHandler(name string, fn func(time.Time)) {
|
||||
v.onDateSelectedHandlers[name] = fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetElement(id string) fyne.CanvasObject {
|
||||
if elem, ok := v.screenElementMap[id]; ok {
|
||||
return elem
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *BaseView) GetLocalizer() *i18n.Localizer {
|
||||
return v.localizer
|
||||
}
|
||||
|
||||
func (v *BaseView) GetIcon(iconName string) fyne.Resource {
|
||||
if strings.HasPrefix(iconName, "theme.") {
|
||||
iconName := strings.SplitN(iconName, ".", 2)[1]
|
||||
return theme.DefaultTheme().Icon(fyne.ThemeIconName(iconName))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *BaseView) GetBinding(bindingName string) binding.DataItem {
|
||||
return v.Ctrl.GetBinding(bindingName)
|
||||
}
|
||||
|
||||
func (v *BaseView) GetListItemTemplate(name string) func() fyne.CanvasObject {
|
||||
fn, ok := v.listItemTemplates[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetListDataItemRenderer(name string) func(binding.DataItem, fyne.CanvasObject) {
|
||||
fn, ok := v.listDataItemRenderers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetListItemRenderer(name string) func(int, fyne.CanvasObject) {
|
||||
fn, ok := v.listItemRenderers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetListLength(name string) func() int {
|
||||
fn, ok := v.listLenghts[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetOnSelectedHandler(name string) func(widget.ListItemID) {
|
||||
fn, ok := v.onSelectedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetOnUnselectedHandler(name string) func(widget.ListItemID) {
|
||||
fn, ok := v.onUnselectedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetClickedHandler(name string) func() {
|
||||
fn, ok := v.onClickedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetCheckChangedHandler(name string) func(bool) {
|
||||
fn, ok := v.onCheckChangedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func (v *BaseView) GetDateSelectedHandler(name string) func(time.Time) {
|
||||
fn, ok := v.onDateSelectedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
@ -1,15 +1,25 @@
|
||||
package ui
|
||||
|
||||
import "fyne.io/fyne/v2/data/binding"
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
)
|
||||
|
||||
type ScreenController interface {
|
||||
GetBinding(string) binding.DataItem
|
||||
GetValidator(string) fyne.StringValidator
|
||||
}
|
||||
|
||||
type Controller interface {
|
||||
ScreenController
|
||||
|
||||
Initialize() error
|
||||
RefreshData() error
|
||||
|
||||
GetBinding(string) binding.DataItem
|
||||
}
|
||||
|
||||
type DialogController interface {
|
||||
ScreenController
|
||||
|
||||
Initialize(data binding.DataItem) error
|
||||
RefreshData() error
|
||||
}
|
||||
|
204
dialog.go
204
dialog.go
@ -1,6 +1,7 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
@ -8,13 +9,22 @@ import (
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/google/uuid"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
)
|
||||
|
||||
type DialogName string
|
||||
type DialogKind string
|
||||
|
||||
type OnConfirmFn func(bool, error, ...interface{})
|
||||
type NewDialogFn func(DialogName, DialogKind, fyne.Window, OnConfirmFn, ...binding.DataItem) Dialog
|
||||
type NewDialogFn func(
|
||||
DialogName,
|
||||
DialogKind,
|
||||
fyne.Window,
|
||||
OnConfirmFn,
|
||||
binding.DataItem,
|
||||
*embed.FS,
|
||||
string,
|
||||
*i18n.Localizer) Dialog
|
||||
|
||||
const (
|
||||
DlgGeneric DialogKind = "Generic"
|
||||
@ -47,12 +57,16 @@ type BaseDialog struct {
|
||||
CanvasObj fyne.CanvasObject
|
||||
Data binding.DataItem
|
||||
focusItem fyne.Focusable
|
||||
|
||||
Ctrl DialogController
|
||||
*ScreenHandler
|
||||
}
|
||||
|
||||
func NewBaseDialog(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
) *BaseDialog {
|
||||
@ -63,13 +77,40 @@ func NewBaseDialog(
|
||||
dlgKind: kind,
|
||||
window: parent,
|
||||
onConfirm: confirm,
|
||||
Ctrl: controller,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBaseDialogWithScreen(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
) *BaseDialog {
|
||||
d := NewBaseDialog(
|
||||
concreteDialog, name, kind, controller,
|
||||
parent, confirm)
|
||||
|
||||
var err error
|
||||
d.ScreenHandler, err = NewScreenHandler(
|
||||
filesystem, screenName, controller, localizer)
|
||||
if err != nil {
|
||||
LogWindowError(d, LoadScreen, err)
|
||||
return nil
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func NewBaseDialogWithData(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
data binding.DataItem,
|
||||
@ -82,9 +123,36 @@ func NewBaseDialogWithData(
|
||||
window: parent,
|
||||
onConfirm: confirm,
|
||||
Data: data,
|
||||
Ctrl: controller,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBaseDialogWithDataAndScreen(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
data binding.DataItem,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
) *BaseDialog {
|
||||
d := NewBaseDialogWithData(
|
||||
concreteDialog, name, kind, controller,
|
||||
parent, confirm, data)
|
||||
|
||||
var err error
|
||||
d.ScreenHandler, err = NewScreenHandler(
|
||||
filesystem, screenName, controller, localizer)
|
||||
if err != nil {
|
||||
LogWindowError(d, LoadScreen, err)
|
||||
return nil
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d BaseDialog) Window() fyne.Window {
|
||||
return d.window
|
||||
}
|
||||
@ -114,6 +182,7 @@ func (d BaseDialog) OnConfirmFn() OnConfirmFn {
|
||||
}
|
||||
|
||||
func (d *BaseDialog) Show(parent ...fyne.Window) {
|
||||
|
||||
d.concreteDialog.OnShow()
|
||||
d.dlg = dialog.NewCustomConfirm(
|
||||
d.concreteDialog.Title(),
|
||||
@ -146,6 +215,17 @@ func (d BaseDialog) Title() string {
|
||||
}
|
||||
|
||||
func (d *BaseDialog) Initialize() fyne.CanvasObject {
|
||||
if err := d.Ctrl.Initialize(d.Data); err != nil {
|
||||
LogWindowError(d, Initialize, err)
|
||||
}
|
||||
if d.ScreenHandler != nil && d.ScreenDefinition() != nil {
|
||||
obj, err := d.ScreenDefinition().Initialize()
|
||||
if err != nil {
|
||||
LogWindowError(d, Initialize, err)
|
||||
return nil
|
||||
}
|
||||
d.CanvasObj = obj
|
||||
}
|
||||
return d.CanvasObj
|
||||
}
|
||||
|
||||
@ -184,35 +264,80 @@ func NewFormDialog(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
itemsFn FormDialogItemsFn,
|
||||
) *FormDialog {
|
||||
return &FormDialog{
|
||||
BaseDialog: NewBaseDialog(concreteDialog, name, kind, parent, confirm),
|
||||
BaseDialog: NewBaseDialog(
|
||||
concreteDialog, name, kind, controller, parent, confirm),
|
||||
itemsFn: itemsFn,
|
||||
confirmLabel: "OK",
|
||||
dismissLabel: "Cancel",
|
||||
}
|
||||
}
|
||||
|
||||
func NewFormDialogWithScreen(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
) *FormDialog {
|
||||
return &FormDialog{
|
||||
BaseDialog: NewBaseDialogWithScreen(
|
||||
concreteDialog, name, kind, controller, parent, confirm,
|
||||
filesystem, screenName, localizer),
|
||||
confirmLabel: "OK",
|
||||
dismissLabel: "Cancel",
|
||||
}
|
||||
}
|
||||
|
||||
func NewformDialogWithData(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
itemsFn FormDialogItemsFn,
|
||||
data binding.DataItem,
|
||||
) *FormDialog {
|
||||
return &FormDialog{
|
||||
BaseDialog: NewBaseDialogWithData(concreteDialog, name, kind, parent, confirm, data),
|
||||
BaseDialog: NewBaseDialogWithData(
|
||||
concreteDialog, name, kind, controller, parent, confirm, data),
|
||||
itemsFn: itemsFn,
|
||||
confirmLabel: "OK",
|
||||
dismissLabel: "Cancel",
|
||||
}
|
||||
}
|
||||
|
||||
func NewFormDialogWithDataAndScreen(
|
||||
concreteDialog Dialog,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
controller DialogController,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
data binding.DataItem,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
) *FormDialog {
|
||||
return &FormDialog{
|
||||
BaseDialog: NewBaseDialogWithDataAndScreen(
|
||||
concreteDialog, name, kind, controller, parent, confirm, data,
|
||||
filesystem, screenName, localizer),
|
||||
confirmLabel: "OK",
|
||||
dismissLabel: "Cancel",
|
||||
}
|
||||
}
|
||||
|
||||
func (d *FormDialog) SetButtonLabels(
|
||||
confirm string,
|
||||
dismiss string,
|
||||
@ -221,7 +346,25 @@ func (d *FormDialog) SetButtonLabels(
|
||||
d.dismissLabel = dismiss
|
||||
}
|
||||
|
||||
func (d *FormDialog) Initialize() fyne.CanvasObject {
|
||||
if d.itemsFn == nil {
|
||||
form := d.BaseDialog.Initialize().(*fyne.Container)
|
||||
d.itemsFn = func() []*widget.FormItem {
|
||||
res := make([]*widget.FormItem, 0, len(form.Objects)/2)
|
||||
for i := 0; i < len(form.Objects); i += 2 {
|
||||
res = append(res, widget.NewFormItem(
|
||||
form.Objects[i].(*widget.Label).Text,
|
||||
form.Objects[i+1]))
|
||||
}
|
||||
return res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *FormDialog) Show(parent ...fyne.Window) {
|
||||
d.concreteDialog.Initialize()
|
||||
d.items = d.itemsFn()
|
||||
|
||||
d.concreteDialog.OnShow()
|
||||
@ -263,7 +406,8 @@ func RegisterDialog(name DialogName, kind DialogKind, fn NewDialogFn) {
|
||||
}
|
||||
|
||||
func NewDialog(
|
||||
name DialogName, kind DialogKind,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
) Dialog {
|
||||
@ -272,14 +416,37 @@ func NewDialog(
|
||||
}
|
||||
if kindCatalog, ok := dialogCatalog[name]; ok {
|
||||
if fn, ok := kindCatalog[kind]; ok {
|
||||
return fn(name, kind, parent, confirm)
|
||||
return fn(name, kind, parent, confirm, nil, nil, "", nil)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewDialogWithScreen(
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
) Dialog {
|
||||
if dialogCatalog == nil {
|
||||
return nil
|
||||
}
|
||||
if kindCatalog, ok := dialogCatalog[name]; ok {
|
||||
if fn, ok := kindCatalog[kind]; ok {
|
||||
return fn(
|
||||
name, kind, parent, confirm, nil,
|
||||
&filesystem, screenName, localizer)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewDialogWithData(
|
||||
name DialogName, kind DialogKind,
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
data binding.DataItem,
|
||||
@ -289,7 +456,30 @@ func NewDialogWithData(
|
||||
}
|
||||
if kindCatalog, ok := dialogCatalog[name]; ok {
|
||||
if fn, ok := kindCatalog[kind]; ok {
|
||||
return fn(name, kind, parent, confirm, data)
|
||||
return fn(name, kind, parent, confirm, data, nil, "", nil)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewDialogWithDataAndScreen(
|
||||
name DialogName,
|
||||
kind DialogKind,
|
||||
parent fyne.Window,
|
||||
confirm OnConfirmFn,
|
||||
data binding.DataItem,
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
localizer *i18n.Localizer,
|
||||
) Dialog {
|
||||
if dialogCatalog == nil {
|
||||
return nil
|
||||
}
|
||||
if kindCatalog, ok := dialogCatalog[name]; ok {
|
||||
if fn, ok := kindCatalog[kind]; ok {
|
||||
return fn(
|
||||
name, kind, parent, confirm, data,
|
||||
&filesystem, screenName, localizer)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
135
screen/layout.go
135
screen/layout.go
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
319
screen/widget.go
319
screen/widget.go
@ -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
|
||||
}
|
||||
|
351
screenhandler.go
Normal file
351
screenhandler.go
Normal file
@ -0,0 +1,351 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"bitbucket.org/hevanto/ui/screen"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
)
|
||||
|
||||
// ScreenHandler represents the handler for a screen.
|
||||
//
|
||||
// It provides:
|
||||
// - The screen definition
|
||||
// - The localizer
|
||||
// - The screen controller
|
||||
// - Exported elements
|
||||
// - List item templates and renderers
|
||||
// - User interaction handlers
|
||||
type ScreenHandler struct {
|
||||
screenDefinition *screen.Screen
|
||||
localizer *i18n.Localizer
|
||||
ctrl ScreenController
|
||||
|
||||
// Map of screen elements that got an id assigned
|
||||
exportedElements map[string]*screen.UIElement
|
||||
|
||||
listItemTemplates map[string]screen.ListItemTemplateFn
|
||||
listItemRenderers map[string]screen.ListItemRendererFn
|
||||
listDataItemRenderers map[string]screen.ListDataItemRendererFn
|
||||
listLengths map[string]screen.ListLengthFn
|
||||
|
||||
onListItemSelectedHandlers map[string]screen.ListItemHandlerFn
|
||||
onListItemUnselectedHandlers map[string]screen.ListItemHandlerFn
|
||||
onClickedHandlers map[string]screen.ClickHandlerFn
|
||||
onCheckChangedHandlers map[string]screen.CheckHandlerFn
|
||||
onDateSelectedHandlers map[string]screen.DateSelectedHandlerFn
|
||||
onValidationChangedHandlers map[string]screen.ValidationChangedHandlerFn
|
||||
}
|
||||
|
||||
// NewScreenHandler initializes a new ScreenHandler with the provided filesystem, screen name, ScreenController, and localizer.
|
||||
//
|
||||
// Arguments:
|
||||
// - filesystem: the embedded filesystem to access screen resources.
|
||||
// - screenName: the name of the screen to load.
|
||||
// - ctrl: the ScreenController for the screen.
|
||||
// - localizer: the i18n.Localizer for localization.
|
||||
//
|
||||
// Returns:
|
||||
// - h: the initialized ScreenHandler.
|
||||
// - err: an error if loading the screen fails.
|
||||
func NewScreenHandler(
|
||||
filesystem embed.FS,
|
||||
screenName string,
|
||||
ctrl ScreenController,
|
||||
localizer *i18n.Localizer,
|
||||
) (h *ScreenHandler, err error) {
|
||||
h = new(ScreenHandler)
|
||||
|
||||
h.ctrl = ctrl
|
||||
h.localizer = localizer
|
||||
|
||||
def, err := screen.New(filesystem, screenName, h)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failure loading screen: %w", err)
|
||||
return
|
||||
}
|
||||
h.screenDefinition = def
|
||||
|
||||
h.exportedElements = make(map[string]*screen.UIElement)
|
||||
h.listItemTemplates = make(map[string]screen.ListItemTemplateFn)
|
||||
h.listItemRenderers = make(map[string]screen.ListItemRendererFn)
|
||||
h.listDataItemRenderers = make(map[string]screen.ListDataItemRendererFn)
|
||||
h.listLengths = make(map[string]screen.ListLengthFn)
|
||||
h.onListItemSelectedHandlers = make(map[string]screen.ListItemHandlerFn)
|
||||
h.onListItemUnselectedHandlers = make(map[string]screen.ListItemHandlerFn)
|
||||
h.onClickedHandlers = make(map[string]screen.ClickHandlerFn)
|
||||
h.onCheckChangedHandlers = make(map[string]screen.CheckHandlerFn)
|
||||
h.onDateSelectedHandlers = make(map[string]screen.DateSelectedHandlerFn)
|
||||
h.onValidationChangedHandlers = make(map[string]screen.ValidationChangedHandlerFn)
|
||||
return
|
||||
}
|
||||
|
||||
// ScreenDefinition returns the screen definition for the ScreenHandler.
|
||||
func (h *ScreenHandler) ScreenDefinition() *screen.Screen {
|
||||
return h.screenDefinition
|
||||
}
|
||||
|
||||
// RegisterElement registers an element with the ScreenHandler.
|
||||
//
|
||||
// This function is called for every element in the screen definition fow which
|
||||
// an ID is defined.
|
||||
func (h *ScreenHandler) RegisterElement(
|
||||
id string,
|
||||
elem fyne.CanvasObject,
|
||||
decorator fyne.CanvasObject,
|
||||
) {
|
||||
h.exportedElements[id] = &screen.UIElement{Object: elem, Decorator: decorator}
|
||||
}
|
||||
|
||||
// RegisterListItemTemplate registers a ListItemTemplate with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the templates for the lists used in the
|
||||
// screen definition.
|
||||
func (h *ScreenHandler) RegisterListItemTemplate(
|
||||
name string,
|
||||
fn screen.ListItemTemplateFn,
|
||||
) {
|
||||
h.listItemTemplates[name] = fn
|
||||
}
|
||||
|
||||
// RegisterListDataItemRenderer registers a ListDataItemRenderer with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the renderers for the lists used in the
|
||||
// screen definition.
|
||||
func (h *ScreenHandler) RegisterListDataItemRenderer(
|
||||
name string,
|
||||
fn screen.ListDataItemRendererFn,
|
||||
) {
|
||||
h.listDataItemRenderers[name] = fn
|
||||
}
|
||||
|
||||
// RegisterListItemRenderer registers a ListItemRenderer with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the renderers for the lists used in the
|
||||
// screen definition.
|
||||
func (h *ScreenHandler) RegisterListItemRenderer(
|
||||
name string,
|
||||
fn screen.ListItemRendererFn,
|
||||
) {
|
||||
h.listItemRenderers[name] = fn
|
||||
}
|
||||
|
||||
// RegisterListLength registers a ListLength with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the lengths for the lists used in the
|
||||
// screen definition.
|
||||
func (h *ScreenHandler) RegisterListLength(
|
||||
name string,
|
||||
fn screen.ListLengthFn,
|
||||
) {
|
||||
h.listLengths[name] = fn
|
||||
}
|
||||
|
||||
// RegisterOnListItemSelectedHandler registers a OnListItemSelectedHandler with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the handler functions used in the screen
|
||||
// definition.
|
||||
func (h *ScreenHandler) RegisterOnListItemSelectedHandler(
|
||||
name string,
|
||||
fn screen.ListItemHandlerFn,
|
||||
) {
|
||||
h.onListItemSelectedHandlers[name] = fn
|
||||
}
|
||||
|
||||
// RegisterOnListItemUnselectedHandler registers a OnListItemUnselectedHandler with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the handler functions used in the screen
|
||||
// definition.
|
||||
func (h *ScreenHandler) RegisterOnListItemUnselectedHandler(
|
||||
name string,
|
||||
fn screen.ListItemHandlerFn,
|
||||
) {
|
||||
h.onListItemUnselectedHandlers[name] = fn
|
||||
}
|
||||
|
||||
// RegisterOnClickHandler registers a OnClickHandler with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the handler functions used in the screen
|
||||
// definition.
|
||||
func (h *ScreenHandler) RegisterOnClickHandler(
|
||||
name string,
|
||||
fn screen.ClickHandlerFn,
|
||||
) {
|
||||
h.onClickedHandlers[name] = fn
|
||||
}
|
||||
|
||||
// RegisterOnCheckChangedHandler registers a OnCheckChangedHandler with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the handler functions used in the screen
|
||||
// definition.
|
||||
func (h *ScreenHandler) RegisterOnCheckChangedHandler(
|
||||
name string,
|
||||
fn screen.CheckHandlerFn,
|
||||
) {
|
||||
h.onCheckChangedHandlers[name] = fn
|
||||
}
|
||||
|
||||
// RegisterOnDateSelectedHandler registers a OnDateSelectedHandler with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the handler functions used in the screen
|
||||
// definition.
|
||||
func (h *ScreenHandler) RegisterOnDateSelectedHandler(
|
||||
name string,
|
||||
fn screen.DateSelectedHandlerFn,
|
||||
) {
|
||||
h.onDateSelectedHandlers[name] = fn
|
||||
}
|
||||
|
||||
// RegisterOnValidationChangedHandler registers a OnValidationChangedHandler with the ScreenHandler.
|
||||
//
|
||||
// Use this function to register the handler functions used in the screen
|
||||
// definition.
|
||||
func (h *ScreenHandler) RegisterOnValidationChangedHandler(
|
||||
name string,
|
||||
fn screen.ValidationChangedHandlerFn,
|
||||
) {
|
||||
h.onValidationChangedHandlers[name] = fn
|
||||
}
|
||||
|
||||
// GetBinding returns the binding with the given name.
|
||||
//
|
||||
// This function forwards the call to the controller. In the controller the
|
||||
// required bindings should be mapped to the screen elements.
|
||||
func (h *ScreenHandler) GetBinding(name string) binding.DataItem {
|
||||
return h.ctrl.GetBinding(name)
|
||||
}
|
||||
|
||||
// GetValidator returns the validator with the given name.
|
||||
//
|
||||
// This function forwards the call to the controller. In the controller the
|
||||
// required validators should be mapped to the screen elements.
|
||||
func (h *ScreenHandler) GetValidator(name string) fyne.StringValidator {
|
||||
return h.ctrl.GetValidator(name)
|
||||
}
|
||||
|
||||
// GetElement returns the UIElement with the given ID.
|
||||
//
|
||||
// This function allows you to retrieve the exported elements (given an ID in
|
||||
// the screen definition). The UIElement contains the object and the decorator.
|
||||
// Should no decorator be present, both point to the same widget. If a decorator
|
||||
// is present it's advices to do hide and show operations on the decorator, and
|
||||
// all other operators on the object.
|
||||
func (h *ScreenHandler) GetElement(id string) *screen.UIElement {
|
||||
if elem, ok := h.exportedElements[id]; ok {
|
||||
return elem
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLocalizer returns the i18n.Localizer used for localization.
|
||||
func (h *ScreenHandler) GetLocalizer() *i18n.Localizer {
|
||||
return h.localizer
|
||||
}
|
||||
|
||||
// GetIcon returns the icon with the given name.
|
||||
//
|
||||
// This handler only implements the default theme icons. If you wish to support
|
||||
// other items, wrap this ScreenHandler and implement the loading of the icons
|
||||
// yourself.
|
||||
func (h *ScreenHandler) GetIcon(iconName string) fyne.Resource {
|
||||
if strings.HasPrefix(iconName, "theme.") {
|
||||
iconName := strings.SplitN(iconName, ".", 2)[1]
|
||||
return theme.DefaultTheme().Icon(fyne.ThemeIconName(iconName))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetListItemTemplate returns the ListItemTemplate with the given name.
|
||||
func (h *ScreenHandler) GetListItemTemplate(name string) screen.ListItemTemplateFn {
|
||||
fn, ok := h.listItemTemplates[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetListDataItemRenderer returns the ListDataItemRenderer with the given name.
|
||||
func (h *ScreenHandler) GetListDataItemRenderer(name string) screen.ListDataItemRendererFn {
|
||||
fn, ok := h.listDataItemRenderers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetListItemRenderer returns the ListItemRenderer with the given name.
|
||||
func (h *ScreenHandler) GetListItemRenderer(name string) screen.ListItemRendererFn {
|
||||
fn, ok := h.listItemRenderers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetListLength returns the ListLength with the given name.
|
||||
func (h *ScreenHandler) GetListLength(name string) screen.ListLengthFn {
|
||||
fn, ok := h.listLengths[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetOnListItemSelectedHandler returns the OnListItemSelectedHandler with the given name.
|
||||
func (h *ScreenHandler) GetOnListItemSelectedHandler(name string) screen.ListItemHandlerFn {
|
||||
fn, ok := h.onListItemSelectedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetOnListItemUnselectedHandler returns the OnListItemUnselectedHandler with the given name.
|
||||
func (h *ScreenHandler) GetOnListItemUnselectedHandler(name string) screen.ListItemHandlerFn {
|
||||
fn, ok := h.onListItemUnselectedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetOnClickedHandler returns the OnClickedHandler with the given name.
|
||||
func (h *ScreenHandler) GetOnClickedHandler(name string) screen.ClickHandlerFn {
|
||||
fn, ok := h.onClickedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetOnCheckChangedHandler returns the OnCheckChangedHandler with the given name.
|
||||
func (h *ScreenHandler) GetOnCheckChangedHandler(name string) screen.CheckHandlerFn {
|
||||
fn, ok := h.onCheckChangedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetOnDateSelectedHandler returns the OnDateSelectedHandler with the given name.
|
||||
func (h *ScreenHandler) GetOnDateSelectedHandler(name string) screen.DateSelectedHandlerFn {
|
||||
fn, ok := h.onDateSelectedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetOnValidationChangedHandler returns the OnValidationChangedHandler with the given name.
|
||||
func (h *ScreenHandler) GetOnValidationChangedHandler(name string) screen.ValidationChangedHandlerFn {
|
||||
fn, ok := h.onValidationChangedHandlers[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
@ -7,6 +7,8 @@ import (
|
||||
"fyne.io/fyne/v2/container"
|
||||
)
|
||||
|
||||
// TODO: Implement screen reading from file!
|
||||
|
||||
type TabbedView struct {
|
||||
*BaseView
|
||||
|
||||
|
@ -2,14 +2,26 @@ package uilayout
|
||||
|
||||
import "fyne.io/fyne/v2"
|
||||
|
||||
// MinSize implements a min size layout.
|
||||
//
|
||||
// The MinSize layout will ensure that the container is rendered at a size that
|
||||
// is at least as large as the minimum size provided.
|
||||
type MinSize struct {
|
||||
minSize fyne.Size
|
||||
}
|
||||
|
||||
// NewMinSizeLayout creates a new MinSize layout with the specified minimum size.
|
||||
//
|
||||
// Arguments:
|
||||
// - minSize: the minimum size for the layout.
|
||||
//
|
||||
// Returns *MinSize: a pointer to the newly created MinSize layout.
|
||||
func NewMinSizeLayout(minSize fyne.Size) *MinSize {
|
||||
return &MinSize{minSize: minSize}
|
||||
}
|
||||
|
||||
// MinSize calculates the minimum size of the layout on the current screen. The
|
||||
// reported size will be at least as large as the configured minimum size.
|
||||
func (l *MinSize) MinSize(objects []fyne.CanvasObject) fyne.Size {
|
||||
size := l.minSize
|
||||
for _, o := range objects {
|
||||
@ -24,6 +36,7 @@ func (l *MinSize) MinSize(objects []fyne.CanvasObject) fyne.Size {
|
||||
return size
|
||||
}
|
||||
|
||||
// Layout implements the Layout interface.
|
||||
func (l *MinSize) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) {
|
||||
pos := fyne.NewPos(0, 0)
|
||||
for _, o := range objects {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
// LabelOpts defines the options for a label.
|
||||
type LabelOpts interface {
|
||||
ApplyTo(*widget.Label)
|
||||
}
|
||||
@ -19,10 +20,12 @@ type allignmentOpt struct {
|
||||
Alignment fyne.TextAlign
|
||||
}
|
||||
|
||||
// AlignmentOpt returns a LabelOpts with the specified alignment.
|
||||
func AlignmentOpt(alignment fyne.TextAlign) LabelOpts {
|
||||
return &allignmentOpt{alignment}
|
||||
}
|
||||
|
||||
// ApplyTo sets the alignment of a label to the specified alignment.
|
||||
func (a *allignmentOpt) ApplyTo(lbl *widget.Label) {
|
||||
lbl.Alignment = a.Alignment
|
||||
}
|
||||
@ -31,10 +34,12 @@ type wrappingOpt struct {
|
||||
Wrapping fyne.TextWrap
|
||||
}
|
||||
|
||||
// WrappingOpt creates a LabelOpts with the specified text wrapping option.
|
||||
func WrappingOpt(wrapping fyne.TextWrap) LabelOpts {
|
||||
return &wrappingOpt{wrapping}
|
||||
}
|
||||
|
||||
// ApplyTo applies the wrapping option to the label.
|
||||
func (w *wrappingOpt) ApplyTo(lbl *widget.Label) {
|
||||
lbl.Wrapping = w.Wrapping
|
||||
}
|
||||
@ -43,10 +48,12 @@ type textStyleOpt struct {
|
||||
Style fyne.TextStyle
|
||||
}
|
||||
|
||||
// TextStyleOpt returns the label options for the given text style.
|
||||
func TextStyleOpt(style fyne.TextStyle) LabelOpts {
|
||||
return &textStyleOpt{style}
|
||||
}
|
||||
|
||||
// ApplyTo applies the text style option to the label.
|
||||
func (t *textStyleOpt) ApplyTo(lbl *widget.Label) {
|
||||
lbl.TextStyle = t.Style
|
||||
}
|
||||
@ -55,10 +62,12 @@ type truncationOpt struct {
|
||||
Truncation fyne.TextTruncation
|
||||
}
|
||||
|
||||
// TruncationOpt returns the label options for the given text truncation option.
|
||||
func TruncationOpt(truncation fyne.TextTruncation) LabelOpts {
|
||||
return &truncationOpt{truncation}
|
||||
}
|
||||
|
||||
// ApplyTo applies the text truncation option to the label.
|
||||
func (t *truncationOpt) ApplyTo(lbl *widget.Label) {
|
||||
lbl.Truncation = t.Truncation
|
||||
}
|
||||
@ -67,14 +76,23 @@ type importanceOpt struct {
|
||||
Importance widget.Importance
|
||||
}
|
||||
|
||||
// ImportanceOpt returns the label options for the given text importance option.
|
||||
func ImportanceOpt(importance widget.Importance) LabelOpts {
|
||||
return &importanceOpt{importance}
|
||||
}
|
||||
|
||||
// ApplyTo applies the text importance option to the label.
|
||||
func (i *importanceOpt) ApplyTo(lbl *widget.Label) {
|
||||
lbl.Importance = i.Importance
|
||||
}
|
||||
|
||||
// NewLabel creates a new label widget with the given text and options.
|
||||
//
|
||||
// Arguments
|
||||
// - text: the text to be displayed on the label.
|
||||
// - opts: optional configuration options for the label.
|
||||
//
|
||||
// Returns *widget.Label: a pointer to the newly created label widget.
|
||||
func NewLabel(text string, opts ...LabelOpts) *widget.Label {
|
||||
lbl := widget.NewLabel(text)
|
||||
for _, opt := range opts {
|
||||
@ -83,6 +101,13 @@ func NewLabel(text string, opts ...LabelOpts) *widget.Label {
|
||||
return lbl
|
||||
}
|
||||
|
||||
// NewLabelWithData creates a new Label widget with the provided data and options.
|
||||
//
|
||||
// Arguments
|
||||
// - data: The string data to be displayed on the label.
|
||||
// - opts: Additional options to customize the label.
|
||||
//
|
||||
// Returns *widget.Label: a pointer to the newly created Label widget.
|
||||
func NewLabelWithData(data binding.String, opts ...LabelOpts) *widget.Label {
|
||||
lbl := widget.NewLabelWithData(data)
|
||||
for _, opt := range opts {
|
||||
@ -91,6 +116,14 @@ func NewLabelWithData(data binding.String, opts ...LabelOpts) *widget.Label {
|
||||
return lbl
|
||||
}
|
||||
|
||||
// NewUpDownLabelWithData creates a new label widget with up and down buttons.
|
||||
//
|
||||
// Arguments
|
||||
// - data: the string data to display in the label.
|
||||
// - upHandler: the function to call when the up button is clicked.
|
||||
// - downHandler: the function to call when the down button is clicked.
|
||||
//
|
||||
// Returns fyne.CanvasObject: the created widget.
|
||||
func NewUpDownLabelWithData(
|
||||
data binding.String,
|
||||
upHandler func(),
|
||||
@ -115,11 +148,25 @@ func NewUpDownLabelWithData(
|
||||
return c1
|
||||
}
|
||||
|
||||
// NewH creates a RichText widget formatted as a header of the provided level.
|
||||
//
|
||||
// Parameters:
|
||||
// - level: an integer representing the level of the text.
|
||||
// - text: a string containing the text to display.
|
||||
//
|
||||
// Returns a pointer to a RichText widget.
|
||||
func NewH(level int, text string) *widget.RichText {
|
||||
return widget.NewRichTextFromMarkdown(
|
||||
fmt.Sprintf("%s %s", strings.Repeat("#", level), text))
|
||||
}
|
||||
|
||||
// NewHWithData creates a new RichText widget formatted as a header of the provided level.
|
||||
//
|
||||
// Parameters:
|
||||
// - level: an integer representing the level of the text.
|
||||
// - data: a string binding containing the text to display.
|
||||
//
|
||||
// Returns a pointer to a RichText widget.
|
||||
func NewHWithData(level int, data binding.String) *widget.RichText {
|
||||
txt, _ := data.Get()
|
||||
w := NewH(level, txt)
|
||||
@ -130,50 +177,62 @@ func NewHWithData(level int, data binding.String) *widget.RichText {
|
||||
return w
|
||||
}
|
||||
|
||||
// NewH1 creates a new RichText widget with header level 1.
|
||||
func NewH1(text string) *widget.RichText {
|
||||
return NewH(1, text)
|
||||
}
|
||||
|
||||
// NewH1WithData creates a new RichText widget with header level 1.
|
||||
func NewH1WithData(data binding.String) *widget.RichText {
|
||||
return NewHWithData(1, data)
|
||||
}
|
||||
|
||||
// NewH2 creates a new RichText widget with header level 2.
|
||||
func NewH2(text string) *widget.RichText {
|
||||
return NewH(2, text)
|
||||
}
|
||||
|
||||
// NewH2WithData creates a new RichText widget with header level 2.
|
||||
func NewH2WithData(data binding.String) *widget.RichText {
|
||||
return NewHWithData(2, data)
|
||||
}
|
||||
|
||||
// NewH3 creates a new RichText widget with header level 3.
|
||||
func NewH3(text string) *widget.RichText {
|
||||
return NewH(3, text)
|
||||
}
|
||||
|
||||
// NewH3WithData creates a new RichText widget with header level 3.
|
||||
func NewH3WithData(data binding.String) *widget.RichText {
|
||||
return NewHWithData(3, data)
|
||||
}
|
||||
|
||||
// NewH4 creates a new RichText widget with header level 4.
|
||||
func NewH4(text string) *widget.RichText {
|
||||
return NewH(4, text)
|
||||
}
|
||||
|
||||
// NewH4WithData creates a new RichText widget with header level 4.
|
||||
func NewH4WithData(data binding.String) *widget.RichText {
|
||||
return NewHWithData(4, data)
|
||||
}
|
||||
|
||||
// NewH5 creates a new RichText widget with header level 5.
|
||||
func NewH5(text string) *widget.RichText {
|
||||
return NewH(5, text)
|
||||
}
|
||||
|
||||
// NewH5WithData creates a new RichText widget with header level 5.
|
||||
func NewH5WithData(data binding.String) *widget.RichText {
|
||||
return NewHWithData(5, data)
|
||||
}
|
||||
|
||||
// NewH6 creates a new RichText widget with header level 6.
|
||||
func NewH6(text string) *widget.RichText {
|
||||
return NewH(6, text)
|
||||
}
|
||||
|
||||
// NewH6WithData creates a new RichText widget with header level 6.
|
||||
func NewH6WithData(data binding.String) *widget.RichText {
|
||||
return NewHWithData(6, data)
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ import (
|
||||
"fyne.io/fyne/v2/theme"
|
||||
)
|
||||
|
||||
// NewWidgetBorder creates a new widget border for the given fyne.CanvasObject.
|
||||
// It does so by wrapping the object in a Stack layout with a border drawn
|
||||
// above the widget.
|
||||
func NewWidgetBorder(widget fyne.CanvasObject) fyne.CanvasObject {
|
||||
b := canvas.NewRectangle(color.Transparent)
|
||||
b.StrokeColor = theme.InputBorderColor()
|
||||
|
Loading…
Reference in New Issue
Block a user