ui/screen/widget.go

383 lines
8.1 KiB
Go
Raw Normal View History

2024-03-30 17:45:07 +01:00
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
}
}