Implement defining screens in yaml
This commit is contained in:
		
							
								
								
									
										63
									
								
								baseview.go
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								baseview.go
									
									
									
									
									
								
							| @@ -1,12 +1,10 @@ | ||||
| package ui | ||||
|  | ||||
| import ( | ||||
| 	"time" | ||||
| 	"embed" | ||||
|  | ||||
| 	"bitbucket.org/hevanto/ui/screen" | ||||
| 	"fyne.io/fyne/v2" | ||||
| 	"fyne.io/fyne/v2/data/binding" | ||||
| 	"fyne.io/fyne/v2/widget" | ||||
| 	"github.com/google/uuid" | ||||
| 	"github.com/nicksnyder/go-i18n/v2/i18n" | ||||
| ) | ||||
| @@ -26,35 +24,8 @@ type BaseView struct { | ||||
| 	// Root CanvasObject of the view | ||||
| 	CanvasObject fyne.CanvasObject | ||||
|  | ||||
| 	// The screen definition | ||||
| 	screenDefinition *screen.Screen | ||||
|  | ||||
| 	// ----------- ScreenHandler -------------// | ||||
|  | ||||
| 	// Localizer to translate screen labels | ||||
| 	localizer *i18n.Localizer | ||||
|  | ||||
| 	// Map of screen elements that got an id assigned | ||||
| 	screenElementMap map[string]fyne.CanvasObject | ||||
|  | ||||
| 	// Map of list item template | ||||
| 	listItemTemplates map[string]func() fyne.CanvasObject | ||||
|  | ||||
| 	// Map of list data item renderers | ||||
| 	listDataItemRenderers map[string]func(binding.DataItem, fyne.CanvasObject) | ||||
|  | ||||
| 	// Map of list item renderers | ||||
| 	listItemRenderers map[string]func(int, fyne.CanvasObject) | ||||
|  | ||||
| 	// Map of list length functions | ||||
| 	listLenghts map[string]func() int | ||||
|  | ||||
| 	// Handlers | ||||
| 	onSelectedHandlers     map[string]func(widget.ListItemID) | ||||
| 	onUnselectedHandlers   map[string]func(widget.ListItemID) | ||||
| 	onClickedHandlers      map[string]func() | ||||
| 	onCheckChangedHandlers map[string]func(bool) | ||||
| 	onDateSelectedHandlers map[string]func(time.Time) | ||||
| 	*ScreenHandler | ||||
| } | ||||
|  | ||||
| // NewBaseView creates a new baseview | ||||
| @@ -80,6 +51,28 @@ func NewBaseView( | ||||
| 	return v | ||||
| } | ||||
|  | ||||
| func NewBaseViewWithScreen( | ||||
| 	concreteView View, | ||||
| 	controller Controller, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) *BaseView { | ||||
| 	v := NewBaseView(concreteView, controller) | ||||
|  | ||||
| 	var err error | ||||
| 	v.ScreenHandler, err = NewScreenHandler( | ||||
| 		filesystem, | ||||
| 		screenName, | ||||
| 		controller, | ||||
| 		localizer) | ||||
| 	if err != nil { | ||||
| 		LogWindowError(v, LoadScreen, err) | ||||
| 		return nil | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
|  | ||||
| // ID returns tie id of the view | ||||
| func (v BaseView) ID() string { | ||||
| 	return v.id | ||||
| @@ -106,8 +99,8 @@ func (v *BaseView) Initialize() fyne.CanvasObject { | ||||
| 	if err := v.Ctrl.Initialize(); err != nil { | ||||
| 		LogWindowError(v, Initialize, err) | ||||
| 	} | ||||
| 	if v.screenDefinition != nil { | ||||
| 		obj, err := v.screenDefinition.Initialize() | ||||
| 	if v.ScreenHandler != nil && v.ScreenDefinition() != nil { | ||||
| 		obj, err := v.ScreenDefinition().Initialize() | ||||
| 		if err != nil { | ||||
| 			LogWindowError(v, Initialize, err) | ||||
| 			return nil | ||||
| @@ -133,3 +126,7 @@ func (v *BaseView) OnShow() { | ||||
| func (v *BaseView) OnHide() { | ||||
| 	LogWindowEvent(v, OnHide) | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetBinding(bindingName string) binding.DataItem { | ||||
| 	return v.Ctrl.GetBinding(bindingName) | ||||
| } | ||||
|   | ||||
| @@ -1,177 +0,0 @@ | ||||
| package ui | ||||
|  | ||||
| import ( | ||||
| 	"embed" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"bitbucket.org/hevanto/ui/screen" | ||||
| 	"fyne.io/fyne/v2" | ||||
| 	"fyne.io/fyne/v2/data/binding" | ||||
| 	"fyne.io/fyne/v2/theme" | ||||
| 	"fyne.io/fyne/v2/widget" | ||||
| 	"github.com/nicksnyder/go-i18n/v2/i18n" | ||||
| ) | ||||
|  | ||||
| func NewBaseViewWithScreen( | ||||
| 	concreteView View, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| 	controller Controller, | ||||
| ) *BaseView { | ||||
| 	v := NewBaseView(concreteView, controller) | ||||
| 	def, err := screen.New(filesystem, screenName, v) | ||||
| 	if err != nil { | ||||
| 		LogWindowError(v, LoadScreen, err) | ||||
| 		return nil | ||||
| 	} | ||||
| 	v.screenDefinition = def | ||||
| 	v.localizer = localizer | ||||
| 	v.screenElementMap = make(map[string]fyne.CanvasObject) | ||||
| 	v.listItemTemplates = make(map[string]func() fyne.CanvasObject) | ||||
| 	v.listDataItemRenderers = make(map[string]func(binding.DataItem, fyne.CanvasObject)) | ||||
| 	v.listItemRenderers = make(map[string]func(int, fyne.CanvasObject)) | ||||
| 	v.listLenghts = make(map[string]func() int) | ||||
| 	v.onSelectedHandlers = make(map[string]func(widget.ListItemID)) | ||||
| 	v.onUnselectedHandlers = make(map[string]func(widget.ListItemID)) | ||||
| 	v.onClickedHandlers = make(map[string]func()) | ||||
| 	v.onCheckChangedHandlers = make(map[string]func(bool)) | ||||
| 	v.onDateSelectedHandlers = make(map[string]func(time.Time)) | ||||
| 	return v | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterElement(id string, elem fyne.CanvasObject) { | ||||
| 	v.screenElementMap[id] = elem | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterListItemTemplate(name string, fn func() fyne.CanvasObject) { | ||||
| 	v.listItemTemplates[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterListDataItemRenderer(name string, fn func(binding.DataItem, fyne.CanvasObject)) { | ||||
| 	v.listDataItemRenderers[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterListItemRenderer(name string, fn func(int, fyne.CanvasObject)) { | ||||
| 	v.listItemRenderers[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterListLength(name string, fn func() int) { | ||||
| 	v.listLenghts[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterOnSelectedHandler(name string, fn func(widget.ListItemID)) { | ||||
| 	v.onSelectedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterOnUnselectedHandler(name string, fn func(widget.ListItemID)) { | ||||
| 	v.onUnselectedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterOnClickHandler(name string, fn func()) { | ||||
| 	v.onClickedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterOnCheckChangedHandler(name string, fn func(bool)) { | ||||
| 	v.onCheckChangedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) RegisterOnDateSelectedHandler(name string, fn func(time.Time)) { | ||||
| 	v.onDateSelectedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetElement(id string) fyne.CanvasObject { | ||||
| 	if elem, ok := v.screenElementMap[id]; ok { | ||||
| 		return elem | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetLocalizer() *i18n.Localizer { | ||||
| 	return v.localizer | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetIcon(iconName string) fyne.Resource { | ||||
| 	if strings.HasPrefix(iconName, "theme.") { | ||||
| 		iconName := strings.SplitN(iconName, ".", 2)[1] | ||||
| 		return theme.DefaultTheme().Icon(fyne.ThemeIconName(iconName)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetBinding(bindingName string) binding.DataItem { | ||||
| 	return v.Ctrl.GetBinding(bindingName) | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetListItemTemplate(name string) func() fyne.CanvasObject { | ||||
| 	fn, ok := v.listItemTemplates[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetListDataItemRenderer(name string) func(binding.DataItem, fyne.CanvasObject) { | ||||
| 	fn, ok := v.listDataItemRenderers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetListItemRenderer(name string) func(int, fyne.CanvasObject) { | ||||
| 	fn, ok := v.listItemRenderers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetListLength(name string) func() int { | ||||
| 	fn, ok := v.listLenghts[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetOnSelectedHandler(name string) func(widget.ListItemID) { | ||||
| 	fn, ok := v.onSelectedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetOnUnselectedHandler(name string) func(widget.ListItemID) { | ||||
| 	fn, ok := v.onUnselectedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetClickedHandler(name string) func() { | ||||
| 	fn, ok := v.onClickedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetCheckChangedHandler(name string) func(bool) { | ||||
| 	fn, ok := v.onCheckChangedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| func (v *BaseView) GetDateSelectedHandler(name string) func(time.Time) { | ||||
| 	fn, ok := v.onDateSelectedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
| @@ -1,15 +1,25 @@ | ||||
| package ui | ||||
|  | ||||
| import "fyne.io/fyne/v2/data/binding" | ||||
| import ( | ||||
| 	"fyne.io/fyne/v2" | ||||
| 	"fyne.io/fyne/v2/data/binding" | ||||
| ) | ||||
|  | ||||
| type ScreenController interface { | ||||
| 	GetBinding(string) binding.DataItem | ||||
| 	GetValidator(string) fyne.StringValidator | ||||
| } | ||||
|  | ||||
| type Controller interface { | ||||
| 	ScreenController | ||||
|  | ||||
| 	Initialize() error | ||||
| 	RefreshData() error | ||||
|  | ||||
| 	GetBinding(string) binding.DataItem | ||||
| } | ||||
|  | ||||
| type DialogController interface { | ||||
| 	ScreenController | ||||
|  | ||||
| 	Initialize(data binding.DataItem) error | ||||
| 	RefreshData() error | ||||
| } | ||||
|   | ||||
							
								
								
									
										204
									
								
								dialog.go
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								dialog.go
									
									
									
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| package ui | ||||
|  | ||||
| import ( | ||||
| 	"embed" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"fyne.io/fyne/v2" | ||||
| @@ -8,13 +9,22 @@ import ( | ||||
| 	"fyne.io/fyne/v2/dialog" | ||||
| 	"fyne.io/fyne/v2/widget" | ||||
| 	"github.com/google/uuid" | ||||
| 	"github.com/nicksnyder/go-i18n/v2/i18n" | ||||
| ) | ||||
|  | ||||
| type DialogName string | ||||
| type DialogKind string | ||||
|  | ||||
| type OnConfirmFn func(bool, error, ...interface{}) | ||||
| type NewDialogFn func(DialogName, DialogKind, fyne.Window, OnConfirmFn, ...binding.DataItem) Dialog | ||||
| type NewDialogFn func( | ||||
| 	DialogName, | ||||
| 	DialogKind, | ||||
| 	fyne.Window, | ||||
| 	OnConfirmFn, | ||||
| 	binding.DataItem, | ||||
| 	*embed.FS, | ||||
| 	string, | ||||
| 	*i18n.Localizer) Dialog | ||||
|  | ||||
| const ( | ||||
| 	DlgGeneric DialogKind = "Generic" | ||||
| @@ -47,12 +57,16 @@ type BaseDialog struct { | ||||
| 	CanvasObj      fyne.CanvasObject | ||||
| 	Data           binding.DataItem | ||||
| 	focusItem      fyne.Focusable | ||||
|  | ||||
| 	Ctrl DialogController | ||||
| 	*ScreenHandler | ||||
| } | ||||
|  | ||||
| func NewBaseDialog( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| ) *BaseDialog { | ||||
| @@ -63,13 +77,40 @@ func NewBaseDialog( | ||||
| 		dlgKind:        kind, | ||||
| 		window:         parent, | ||||
| 		onConfirm:      confirm, | ||||
| 		Ctrl:           controller, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewBaseDialogWithScreen( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) *BaseDialog { | ||||
| 	d := NewBaseDialog( | ||||
| 		concreteDialog, name, kind, controller, | ||||
| 		parent, confirm) | ||||
|  | ||||
| 	var err error | ||||
| 	d.ScreenHandler, err = NewScreenHandler( | ||||
| 		filesystem, screenName, controller, localizer) | ||||
| 	if err != nil { | ||||
| 		LogWindowError(d, LoadScreen, err) | ||||
| 		return nil | ||||
| 	} | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| func NewBaseDialogWithData( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	data binding.DataItem, | ||||
| @@ -82,9 +123,36 @@ func NewBaseDialogWithData( | ||||
| 		window:         parent, | ||||
| 		onConfirm:      confirm, | ||||
| 		Data:           data, | ||||
| 		Ctrl:           controller, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewBaseDialogWithDataAndScreen( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	data binding.DataItem, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) *BaseDialog { | ||||
| 	d := NewBaseDialogWithData( | ||||
| 		concreteDialog, name, kind, controller, | ||||
| 		parent, confirm, data) | ||||
|  | ||||
| 	var err error | ||||
| 	d.ScreenHandler, err = NewScreenHandler( | ||||
| 		filesystem, screenName, controller, localizer) | ||||
| 	if err != nil { | ||||
| 		LogWindowError(d, LoadScreen, err) | ||||
| 		return nil | ||||
| 	} | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| func (d BaseDialog) Window() fyne.Window { | ||||
| 	return d.window | ||||
| } | ||||
| @@ -114,6 +182,7 @@ func (d BaseDialog) OnConfirmFn() OnConfirmFn { | ||||
| } | ||||
|  | ||||
| func (d *BaseDialog) Show(parent ...fyne.Window) { | ||||
|  | ||||
| 	d.concreteDialog.OnShow() | ||||
| 	d.dlg = dialog.NewCustomConfirm( | ||||
| 		d.concreteDialog.Title(), | ||||
| @@ -146,6 +215,17 @@ func (d BaseDialog) Title() string { | ||||
| } | ||||
|  | ||||
| func (d *BaseDialog) Initialize() fyne.CanvasObject { | ||||
| 	if err := d.Ctrl.Initialize(d.Data); err != nil { | ||||
| 		LogWindowError(d, Initialize, err) | ||||
| 	} | ||||
| 	if d.ScreenHandler != nil && d.ScreenDefinition() != nil { | ||||
| 		obj, err := d.ScreenDefinition().Initialize() | ||||
| 		if err != nil { | ||||
| 			LogWindowError(d, Initialize, err) | ||||
| 			return nil | ||||
| 		} | ||||
| 		d.CanvasObj = obj | ||||
| 	} | ||||
| 	return d.CanvasObj | ||||
| } | ||||
|  | ||||
| @@ -184,35 +264,80 @@ func NewFormDialog( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	itemsFn FormDialogItemsFn, | ||||
| ) *FormDialog { | ||||
| 	return &FormDialog{ | ||||
| 		BaseDialog:   NewBaseDialog(concreteDialog, name, kind, parent, confirm), | ||||
| 		BaseDialog: NewBaseDialog( | ||||
| 			concreteDialog, name, kind, controller, parent, confirm), | ||||
| 		itemsFn:      itemsFn, | ||||
| 		confirmLabel: "OK", | ||||
| 		dismissLabel: "Cancel", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewFormDialogWithScreen( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) *FormDialog { | ||||
| 	return &FormDialog{ | ||||
| 		BaseDialog: NewBaseDialogWithScreen( | ||||
| 			concreteDialog, name, kind, controller, parent, confirm, | ||||
| 			filesystem, screenName, localizer), | ||||
| 		confirmLabel: "OK", | ||||
| 		dismissLabel: "Cancel", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewformDialogWithData( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	itemsFn FormDialogItemsFn, | ||||
| 	data binding.DataItem, | ||||
| ) *FormDialog { | ||||
| 	return &FormDialog{ | ||||
| 		BaseDialog:   NewBaseDialogWithData(concreteDialog, name, kind, parent, confirm, data), | ||||
| 		BaseDialog: NewBaseDialogWithData( | ||||
| 			concreteDialog, name, kind, controller, parent, confirm, data), | ||||
| 		itemsFn:      itemsFn, | ||||
| 		confirmLabel: "OK", | ||||
| 		dismissLabel: "Cancel", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewFormDialogWithDataAndScreen( | ||||
| 	concreteDialog Dialog, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	controller DialogController, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	data binding.DataItem, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) *FormDialog { | ||||
| 	return &FormDialog{ | ||||
| 		BaseDialog: NewBaseDialogWithDataAndScreen( | ||||
| 			concreteDialog, name, kind, controller, parent, confirm, data, | ||||
| 			filesystem, screenName, localizer), | ||||
| 		confirmLabel: "OK", | ||||
| 		dismissLabel: "Cancel", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d *FormDialog) SetButtonLabels( | ||||
| 	confirm string, | ||||
| 	dismiss string, | ||||
| @@ -221,7 +346,25 @@ func (d *FormDialog) SetButtonLabels( | ||||
| 	d.dismissLabel = dismiss | ||||
| } | ||||
|  | ||||
| func (d *FormDialog) Initialize() fyne.CanvasObject { | ||||
| 	if d.itemsFn == nil { | ||||
| 		form := d.BaseDialog.Initialize().(*fyne.Container) | ||||
| 		d.itemsFn = func() []*widget.FormItem { | ||||
| 			res := make([]*widget.FormItem, 0, len(form.Objects)/2) | ||||
| 			for i := 0; i < len(form.Objects); i += 2 { | ||||
| 				res = append(res, widget.NewFormItem( | ||||
| 					form.Objects[i].(*widget.Label).Text, | ||||
| 					form.Objects[i+1])) | ||||
| 			} | ||||
| 			return res | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (d *FormDialog) Show(parent ...fyne.Window) { | ||||
| 	d.concreteDialog.Initialize() | ||||
| 	d.items = d.itemsFn() | ||||
|  | ||||
| 	d.concreteDialog.OnShow() | ||||
| @@ -263,7 +406,8 @@ func RegisterDialog(name DialogName, kind DialogKind, fn NewDialogFn) { | ||||
| } | ||||
|  | ||||
| func NewDialog( | ||||
| 	name DialogName, kind DialogKind, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| ) Dialog { | ||||
| @@ -272,14 +416,37 @@ func NewDialog( | ||||
| 	} | ||||
| 	if kindCatalog, ok := dialogCatalog[name]; ok { | ||||
| 		if fn, ok := kindCatalog[kind]; ok { | ||||
| 			return fn(name, kind, parent, confirm) | ||||
| 			return fn(name, kind, parent, confirm, nil, nil, "", nil) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func NewDialogWithScreen( | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) Dialog { | ||||
| 	if dialogCatalog == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if kindCatalog, ok := dialogCatalog[name]; ok { | ||||
| 		if fn, ok := kindCatalog[kind]; ok { | ||||
| 			return fn( | ||||
| 				name, kind, parent, confirm, nil, | ||||
| 				&filesystem, screenName, localizer) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func NewDialogWithData( | ||||
| 	name DialogName, kind DialogKind, | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	data binding.DataItem, | ||||
| @@ -289,7 +456,30 @@ func NewDialogWithData( | ||||
| 	} | ||||
| 	if kindCatalog, ok := dialogCatalog[name]; ok { | ||||
| 		if fn, ok := kindCatalog[kind]; ok { | ||||
| 			return fn(name, kind, parent, confirm, data) | ||||
| 			return fn(name, kind, parent, confirm, data, nil, "", nil) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func NewDialogWithDataAndScreen( | ||||
| 	name DialogName, | ||||
| 	kind DialogKind, | ||||
| 	parent fyne.Window, | ||||
| 	confirm OnConfirmFn, | ||||
| 	data binding.DataItem, | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) Dialog { | ||||
| 	if dialogCatalog == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if kindCatalog, ok := dialogCatalog[name]; ok { | ||||
| 		if fn, ok := kindCatalog[kind]; ok { | ||||
| 			return fn( | ||||
| 				name, kind, parent, confirm, data, | ||||
| 				&filesystem, screenName, localizer) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
|   | ||||
| @@ -9,45 +9,85 @@ import ( | ||||
| 	"fyne.io/fyne/v2/container" | ||||
| ) | ||||
|  | ||||
| // The constants for the Containers | ||||
| // | ||||
| // Available yaml options for all containers: | ||||
| //   - id: The ID for exporting the container to code | ||||
| //   - decorators: The decorators to wrap the container into | ||||
| //   - hidden: Wether the container is hidden or not | ||||
| type Container string | ||||
|  | ||||
| const ( | ||||
| 	// HScroll Container | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- content: The content of the container | ||||
| 	HScroll Container = "HScroll" | ||||
|  | ||||
| 	// Scroll Container | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- content: The content of the container | ||||
| 	Scroll Container = "Scroll" | ||||
|  | ||||
| 	// VScroll Container | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- content: The content of the container | ||||
| 	VScroll Container = "VScroll" | ||||
| ) | ||||
|  | ||||
| func (cnt Container) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| // Build builds the container and decorator for the given Container and Element, | ||||
| // using the provided ScreenHandler to fetch functions, data bindings, etc. | ||||
| // | ||||
| // Parameters: | ||||
| // - e *Element - the element to build the container for | ||||
| // - s ScreenHandler - the screen handler for the container | ||||
| // | ||||
| // Returns the CanvasObject for the widget, the CanvasObject for the decorator | ||||
| // I fno decorators are specified, the widget and decorator will be the same. | ||||
| func (cnt Container) Build( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) ( | ||||
| 	container fyne.CanvasObject, | ||||
| 	decorator fyne.CanvasObject, | ||||
| 	err error, | ||||
| ) { | ||||
| 	switch cnt { | ||||
| 	case HScroll: | ||||
| 		c, err = cnt.buildHScrollContainer(e, s) | ||||
| 		container, err = cnt.buildHScrollContainer(e, s) | ||||
| 	case Scroll: | ||||
| 		c, err = cnt.buildScrollContainer(e, s) | ||||
| 		container, err = cnt.buildScrollContainer(e, s) | ||||
| 	case VScroll: | ||||
| 		c, err = cnt.buildVScrollContainer(e, s) | ||||
| 		container, err = cnt.buildVScrollContainer(e, s) | ||||
| 	default: | ||||
| 		err = errors.New("invalid container") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if e.Decorators != nil { | ||||
|  | ||||
| 	decorator = container | ||||
| 	if e.Decorators != nil { | ||||
| 		for _, dec := range e.Decorators { | ||||
| 			switch dec { | ||||
| 			case "Border": | ||||
| 				c = uiwidget.NewWidgetBorder(c) | ||||
| 				decorator = uiwidget.NewWidgetBorder(decorator) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if e.Hidden { | ||||
| 		c.Hide() | ||||
| 		decorator.Hide() | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (ctn Container) buildHScrollContainer(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (ctn Container) buildHScrollContainer( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	if e.Content == nil { | ||||
| 		err = errors.New("HScroll: no content defined") | ||||
| 		return | ||||
| @@ -62,7 +102,10 @@ func (ctn Container) buildHScrollContainer(e *Element, s ScreenHandler) (c fyne. | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (ctn Container) buildScrollContainer(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (ctn Container) buildScrollContainer( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	if e.Content == nil { | ||||
| 		err = errors.New("Scroll: no content defined") | ||||
| 		return | ||||
| @@ -77,7 +120,10 @@ func (ctn Container) buildScrollContainer(e *Element, s ScreenHandler) (c fyne.C | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (ctn Container) buildVScrollContainer(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (ctn Container) buildVScrollContainer( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	if e.Content == nil { | ||||
| 		err = errors.New("VScroll: no content defined") | ||||
| 		return | ||||
|   | ||||
| @@ -7,11 +7,13 @@ import ( | ||||
| 	"fyne.io/fyne/v2" | ||||
| ) | ||||
|  | ||||
| // Size represents the yaml description of a ui size | ||||
| type Size struct { | ||||
| 	Width  float32 `yaml:"width"` | ||||
| 	Height float32 `yaml:"height"` | ||||
| } | ||||
|  | ||||
| // Element represents the yaml description of a ui element | ||||
| type Element struct { | ||||
| 	ID string `yaml:"id"` | ||||
|  | ||||
| @@ -57,6 +59,12 @@ type Element struct { | ||||
| 	Time       *string `yaml:"time"` | ||||
| 	TimeFormat *string `yaml:"timeFormat"` | ||||
|  | ||||
| 	// Entry Properties | ||||
| 	MultiLine            bool   `yaml:"multiLine"` | ||||
| 	Placeholder          string `yaml:"placeholder"` | ||||
| 	PlaceholderLocalized bool   `yaml:"placeholderLocalized"` | ||||
| 	Validator            string `yaml:"validator"` | ||||
|  | ||||
| 	// List Properties | ||||
| 	ItemTemplate string `yaml:"itemTemplate"` | ||||
| 	ItemRenderer string `yaml:"itemRenderer"` | ||||
| @@ -77,31 +85,37 @@ type Element struct { | ||||
| 	OnSelected          string `yaml:"onSelected"` | ||||
| 	OnUnselected        string `yaml:"onUnselected"` | ||||
| 	OnDateSelected      string `yaml:"onDateSelected"` | ||||
| 	OnValidationChanged string `yaml:"onValidationChanged"` | ||||
| } | ||||
|  | ||||
| // BuildUI generates the UI for the Element. | ||||
| // | ||||
| // It takes a ScreenHandler parameter and returns a fyne.CanvasObject and an error. | ||||
| func (e *Element) BuildUI(s ScreenHandler) (obj fyne.CanvasObject, err error) { | ||||
| 	var baseObject fyne.CanvasObject | ||||
|  | ||||
| 	defer func() { | ||||
| 		if e.ID != "" && obj != nil { | ||||
| 			s.RegisterElement(e.ID, obj) | ||||
| 		if e.ID != "" && baseObject != nil { | ||||
| 			s.RegisterElement(e.ID, baseObject, obj) | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	if e.Container != "" { | ||||
| 		if obj, err = e.Container.Build(e, s); err != nil { | ||||
| 		if baseObject, obj, err = e.Container.Build(e, s); err != nil { | ||||
| 			err = fmt.Errorf("failed to build container element: %w", err) | ||||
| 			return | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	if e.Layout != "" { | ||||
| 		if obj, err = e.Layout.Build(e, s); err != nil { | ||||
| 		if baseObject, obj, err = e.Layout.Build(e, s); err != nil { | ||||
| 			err = fmt.Errorf("failed to build layout element: %w", err) | ||||
| 			return | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	if e.Widget != "" { | ||||
| 		if obj, err = e.Widget.Build(e, s); err != nil { | ||||
| 		if baseObject, obj, err = e.Widget.Build(e, s); err != nil { | ||||
| 			err = fmt.Errorf("failed to build widget element: %w", err) | ||||
| 			return | ||||
| 		} | ||||
| @@ -115,4 +129,7 @@ func (e *Element) localize(s ScreenHandler) { | ||||
| 	if e.Localized { | ||||
| 		e.Text = i18n.T(s.GetLocalizer(), e.Text) | ||||
| 	} | ||||
| 	if e.PlaceholderLocalized { | ||||
| 		e.Placeholder = i18n.T(s.GetLocalizer(), e.Placeholder) | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										123
									
								
								screen/layout.go
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								screen/layout.go
									
									
									
									
									
								
							| @@ -11,34 +11,101 @@ import ( | ||||
| 	"fyne.io/fyne/v2/layout" | ||||
| ) | ||||
|  | ||||
| // The constants for the Layouts | ||||
| // | ||||
| // Available yaml options for all layouts: | ||||
| //   - id: The ID for exporting the layout to code | ||||
| //   - decorators: The decorators to wrap the layout into | ||||
| //   - hidden: Wether the layout is hidden or not | ||||
| type Layout string | ||||
|  | ||||
| const ( | ||||
| 	// Border Layout | ||||
| 	// | ||||
| 	// Available yaml options | ||||
| 	//	- top: The top pane (contains 1 widget) | ||||
| 	//	- bottom: The bottom pane (contains 1 widget) | ||||
| 	//	- left: The left pane (contains 1 widget) | ||||
| 	//	- right: The right pane (contains 1 widget) | ||||
| 	//	- center: The center pane (contains multiple widgets) | ||||
| 	Border Layout = "Border" | ||||
|  | ||||
| 	// Form Layout | ||||
| 	// | ||||
| 	// Available yaml options | ||||
| 	//	- children: The children of the form | ||||
| 	//		- label: The label of the form element | ||||
| 	//		- field: The field of the form element | ||||
| 	Form Layout = "Form" | ||||
|  | ||||
| 	// Grid Layout | ||||
| 	// | ||||
| 	// Available yaml options | ||||
| 	//	- columns: The number of columns (GridWithColumns) | ||||
| 	//	- rows: The number of rows (GridWithRows) | ||||
| 	//	- rowColumns: The number of rows and columns (AdaptiveGrid) | ||||
| 	//	- elementSize: The size of the elements (GridWrap) | ||||
| 	//	- children: The children of the grid | ||||
| 	Grid Layout = "Grid" | ||||
|  | ||||
| 	// HBox Layout | ||||
| 	// | ||||
| 	// Available yaml options | ||||
| 	//	- children: The children of the HBox | ||||
| 	HBox Layout = "HBox" | ||||
|  | ||||
| 	// MinSize Layout | ||||
| 	// | ||||
| 	// Available yaml options | ||||
| 	//	- minSize: The minimum size of the layout | ||||
| 	//  - children: The children of the MinSize | ||||
| 	MinSize Layout = "MinSize" | ||||
|  | ||||
| 	// Stack Layout | ||||
| 	// | ||||
| 	// Available yaml options | ||||
| 	// - children: The children of the Stack | ||||
| 	Stack Layout = "Stack" | ||||
|  | ||||
| 	// VBox Layout | ||||
| 	// | ||||
| 	// Available yaml options | ||||
| 	//	- children: The children of the VBox | ||||
| 	VBox Layout = "VBox" | ||||
| ) | ||||
|  | ||||
| func (l Layout) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| // Build builds the layout based on the given Layout and Element | ||||
| // using the provided ScreenHandler to fetch functions, data bindings, etc. | ||||
| // | ||||
| // Parameters: | ||||
| // - e: The Element to build the Layout for | ||||
| // - s: The ScreenHandler to use to fetch functions, data bindings, etc. | ||||
| // Returns the CanvasObject for the Layout, the CanvasObject for the decorator | ||||
| // and an error if any. | ||||
| // If no decorators are specified, the widget and decorator will be the same. | ||||
| func (l Layout) Build( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) ( | ||||
| 	layout fyne.CanvasObject, | ||||
| 	decorator fyne.CanvasObject, | ||||
| 	err error, | ||||
| ) { | ||||
| 	switch l { | ||||
| 	case Border: | ||||
| 		c, err = l.buildBorderLayout(e, s) | ||||
| 		layout, err = l.buildBorderLayout(e, s) | ||||
| 	case Form: | ||||
| 		c, err = l.buildFormLayout(e, s) | ||||
| 		layout, err = l.buildFormLayout(e, s) | ||||
| 	case Grid: | ||||
| 		c, err = l.buildGridLayout(e, s) | ||||
| 		layout, err = l.buildGridLayout(e, s) | ||||
| 	case HBox: | ||||
| 		c, err = l.buildHBoxLayout(e, s) | ||||
| 		layout, err = l.buildHBoxLayout(e, s) | ||||
| 	case MinSize: | ||||
| 		c, err = l.buildMinSizeLayout(e, s) | ||||
| 		layout, err = l.buildMinSizeLayout(e, s) | ||||
| 	case Stack: | ||||
| 		c, err = l.buildStackLayout(e, s) | ||||
| 		layout, err = l.buildStackLayout(e, s) | ||||
| 	case VBox: | ||||
| 		c, err = l.buildVBoxLayout(e, s) | ||||
| 		layout, err = l.buildVBoxLayout(e, s) | ||||
| 	default: | ||||
| 		err = errors.New("invalid layout") | ||||
| 	} | ||||
| @@ -46,22 +113,26 @@ func (l Layout) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err err | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	decorator = layout | ||||
| 	if e.Decorators != nil { | ||||
| 		for _, dec := range e.Decorators { | ||||
| 			switch dec { | ||||
| 			case "Border": | ||||
| 				c = uiwidget.NewWidgetBorder(c) | ||||
| 				decorator = uiwidget.NewWidgetBorder(decorator) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if e.Hidden { | ||||
| 		c.Hide() | ||||
| 		decorator.Hide() | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l Layout) buildBorderLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||
| func (l Layout) buildBorderLayout( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c *fyne.Container, err error) { | ||||
| 	var top, left, right, bottom fyne.CanvasObject | ||||
| 	var center []fyne.CanvasObject | ||||
|  | ||||
| @@ -109,7 +180,10 @@ func (l Layout) buildBorderLayout(e *Element, s ScreenHandler) (c *fyne.Containe | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l Layout) buildFormLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||
| func (l Layout) buildFormLayout( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c *fyne.Container, err error) { | ||||
| 	children := make([]fyne.CanvasObject, 0, len(e.Children)*2) | ||||
| 	for _, child := range e.Children { | ||||
| 		if child.Label == nil { | ||||
| @@ -149,7 +223,10 @@ func (l Layout) buildFormLayout(e *Element, s ScreenHandler) (c *fyne.Container, | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l Layout) buildGridLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||
| func (l Layout) buildGridLayout( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c *fyne.Container, err error) { | ||||
| 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||
| 	for _, child := range e.Children { | ||||
| 		var obj fyne.CanvasObject | ||||
| @@ -179,7 +256,10 @@ func (l Layout) buildGridLayout(e *Element, s ScreenHandler) (c *fyne.Container, | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l Layout) buildHBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||
| func (l Layout) buildHBoxLayout( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c *fyne.Container, err error) { | ||||
| 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||
| 	for _, child := range e.Children { | ||||
| 		var obj fyne.CanvasObject | ||||
| @@ -193,7 +273,10 @@ func (l Layout) buildHBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container, | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l Layout) buildMinSizeLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||
| func (l Layout) buildMinSizeLayout( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c *fyne.Container, err error) { | ||||
| 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||
| 	for _, child := range e.Children { | ||||
| 		var obj fyne.CanvasObject | ||||
| @@ -216,7 +299,10 @@ func (l Layout) buildMinSizeLayout(e *Element, s ScreenHandler) (c *fyne.Contain | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l Layout) buildStackLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||
| func (l Layout) buildStackLayout( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c *fyne.Container, err error) { | ||||
| 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||
| 	for _, child := range e.Children { | ||||
| 		var obj fyne.CanvasObject | ||||
| @@ -230,7 +316,10 @@ func (l Layout) buildStackLayout(e *Element, s ScreenHandler) (c *fyne.Container | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l Layout) buildVBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||
| func (l Layout) buildVBoxLayout( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c *fyne.Container, err error) { | ||||
| 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||
| 	for _, child := range e.Children { | ||||
| 		var obj fyne.CanvasObject | ||||
|   | ||||
| @@ -5,15 +5,19 @@ import ( | ||||
| 	"fyne.io/fyne/v2/widget" | ||||
| ) | ||||
|  | ||||
| // ListItemTemplate is a template for a list item. | ||||
| // It implements the fyne.CanvasObject interface and TemplateScreenHandler | ||||
| type ListItemTemplate struct { | ||||
| 	fyne.CanvasObject | ||||
| 	*TemplateScreenHandler | ||||
| } | ||||
|  | ||||
| // CreateRenderer implements the fyne.CanvasObject interface | ||||
| func (i *ListItemTemplate) CreateRenderer() fyne.WidgetRenderer { | ||||
| 	return widget.NewSimpleRenderer(i.CanvasObject) | ||||
| } | ||||
|  | ||||
| // NewListItemTemplate creates a new ListItemTemplate | ||||
| func NewListItemTemplate( | ||||
| 	obj fyne.CanvasObject, | ||||
| 	screenHandler *TemplateScreenHandler, | ||||
|   | ||||
| @@ -16,22 +16,39 @@ import ( | ||||
| 	"gopkg.in/yaml.v2" | ||||
| ) | ||||
|  | ||||
| type ListItemTemplateFn func() fyne.CanvasObject | ||||
| type ListDataItemRendererFn func(binding.DataItem, fyne.CanvasObject) | ||||
| type ListItemRendererFn func(int, fyne.CanvasObject) | ||||
| type ListLengthFn func() int | ||||
| type ListItemHandlerFn func(widget.ListItemID) | ||||
| type ClickHandlerFn func() | ||||
| type CheckHandlerFn func(bool) | ||||
| type DateSelectedHandlerFn func(time.Time) | ||||
| type ValidationChangedHandlerFn func(error) | ||||
|  | ||||
| type UIElement struct { | ||||
| 	Object    fyne.CanvasObject | ||||
| 	Decorator fyne.CanvasObject | ||||
| } | ||||
|  | ||||
| type ScreenHandler interface { | ||||
| 	RegisterElement(string, fyne.CanvasObject) | ||||
| 	RegisterElement(string, fyne.CanvasObject, fyne.CanvasObject) | ||||
|  | ||||
| 	GetLocalizer() *i18n.Localizer | ||||
| 	GetIcon(string) fyne.Resource | ||||
| 	GetBinding(string) binding.DataItem | ||||
| 	GetListItemTemplate(string) func() fyne.CanvasObject | ||||
| 	GetListDataItemRenderer(string) func(binding.DataItem, fyne.CanvasObject) | ||||
| 	GetListItemRenderer(string) func(int, fyne.CanvasObject) | ||||
| 	GetListLength(string) func() int | ||||
| 	GetValidator(string) fyne.StringValidator | ||||
| 	GetListItemTemplate(string) ListItemTemplateFn | ||||
| 	GetListDataItemRenderer(string) ListDataItemRendererFn | ||||
| 	GetListItemRenderer(string) ListItemRendererFn | ||||
| 	GetListLength(string) ListLengthFn | ||||
|  | ||||
| 	GetOnSelectedHandler(string) func(widget.ListItemID) | ||||
| 	GetOnUnselectedHandler(string) func(widget.ListItemID) | ||||
| 	GetClickedHandler(string) func() | ||||
| 	GetCheckChangedHandler(string) func(bool) | ||||
| 	GetDateSelectedHandler(string) func(time.Time) | ||||
| 	GetOnListItemSelectedHandler(string) ListItemHandlerFn | ||||
| 	GetOnListItemUnselectedHandler(string) ListItemHandlerFn | ||||
| 	GetOnClickedHandler(string) ClickHandlerFn | ||||
| 	GetOnCheckChangedHandler(string) CheckHandlerFn | ||||
| 	GetOnDateSelectedHandler(string) DateSelectedHandlerFn | ||||
| 	GetOnValidationChangedHandler(string) ValidationChangedHandlerFn | ||||
| } | ||||
|  | ||||
| type Screen struct { | ||||
| @@ -79,7 +96,7 @@ func NewTemplate( | ||||
| 	handler *TemplateScreenHandler, | ||||
| 	err error, | ||||
| ) { | ||||
| 	handler = NewDummyScreenHandler(localizer) | ||||
| 	handler = NewTemplateScreenHandler(localizer) | ||||
| 	scr, err = New(filesystem, name, handler) | ||||
| 	return | ||||
| } | ||||
| @@ -94,21 +111,27 @@ func (s *Screen) Initialize() (obj fyne.CanvasObject, err error) { | ||||
|  | ||||
| type TemplateScreenHandler struct { | ||||
| 	localizer   *i18n.Localizer | ||||
| 	elementsMap map[string]fyne.CanvasObject | ||||
| 	elementsMap map[string]*UIElement | ||||
| } | ||||
|  | ||||
| func NewDummyScreenHandler(localizer *i18n.Localizer) *TemplateScreenHandler { | ||||
| func NewTemplateScreenHandler( | ||||
| 	localizer *i18n.Localizer, | ||||
| ) *TemplateScreenHandler { | ||||
| 	return &TemplateScreenHandler{ | ||||
| 		localizer:   localizer, | ||||
| 		elementsMap: make(map[string]fyne.CanvasObject), | ||||
| 		elementsMap: make(map[string]*UIElement), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d *TemplateScreenHandler) RegisterElement(name string, element fyne.CanvasObject) { | ||||
| 	d.elementsMap[name] = element | ||||
| func (d *TemplateScreenHandler) RegisterElement( | ||||
| 	name string, | ||||
| 	element fyne.CanvasObject, | ||||
| 	decorator fyne.CanvasObject, | ||||
| ) { | ||||
| 	d.elementsMap[name] = &UIElement{element, decorator} | ||||
| } | ||||
|  | ||||
| func (d *TemplateScreenHandler) GetElement(name string) fyne.CanvasObject { | ||||
| func (d *TemplateScreenHandler) GetElement(name string) *UIElement { | ||||
| 	elem, ok := d.elementsMap[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| @@ -132,38 +155,46 @@ func (*TemplateScreenHandler) GetBinding(string) binding.DataItem { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetListItemTemplate(string) func() fyne.CanvasObject { | ||||
| func (*TemplateScreenHandler) GetValidator(string) fyne.StringValidator { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetListItemTemplate(string) ListItemTemplateFn { | ||||
| 	return func() fyne.CanvasObject { return nil } | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetListDataItemRenderer(string) func(binding.DataItem, fyne.CanvasObject) { | ||||
| func (*TemplateScreenHandler) GetListDataItemRenderer(string) ListDataItemRendererFn { | ||||
| 	return func(binding.DataItem, fyne.CanvasObject) {} | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetListItemRenderer(string) func(int, fyne.CanvasObject) { | ||||
| func (*TemplateScreenHandler) GetListItemRenderer(string) ListItemRendererFn { | ||||
| 	return func(int, fyne.CanvasObject) {} | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetListLength(string) func() int { | ||||
| func (*TemplateScreenHandler) GetListLength(string) ListLengthFn { | ||||
| 	return func() int { return 0 } | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetOnSelectedHandler(string) func(widget.ListItemID) { | ||||
| func (*TemplateScreenHandler) GetOnListItemSelectedHandler(string) ListItemHandlerFn { | ||||
| 	return func(widget.ListItemID) {} | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetOnUnselectedHandler(string) func(widget.ListItemID) { | ||||
| func (*TemplateScreenHandler) GetOnListItemUnselectedHandler(string) ListItemHandlerFn { | ||||
| 	return func(widget.ListItemID) {} | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetClickedHandler(string) func() { | ||||
| func (*TemplateScreenHandler) GetOnClickedHandler(string) ClickHandlerFn { | ||||
| 	return func() {} | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetCheckChangedHandler(string) func(bool) { | ||||
| func (*TemplateScreenHandler) GetOnCheckChangedHandler(string) CheckHandlerFn { | ||||
| 	return func(bool) {} | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetDateSelectedHandler(string) func(time.Time) { | ||||
| func (*TemplateScreenHandler) GetOnDateSelectedHandler(string) DateSelectedHandlerFn { | ||||
| 	return func(time.Time) {} | ||||
| } | ||||
|  | ||||
| func (*TemplateScreenHandler) GetOnValidationChangedHandler(string) ValidationChangedHandlerFn { | ||||
| 	return func(error) {} | ||||
| } | ||||
|   | ||||
							
								
								
									
										293
									
								
								screen/widget.go
									
									
									
									
									
								
							
							
						
						
									
										293
									
								
								screen/widget.go
									
									
									
									
									
								
							| @@ -13,47 +13,216 @@ import ( | ||||
| 	xwidget "fyne.io/x/fyne/widget" | ||||
| ) | ||||
|  | ||||
| // The constants for the Widgets | ||||
| // | ||||
| // Available yaml options for all widgets: | ||||
| //   - id: The ID for exporting the widget to code | ||||
| //   - decorators: The decorators to wrap the widget into | ||||
| //   - hidden: Wether the widget is hidden or not | ||||
| type Widget string | ||||
|  | ||||
| const ( | ||||
| 	// Button Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the button | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	//	- icon: The icon for the button | ||||
| 	//	- disabled: Wether the button is disabled or not | ||||
| 	//	- options: Additional options for the button | ||||
| 	//		- alignment: The alignment of the button | ||||
| 	//		- iconPlacement: The icon placement of the button | ||||
| 	//		- importance: The importance of the button | ||||
| 	//	- onclicked: The function to call when the button is clicked | ||||
| 	Button Widget = "Button" | ||||
|  | ||||
| 	// Calendar Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- time: The current time to use for the calendar | ||||
| 	//	- timeFormat: The format to use to interpret the time field (default time.DateOnly) | ||||
| 	//	- onDateSelected: The function to call when a date is selected | ||||
| 	Calendar Widget = "Calendar" | ||||
|  | ||||
| 	// Checkbox Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the checkbox | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	//	- binding: The databinding for the checkbox | ||||
| 	//	- checked: The checked state of the checkbox | ||||
| 	//	- disabled: Wether the button is disabled or not | ||||
| 	//	- onChanged: The function to call when the checkbox is changed | ||||
| 	Check Widget = "Check" | ||||
|  | ||||
| 	// Entry Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the entry | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	//	- binding: The databinding for the entry | ||||
| 	//	- placeholder: The placeholder for the entry | ||||
| 	//	- placeholderLocalized: If the placeholder represents a localization key | ||||
| 	//	- multiLine: If the entry is multiline | ||||
| 	//	- disabled: Wether the button is disabled or not | ||||
| 	//	- validator: The validator for the entry | ||||
| 	//	- onValidationChanged: The function to call when the validation changes | ||||
| 	Entry Widget = "Entry" | ||||
|  | ||||
| 	// H1 Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the H1 | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	// 	- binding: The databinding for the H1 | ||||
| 	//	- options: The options for the H1 | ||||
| 	//		- wrapping: The wrapping option for the H1 | ||||
| 	//		- truncation: The truncation option for the H1 | ||||
| 	H1 Widget = "H1" | ||||
|  | ||||
| 	// H2 Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the H2 | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	// 	- binding: The databinding for the H2 | ||||
| 	//	- options: The options for the H2 | ||||
| 	//		- wrapping: The wrapping option for the H2 | ||||
| 	//		- truncation: The truncation option for the H2 | ||||
| 	H2 Widget = "H2" | ||||
|  | ||||
| 	// H3 Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the H3 | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	// 	- binding: The databinding for the H3 | ||||
| 	//	- options: The options for the H3 | ||||
| 	//		- wrapping: The wrapping option for the H3 | ||||
| 	//		- truncation: The truncation option for the H3 | ||||
| 	H3 Widget = "H3" | ||||
|  | ||||
| 	// H4 Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the H4 | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	// 	- binding: The databinding for the H4 | ||||
| 	//	- options: The options for the H4 | ||||
| 	//		- wrapping: The wrapping option for the H4 | ||||
| 	//		- truncation: The truncation option for the H4 | ||||
| 	H4 Widget = "H4" | ||||
|  | ||||
| 	// H5 Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the H5 | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	// 	- binding: The databinding for the H5 | ||||
| 	//	- options: The options for the H5 | ||||
| 	//		- wrapping: The wrapping option for the H5 | ||||
| 	//		- truncation: The truncation option for the H5 | ||||
| 	H5 Widget = "H5" | ||||
|  | ||||
| 	// H6 Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the H6 | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	// 	- binding: The databinding for the H6 | ||||
| 	//	- options: The options for the H6 | ||||
| 	//		- wrapping: The wrapping option for the H6 | ||||
| 	//		- truncation: The truncation option for the H6 | ||||
| 	H6 Widget = "H6" | ||||
|  | ||||
| 	// Icon Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- icon: The icon for the icon | ||||
| 	Icon Widget = "Icon" | ||||
|  | ||||
| 	// Label Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- text: The text for the label | ||||
| 	//	- localized: If the text represents a localization key | ||||
| 	// 	- binding: The databinding for the label | ||||
| 	//	- options: The options for the label | ||||
| 	//		- allignment: The alignment option for the label | ||||
| 	//		- wrapping: The wrapping option for the label | ||||
| 	// 		- textStyle: The text style option for the label | ||||
| 	//		- truncation: The truncation option for the label | ||||
| 	Label Widget = "Label" | ||||
|  | ||||
| 	// List Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- binding: The databinding for the list | ||||
| 	//	- listLength: The length of the list | ||||
| 	//	- itemTemplate: The item template for the list | ||||
| 	//	- itemRenderer: The item renderer for the list | ||||
| 	//	- onSelect: The on select function for the list | ||||
| 	//	- onUnselect: The on unselect function for the list | ||||
| 	List Widget = "List" | ||||
|  | ||||
| 	// Separator Widget | ||||
| 	Separator Widget = "Separator" | ||||
|  | ||||
| 	// Spacer Widget | ||||
| 	Spacer Widget = "Spacer" | ||||
|  | ||||
| 	// UpDownLabel Widget | ||||
| 	// | ||||
| 	// Available yaml options: | ||||
| 	//	- binding: The databinding for the up down label | ||||
| 	//	- onUpClicked: The on up clicked function for the up down label | ||||
| 	//	- onDownClicked: The on down clicked function for the up down label | ||||
| 	UpDownLabel Widget = "UpDownLabel" | ||||
| ) | ||||
|  | ||||
| func (w Widget) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| // Build builds a fyne.CanvasObject for the given Widget and Element, | ||||
| // using the provided ScreenHandler to fetch functions, data bindings, etc. | ||||
| // | ||||
| // Arguments: | ||||
| // - e: The Element to build the Widget for. | ||||
| // - s: The ScreenHandler to use to fetch functions, data bindings, etc. | ||||
| // | ||||
| // Returns the CanvasObject for the widget, the CanvasObject for the decorator, | ||||
| // and an error if any. | ||||
| // If no decorators are specified, the widget and decorator will be the same. | ||||
| func (w Widget) Build( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) ( | ||||
| 	widget fyne.CanvasObject, | ||||
| 	decorator fyne.CanvasObject, | ||||
| 	err error, | ||||
| ) { | ||||
| 	e.localize(s) | ||||
|  | ||||
| 	switch w { | ||||
| 	case Button: | ||||
| 		c, err = w.buildButtonWidget(e, s) | ||||
| 		widget, err = w.buildButtonWidget(e, s) | ||||
| 	case Calendar: | ||||
| 		c, err = w.buildCalendarWidget(e, s) | ||||
| 		widget, err = w.buildCalendarWidget(e, s) | ||||
| 	case Check: | ||||
| 		c, err = w.buildCheckWidget(e, s) | ||||
| 		widget, err = w.buildCheckWidget(e, s) | ||||
| 	case Entry: | ||||
| 		widget, err = w.buildEntryWidget(e, s) | ||||
| 	case H1, H2, H3, H4, H5, H6: | ||||
| 		c, err = w.buildHeaderLabelWidget(e, s) | ||||
| 		widget, err = w.buildHeaderLabelWidget(e, s) | ||||
| 	case Icon: | ||||
| 		widget, err = w.buildIconWidget(e, s) | ||||
| 	case Label: | ||||
| 		c, err = w.buildLabelWidget(e, s) | ||||
| 		widget, err = w.buildLabelWidget(e, s) | ||||
| 	case List: | ||||
| 		c, err = w.buildListWidget(e, s) | ||||
| 		widget, err = w.buildListWidget(e, s) | ||||
| 	case Separator: | ||||
| 		c, err = w.buildSeparatorWidget(e, s) | ||||
| 		widget, err = w.buildSeparatorWidget(e, s) | ||||
| 	case Spacer: | ||||
| 		c, err = w.buildSpacerWidget(e, s) | ||||
| 		widget, err = w.buildSpacerWidget(e, s) | ||||
| 	case UpDownLabel: | ||||
| 		c, err = w.buildUpDownLabelWidget(e, s) | ||||
| 		widget, err = w.buildUpDownLabelWidget(e, s) | ||||
| 	default: | ||||
| 		err = errors.New("invalid widget") | ||||
| 	} | ||||
| @@ -61,28 +230,32 @@ func (w Widget) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err err | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	decorator = widget | ||||
| 	if e.Decorators != nil { | ||||
| 		for _, dec := range e.Decorators { | ||||
| 			switch dec { | ||||
| 			case "Border": | ||||
| 				c = uiwidget.NewWidgetBorder(c) | ||||
| 				decorator = uiwidget.NewWidgetBorder(decorator) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if e.Hidden { | ||||
| 		c.Hide() | ||||
| 		decorator.Hide() | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildButtonWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildButtonWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	var btn *widget.Button | ||||
| 	if e.Icon != "" { | ||||
| 		btn = widget.NewButtonWithIcon( | ||||
| 			e.Text, s.GetIcon(e.Icon), s.GetClickedHandler(e.OnClicked)) | ||||
| 			e.Text, s.GetIcon(e.Icon), s.GetOnClickedHandler(e.OnClicked)) | ||||
| 	} else { | ||||
| 		btn = widget.NewButton(e.Text, s.GetClickedHandler(e.OnClicked)) | ||||
| 		btn = widget.NewButton(e.Text, s.GetOnClickedHandler(e.OnClicked)) | ||||
| 	} | ||||
|  | ||||
| 	for opt, val := range e.Options { | ||||
| @@ -103,7 +276,10 @@ func (w Widget) buildButtonWidget(e *Element, s ScreenHandler) (c fyne.CanvasObj | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildCalendarWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildCalendarWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	t := time.Now() | ||||
| 	if e.Time != nil { | ||||
| 		timeFormat := time.DateOnly | ||||
| @@ -116,18 +292,21 @@ func (w Widget) buildCalendarWidget(e *Element, s ScreenHandler) (c fyne.CanvasO | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	c = xwidget.NewCalendar(t, s.GetDateSelectedHandler(e.OnDateSelected)) | ||||
| 	c = xwidget.NewCalendar(t, s.GetOnDateSelectedHandler(e.OnDateSelected)) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildCheckWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildCheckWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	var chk *widget.Check | ||||
| 	if e.Binding != "" { | ||||
| 		chk = widget.NewCheckWithData( | ||||
| 			e.Text, s.GetBinding(e.Binding).(binding.Bool)) | ||||
| 	} else { | ||||
| 		chk = widget.NewCheck( | ||||
| 			e.Text, s.GetCheckChangedHandler(e.OnChanged)) | ||||
| 			e.Text, s.GetOnCheckChangedHandler(e.OnChanged)) | ||||
| 		chk.SetChecked(e.Checked) | ||||
| 	} | ||||
|  | ||||
| @@ -138,7 +317,40 @@ func (w Widget) buildCheckWidget(e *Element, s ScreenHandler) (c fyne.CanvasObje | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildHeaderLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildEntryWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	var ent *widget.Entry | ||||
| 	if e.MultiLine { | ||||
| 		ent = widget.NewMultiLineEntry() | ||||
| 	} else { | ||||
| 		ent = widget.NewEntry() | ||||
| 	} | ||||
| 	if e.Binding != "" { | ||||
| 		ent.Bind(s.GetBinding(e.Binding).(binding.String)) | ||||
| 	} else { | ||||
| 		ent.Text = e.Text | ||||
| 	} | ||||
| 	ent.PlaceHolder = e.Placeholder | ||||
| 	if e.Validator != "" { | ||||
| 		ent.Validator = s.GetValidator(e.Validator) | ||||
| 	} | ||||
| 	if e.OnValidationChanged != "" { | ||||
| 		ent.SetOnValidationChanged(s.GetOnValidationChangedHandler(e.OnValidationChanged)) | ||||
| 	} | ||||
|  | ||||
| 	if e.Disabled { | ||||
| 		ent.Disable() | ||||
| 	} | ||||
| 	c = ent | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildHeaderLabelWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	var rt *widget.RichText | ||||
|  | ||||
| 	level := 1 | ||||
| @@ -174,7 +386,18 @@ func (w Widget) buildHeaderLabelWidget(e *Element, s ScreenHandler) (c fyne.Canv | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildIconWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	c = widget.NewIcon(s.GetIcon(e.Icon)) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildLabelWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	var lbl *widget.Label | ||||
|  | ||||
| 	if e.Binding != "" { | ||||
| @@ -201,7 +424,10 @@ func (w Widget) buildLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObje | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildListWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildListWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	var lst *widget.List | ||||
|  | ||||
| 	if e.Binding != "" { | ||||
| @@ -217,22 +443,28 @@ func (w Widget) buildListWidget(e *Element, s ScreenHandler) (c fyne.CanvasObjec | ||||
| 	} | ||||
|  | ||||
| 	if e.OnSelected != "" { | ||||
| 		lst.OnSelected = s.GetOnSelectedHandler(e.OnSelected) | ||||
| 		lst.OnSelected = s.GetOnListItemSelectedHandler(e.OnSelected) | ||||
| 	} | ||||
| 	if e.OnUnselected != "" { | ||||
| 		lst.OnUnselected = s.GetOnUnselectedHandler(e.OnUnselected) | ||||
| 		lst.OnUnselected = s.GetOnListItemUnselectedHandler(e.OnUnselected) | ||||
| 	} | ||||
| 	c = lst | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildSeparatorWidget(_ *Element, _ ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildSeparatorWidget( | ||||
| 	_ *Element, | ||||
| 	_ ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	sep := widget.NewSeparator() | ||||
| 	c = sep | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildSpacerWidget(e *Element, _ ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildSpacerWidget( | ||||
| 	e *Element, | ||||
| 	_ ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	spc := &layout.Spacer{ | ||||
| 		FixHorizontal: e.FixHorizontal, | ||||
| 		FixVertical:   e.FixVertical, | ||||
| @@ -241,11 +473,14 @@ func (w Widget) buildSpacerWidget(e *Element, _ ScreenHandler) (c fyne.CanvasObj | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w Widget) buildUpDownLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||
| func (w Widget) buildUpDownLabelWidget( | ||||
| 	e *Element, | ||||
| 	s ScreenHandler, | ||||
| ) (c fyne.CanvasObject, err error) { | ||||
| 	btn := uiwidget.NewUpDownLabelWithData( | ||||
| 		s.GetBinding(e.Binding).(binding.String), | ||||
| 		s.GetClickedHandler(e.OnUpClicked), | ||||
| 		s.GetClickedHandler(e.OnDownClicked)) | ||||
| 		s.GetOnClickedHandler(e.OnUpClicked), | ||||
| 		s.GetOnClickedHandler(e.OnDownClicked)) | ||||
| 	c = btn | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										351
									
								
								screenhandler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								screenhandler.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,351 @@ | ||||
| package ui | ||||
|  | ||||
| import ( | ||||
| 	"embed" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"bitbucket.org/hevanto/ui/screen" | ||||
| 	"fyne.io/fyne/v2" | ||||
| 	"fyne.io/fyne/v2/data/binding" | ||||
| 	"fyne.io/fyne/v2/theme" | ||||
| 	"github.com/nicksnyder/go-i18n/v2/i18n" | ||||
| ) | ||||
|  | ||||
| // ScreenHandler represents the handler for a screen. | ||||
| // | ||||
| // It provides: | ||||
| //   - The screen definition | ||||
| //   - The localizer | ||||
| //   - The screen controller | ||||
| //   - Exported elements | ||||
| //   - List item templates and renderers | ||||
| //   - User interaction handlers | ||||
| type ScreenHandler struct { | ||||
| 	screenDefinition *screen.Screen | ||||
| 	localizer        *i18n.Localizer | ||||
| 	ctrl             ScreenController | ||||
|  | ||||
| 	// Map of screen elements that got an id assigned | ||||
| 	exportedElements map[string]*screen.UIElement | ||||
|  | ||||
| 	listItemTemplates     map[string]screen.ListItemTemplateFn | ||||
| 	listItemRenderers     map[string]screen.ListItemRendererFn | ||||
| 	listDataItemRenderers map[string]screen.ListDataItemRendererFn | ||||
| 	listLengths           map[string]screen.ListLengthFn | ||||
|  | ||||
| 	onListItemSelectedHandlers   map[string]screen.ListItemHandlerFn | ||||
| 	onListItemUnselectedHandlers map[string]screen.ListItemHandlerFn | ||||
| 	onClickedHandlers            map[string]screen.ClickHandlerFn | ||||
| 	onCheckChangedHandlers       map[string]screen.CheckHandlerFn | ||||
| 	onDateSelectedHandlers       map[string]screen.DateSelectedHandlerFn | ||||
| 	onValidationChangedHandlers  map[string]screen.ValidationChangedHandlerFn | ||||
| } | ||||
|  | ||||
| // NewScreenHandler initializes a new ScreenHandler with the provided filesystem, screen name, ScreenController, and localizer. | ||||
| // | ||||
| // Arguments: | ||||
| //   - filesystem: the embedded filesystem to access screen resources. | ||||
| //   - screenName: the name of the screen to load. | ||||
| //   - ctrl: the ScreenController for the screen. | ||||
| //   - localizer: the i18n.Localizer for localization. | ||||
| // | ||||
| // Returns: | ||||
| //   - h: the initialized ScreenHandler. | ||||
| //   - err: an error if loading the screen fails. | ||||
| func NewScreenHandler( | ||||
| 	filesystem embed.FS, | ||||
| 	screenName string, | ||||
| 	ctrl ScreenController, | ||||
| 	localizer *i18n.Localizer, | ||||
| ) (h *ScreenHandler, err error) { | ||||
| 	h = new(ScreenHandler) | ||||
|  | ||||
| 	h.ctrl = ctrl | ||||
| 	h.localizer = localizer | ||||
|  | ||||
| 	def, err := screen.New(filesystem, screenName, h) | ||||
| 	if err != nil { | ||||
| 		err = fmt.Errorf("failure loading screen: %w", err) | ||||
| 		return | ||||
| 	} | ||||
| 	h.screenDefinition = def | ||||
|  | ||||
| 	h.exportedElements = make(map[string]*screen.UIElement) | ||||
| 	h.listItemTemplates = make(map[string]screen.ListItemTemplateFn) | ||||
| 	h.listItemRenderers = make(map[string]screen.ListItemRendererFn) | ||||
| 	h.listDataItemRenderers = make(map[string]screen.ListDataItemRendererFn) | ||||
| 	h.listLengths = make(map[string]screen.ListLengthFn) | ||||
| 	h.onListItemSelectedHandlers = make(map[string]screen.ListItemHandlerFn) | ||||
| 	h.onListItemUnselectedHandlers = make(map[string]screen.ListItemHandlerFn) | ||||
| 	h.onClickedHandlers = make(map[string]screen.ClickHandlerFn) | ||||
| 	h.onCheckChangedHandlers = make(map[string]screen.CheckHandlerFn) | ||||
| 	h.onDateSelectedHandlers = make(map[string]screen.DateSelectedHandlerFn) | ||||
| 	h.onValidationChangedHandlers = make(map[string]screen.ValidationChangedHandlerFn) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ScreenDefinition returns the screen definition for the ScreenHandler. | ||||
| func (h *ScreenHandler) ScreenDefinition() *screen.Screen { | ||||
| 	return h.screenDefinition | ||||
| } | ||||
|  | ||||
| // RegisterElement registers an element with the ScreenHandler. | ||||
| // | ||||
| // This function is called for every element in the screen definition fow which | ||||
| // an ID is defined. | ||||
| func (h *ScreenHandler) RegisterElement( | ||||
| 	id string, | ||||
| 	elem fyne.CanvasObject, | ||||
| 	decorator fyne.CanvasObject, | ||||
| ) { | ||||
| 	h.exportedElements[id] = &screen.UIElement{Object: elem, Decorator: decorator} | ||||
| } | ||||
|  | ||||
| // RegisterListItemTemplate registers a ListItemTemplate with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the templates for the lists used in the | ||||
| // screen definition. | ||||
| func (h *ScreenHandler) RegisterListItemTemplate( | ||||
| 	name string, | ||||
| 	fn screen.ListItemTemplateFn, | ||||
| ) { | ||||
| 	h.listItemTemplates[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterListDataItemRenderer registers a ListDataItemRenderer with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the renderers for the lists used in the | ||||
| // screen definition. | ||||
| func (h *ScreenHandler) RegisterListDataItemRenderer( | ||||
| 	name string, | ||||
| 	fn screen.ListDataItemRendererFn, | ||||
| ) { | ||||
| 	h.listDataItemRenderers[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterListItemRenderer registers a ListItemRenderer with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the renderers for the lists used in the | ||||
| // screen definition. | ||||
| func (h *ScreenHandler) RegisterListItemRenderer( | ||||
| 	name string, | ||||
| 	fn screen.ListItemRendererFn, | ||||
| ) { | ||||
| 	h.listItemRenderers[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterListLength registers a ListLength with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the lengths for the lists used in the | ||||
| // screen definition. | ||||
| func (h *ScreenHandler) RegisterListLength( | ||||
| 	name string, | ||||
| 	fn screen.ListLengthFn, | ||||
| ) { | ||||
| 	h.listLengths[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterOnListItemSelectedHandler registers a OnListItemSelectedHandler with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the handler functions used in the screen | ||||
| // definition. | ||||
| func (h *ScreenHandler) RegisterOnListItemSelectedHandler( | ||||
| 	name string, | ||||
| 	fn screen.ListItemHandlerFn, | ||||
| ) { | ||||
| 	h.onListItemSelectedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterOnListItemUnselectedHandler registers a OnListItemUnselectedHandler with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the handler functions used in the screen | ||||
| // definition. | ||||
| func (h *ScreenHandler) RegisterOnListItemUnselectedHandler( | ||||
| 	name string, | ||||
| 	fn screen.ListItemHandlerFn, | ||||
| ) { | ||||
| 	h.onListItemUnselectedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterOnClickHandler registers a OnClickHandler with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the handler functions used in the screen | ||||
| // definition. | ||||
| func (h *ScreenHandler) RegisterOnClickHandler( | ||||
| 	name string, | ||||
| 	fn screen.ClickHandlerFn, | ||||
| ) { | ||||
| 	h.onClickedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterOnCheckChangedHandler registers a OnCheckChangedHandler with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the handler functions used in the screen | ||||
| // definition. | ||||
| func (h *ScreenHandler) RegisterOnCheckChangedHandler( | ||||
| 	name string, | ||||
| 	fn screen.CheckHandlerFn, | ||||
| ) { | ||||
| 	h.onCheckChangedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterOnDateSelectedHandler registers a OnDateSelectedHandler with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the handler functions used in the screen | ||||
| // definition. | ||||
| func (h *ScreenHandler) RegisterOnDateSelectedHandler( | ||||
| 	name string, | ||||
| 	fn screen.DateSelectedHandlerFn, | ||||
| ) { | ||||
| 	h.onDateSelectedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| // RegisterOnValidationChangedHandler registers a OnValidationChangedHandler with the ScreenHandler. | ||||
| // | ||||
| // Use this function to register the handler functions used in the screen | ||||
| // definition. | ||||
| func (h *ScreenHandler) RegisterOnValidationChangedHandler( | ||||
| 	name string, | ||||
| 	fn screen.ValidationChangedHandlerFn, | ||||
| ) { | ||||
| 	h.onValidationChangedHandlers[name] = fn | ||||
| } | ||||
|  | ||||
| // GetBinding returns the binding with the given name. | ||||
| // | ||||
| // This function forwards the call to the controller. In the controller the | ||||
| // required bindings should be mapped to the screen elements. | ||||
| func (h *ScreenHandler) GetBinding(name string) binding.DataItem { | ||||
| 	return h.ctrl.GetBinding(name) | ||||
| } | ||||
|  | ||||
| // GetValidator returns the validator with the given name. | ||||
| // | ||||
| // This function forwards the call to the controller. In the controller the | ||||
| // required validators should be mapped to the screen elements. | ||||
| func (h *ScreenHandler) GetValidator(name string) fyne.StringValidator { | ||||
| 	return h.ctrl.GetValidator(name) | ||||
| } | ||||
|  | ||||
| // GetElement returns the UIElement with the given ID. | ||||
| // | ||||
| // This function allows you to retrieve the exported elements (given an ID in | ||||
| // the screen definition). The UIElement contains the object and the decorator. | ||||
| // Should no decorator be present, both point to the same widget. If a decorator | ||||
| // is present it's advices to do hide and show operations on the decorator, and | ||||
| // all other operators on the object. | ||||
| func (h *ScreenHandler) GetElement(id string) *screen.UIElement { | ||||
| 	if elem, ok := h.exportedElements[id]; ok { | ||||
| 		return elem | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GetLocalizer returns the i18n.Localizer used for localization. | ||||
| func (h *ScreenHandler) GetLocalizer() *i18n.Localizer { | ||||
| 	return h.localizer | ||||
| } | ||||
|  | ||||
| // GetIcon returns the icon with the given name. | ||||
| // | ||||
| // This handler only implements the default theme icons. If you wish to support | ||||
| // other items, wrap this ScreenHandler and implement the loading of the icons | ||||
| // yourself. | ||||
| func (h *ScreenHandler) GetIcon(iconName string) fyne.Resource { | ||||
| 	if strings.HasPrefix(iconName, "theme.") { | ||||
| 		iconName := strings.SplitN(iconName, ".", 2)[1] | ||||
| 		return theme.DefaultTheme().Icon(fyne.ThemeIconName(iconName)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GetListItemTemplate returns the ListItemTemplate with the given name. | ||||
| func (h *ScreenHandler) GetListItemTemplate(name string) screen.ListItemTemplateFn { | ||||
| 	fn, ok := h.listItemTemplates[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetListDataItemRenderer returns the ListDataItemRenderer with the given name. | ||||
| func (h *ScreenHandler) GetListDataItemRenderer(name string) screen.ListDataItemRendererFn { | ||||
| 	fn, ok := h.listDataItemRenderers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetListItemRenderer returns the ListItemRenderer with the given name. | ||||
| func (h *ScreenHandler) GetListItemRenderer(name string) screen.ListItemRendererFn { | ||||
| 	fn, ok := h.listItemRenderers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetListLength returns the ListLength with the given name. | ||||
| func (h *ScreenHandler) GetListLength(name string) screen.ListLengthFn { | ||||
| 	fn, ok := h.listLengths[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetOnListItemSelectedHandler returns the OnListItemSelectedHandler with the given name. | ||||
| func (h *ScreenHandler) GetOnListItemSelectedHandler(name string) screen.ListItemHandlerFn { | ||||
| 	fn, ok := h.onListItemSelectedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetOnListItemUnselectedHandler returns the OnListItemUnselectedHandler with the given name. | ||||
| func (h *ScreenHandler) GetOnListItemUnselectedHandler(name string) screen.ListItemHandlerFn { | ||||
| 	fn, ok := h.onListItemUnselectedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetOnClickedHandler returns the OnClickedHandler with the given name. | ||||
| func (h *ScreenHandler) GetOnClickedHandler(name string) screen.ClickHandlerFn { | ||||
| 	fn, ok := h.onClickedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetOnCheckChangedHandler returns the OnCheckChangedHandler with the given name. | ||||
| func (h *ScreenHandler) GetOnCheckChangedHandler(name string) screen.CheckHandlerFn { | ||||
| 	fn, ok := h.onCheckChangedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetOnDateSelectedHandler returns the OnDateSelectedHandler with the given name. | ||||
| func (h *ScreenHandler) GetOnDateSelectedHandler(name string) screen.DateSelectedHandlerFn { | ||||
| 	fn, ok := h.onDateSelectedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
|  | ||||
| // GetOnValidationChangedHandler returns the OnValidationChangedHandler with the given name. | ||||
| func (h *ScreenHandler) GetOnValidationChangedHandler(name string) screen.ValidationChangedHandlerFn { | ||||
| 	fn, ok := h.onValidationChangedHandlers[name] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fn | ||||
| } | ||||
| @@ -7,6 +7,8 @@ import ( | ||||
| 	"fyne.io/fyne/v2/container" | ||||
| ) | ||||
|  | ||||
| // TODO: Implement screen reading from file! | ||||
|  | ||||
| type TabbedView struct { | ||||
| 	*BaseView | ||||
|  | ||||
|   | ||||
| @@ -2,14 +2,26 @@ package uilayout | ||||
|  | ||||
| import "fyne.io/fyne/v2" | ||||
|  | ||||
| // MinSize implements a min size layout. | ||||
| // | ||||
| // The MinSize layout will ensure that the container is rendered at a size that | ||||
| // is at least as large as the minimum size provided. | ||||
| type MinSize struct { | ||||
| 	minSize fyne.Size | ||||
| } | ||||
|  | ||||
| // NewMinSizeLayout creates a new MinSize layout with the specified minimum size. | ||||
| // | ||||
| // Arguments: | ||||
| // - minSize: the minimum size for the layout. | ||||
| // | ||||
| // Returns *MinSize: a pointer to the newly created MinSize layout. | ||||
| func NewMinSizeLayout(minSize fyne.Size) *MinSize { | ||||
| 	return &MinSize{minSize: minSize} | ||||
| } | ||||
|  | ||||
| // MinSize calculates the minimum size of the layout on the current screen. The | ||||
| // reported size will be at least as large as the configured minimum size. | ||||
| func (l *MinSize) MinSize(objects []fyne.CanvasObject) fyne.Size { | ||||
| 	size := l.minSize | ||||
| 	for _, o := range objects { | ||||
| @@ -24,6 +36,7 @@ func (l *MinSize) MinSize(objects []fyne.CanvasObject) fyne.Size { | ||||
| 	return size | ||||
| } | ||||
|  | ||||
| // Layout implements the Layout interface. | ||||
| func (l *MinSize) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) { | ||||
| 	pos := fyne.NewPos(0, 0) | ||||
| 	for _, o := range objects { | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import ( | ||||
| 	"fyne.io/fyne/v2/widget" | ||||
| ) | ||||
|  | ||||
| // LabelOpts defines the options for a label. | ||||
| type LabelOpts interface { | ||||
| 	ApplyTo(*widget.Label) | ||||
| } | ||||
| @@ -19,10 +20,12 @@ type allignmentOpt struct { | ||||
| 	Alignment fyne.TextAlign | ||||
| } | ||||
|  | ||||
| // AlignmentOpt returns a LabelOpts with the specified alignment. | ||||
| func AlignmentOpt(alignment fyne.TextAlign) LabelOpts { | ||||
| 	return &allignmentOpt{alignment} | ||||
| } | ||||
|  | ||||
| // ApplyTo sets the alignment of a label to the specified alignment. | ||||
| func (a *allignmentOpt) ApplyTo(lbl *widget.Label) { | ||||
| 	lbl.Alignment = a.Alignment | ||||
| } | ||||
| @@ -31,10 +34,12 @@ type wrappingOpt struct { | ||||
| 	Wrapping fyne.TextWrap | ||||
| } | ||||
|  | ||||
| // WrappingOpt creates a LabelOpts with the specified text wrapping option. | ||||
| func WrappingOpt(wrapping fyne.TextWrap) LabelOpts { | ||||
| 	return &wrappingOpt{wrapping} | ||||
| } | ||||
|  | ||||
| // ApplyTo applies the wrapping option to the label. | ||||
| func (w *wrappingOpt) ApplyTo(lbl *widget.Label) { | ||||
| 	lbl.Wrapping = w.Wrapping | ||||
| } | ||||
| @@ -43,10 +48,12 @@ type textStyleOpt struct { | ||||
| 	Style fyne.TextStyle | ||||
| } | ||||
|  | ||||
| // TextStyleOpt returns the label options for the given text style. | ||||
| func TextStyleOpt(style fyne.TextStyle) LabelOpts { | ||||
| 	return &textStyleOpt{style} | ||||
| } | ||||
|  | ||||
| // ApplyTo applies the text style option to the label. | ||||
| func (t *textStyleOpt) ApplyTo(lbl *widget.Label) { | ||||
| 	lbl.TextStyle = t.Style | ||||
| } | ||||
| @@ -55,10 +62,12 @@ type truncationOpt struct { | ||||
| 	Truncation fyne.TextTruncation | ||||
| } | ||||
|  | ||||
| // TruncationOpt returns the label options for the given text truncation option. | ||||
| func TruncationOpt(truncation fyne.TextTruncation) LabelOpts { | ||||
| 	return &truncationOpt{truncation} | ||||
| } | ||||
|  | ||||
| // ApplyTo applies the text truncation option to the label. | ||||
| func (t *truncationOpt) ApplyTo(lbl *widget.Label) { | ||||
| 	lbl.Truncation = t.Truncation | ||||
| } | ||||
| @@ -67,14 +76,23 @@ type importanceOpt struct { | ||||
| 	Importance widget.Importance | ||||
| } | ||||
|  | ||||
| // ImportanceOpt returns the label options for the given text importance option. | ||||
| func ImportanceOpt(importance widget.Importance) LabelOpts { | ||||
| 	return &importanceOpt{importance} | ||||
| } | ||||
|  | ||||
| // ApplyTo applies the text importance option to the label. | ||||
| func (i *importanceOpt) ApplyTo(lbl *widget.Label) { | ||||
| 	lbl.Importance = i.Importance | ||||
| } | ||||
|  | ||||
| // NewLabel creates a new label widget with the given text and options. | ||||
| // | ||||
| // Arguments | ||||
| // - text: the text to be displayed on the label. | ||||
| // - opts: optional configuration options for the label. | ||||
| // | ||||
| // Returns *widget.Label: a pointer to the newly created label widget. | ||||
| func NewLabel(text string, opts ...LabelOpts) *widget.Label { | ||||
| 	lbl := widget.NewLabel(text) | ||||
| 	for _, opt := range opts { | ||||
| @@ -83,6 +101,13 @@ func NewLabel(text string, opts ...LabelOpts) *widget.Label { | ||||
| 	return lbl | ||||
| } | ||||
|  | ||||
| // NewLabelWithData creates a new Label widget with the provided data and options. | ||||
| // | ||||
| // Arguments | ||||
| // - data: The string data to be displayed on the label. | ||||
| // - opts: Additional options to customize the label. | ||||
| // | ||||
| // Returns *widget.Label: a pointer to the newly created Label widget. | ||||
| func NewLabelWithData(data binding.String, opts ...LabelOpts) *widget.Label { | ||||
| 	lbl := widget.NewLabelWithData(data) | ||||
| 	for _, opt := range opts { | ||||
| @@ -91,6 +116,14 @@ func NewLabelWithData(data binding.String, opts ...LabelOpts) *widget.Label { | ||||
| 	return lbl | ||||
| } | ||||
|  | ||||
| // NewUpDownLabelWithData creates a new label widget with up and down buttons. | ||||
| // | ||||
| // Arguments | ||||
| // - data: the string data to display in the label. | ||||
| // - upHandler: the function to call when the up button is clicked. | ||||
| // - downHandler: the function to call when the down button is clicked. | ||||
| // | ||||
| // Returns fyne.CanvasObject: the created widget. | ||||
| func NewUpDownLabelWithData( | ||||
| 	data binding.String, | ||||
| 	upHandler func(), | ||||
| @@ -115,11 +148,25 @@ func NewUpDownLabelWithData( | ||||
| 	return c1 | ||||
| } | ||||
|  | ||||
| // NewH creates a RichText widget formatted as a header of the provided level. | ||||
| // | ||||
| // Parameters: | ||||
| // - level: an integer representing the level of the text. | ||||
| // - text: a string containing the text to display. | ||||
| // | ||||
| // Returns a pointer to a RichText widget. | ||||
| func NewH(level int, text string) *widget.RichText { | ||||
| 	return widget.NewRichTextFromMarkdown( | ||||
| 		fmt.Sprintf("%s %s", strings.Repeat("#", level), text)) | ||||
| } | ||||
|  | ||||
| // NewHWithData creates a new RichText widget formatted as a header of the provided level. | ||||
| // | ||||
| // Parameters: | ||||
| // - level: an integer representing the level of the text. | ||||
| // - data: a string binding containing the text to display. | ||||
| // | ||||
| // Returns a pointer to a RichText widget. | ||||
| func NewHWithData(level int, data binding.String) *widget.RichText { | ||||
| 	txt, _ := data.Get() | ||||
| 	w := NewH(level, txt) | ||||
| @@ -130,50 +177,62 @@ func NewHWithData(level int, data binding.String) *widget.RichText { | ||||
| 	return w | ||||
| } | ||||
|  | ||||
| // NewH1 creates a new RichText widget with header level 1. | ||||
| func NewH1(text string) *widget.RichText { | ||||
| 	return NewH(1, text) | ||||
| } | ||||
|  | ||||
| // NewH1WithData creates a new RichText widget with header level 1. | ||||
| func NewH1WithData(data binding.String) *widget.RichText { | ||||
| 	return NewHWithData(1, data) | ||||
| } | ||||
|  | ||||
| // NewH2 creates a new RichText widget with header level 2. | ||||
| func NewH2(text string) *widget.RichText { | ||||
| 	return NewH(2, text) | ||||
| } | ||||
|  | ||||
| // NewH2WithData creates a new RichText widget with header level 2. | ||||
| func NewH2WithData(data binding.String) *widget.RichText { | ||||
| 	return NewHWithData(2, data) | ||||
| } | ||||
|  | ||||
| // NewH3 creates a new RichText widget with header level 3. | ||||
| func NewH3(text string) *widget.RichText { | ||||
| 	return NewH(3, text) | ||||
| } | ||||
|  | ||||
| // NewH3WithData creates a new RichText widget with header level 3. | ||||
| func NewH3WithData(data binding.String) *widget.RichText { | ||||
| 	return NewHWithData(3, data) | ||||
| } | ||||
|  | ||||
| // NewH4 creates a new RichText widget with header level 4. | ||||
| func NewH4(text string) *widget.RichText { | ||||
| 	return NewH(4, text) | ||||
| } | ||||
|  | ||||
| // NewH4WithData creates a new RichText widget with header level 4. | ||||
| func NewH4WithData(data binding.String) *widget.RichText { | ||||
| 	return NewHWithData(4, data) | ||||
| } | ||||
|  | ||||
| // NewH5 creates a new RichText widget with header level 5. | ||||
| func NewH5(text string) *widget.RichText { | ||||
| 	return NewH(5, text) | ||||
| } | ||||
|  | ||||
| // NewH5WithData creates a new RichText widget with header level 5. | ||||
| func NewH5WithData(data binding.String) *widget.RichText { | ||||
| 	return NewHWithData(5, data) | ||||
| } | ||||
|  | ||||
| // NewH6 creates a new RichText widget with header level 6. | ||||
| func NewH6(text string) *widget.RichText { | ||||
| 	return NewH(6, text) | ||||
| } | ||||
|  | ||||
| // NewH6WithData creates a new RichText widget with header level 6. | ||||
| func NewH6WithData(data binding.String) *widget.RichText { | ||||
| 	return NewHWithData(6, data) | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,9 @@ import ( | ||||
| 	"fyne.io/fyne/v2/theme" | ||||
| ) | ||||
|  | ||||
| // NewWidgetBorder creates a new widget border for the given fyne.CanvasObject. | ||||
| // It does so by wrapping the object in a Stack layout with a border drawn | ||||
| // above the widget. | ||||
| func NewWidgetBorder(widget fyne.CanvasObject) fyne.CanvasObject { | ||||
| 	b := canvas.NewRectangle(color.Transparent) | ||||
| 	b.StrokeColor = theme.InputBorderColor() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Maarten Heremans
					Maarten Heremans