Implement defining screens in yaml
This commit is contained in:
		
							
								
								
									
										63
									
								
								baseview.go
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								baseview.go
									
									
									
									
									
								
							| @@ -1,12 +1,10 @@ | |||||||
| package ui | package ui | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"time" | 	"embed" | ||||||
|  |  | ||||||
| 	"bitbucket.org/hevanto/ui/screen" |  | ||||||
| 	"fyne.io/fyne/v2" | 	"fyne.io/fyne/v2" | ||||||
| 	"fyne.io/fyne/v2/data/binding" | 	"fyne.io/fyne/v2/data/binding" | ||||||
| 	"fyne.io/fyne/v2/widget" |  | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/nicksnyder/go-i18n/v2/i18n" | 	"github.com/nicksnyder/go-i18n/v2/i18n" | ||||||
| ) | ) | ||||||
| @@ -26,35 +24,8 @@ type BaseView struct { | |||||||
| 	// Root CanvasObject of the view | 	// Root CanvasObject of the view | ||||||
| 	CanvasObject fyne.CanvasObject | 	CanvasObject fyne.CanvasObject | ||||||
|  |  | ||||||
| 	// The screen definition |  | ||||||
| 	screenDefinition *screen.Screen |  | ||||||
|  |  | ||||||
| 	// ----------- ScreenHandler -------------// | 	// ----------- ScreenHandler -------------// | ||||||
|  | 	*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) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // NewBaseView creates a new baseview | // NewBaseView creates a new baseview | ||||||
| @@ -80,6 +51,28 @@ func NewBaseView( | |||||||
| 	return v | 	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 | // ID returns tie id of the view | ||||||
| func (v BaseView) ID() string { | func (v BaseView) ID() string { | ||||||
| 	return v.id | 	return v.id | ||||||
| @@ -106,8 +99,8 @@ func (v *BaseView) Initialize() fyne.CanvasObject { | |||||||
| 	if err := v.Ctrl.Initialize(); err != nil { | 	if err := v.Ctrl.Initialize(); err != nil { | ||||||
| 		LogWindowError(v, Initialize, err) | 		LogWindowError(v, Initialize, err) | ||||||
| 	} | 	} | ||||||
| 	if v.screenDefinition != nil { | 	if v.ScreenHandler != nil && v.ScreenDefinition() != nil { | ||||||
| 		obj, err := v.screenDefinition.Initialize() | 		obj, err := v.ScreenDefinition().Initialize() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			LogWindowError(v, Initialize, err) | 			LogWindowError(v, Initialize, err) | ||||||
| 			return nil | 			return nil | ||||||
| @@ -133,3 +126,7 @@ func (v *BaseView) OnShow() { | |||||||
| func (v *BaseView) OnHide() { | func (v *BaseView) OnHide() { | ||||||
| 	LogWindowEvent(v, 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 | 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 { | type Controller interface { | ||||||
|  | 	ScreenController | ||||||
|  |  | ||||||
| 	Initialize() error | 	Initialize() error | ||||||
| 	RefreshData() error | 	RefreshData() error | ||||||
|  |  | ||||||
| 	GetBinding(string) binding.DataItem |  | ||||||
| } | } | ||||||
|  |  | ||||||
| type DialogController interface { | type DialogController interface { | ||||||
|  | 	ScreenController | ||||||
|  |  | ||||||
| 	Initialize(data binding.DataItem) error | 	Initialize(data binding.DataItem) error | ||||||
| 	RefreshData() error | 	RefreshData() error | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										204
									
								
								dialog.go
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								dialog.go
									
									
									
									
									
								
							| @@ -1,6 +1,7 @@ | |||||||
| package ui | package ui | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"embed" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
| 	"fyne.io/fyne/v2" | 	"fyne.io/fyne/v2" | ||||||
| @@ -8,13 +9,22 @@ import ( | |||||||
| 	"fyne.io/fyne/v2/dialog" | 	"fyne.io/fyne/v2/dialog" | ||||||
| 	"fyne.io/fyne/v2/widget" | 	"fyne.io/fyne/v2/widget" | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
|  | 	"github.com/nicksnyder/go-i18n/v2/i18n" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type DialogName string | type DialogName string | ||||||
| type DialogKind string | type DialogKind string | ||||||
|  |  | ||||||
| type OnConfirmFn func(bool, error, ...interface{}) | 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 ( | const ( | ||||||
| 	DlgGeneric DialogKind = "Generic" | 	DlgGeneric DialogKind = "Generic" | ||||||
| @@ -47,12 +57,16 @@ type BaseDialog struct { | |||||||
| 	CanvasObj      fyne.CanvasObject | 	CanvasObj      fyne.CanvasObject | ||||||
| 	Data           binding.DataItem | 	Data           binding.DataItem | ||||||
| 	focusItem      fyne.Focusable | 	focusItem      fyne.Focusable | ||||||
|  |  | ||||||
|  | 	Ctrl DialogController | ||||||
|  | 	*ScreenHandler | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewBaseDialog( | func NewBaseDialog( | ||||||
| 	concreteDialog Dialog, | 	concreteDialog Dialog, | ||||||
| 	name DialogName, | 	name DialogName, | ||||||
| 	kind DialogKind, | 	kind DialogKind, | ||||||
|  | 	controller DialogController, | ||||||
| 	parent fyne.Window, | 	parent fyne.Window, | ||||||
| 	confirm OnConfirmFn, | 	confirm OnConfirmFn, | ||||||
| ) *BaseDialog { | ) *BaseDialog { | ||||||
| @@ -63,13 +77,40 @@ func NewBaseDialog( | |||||||
| 		dlgKind:        kind, | 		dlgKind:        kind, | ||||||
| 		window:         parent, | 		window:         parent, | ||||||
| 		onConfirm:      confirm, | 		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( | func NewBaseDialogWithData( | ||||||
| 	concreteDialog Dialog, | 	concreteDialog Dialog, | ||||||
| 	name DialogName, | 	name DialogName, | ||||||
| 	kind DialogKind, | 	kind DialogKind, | ||||||
|  | 	controller DialogController, | ||||||
| 	parent fyne.Window, | 	parent fyne.Window, | ||||||
| 	confirm OnConfirmFn, | 	confirm OnConfirmFn, | ||||||
| 	data binding.DataItem, | 	data binding.DataItem, | ||||||
| @@ -82,9 +123,36 @@ func NewBaseDialogWithData( | |||||||
| 		window:         parent, | 		window:         parent, | ||||||
| 		onConfirm:      confirm, | 		onConfirm:      confirm, | ||||||
| 		Data:           data, | 		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 { | func (d BaseDialog) Window() fyne.Window { | ||||||
| 	return d.window | 	return d.window | ||||||
| } | } | ||||||
| @@ -114,6 +182,7 @@ func (d BaseDialog) OnConfirmFn() OnConfirmFn { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (d *BaseDialog) Show(parent ...fyne.Window) { | func (d *BaseDialog) Show(parent ...fyne.Window) { | ||||||
|  |  | ||||||
| 	d.concreteDialog.OnShow() | 	d.concreteDialog.OnShow() | ||||||
| 	d.dlg = dialog.NewCustomConfirm( | 	d.dlg = dialog.NewCustomConfirm( | ||||||
| 		d.concreteDialog.Title(), | 		d.concreteDialog.Title(), | ||||||
| @@ -146,6 +215,17 @@ func (d BaseDialog) Title() string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (d *BaseDialog) Initialize() fyne.CanvasObject { | 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 | 	return d.CanvasObj | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -184,35 +264,80 @@ func NewFormDialog( | |||||||
| 	concreteDialog Dialog, | 	concreteDialog Dialog, | ||||||
| 	name DialogName, | 	name DialogName, | ||||||
| 	kind DialogKind, | 	kind DialogKind, | ||||||
|  | 	controller DialogController, | ||||||
| 	parent fyne.Window, | 	parent fyne.Window, | ||||||
| 	confirm OnConfirmFn, | 	confirm OnConfirmFn, | ||||||
| 	itemsFn FormDialogItemsFn, | 	itemsFn FormDialogItemsFn, | ||||||
| ) *FormDialog { | ) *FormDialog { | ||||||
| 	return &FormDialog{ | 	return &FormDialog{ | ||||||
| 		BaseDialog:   NewBaseDialog(concreteDialog, name, kind, parent, confirm), | 		BaseDialog: NewBaseDialog( | ||||||
|  | 			concreteDialog, name, kind, controller, parent, confirm), | ||||||
| 		itemsFn:      itemsFn, | 		itemsFn:      itemsFn, | ||||||
| 		confirmLabel: "OK", | 		confirmLabel: "OK", | ||||||
| 		dismissLabel: "Cancel", | 		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( | func NewformDialogWithData( | ||||||
| 	concreteDialog Dialog, | 	concreteDialog Dialog, | ||||||
| 	name DialogName, | 	name DialogName, | ||||||
| 	kind DialogKind, | 	kind DialogKind, | ||||||
|  | 	controller DialogController, | ||||||
| 	parent fyne.Window, | 	parent fyne.Window, | ||||||
| 	confirm OnConfirmFn, | 	confirm OnConfirmFn, | ||||||
| 	itemsFn FormDialogItemsFn, | 	itemsFn FormDialogItemsFn, | ||||||
| 	data binding.DataItem, | 	data binding.DataItem, | ||||||
| ) *FormDialog { | ) *FormDialog { | ||||||
| 	return &FormDialog{ | 	return &FormDialog{ | ||||||
| 		BaseDialog:   NewBaseDialogWithData(concreteDialog, name, kind, parent, confirm, data), | 		BaseDialog: NewBaseDialogWithData( | ||||||
|  | 			concreteDialog, name, kind, controller, parent, confirm, data), | ||||||
| 		itemsFn:      itemsFn, | 		itemsFn:      itemsFn, | ||||||
| 		confirmLabel: "OK", | 		confirmLabel: "OK", | ||||||
| 		dismissLabel: "Cancel", | 		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( | func (d *FormDialog) SetButtonLabels( | ||||||
| 	confirm string, | 	confirm string, | ||||||
| 	dismiss string, | 	dismiss string, | ||||||
| @@ -221,7 +346,25 @@ func (d *FormDialog) SetButtonLabels( | |||||||
| 	d.dismissLabel = dismiss | 	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) { | func (d *FormDialog) Show(parent ...fyne.Window) { | ||||||
|  | 	d.concreteDialog.Initialize() | ||||||
| 	d.items = d.itemsFn() | 	d.items = d.itemsFn() | ||||||
|  |  | ||||||
| 	d.concreteDialog.OnShow() | 	d.concreteDialog.OnShow() | ||||||
| @@ -263,7 +406,8 @@ func RegisterDialog(name DialogName, kind DialogKind, fn NewDialogFn) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func NewDialog( | func NewDialog( | ||||||
| 	name DialogName, kind DialogKind, | 	name DialogName, | ||||||
|  | 	kind DialogKind, | ||||||
| 	parent fyne.Window, | 	parent fyne.Window, | ||||||
| 	confirm OnConfirmFn, | 	confirm OnConfirmFn, | ||||||
| ) Dialog { | ) Dialog { | ||||||
| @@ -272,14 +416,37 @@ func NewDialog( | |||||||
| 	} | 	} | ||||||
| 	if kindCatalog, ok := dialogCatalog[name]; ok { | 	if kindCatalog, ok := dialogCatalog[name]; ok { | ||||||
| 		if fn, ok := kindCatalog[kind]; 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 | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewDialogWithData( | func NewDialogWithData( | ||||||
| 	name DialogName, kind DialogKind, | 	name DialogName, | ||||||
|  | 	kind DialogKind, | ||||||
| 	parent fyne.Window, | 	parent fyne.Window, | ||||||
| 	confirm OnConfirmFn, | 	confirm OnConfirmFn, | ||||||
| 	data binding.DataItem, | 	data binding.DataItem, | ||||||
| @@ -289,7 +456,30 @@ func NewDialogWithData( | |||||||
| 	} | 	} | ||||||
| 	if kindCatalog, ok := dialogCatalog[name]; ok { | 	if kindCatalog, ok := dialogCatalog[name]; ok { | ||||||
| 		if fn, ok := kindCatalog[kind]; 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 | 	return nil | ||||||
|   | |||||||
| @@ -9,45 +9,85 @@ import ( | |||||||
| 	"fyne.io/fyne/v2/container" | 	"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 | type Container string | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
|  | 	// HScroll Container | ||||||
|  | 	// | ||||||
|  | 	// Available yaml options: | ||||||
|  | 	//	- content: The content of the container | ||||||
| 	HScroll Container = "HScroll" | 	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" | 	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 { | 	switch cnt { | ||||||
| 	case HScroll: | 	case HScroll: | ||||||
| 		c, err = cnt.buildHScrollContainer(e, s) | 		container, err = cnt.buildHScrollContainer(e, s) | ||||||
| 	case Scroll: | 	case Scroll: | ||||||
| 		c, err = cnt.buildScrollContainer(e, s) | 		container, err = cnt.buildScrollContainer(e, s) | ||||||
| 	case VScroll: | 	case VScroll: | ||||||
| 		c, err = cnt.buildVScrollContainer(e, s) | 		container, err = cnt.buildVScrollContainer(e, s) | ||||||
| 	default: | 	default: | ||||||
| 		err = errors.New("invalid container") | 		err = errors.New("invalid container") | ||||||
| 	} | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if e.Decorators != nil { |  | ||||||
|  |  | ||||||
|  | 	decorator = container | ||||||
|  | 	if e.Decorators != nil { | ||||||
| 		for _, dec := range e.Decorators { | 		for _, dec := range e.Decorators { | ||||||
| 			switch dec { | 			switch dec { | ||||||
| 			case "Border": | 			case "Border": | ||||||
| 				c = uiwidget.NewWidgetBorder(c) | 				decorator = uiwidget.NewWidgetBorder(decorator) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if e.Hidden { | 	if e.Hidden { | ||||||
| 		c.Hide() | 		decorator.Hide() | ||||||
| 	} | 	} | ||||||
| 	return | 	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 { | 	if e.Content == nil { | ||||||
| 		err = errors.New("HScroll: no content defined") | 		err = errors.New("HScroll: no content defined") | ||||||
| 		return | 		return | ||||||
| @@ -62,7 +102,10 @@ func (ctn Container) buildHScrollContainer(e *Element, s ScreenHandler) (c fyne. | |||||||
| 	return | 	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 { | 	if e.Content == nil { | ||||||
| 		err = errors.New("Scroll: no content defined") | 		err = errors.New("Scroll: no content defined") | ||||||
| 		return | 		return | ||||||
| @@ -77,7 +120,10 @@ func (ctn Container) buildScrollContainer(e *Element, s ScreenHandler) (c fyne.C | |||||||
| 	return | 	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 { | 	if e.Content == nil { | ||||||
| 		err = errors.New("VScroll: no content defined") | 		err = errors.New("VScroll: no content defined") | ||||||
| 		return | 		return | ||||||
|   | |||||||
| @@ -7,11 +7,13 @@ import ( | |||||||
| 	"fyne.io/fyne/v2" | 	"fyne.io/fyne/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // Size represents the yaml description of a ui size | ||||||
| type Size struct { | type Size struct { | ||||||
| 	Width  float32 `yaml:"width"` | 	Width  float32 `yaml:"width"` | ||||||
| 	Height float32 `yaml:"height"` | 	Height float32 `yaml:"height"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Element represents the yaml description of a ui element | ||||||
| type Element struct { | type Element struct { | ||||||
| 	ID string `yaml:"id"` | 	ID string `yaml:"id"` | ||||||
|  |  | ||||||
| @@ -57,6 +59,12 @@ type Element struct { | |||||||
| 	Time       *string `yaml:"time"` | 	Time       *string `yaml:"time"` | ||||||
| 	TimeFormat *string `yaml:"timeFormat"` | 	TimeFormat *string `yaml:"timeFormat"` | ||||||
|  |  | ||||||
|  | 	// Entry Properties | ||||||
|  | 	MultiLine            bool   `yaml:"multiLine"` | ||||||
|  | 	Placeholder          string `yaml:"placeholder"` | ||||||
|  | 	PlaceholderLocalized bool   `yaml:"placeholderLocalized"` | ||||||
|  | 	Validator            string `yaml:"validator"` | ||||||
|  |  | ||||||
| 	// List Properties | 	// List Properties | ||||||
| 	ItemTemplate string `yaml:"itemTemplate"` | 	ItemTemplate string `yaml:"itemTemplate"` | ||||||
| 	ItemRenderer string `yaml:"itemRenderer"` | 	ItemRenderer string `yaml:"itemRenderer"` | ||||||
| @@ -70,38 +78,44 @@ type Element struct { | |||||||
| 	FixVertical   bool `yaml:"fixVertical"` | 	FixVertical   bool `yaml:"fixVertical"` | ||||||
|  |  | ||||||
| 	// Handlers | 	// Handlers | ||||||
| 	OnClicked      string `yaml:"onClicked"` | 	OnClicked           string `yaml:"onClicked"` | ||||||
| 	OnUpClicked    string `yaml:"onUpClicked"` | 	OnUpClicked         string `yaml:"onUpClicked"` | ||||||
| 	OnDownClicked  string `yaml:"onDownClicked"` | 	OnDownClicked       string `yaml:"onDownClicked"` | ||||||
| 	OnChanged      string `yaml:"onChanged"` | 	OnChanged           string `yaml:"onChanged"` | ||||||
| 	OnSelected     string `yaml:"onSelected"` | 	OnSelected          string `yaml:"onSelected"` | ||||||
| 	OnUnselected   string `yaml:"onUnselected"` | 	OnUnselected        string `yaml:"onUnselected"` | ||||||
| 	OnDateSelected string `yaml:"onDateSelected"` | 	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) { | func (e *Element) BuildUI(s ScreenHandler) (obj fyne.CanvasObject, err error) { | ||||||
|  | 	var baseObject fyne.CanvasObject | ||||||
|  |  | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if e.ID != "" && obj != nil { | 		if e.ID != "" && baseObject != nil { | ||||||
| 			s.RegisterElement(e.ID, obj) | 			s.RegisterElement(e.ID, baseObject, obj) | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	if e.Container != "" { | 	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) | 			err = fmt.Errorf("failed to build container element: %w", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if e.Layout != "" { | 	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) | 			err = fmt.Errorf("failed to build layout element: %w", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if e.Widget != "" { | 	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) | 			err = fmt.Errorf("failed to build widget element: %w", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| @@ -115,4 +129,7 @@ func (e *Element) localize(s ScreenHandler) { | |||||||
| 	if e.Localized { | 	if e.Localized { | ||||||
| 		e.Text = i18n.T(s.GetLocalizer(), e.Text) | 		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" | 	"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 | type Layout string | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	Border  Layout = "Border" | 	// Border Layout | ||||||
| 	Form    Layout = "Form" | 	// | ||||||
| 	Grid    Layout = "Grid" | 	// Available yaml options | ||||||
| 	HBox    Layout = "HBox" | 	//	- 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" | 	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 { | 	switch l { | ||||||
| 	case Border: | 	case Border: | ||||||
| 		c, err = l.buildBorderLayout(e, s) | 		layout, err = l.buildBorderLayout(e, s) | ||||||
| 	case Form: | 	case Form: | ||||||
| 		c, err = l.buildFormLayout(e, s) | 		layout, err = l.buildFormLayout(e, s) | ||||||
| 	case Grid: | 	case Grid: | ||||||
| 		c, err = l.buildGridLayout(e, s) | 		layout, err = l.buildGridLayout(e, s) | ||||||
| 	case HBox: | 	case HBox: | ||||||
| 		c, err = l.buildHBoxLayout(e, s) | 		layout, err = l.buildHBoxLayout(e, s) | ||||||
| 	case MinSize: | 	case MinSize: | ||||||
| 		c, err = l.buildMinSizeLayout(e, s) | 		layout, err = l.buildMinSizeLayout(e, s) | ||||||
| 	case Stack: | 	case Stack: | ||||||
| 		c, err = l.buildStackLayout(e, s) | 		layout, err = l.buildStackLayout(e, s) | ||||||
| 	case VBox: | 	case VBox: | ||||||
| 		c, err = l.buildVBoxLayout(e, s) | 		layout, err = l.buildVBoxLayout(e, s) | ||||||
| 	default: | 	default: | ||||||
| 		err = errors.New("invalid layout") | 		err = errors.New("invalid layout") | ||||||
| 	} | 	} | ||||||
| @@ -46,22 +113,26 @@ func (l Layout) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err err | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	decorator = layout | ||||||
| 	if e.Decorators != nil { | 	if e.Decorators != nil { | ||||||
| 		for _, dec := range e.Decorators { | 		for _, dec := range e.Decorators { | ||||||
| 			switch dec { | 			switch dec { | ||||||
| 			case "Border": | 			case "Border": | ||||||
| 				c = uiwidget.NewWidgetBorder(c) | 				decorator = uiwidget.NewWidgetBorder(decorator) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if e.Hidden { | 	if e.Hidden { | ||||||
| 		c.Hide() | 		decorator.Hide() | ||||||
| 	} | 	} | ||||||
| 	return | 	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 top, left, right, bottom fyne.CanvasObject | ||||||
| 	var center []fyne.CanvasObject | 	var center []fyne.CanvasObject | ||||||
|  |  | ||||||
| @@ -109,7 +180,10 @@ func (l Layout) buildBorderLayout(e *Element, s ScreenHandler) (c *fyne.Containe | |||||||
| 	return | 	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) | 	children := make([]fyne.CanvasObject, 0, len(e.Children)*2) | ||||||
| 	for _, child := range e.Children { | 	for _, child := range e.Children { | ||||||
| 		if child.Label == nil { | 		if child.Label == nil { | ||||||
| @@ -149,7 +223,10 @@ func (l Layout) buildFormLayout(e *Element, s ScreenHandler) (c *fyne.Container, | |||||||
| 	return | 	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)) | 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||||
| 	for _, child := range e.Children { | 	for _, child := range e.Children { | ||||||
| 		var obj fyne.CanvasObject | 		var obj fyne.CanvasObject | ||||||
| @@ -179,7 +256,10 @@ func (l Layout) buildGridLayout(e *Element, s ScreenHandler) (c *fyne.Container, | |||||||
| 	return | 	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)) | 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||||
| 	for _, child := range e.Children { | 	for _, child := range e.Children { | ||||||
| 		var obj fyne.CanvasObject | 		var obj fyne.CanvasObject | ||||||
| @@ -193,7 +273,10 @@ func (l Layout) buildHBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container, | |||||||
| 	return | 	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)) | 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||||
| 	for _, child := range e.Children { | 	for _, child := range e.Children { | ||||||
| 		var obj fyne.CanvasObject | 		var obj fyne.CanvasObject | ||||||
| @@ -216,7 +299,10 @@ func (l Layout) buildMinSizeLayout(e *Element, s ScreenHandler) (c *fyne.Contain | |||||||
| 	return | 	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)) | 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||||
| 	for _, child := range e.Children { | 	for _, child := range e.Children { | ||||||
| 		var obj fyne.CanvasObject | 		var obj fyne.CanvasObject | ||||||
| @@ -230,7 +316,10 @@ func (l Layout) buildStackLayout(e *Element, s ScreenHandler) (c *fyne.Container | |||||||
| 	return | 	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)) | 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||||
| 	for _, child := range e.Children { | 	for _, child := range e.Children { | ||||||
| 		var obj fyne.CanvasObject | 		var obj fyne.CanvasObject | ||||||
|   | |||||||
| @@ -5,15 +5,19 @@ import ( | |||||||
| 	"fyne.io/fyne/v2/widget" | 	"fyne.io/fyne/v2/widget" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // ListItemTemplate is a template for a list item. | ||||||
|  | // It implements the fyne.CanvasObject interface and TemplateScreenHandler | ||||||
| type ListItemTemplate struct { | type ListItemTemplate struct { | ||||||
| 	fyne.CanvasObject | 	fyne.CanvasObject | ||||||
| 	*TemplateScreenHandler | 	*TemplateScreenHandler | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // CreateRenderer implements the fyne.CanvasObject interface | ||||||
| func (i *ListItemTemplate) CreateRenderer() fyne.WidgetRenderer { | func (i *ListItemTemplate) CreateRenderer() fyne.WidgetRenderer { | ||||||
| 	return widget.NewSimpleRenderer(i.CanvasObject) | 	return widget.NewSimpleRenderer(i.CanvasObject) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewListItemTemplate creates a new ListItemTemplate | ||||||
| func NewListItemTemplate( | func NewListItemTemplate( | ||||||
| 	obj fyne.CanvasObject, | 	obj fyne.CanvasObject, | ||||||
| 	screenHandler *TemplateScreenHandler, | 	screenHandler *TemplateScreenHandler, | ||||||
|   | |||||||
| @@ -16,22 +16,39 @@ import ( | |||||||
| 	"gopkg.in/yaml.v2" | 	"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 { | type ScreenHandler interface { | ||||||
| 	RegisterElement(string, fyne.CanvasObject) | 	RegisterElement(string, fyne.CanvasObject, fyne.CanvasObject) | ||||||
|  |  | ||||||
| 	GetLocalizer() *i18n.Localizer | 	GetLocalizer() *i18n.Localizer | ||||||
| 	GetIcon(string) fyne.Resource | 	GetIcon(string) fyne.Resource | ||||||
| 	GetBinding(string) binding.DataItem | 	GetBinding(string) binding.DataItem | ||||||
| 	GetListItemTemplate(string) func() fyne.CanvasObject | 	GetValidator(string) fyne.StringValidator | ||||||
| 	GetListDataItemRenderer(string) func(binding.DataItem, fyne.CanvasObject) | 	GetListItemTemplate(string) ListItemTemplateFn | ||||||
| 	GetListItemRenderer(string) func(int, fyne.CanvasObject) | 	GetListDataItemRenderer(string) ListDataItemRendererFn | ||||||
| 	GetListLength(string) func() int | 	GetListItemRenderer(string) ListItemRendererFn | ||||||
|  | 	GetListLength(string) ListLengthFn | ||||||
|  |  | ||||||
| 	GetOnSelectedHandler(string) func(widget.ListItemID) | 	GetOnListItemSelectedHandler(string) ListItemHandlerFn | ||||||
| 	GetOnUnselectedHandler(string) func(widget.ListItemID) | 	GetOnListItemUnselectedHandler(string) ListItemHandlerFn | ||||||
| 	GetClickedHandler(string) func() | 	GetOnClickedHandler(string) ClickHandlerFn | ||||||
| 	GetCheckChangedHandler(string) func(bool) | 	GetOnCheckChangedHandler(string) CheckHandlerFn | ||||||
| 	GetDateSelectedHandler(string) func(time.Time) | 	GetOnDateSelectedHandler(string) DateSelectedHandlerFn | ||||||
|  | 	GetOnValidationChangedHandler(string) ValidationChangedHandlerFn | ||||||
| } | } | ||||||
|  |  | ||||||
| type Screen struct { | type Screen struct { | ||||||
| @@ -79,7 +96,7 @@ func NewTemplate( | |||||||
| 	handler *TemplateScreenHandler, | 	handler *TemplateScreenHandler, | ||||||
| 	err error, | 	err error, | ||||||
| ) { | ) { | ||||||
| 	handler = NewDummyScreenHandler(localizer) | 	handler = NewTemplateScreenHandler(localizer) | ||||||
| 	scr, err = New(filesystem, name, handler) | 	scr, err = New(filesystem, name, handler) | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -94,21 +111,27 @@ func (s *Screen) Initialize() (obj fyne.CanvasObject, err error) { | |||||||
|  |  | ||||||
| type TemplateScreenHandler struct { | type TemplateScreenHandler struct { | ||||||
| 	localizer   *i18n.Localizer | 	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{ | 	return &TemplateScreenHandler{ | ||||||
| 		localizer:   localizer, | 		localizer:   localizer, | ||||||
| 		elementsMap: make(map[string]fyne.CanvasObject), | 		elementsMap: make(map[string]*UIElement), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (d *TemplateScreenHandler) RegisterElement(name string, element fyne.CanvasObject) { | func (d *TemplateScreenHandler) RegisterElement( | ||||||
| 	d.elementsMap[name] = element | 	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] | 	elem, ok := d.elementsMap[name] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		return nil | 		return nil | ||||||
| @@ -132,38 +155,46 @@ func (*TemplateScreenHandler) GetBinding(string) binding.DataItem { | |||||||
| 	return nil | 	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 } | 	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) {} | 	return func(binding.DataItem, fyne.CanvasObject) {} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*TemplateScreenHandler) GetListItemRenderer(string) func(int, fyne.CanvasObject) { | func (*TemplateScreenHandler) GetListItemRenderer(string) ListItemRendererFn { | ||||||
| 	return func(int, fyne.CanvasObject) {} | 	return func(int, fyne.CanvasObject) {} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*TemplateScreenHandler) GetListLength(string) func() int { | func (*TemplateScreenHandler) GetListLength(string) ListLengthFn { | ||||||
| 	return func() int { return 0 } | 	return func() int { return 0 } | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*TemplateScreenHandler) GetOnSelectedHandler(string) func(widget.ListItemID) { | func (*TemplateScreenHandler) GetOnListItemSelectedHandler(string) ListItemHandlerFn { | ||||||
| 	return func(widget.ListItemID) {} | 	return func(widget.ListItemID) {} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*TemplateScreenHandler) GetOnUnselectedHandler(string) func(widget.ListItemID) { | func (*TemplateScreenHandler) GetOnListItemUnselectedHandler(string) ListItemHandlerFn { | ||||||
| 	return func(widget.ListItemID) {} | 	return func(widget.ListItemID) {} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*TemplateScreenHandler) GetClickedHandler(string) func() { | func (*TemplateScreenHandler) GetOnClickedHandler(string) ClickHandlerFn { | ||||||
| 	return func() {} | 	return func() {} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*TemplateScreenHandler) GetCheckChangedHandler(string) func(bool) { | func (*TemplateScreenHandler) GetOnCheckChangedHandler(string) CheckHandlerFn { | ||||||
| 	return func(bool) {} | 	return func(bool) {} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*TemplateScreenHandler) GetDateSelectedHandler(string) func(time.Time) { | func (*TemplateScreenHandler) GetOnDateSelectedHandler(string) DateSelectedHandlerFn { | ||||||
| 	return func(time.Time) {} | 	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" | 	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 | type Widget string | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	Button      Widget = "Button" | 	// Button Widget | ||||||
| 	Calendar    Widget = "Calendar" | 	// | ||||||
| 	Check       Widget = "Check" | 	// Available yaml options: | ||||||
| 	H1          Widget = "H1" | 	//	- text: The text for the button | ||||||
| 	H2          Widget = "H2" | 	//	- localized: If the text represents a localization key | ||||||
| 	H3          Widget = "H3" | 	//	- icon: The icon for the button | ||||||
| 	H4          Widget = "H4" | 	//	- disabled: Wether the button is disabled or not | ||||||
| 	H5          Widget = "H5" | 	//	- options: Additional options for the button | ||||||
| 	H6          Widget = "H6" | 	//		- alignment: The alignment of the button | ||||||
| 	Label       Widget = "Label" | 	//		- iconPlacement: The icon placement of the button | ||||||
| 	List        Widget = "List" | 	//		- importance: The importance of the button | ||||||
| 	Separator   Widget = "Separator" | 	//	- onclicked: The function to call when the button is clicked | ||||||
| 	Spacer      Widget = "Spacer" | 	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" | 	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) | 	e.localize(s) | ||||||
|  |  | ||||||
| 	switch w { | 	switch w { | ||||||
| 	case Button: | 	case Button: | ||||||
| 		c, err = w.buildButtonWidget(e, s) | 		widget, err = w.buildButtonWidget(e, s) | ||||||
| 	case Calendar: | 	case Calendar: | ||||||
| 		c, err = w.buildCalendarWidget(e, s) | 		widget, err = w.buildCalendarWidget(e, s) | ||||||
| 	case Check: | 	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: | 	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: | 	case Label: | ||||||
| 		c, err = w.buildLabelWidget(e, s) | 		widget, err = w.buildLabelWidget(e, s) | ||||||
| 	case List: | 	case List: | ||||||
| 		c, err = w.buildListWidget(e, s) | 		widget, err = w.buildListWidget(e, s) | ||||||
| 	case Separator: | 	case Separator: | ||||||
| 		c, err = w.buildSeparatorWidget(e, s) | 		widget, err = w.buildSeparatorWidget(e, s) | ||||||
| 	case Spacer: | 	case Spacer: | ||||||
| 		c, err = w.buildSpacerWidget(e, s) | 		widget, err = w.buildSpacerWidget(e, s) | ||||||
| 	case UpDownLabel: | 	case UpDownLabel: | ||||||
| 		c, err = w.buildUpDownLabelWidget(e, s) | 		widget, err = w.buildUpDownLabelWidget(e, s) | ||||||
| 	default: | 	default: | ||||||
| 		err = errors.New("invalid widget") | 		err = errors.New("invalid widget") | ||||||
| 	} | 	} | ||||||
| @@ -61,28 +230,32 @@ func (w Widget) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err err | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	decorator = widget | ||||||
| 	if e.Decorators != nil { | 	if e.Decorators != nil { | ||||||
| 		for _, dec := range e.Decorators { | 		for _, dec := range e.Decorators { | ||||||
| 			switch dec { | 			switch dec { | ||||||
| 			case "Border": | 			case "Border": | ||||||
| 				c = uiwidget.NewWidgetBorder(c) | 				decorator = uiwidget.NewWidgetBorder(decorator) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if e.Hidden { | 	if e.Hidden { | ||||||
| 		c.Hide() | 		decorator.Hide() | ||||||
| 	} | 	} | ||||||
| 	return | 	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 | 	var btn *widget.Button | ||||||
| 	if e.Icon != "" { | 	if e.Icon != "" { | ||||||
| 		btn = widget.NewButtonWithIcon( | 		btn = widget.NewButtonWithIcon( | ||||||
| 			e.Text, s.GetIcon(e.Icon), s.GetClickedHandler(e.OnClicked)) | 			e.Text, s.GetIcon(e.Icon), s.GetOnClickedHandler(e.OnClicked)) | ||||||
| 	} else { | 	} 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 { | 	for opt, val := range e.Options { | ||||||
| @@ -103,7 +276,10 @@ func (w Widget) buildButtonWidget(e *Element, s ScreenHandler) (c fyne.CanvasObj | |||||||
| 	return | 	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() | 	t := time.Now() | ||||||
| 	if e.Time != nil { | 	if e.Time != nil { | ||||||
| 		timeFormat := time.DateOnly | 		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 | 	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 | 	var chk *widget.Check | ||||||
| 	if e.Binding != "" { | 	if e.Binding != "" { | ||||||
| 		chk = widget.NewCheckWithData( | 		chk = widget.NewCheckWithData( | ||||||
| 			e.Text, s.GetBinding(e.Binding).(binding.Bool)) | 			e.Text, s.GetBinding(e.Binding).(binding.Bool)) | ||||||
| 	} else { | 	} else { | ||||||
| 		chk = widget.NewCheck( | 		chk = widget.NewCheck( | ||||||
| 			e.Text, s.GetCheckChangedHandler(e.OnChanged)) | 			e.Text, s.GetOnCheckChangedHandler(e.OnChanged)) | ||||||
| 		chk.SetChecked(e.Checked) | 		chk.SetChecked(e.Checked) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -138,7 +317,40 @@ func (w Widget) buildCheckWidget(e *Element, s ScreenHandler) (c fyne.CanvasObje | |||||||
| 	return | 	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 | 	var rt *widget.RichText | ||||||
|  |  | ||||||
| 	level := 1 | 	level := 1 | ||||||
| @@ -174,7 +386,18 @@ func (w Widget) buildHeaderLabelWidget(e *Element, s ScreenHandler) (c fyne.Canv | |||||||
| 	return | 	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 | 	var lbl *widget.Label | ||||||
|  |  | ||||||
| 	if e.Binding != "" { | 	if e.Binding != "" { | ||||||
| @@ -201,7 +424,10 @@ func (w Widget) buildLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObje | |||||||
| 	return | 	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 | 	var lst *widget.List | ||||||
|  |  | ||||||
| 	if e.Binding != "" { | 	if e.Binding != "" { | ||||||
| @@ -217,22 +443,28 @@ func (w Widget) buildListWidget(e *Element, s ScreenHandler) (c fyne.CanvasObjec | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if e.OnSelected != "" { | 	if e.OnSelected != "" { | ||||||
| 		lst.OnSelected = s.GetOnSelectedHandler(e.OnSelected) | 		lst.OnSelected = s.GetOnListItemSelectedHandler(e.OnSelected) | ||||||
| 	} | 	} | ||||||
| 	if e.OnUnselected != "" { | 	if e.OnUnselected != "" { | ||||||
| 		lst.OnUnselected = s.GetOnUnselectedHandler(e.OnUnselected) | 		lst.OnUnselected = s.GetOnListItemUnselectedHandler(e.OnUnselected) | ||||||
| 	} | 	} | ||||||
| 	c = lst | 	c = lst | ||||||
| 	return | 	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() | 	sep := widget.NewSeparator() | ||||||
| 	c = sep | 	c = sep | ||||||
| 	return | 	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{ | 	spc := &layout.Spacer{ | ||||||
| 		FixHorizontal: e.FixHorizontal, | 		FixHorizontal: e.FixHorizontal, | ||||||
| 		FixVertical:   e.FixVertical, | 		FixVertical:   e.FixVertical, | ||||||
| @@ -241,11 +473,14 @@ func (w Widget) buildSpacerWidget(e *Element, _ ScreenHandler) (c fyne.CanvasObj | |||||||
| 	return | 	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( | 	btn := uiwidget.NewUpDownLabelWithData( | ||||||
| 		s.GetBinding(e.Binding).(binding.String), | 		s.GetBinding(e.Binding).(binding.String), | ||||||
| 		s.GetClickedHandler(e.OnUpClicked), | 		s.GetOnClickedHandler(e.OnUpClicked), | ||||||
| 		s.GetClickedHandler(e.OnDownClicked)) | 		s.GetOnClickedHandler(e.OnDownClicked)) | ||||||
| 	c = btn | 	c = btn | ||||||
| 	return | 	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" | 	"fyne.io/fyne/v2/container" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // TODO: Implement screen reading from file! | ||||||
|  |  | ||||||
| type TabbedView struct { | type TabbedView struct { | ||||||
| 	*BaseView | 	*BaseView | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,14 +2,26 @@ package uilayout | |||||||
|  |  | ||||||
| import "fyne.io/fyne/v2" | 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 { | type MinSize struct { | ||||||
| 	minSize fyne.Size | 	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 { | func NewMinSizeLayout(minSize fyne.Size) *MinSize { | ||||||
| 	return &MinSize{minSize: 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 { | func (l *MinSize) MinSize(objects []fyne.CanvasObject) fyne.Size { | ||||||
| 	size := l.minSize | 	size := l.minSize | ||||||
| 	for _, o := range objects { | 	for _, o := range objects { | ||||||
| @@ -24,6 +36,7 @@ func (l *MinSize) MinSize(objects []fyne.CanvasObject) fyne.Size { | |||||||
| 	return size | 	return size | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Layout implements the Layout interface. | ||||||
| func (l *MinSize) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) { | func (l *MinSize) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) { | ||||||
| 	pos := fyne.NewPos(0, 0) | 	pos := fyne.NewPos(0, 0) | ||||||
| 	for _, o := range objects { | 	for _, o := range objects { | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ import ( | |||||||
| 	"fyne.io/fyne/v2/widget" | 	"fyne.io/fyne/v2/widget" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // LabelOpts defines the options for a label. | ||||||
| type LabelOpts interface { | type LabelOpts interface { | ||||||
| 	ApplyTo(*widget.Label) | 	ApplyTo(*widget.Label) | ||||||
| } | } | ||||||
| @@ -19,10 +20,12 @@ type allignmentOpt struct { | |||||||
| 	Alignment fyne.TextAlign | 	Alignment fyne.TextAlign | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // AlignmentOpt returns a LabelOpts with the specified alignment. | ||||||
| func AlignmentOpt(alignment fyne.TextAlign) LabelOpts { | func AlignmentOpt(alignment fyne.TextAlign) LabelOpts { | ||||||
| 	return &allignmentOpt{alignment} | 	return &allignmentOpt{alignment} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ApplyTo sets the alignment of a label to the specified alignment. | ||||||
| func (a *allignmentOpt) ApplyTo(lbl *widget.Label) { | func (a *allignmentOpt) ApplyTo(lbl *widget.Label) { | ||||||
| 	lbl.Alignment = a.Alignment | 	lbl.Alignment = a.Alignment | ||||||
| } | } | ||||||
| @@ -31,10 +34,12 @@ type wrappingOpt struct { | |||||||
| 	Wrapping fyne.TextWrap | 	Wrapping fyne.TextWrap | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // WrappingOpt creates a LabelOpts with the specified text wrapping option. | ||||||
| func WrappingOpt(wrapping fyne.TextWrap) LabelOpts { | func WrappingOpt(wrapping fyne.TextWrap) LabelOpts { | ||||||
| 	return &wrappingOpt{wrapping} | 	return &wrappingOpt{wrapping} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ApplyTo applies the wrapping option to the label. | ||||||
| func (w *wrappingOpt) ApplyTo(lbl *widget.Label) { | func (w *wrappingOpt) ApplyTo(lbl *widget.Label) { | ||||||
| 	lbl.Wrapping = w.Wrapping | 	lbl.Wrapping = w.Wrapping | ||||||
| } | } | ||||||
| @@ -43,10 +48,12 @@ type textStyleOpt struct { | |||||||
| 	Style fyne.TextStyle | 	Style fyne.TextStyle | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TextStyleOpt returns the label options for the given text style. | ||||||
| func TextStyleOpt(style fyne.TextStyle) LabelOpts { | func TextStyleOpt(style fyne.TextStyle) LabelOpts { | ||||||
| 	return &textStyleOpt{style} | 	return &textStyleOpt{style} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ApplyTo applies the text style option to the label. | ||||||
| func (t *textStyleOpt) ApplyTo(lbl *widget.Label) { | func (t *textStyleOpt) ApplyTo(lbl *widget.Label) { | ||||||
| 	lbl.TextStyle = t.Style | 	lbl.TextStyle = t.Style | ||||||
| } | } | ||||||
| @@ -55,10 +62,12 @@ type truncationOpt struct { | |||||||
| 	Truncation fyne.TextTruncation | 	Truncation fyne.TextTruncation | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TruncationOpt returns the label options for the given text truncation option. | ||||||
| func TruncationOpt(truncation fyne.TextTruncation) LabelOpts { | func TruncationOpt(truncation fyne.TextTruncation) LabelOpts { | ||||||
| 	return &truncationOpt{truncation} | 	return &truncationOpt{truncation} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ApplyTo applies the text truncation option to the label. | ||||||
| func (t *truncationOpt) ApplyTo(lbl *widget.Label) { | func (t *truncationOpt) ApplyTo(lbl *widget.Label) { | ||||||
| 	lbl.Truncation = t.Truncation | 	lbl.Truncation = t.Truncation | ||||||
| } | } | ||||||
| @@ -67,14 +76,23 @@ type importanceOpt struct { | |||||||
| 	Importance widget.Importance | 	Importance widget.Importance | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ImportanceOpt returns the label options for the given text importance option. | ||||||
| func ImportanceOpt(importance widget.Importance) LabelOpts { | func ImportanceOpt(importance widget.Importance) LabelOpts { | ||||||
| 	return &importanceOpt{importance} | 	return &importanceOpt{importance} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ApplyTo applies the text importance option to the label. | ||||||
| func (i *importanceOpt) ApplyTo(lbl *widget.Label) { | func (i *importanceOpt) ApplyTo(lbl *widget.Label) { | ||||||
| 	lbl.Importance = i.Importance | 	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 { | func NewLabel(text string, opts ...LabelOpts) *widget.Label { | ||||||
| 	lbl := widget.NewLabel(text) | 	lbl := widget.NewLabel(text) | ||||||
| 	for _, opt := range opts { | 	for _, opt := range opts { | ||||||
| @@ -83,6 +101,13 @@ func NewLabel(text string, opts ...LabelOpts) *widget.Label { | |||||||
| 	return lbl | 	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 { | func NewLabelWithData(data binding.String, opts ...LabelOpts) *widget.Label { | ||||||
| 	lbl := widget.NewLabelWithData(data) | 	lbl := widget.NewLabelWithData(data) | ||||||
| 	for _, opt := range opts { | 	for _, opt := range opts { | ||||||
| @@ -91,6 +116,14 @@ func NewLabelWithData(data binding.String, opts ...LabelOpts) *widget.Label { | |||||||
| 	return lbl | 	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( | func NewUpDownLabelWithData( | ||||||
| 	data binding.String, | 	data binding.String, | ||||||
| 	upHandler func(), | 	upHandler func(), | ||||||
| @@ -115,11 +148,25 @@ func NewUpDownLabelWithData( | |||||||
| 	return c1 | 	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 { | func NewH(level int, text string) *widget.RichText { | ||||||
| 	return widget.NewRichTextFromMarkdown( | 	return widget.NewRichTextFromMarkdown( | ||||||
| 		fmt.Sprintf("%s %s", strings.Repeat("#", level), text)) | 		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 { | func NewHWithData(level int, data binding.String) *widget.RichText { | ||||||
| 	txt, _ := data.Get() | 	txt, _ := data.Get() | ||||||
| 	w := NewH(level, txt) | 	w := NewH(level, txt) | ||||||
| @@ -130,50 +177,62 @@ func NewHWithData(level int, data binding.String) *widget.RichText { | |||||||
| 	return w | 	return w | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH1 creates a new RichText widget with header level 1. | ||||||
| func NewH1(text string) *widget.RichText { | func NewH1(text string) *widget.RichText { | ||||||
| 	return NewH(1, text) | 	return NewH(1, text) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH1WithData creates a new RichText widget with header level 1. | ||||||
| func NewH1WithData(data binding.String) *widget.RichText { | func NewH1WithData(data binding.String) *widget.RichText { | ||||||
| 	return NewHWithData(1, data) | 	return NewHWithData(1, data) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH2 creates a new RichText widget with header level 2. | ||||||
| func NewH2(text string) *widget.RichText { | func NewH2(text string) *widget.RichText { | ||||||
| 	return NewH(2, text) | 	return NewH(2, text) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH2WithData creates a new RichText widget with header level 2. | ||||||
| func NewH2WithData(data binding.String) *widget.RichText { | func NewH2WithData(data binding.String) *widget.RichText { | ||||||
| 	return NewHWithData(2, data) | 	return NewHWithData(2, data) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH3 creates a new RichText widget with header level 3. | ||||||
| func NewH3(text string) *widget.RichText { | func NewH3(text string) *widget.RichText { | ||||||
| 	return NewH(3, text) | 	return NewH(3, text) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH3WithData creates a new RichText widget with header level 3. | ||||||
| func NewH3WithData(data binding.String) *widget.RichText { | func NewH3WithData(data binding.String) *widget.RichText { | ||||||
| 	return NewHWithData(3, data) | 	return NewHWithData(3, data) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH4 creates a new RichText widget with header level 4. | ||||||
| func NewH4(text string) *widget.RichText { | func NewH4(text string) *widget.RichText { | ||||||
| 	return NewH(4, text) | 	return NewH(4, text) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH4WithData creates a new RichText widget with header level 4. | ||||||
| func NewH4WithData(data binding.String) *widget.RichText { | func NewH4WithData(data binding.String) *widget.RichText { | ||||||
| 	return NewHWithData(4, data) | 	return NewHWithData(4, data) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH5 creates a new RichText widget with header level 5. | ||||||
| func NewH5(text string) *widget.RichText { | func NewH5(text string) *widget.RichText { | ||||||
| 	return NewH(5, text) | 	return NewH(5, text) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH5WithData creates a new RichText widget with header level 5. | ||||||
| func NewH5WithData(data binding.String) *widget.RichText { | func NewH5WithData(data binding.String) *widget.RichText { | ||||||
| 	return NewHWithData(5, data) | 	return NewHWithData(5, data) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH6 creates a new RichText widget with header level 6. | ||||||
| func NewH6(text string) *widget.RichText { | func NewH6(text string) *widget.RichText { | ||||||
| 	return NewH(6, text) | 	return NewH(6, text) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewH6WithData creates a new RichText widget with header level 6. | ||||||
| func NewH6WithData(data binding.String) *widget.RichText { | func NewH6WithData(data binding.String) *widget.RichText { | ||||||
| 	return NewHWithData(6, data) | 	return NewHWithData(6, data) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,6 +9,9 @@ import ( | |||||||
| 	"fyne.io/fyne/v2/theme" | 	"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 { | func NewWidgetBorder(widget fyne.CanvasObject) fyne.CanvasObject { | ||||||
| 	b := canvas.NewRectangle(color.Transparent) | 	b := canvas.NewRectangle(color.Transparent) | ||||||
| 	b.StrokeColor = theme.InputBorderColor() | 	b.StrokeColor = theme.InputBorderColor() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Maarten Heremans
					Maarten Heremans