Initial Commit
This commit is contained in:
106
screen/element.go
Normal file
106
screen/element.go
Normal file
@ -0,0 +1,106 @@
|
||||
package screen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"bitbucket.org/hevanto/i18n"
|
||||
"fyne.io/fyne/v2"
|
||||
)
|
||||
|
||||
type Size struct {
|
||||
Width float32 `yaml:"width"`
|
||||
Height float32 `yaml:"height"`
|
||||
}
|
||||
|
||||
type Element struct {
|
||||
ID string `yaml:"id"`
|
||||
|
||||
Layout Layout `yaml:"layout"`
|
||||
Widget Widget `yaml:"widget"`
|
||||
|
||||
// Border Layout Elements
|
||||
Top *Element `yaml:"top"`
|
||||
Bottom *Element `yaml:"bottom"`
|
||||
Left *Element `yaml:"left"`
|
||||
Right *Element `yaml:"right"`
|
||||
Center []*Element `yaml:"center"`
|
||||
|
||||
// Other Layout Elements
|
||||
Children []*Element `yaml:"children"`
|
||||
|
||||
// Form Element
|
||||
Label *Element `yaml:"label"`
|
||||
Field *Element `yaml:"field"`
|
||||
|
||||
// Grid configuration
|
||||
Columns *int `yaml:"columns"`
|
||||
Rows *int `yaml:"rows"`
|
||||
RowColumns *int `yaml:"rowColumns"`
|
||||
ElementSize *Size `yaml:"elementSize"`
|
||||
|
||||
// Widget Properties
|
||||
Text string `yaml:"text"`
|
||||
Localized bool `yaml:"localized"`
|
||||
Icon string `yaml:"icon"`
|
||||
Binding string `yaml:"binding"`
|
||||
Decorators []string `yaml:"decorators"`
|
||||
Options map[string]any `yaml:"options"`
|
||||
Disabled bool `yaml:"disabled"`
|
||||
Hidden bool `yaml:"hidden"`
|
||||
|
||||
// Calendar Properties
|
||||
Time *string `yaml:"time"`
|
||||
TimeFormat *string `yaml:"timeFormat"`
|
||||
|
||||
// List Properties
|
||||
ItemTemplate string `yaml:"itemTemplate"`
|
||||
ItemRenderer string `yaml:"itemRenderer"`
|
||||
ListLength string `yaml:"listLength"`
|
||||
|
||||
// Check Properties
|
||||
Checked bool `yaml:"checked"`
|
||||
|
||||
// Spacer Properties
|
||||
FixHorizontal bool `yaml:"fixHorizontal"`
|
||||
FixVertical bool `yaml:"fixVertical"`
|
||||
|
||||
// Handlers
|
||||
OnClicked string `yaml:"onClicked"`
|
||||
OnUpClicked string `yaml:"onUpClicked"`
|
||||
OnDownClicked string `yaml:"onDownClicked"`
|
||||
OnChanged string `yaml:"onChanged"`
|
||||
OnSelected string `yaml:"onSelected"`
|
||||
OnUnselected string `yaml:"onUnselected"`
|
||||
OnDateSelected string `yaml:"onDateSelected"`
|
||||
}
|
||||
|
||||
func (e *Element) BuildUI(s ScreenHandler) (obj fyne.CanvasObject, err error) {
|
||||
defer func() {
|
||||
if e.ID != "" && obj != nil {
|
||||
s.RegisterElement(e.ID, obj)
|
||||
}
|
||||
}()
|
||||
|
||||
if e.Layout != "" {
|
||||
if 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 {
|
||||
err = fmt.Errorf("failed to build widget element: %w", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Element) localize(s ScreenHandler) {
|
||||
if e.Localized {
|
||||
e.Text = i18n.T(s.GetLocalizer(), e.Text)
|
||||
}
|
||||
}
|
208
screen/layout.go
Normal file
208
screen/layout.go
Normal file
@ -0,0 +1,208 @@
|
||||
package screen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
)
|
||||
|
||||
type Layout string
|
||||
|
||||
const (
|
||||
Border Layout = "Border"
|
||||
Form Layout = "Form"
|
||||
Grid Layout = "Grid"
|
||||
HBox Layout = "HBox"
|
||||
Stack Layout = "Stack"
|
||||
VBox Layout = "VBox"
|
||||
)
|
||||
|
||||
func (l Layout) Build(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
|
||||
switch l {
|
||||
case Border:
|
||||
c, err = l.buildBorderLayout(e, s)
|
||||
case Form:
|
||||
c, err = l.buildFormLayout(e, s)
|
||||
case Grid:
|
||||
c, err = l.buildGridLayout(e, s)
|
||||
case HBox:
|
||||
c, err = l.buildHBoxLayout(e, s)
|
||||
case Stack:
|
||||
c, err = l.buildStackLayout(e, s)
|
||||
case VBox:
|
||||
c, err = l.buildVBoxLayout(e, s)
|
||||
default:
|
||||
err = errors.New("invalid layout")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e.Hidden {
|
||||
c.Hide()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (l Layout) buildBorderLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) {
|
||||
var top, left, right, bottom fyne.CanvasObject
|
||||
var center []fyne.CanvasObject
|
||||
|
||||
if e.Top != nil {
|
||||
if top, err = e.Top.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("BorderLayout: failed to create top element: %w", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if e.Left != nil {
|
||||
if left, err = e.Left.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("BorderLayout: failed to create left element: %w", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if e.Center != nil {
|
||||
center = make([]fyne.CanvasObject, 0, len(e.Center))
|
||||
for _, elem := range e.Center {
|
||||
var ce fyne.CanvasObject
|
||||
if ce, err = elem.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("BorderLayout: failed to create center element: %w", err)
|
||||
return
|
||||
}
|
||||
center = append(center, ce)
|
||||
}
|
||||
}
|
||||
|
||||
if e.Right != nil {
|
||||
if right, err = e.Right.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("BorderLayout: failed to create right element: %w", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if e.Bottom != nil {
|
||||
if bottom, err = e.Bottom.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("BorderLayout: failed to create bottom element: %w", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c = container.NewBorder(top, bottom, left, right, center...)
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
child.Label = &Element{
|
||||
Text: "",
|
||||
}
|
||||
}
|
||||
if child.Field == nil {
|
||||
child.Field = &Element{
|
||||
Widget: Label,
|
||||
Text: "",
|
||||
}
|
||||
}
|
||||
|
||||
child.Label.Widget = Label
|
||||
if child.Label.Options == nil {
|
||||
child.Label.Options = make(map[string]any)
|
||||
}
|
||||
if child.Label.Options["TextStyle"] == nil {
|
||||
child.Label.Options["TextStyle"] = make(map[string]any)
|
||||
}
|
||||
child.Label.Options["TextStyle"].(map[string]any)["Bold"] = true
|
||||
|
||||
var label, field fyne.CanvasObject
|
||||
if label, err = child.Label.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("FormLayout: failed to create label element: %w", err)
|
||||
return
|
||||
}
|
||||
if field, err = child.Field.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("FormLayout: failed to create field element: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
children = append(children, label, field)
|
||||
}
|
||||
c = container.New(layout.NewFormLayout(), children...)
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
if obj, err = child.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("GridLayout failed to create child element %w", err)
|
||||
return
|
||||
}
|
||||
children = append(children, obj)
|
||||
}
|
||||
if e.Columns != nil {
|
||||
c = container.NewGridWithColumns(*e.Columns, children...)
|
||||
return
|
||||
}
|
||||
if e.Rows != nil {
|
||||
c = container.NewGridWithRows(*e.Rows, children...)
|
||||
return
|
||||
}
|
||||
if e.RowColumns != nil {
|
||||
c = container.NewAdaptiveGrid(*e.RowColumns, children...)
|
||||
return
|
||||
}
|
||||
if e.ElementSize != nil {
|
||||
c = container.NewGridWrap(fyne.NewSize(e.ElementSize.Width, e.ElementSize.Height), children...)
|
||||
return
|
||||
}
|
||||
err = errors.New("GridLayout failed due to incomplete grid type definition")
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
if obj, err = child.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("HBoxLayout failed to create child element: %w", err)
|
||||
return
|
||||
}
|
||||
children = append(children, obj)
|
||||
}
|
||||
c = container.New(layout.NewHBoxLayout(), children...)
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
if obj, err = child.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("StackLayout failed to create child element: %w", err)
|
||||
return
|
||||
}
|
||||
children = append(children, obj)
|
||||
}
|
||||
c = container.New(layout.NewStackLayout(), children...)
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
if obj, err = child.BuildUI(s); err != nil {
|
||||
err = fmt.Errorf("VBoxLayout failed to create child element: %w", err)
|
||||
return
|
||||
}
|
||||
children = append(children, obj)
|
||||
}
|
||||
c = container.New(layout.NewVBoxLayout(), children...)
|
||||
return
|
||||
}
|
25
screen/listtemplate.go
Normal file
25
screen/listtemplate.go
Normal file
@ -0,0 +1,25 @@
|
||||
package screen
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
type ListItemTemplate struct {
|
||||
fyne.CanvasObject
|
||||
*TemplateScreenHandler
|
||||
}
|
||||
|
||||
func (i *ListItemTemplate) CreateRenderer() fyne.WidgetRenderer {
|
||||
return widget.NewSimpleRenderer(i.CanvasObject)
|
||||
}
|
||||
|
||||
func NewListItemTemplate(
|
||||
obj fyne.CanvasObject,
|
||||
screenHandler *TemplateScreenHandler,
|
||||
) *ListItemTemplate {
|
||||
return &ListItemTemplate{
|
||||
CanvasObject: obj,
|
||||
TemplateScreenHandler: screenHandler,
|
||||
}
|
||||
}
|
169
screen/screen.go
Normal file
169
screen/screen.go
Normal file
@ -0,0 +1,169 @@
|
||||
package screen
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type ScreenHandler interface {
|
||||
RegisterElement(string, 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
|
||||
|
||||
GetOnSelectedHandler(string) func(widget.ListItemID)
|
||||
GetOnUnselectedHandler(string) func(widget.ListItemID)
|
||||
GetClickedHandler(string) func()
|
||||
GetCheckChangedHandler(string) func(bool)
|
||||
GetDateSelectedHandler(string) func(time.Time)
|
||||
}
|
||||
|
||||
type Screen struct {
|
||||
rootElement *Element
|
||||
screenHandler ScreenHandler
|
||||
}
|
||||
|
||||
func New(
|
||||
filesystem embed.FS,
|
||||
name string,
|
||||
screenHandler ScreenHandler,
|
||||
) (scr *Screen, err error) {
|
||||
var bytes []byte
|
||||
var fh fs.File
|
||||
|
||||
if fh, err = filesystem.Open(name); err != nil {
|
||||
err = fmt.Errorf("no screen definition found: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if bytes, err = io.ReadAll(fh); err != nil {
|
||||
err = fmt.Errorf("unable to read screen definition: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
root := &Element{}
|
||||
if err = yaml.Unmarshal(bytes, root); err != nil {
|
||||
err = fmt.Errorf("failure parsing screen definition: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
scr = &Screen{
|
||||
rootElement: root,
|
||||
screenHandler: screenHandler,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NewTemplate(
|
||||
filesystem embed.FS,
|
||||
name string,
|
||||
localizer *i18n.Localizer,
|
||||
) (
|
||||
scr *Screen,
|
||||
handler *TemplateScreenHandler,
|
||||
err error,
|
||||
) {
|
||||
handler = NewDummyScreenHandler(localizer)
|
||||
scr, err = New(filesystem, name, handler)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Screen) Initialize() (obj fyne.CanvasObject, err error) {
|
||||
if obj, err = s.rootElement.BuildUI(s.screenHandler); err != nil {
|
||||
err = fmt.Errorf("failed to build screen: %w", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type TemplateScreenHandler struct {
|
||||
localizer *i18n.Localizer
|
||||
elementsMap map[string]fyne.CanvasObject
|
||||
}
|
||||
|
||||
func NewDummyScreenHandler(localizer *i18n.Localizer) *TemplateScreenHandler {
|
||||
return &TemplateScreenHandler{
|
||||
localizer: localizer,
|
||||
elementsMap: make(map[string]fyne.CanvasObject),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *TemplateScreenHandler) RegisterElement(name string, element fyne.CanvasObject) {
|
||||
d.elementsMap[name] = element
|
||||
}
|
||||
|
||||
func (d *TemplateScreenHandler) GetElement(name string) fyne.CanvasObject {
|
||||
elem, ok := d.elementsMap[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return elem
|
||||
}
|
||||
|
||||
func (d *TemplateScreenHandler) GetLocalizer() *i18n.Localizer {
|
||||
return d.localizer
|
||||
}
|
||||
|
||||
func (d *TemplateScreenHandler) 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 (*TemplateScreenHandler) GetBinding(string) binding.DataItem {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetListItemTemplate(string) func() fyne.CanvasObject {
|
||||
return func() fyne.CanvasObject { return nil }
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetListDataItemRenderer(string) func(binding.DataItem, fyne.CanvasObject) {
|
||||
return func(binding.DataItem, fyne.CanvasObject) {}
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetListItemRenderer(string) func(int, fyne.CanvasObject) {
|
||||
return func(int, fyne.CanvasObject) {}
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetListLength(string) func() int {
|
||||
return func() int { return 0 }
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetOnSelectedHandler(string) func(widget.ListItemID) {
|
||||
return func(widget.ListItemID) {}
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetOnUnselectedHandler(string) func(widget.ListItemID) {
|
||||
return func(widget.ListItemID) {}
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetClickedHandler(string) func() {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetCheckChangedHandler(string) func(bool) {
|
||||
return func(bool) {}
|
||||
}
|
||||
|
||||
func (*TemplateScreenHandler) GetDateSelectedHandler(string) func(time.Time) {
|
||||
return func(time.Time) {}
|
||||
}
|
382
screen/widget.go
Normal file
382
screen/widget.go
Normal file
@ -0,0 +1,382 @@
|
||||
package screen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/hevanto/ui/uiwidget"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
xwidget "fyne.io/x/fyne/widget"
|
||||
)
|
||||
|
||||
type Widget string
|
||||
|
||||
const (
|
||||
Button Widget = "Button"
|
||||
Calendar Widget = "Calendar"
|
||||
Check Widget = "Check"
|
||||
H1 Widget = "H1"
|
||||
H2 Widget = "H2"
|
||||
H3 Widget = "H3"
|
||||
H4 Widget = "H4"
|
||||
H5 Widget = "H5"
|
||||
H6 Widget = "H6"
|
||||
Label Widget = "Label"
|
||||
List Widget = "List"
|
||||
Separator Widget = "Separator"
|
||||
Spacer Widget = "Spacer"
|
||||
UpDownLabel Widget = "UpDownLabel"
|
||||
)
|
||||
|
||||
func (w Widget) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
|
||||
e.localize(s)
|
||||
|
||||
switch w {
|
||||
case Button:
|
||||
c, err = w.buildButtonWidget(e, s)
|
||||
case Calendar:
|
||||
c, err = w.buildCalendarWidget(e, s)
|
||||
case Check:
|
||||
c, err = w.buildCheckWidget(e, s)
|
||||
case H1, H2, H3, H4, H5, H6:
|
||||
c, err = w.buildHeaderLabelWidget(e, s)
|
||||
case Label:
|
||||
c, err = w.buildLabelWidget(e, s)
|
||||
case List:
|
||||
c, err = w.buildListWidget(e, s)
|
||||
case Separator:
|
||||
c, err = w.buildSeparatorWidget(e, s)
|
||||
case Spacer:
|
||||
c, err = w.buildSpacerWidget(e, s)
|
||||
case UpDownLabel:
|
||||
c, err = w.buildUpDownLabelWidget(e, s)
|
||||
default:
|
||||
err = errors.New("invalid widget")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e.Decorators != nil {
|
||||
for _, dec := range e.Decorators {
|
||||
switch dec {
|
||||
case "Border":
|
||||
c = uiwidget.NewWidgetBorder(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if e.Hidden {
|
||||
c.Hide()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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))
|
||||
} else {
|
||||
btn = widget.NewButton(e.Text, s.GetClickedHandler(e.OnClicked))
|
||||
}
|
||||
|
||||
for opt, val := range e.Options {
|
||||
switch opt {
|
||||
case "alignment":
|
||||
btn.Alignment = getButtonAlignment(val)
|
||||
case "iconPlacement":
|
||||
btn.IconPlacement = getButtonIconPlacement(val)
|
||||
case "importance":
|
||||
btn.Importance = getImportance(val)
|
||||
}
|
||||
}
|
||||
|
||||
if e.Disabled {
|
||||
btn.Disable()
|
||||
}
|
||||
c = btn
|
||||
return
|
||||
}
|
||||
|
||||
func (w Widget) buildCalendarWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
|
||||
t := time.Now()
|
||||
if e.Time != nil {
|
||||
timeFormat := time.DateOnly
|
||||
if e.TimeFormat != nil {
|
||||
timeFormat = parseTimeFormat(*e.TimeFormat)
|
||||
}
|
||||
if t, err = time.Parse(timeFormat, *e.Time); err != nil {
|
||||
err = fmt.Errorf("CalendarWidget: failed to parse time: %w", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c = xwidget.NewCalendar(t, s.GetDateSelectedHandler(e.OnDateSelected))
|
||||
return
|
||||
}
|
||||
|
||||
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))
|
||||
chk.SetChecked(e.Checked)
|
||||
}
|
||||
|
||||
if e.Disabled {
|
||||
chk.Disable()
|
||||
}
|
||||
c = chk
|
||||
return
|
||||
}
|
||||
|
||||
func (w Widget) buildHeaderLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
|
||||
var rt *widget.RichText
|
||||
|
||||
level := 1
|
||||
switch e.Widget {
|
||||
case H1:
|
||||
level = 1
|
||||
case H2:
|
||||
level = 2
|
||||
case H3:
|
||||
level = 3
|
||||
case H4:
|
||||
level = 4
|
||||
case H5:
|
||||
level = 5
|
||||
case H6:
|
||||
level = 6
|
||||
}
|
||||
if e.Binding != "" {
|
||||
rt = uiwidget.NewHWithData(level, s.GetBinding(e.Binding).(binding.String))
|
||||
} else {
|
||||
rt = uiwidget.NewH(level, e.Text)
|
||||
}
|
||||
|
||||
for opt, val := range e.Options {
|
||||
switch opt {
|
||||
case "wrapping":
|
||||
rt.Wrapping = getTextWrap(val)
|
||||
case "truncation":
|
||||
rt.Truncation = getTruncation(val)
|
||||
}
|
||||
}
|
||||
c = rt
|
||||
return
|
||||
}
|
||||
|
||||
func (w Widget) buildLabelWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
|
||||
var lbl *widget.Label
|
||||
|
||||
if e.Binding != "" {
|
||||
lbl = widget.NewLabelWithData(s.GetBinding(e.Binding).(binding.String))
|
||||
} else {
|
||||
lbl = widget.NewLabel(e.Text)
|
||||
}
|
||||
|
||||
for opt, val := range e.Options {
|
||||
switch opt {
|
||||
case "alignment":
|
||||
lbl.Alignment = getTextAlignment(val)
|
||||
case "wrapping":
|
||||
lbl.Wrapping = getTextWrap(val)
|
||||
case "textStyle":
|
||||
lbl.TextStyle = getTextStyle(val)
|
||||
case "truncation":
|
||||
lbl.Truncation = getTruncation(val)
|
||||
case "importance":
|
||||
lbl.Importance = getImportance(val)
|
||||
}
|
||||
}
|
||||
c = lbl
|
||||
return
|
||||
}
|
||||
|
||||
func (w Widget) buildListWidget(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) {
|
||||
var lst *widget.List
|
||||
|
||||
if e.Binding != "" {
|
||||
lst = widget.NewListWithData(
|
||||
s.GetBinding(e.Binding).(binding.DataList),
|
||||
s.GetListItemTemplate(e.ItemTemplate),
|
||||
s.GetListDataItemRenderer(e.ItemRenderer))
|
||||
} else {
|
||||
lst = widget.NewList(
|
||||
s.GetListLength(e.ListLength),
|
||||
s.GetListItemTemplate(e.ItemTemplate),
|
||||
s.GetListItemRenderer(e.ItemRenderer))
|
||||
}
|
||||
|
||||
if e.OnSelected != "" {
|
||||
lst.OnSelected = s.GetOnSelectedHandler(e.OnSelected)
|
||||
}
|
||||
if e.OnUnselected != "" {
|
||||
lst.OnUnselected = s.GetOnUnselectedHandler(e.OnUnselected)
|
||||
}
|
||||
c = lst
|
||||
return
|
||||
}
|
||||
|
||||
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) {
|
||||
spc := &layout.Spacer{
|
||||
FixHorizontal: e.FixHorizontal,
|
||||
FixVertical: e.FixVertical,
|
||||
}
|
||||
c = spc
|
||||
return
|
||||
}
|
||||
|
||||
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))
|
||||
c = btn
|
||||
return
|
||||
}
|
||||
|
||||
func getButtonAlignment(v any) widget.ButtonAlign {
|
||||
switch v.(string) {
|
||||
case "ButtonAlignLeading":
|
||||
return widget.ButtonAlignLeading
|
||||
case "ButtonAlignTrailing":
|
||||
return widget.ButtonAlignTrailing
|
||||
}
|
||||
return widget.ButtonAlignCenter
|
||||
}
|
||||
|
||||
func getButtonIconPlacement(v any) widget.ButtonIconPlacement {
|
||||
if v.(string) == "ButtonIconTrailingText" {
|
||||
return widget.ButtonIconTrailingText
|
||||
}
|
||||
return widget.ButtonIconLeadingText
|
||||
}
|
||||
|
||||
func getImportance(v any) widget.Importance {
|
||||
switch v.(string) {
|
||||
case "LowImportance":
|
||||
return widget.LowImportance
|
||||
case "HighImportance":
|
||||
return widget.HighImportance
|
||||
case "DangerImportance":
|
||||
return widget.DangerImportance
|
||||
case "WarningImportance":
|
||||
return widget.WarningImportance
|
||||
case "SuccessImportance":
|
||||
return widget.SuccessImportance
|
||||
}
|
||||
return widget.MediumImportance
|
||||
}
|
||||
|
||||
func getTextAlignment(v any) fyne.TextAlign {
|
||||
switch v.(string) {
|
||||
case "TextAlignCenter":
|
||||
return fyne.TextAlignCenter
|
||||
case "TextAlignTrailing":
|
||||
return fyne.TextAlignTrailing
|
||||
}
|
||||
return fyne.TextAlignLeading
|
||||
}
|
||||
|
||||
func getTextStyle(v any) fyne.TextStyle {
|
||||
var ts fyne.TextStyle
|
||||
|
||||
props, ok := v.(map[string]any)
|
||||
if !ok {
|
||||
return ts
|
||||
}
|
||||
|
||||
for key, val := range props {
|
||||
switch key {
|
||||
case "bold":
|
||||
ts.Bold, _ = val.(bool)
|
||||
case "italic":
|
||||
ts.Italic, _ = val.(bool)
|
||||
case "monospace":
|
||||
ts.Monospace, _ = val.(bool)
|
||||
case "symbol":
|
||||
ts.Symbol, _ = val.(bool)
|
||||
case "tabWidth":
|
||||
ts.TabWidth, _ = val.(int)
|
||||
}
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
func getTextWrap(v any) fyne.TextWrap {
|
||||
switch v.(string) {
|
||||
case "TextWrapBreak":
|
||||
return fyne.TextWrapBreak
|
||||
case "TextWrapWord":
|
||||
return fyne.TextWrapWord
|
||||
}
|
||||
return fyne.TextWrapOff
|
||||
}
|
||||
|
||||
func getTruncation(v any) fyne.TextTruncation {
|
||||
switch v.(string) {
|
||||
case "TextTruncateClip":
|
||||
return fyne.TextTruncateClip
|
||||
case "TextTruncateEllipsis":
|
||||
return fyne.TextTruncateEllipsis
|
||||
}
|
||||
return fyne.TextTruncateOff
|
||||
}
|
||||
|
||||
func parseTimeFormat(format string) string {
|
||||
switch format {
|
||||
case "ANSIC":
|
||||
return time.ANSIC
|
||||
case "UnixDate":
|
||||
return time.UnixDate
|
||||
case "RubyDate":
|
||||
return time.RubyDate
|
||||
case "RFC822":
|
||||
return time.RFC822
|
||||
case "RFC822Z":
|
||||
return time.RFC822Z
|
||||
case "RFC850":
|
||||
return time.RFC850
|
||||
case "RFC1123":
|
||||
return time.RFC1123
|
||||
case "RFC1123Z":
|
||||
return time.RFC1123Z
|
||||
case "RFC3339":
|
||||
return time.RFC3339
|
||||
case "RFC3339Nano":
|
||||
return time.RFC3339Nano
|
||||
case "Kitchen":
|
||||
return time.Kitchen
|
||||
case "Stamp":
|
||||
return time.Stamp
|
||||
case "StampMilli":
|
||||
return time.StampMilli
|
||||
case "StampMicro":
|
||||
return time.StampMicro
|
||||
case "StampNano":
|
||||
return time.StampNano
|
||||
case "DateTime":
|
||||
return time.DateTime
|
||||
case "DateOnly":
|
||||
return time.DateOnly
|
||||
case "TimeOnly":
|
||||
return time.TimeOnly
|
||||
default:
|
||||
return format
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user