Compare commits
6 Commits
050b94dd3a
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7325554288 | ||
![]() |
40dad494d9 | ||
![]() |
ce11540123 | ||
64e96e6800 | |||
![]() |
e2fa726a37 | ||
987d25ecd0 |
@@ -148,3 +148,7 @@ func (v *BaseView) RegisterResizeCallback(cb ResizeCallbackFn) {
|
|||||||
func (v *BaseView) RegisterMoveCallback(cb MoveCallbackFn) {
|
func (v *BaseView) RegisterMoveCallback(cb MoveCallbackFn) {
|
||||||
v.ScreenHandler.RegisterMoveCallback(cb)
|
v.ScreenHandler.RegisterMoveCallback(cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v BaseView) PreventClose() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
14
dialog.go
14
dialog.go
@@ -5,11 +5,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
|
||||||
"bitbucket.org/hevanto/ui/screen"
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/data/binding"
|
"fyne.io/fyne/v2/data/binding"
|
||||||
"fyne.io/fyne/v2/dialog"
|
"fyne.io/fyne/v2/dialog"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"gitea.hevanto-it.com/hevanto/ui/screen"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
)
|
)
|
||||||
@@ -100,7 +100,7 @@ func NewBaseDialogWithScreen(
|
|||||||
parent, confirm)
|
parent, confirm)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
d.ScreenHandler, err = NewScreenHandler(
|
d.ScreenHandler, err = NewDialogScreenHandler(
|
||||||
filesystem, screenName, viewModel, localizer, assetLoader)
|
filesystem, screenName, viewModel, localizer, assetLoader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWindowError(d, LoadScreen, err)
|
LogWindowError(d, LoadScreen, err)
|
||||||
@@ -148,7 +148,7 @@ func NewBaseDialogWithDataAndScreen(
|
|||||||
parent, confirm, data)
|
parent, confirm, data)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
d.ScreenHandler, err = NewScreenHandler(
|
d.ScreenHandler, err = NewDialogScreenHandler(
|
||||||
filesystem, screenName, viewModel, localizer, assetLoader)
|
filesystem, screenName, viewModel, localizer, assetLoader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWindowError(d, LoadScreen, err)
|
LogWindowError(d, LoadScreen, err)
|
||||||
@@ -228,7 +228,7 @@ func (d *BaseDialog) Initialize() fyne.CanvasObject {
|
|||||||
LogWindowError(d, Initialize, err)
|
LogWindowError(d, Initialize, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
d.CanvasObj = obj
|
d.CanvasObj = obj.(*screen.DialogScreen).AsContainer()
|
||||||
}
|
}
|
||||||
return d.CanvasObj
|
return d.CanvasObj
|
||||||
}
|
}
|
||||||
@@ -256,6 +256,10 @@ func (d *BaseDialog) GetCanvasObject() fyne.CanvasObject {
|
|||||||
return d.CanvasObj
|
return d.CanvasObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d BaseDialog) PreventClose() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type FormDialogItemsFn func() []*widget.FormItem
|
type FormDialogItemsFn func() []*widget.FormItem
|
||||||
|
|
||||||
type FormDialog struct {
|
type FormDialog struct {
|
||||||
@@ -358,7 +362,7 @@ func (d *FormDialog) SetButtonLabels(
|
|||||||
|
|
||||||
func (d *FormDialog) Initialize() fyne.CanvasObject {
|
func (d *FormDialog) Initialize() fyne.CanvasObject {
|
||||||
if d.itemsFn == nil {
|
if d.itemsFn == nil {
|
||||||
form := d.BaseDialog.Initialize().(*screen.Screen).AsContainer()
|
form := d.BaseDialog.Initialize().(*fyne.Container)
|
||||||
d.itemsFn = func() []*widget.FormItem {
|
d.itemsFn = func() []*widget.FormItem {
|
||||||
res := make([]*widget.FormItem, 0, len(form.Objects)/2)
|
res := make([]*widget.FormItem, 0, len(form.Objects)/2)
|
||||||
for i := 0; i < len(form.Objects); i += 2 {
|
for i := 0; i < len(form.Objects); i += 2 {
|
||||||
|
4
go.mod
4
go.mod
@@ -1,11 +1,11 @@
|
|||||||
module bitbucket.org/hevanto/ui
|
module gitea.hevanto-it.com/hevanto/ui
|
||||||
|
|
||||||
go 1.22.1
|
go 1.22.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
bitbucket.org/hevanto/i18n v0.0.0-20240508095543-e6c69773011a
|
|
||||||
fyne.io/fyne/v2 v2.4.5
|
fyne.io/fyne/v2 v2.4.5
|
||||||
fyne.io/x/fyne v0.0.0-20240421102438-d5a080914907
|
fyne.io/x/fyne v0.0.0-20240421102438-d5a080914907
|
||||||
|
gitea.hevanto-it.com/hevanto/i18n v0.1.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
4
go.sum
4
go.sum
@@ -1,5 +1,3 @@
|
|||||||
bitbucket.org/hevanto/i18n v0.0.0-20240508095543-e6c69773011a h1:c2jY4iLeCeWGPX7gi92w21OPzeR2jwbPrb4G2FtsEpE=
|
|
||||||
bitbucket.org/hevanto/i18n v0.0.0-20240508095543-e6c69773011a/go.mod h1:H9tdjNHWWrrOOqOduC1WCTRLswAmjvxb19akWOef9EU=
|
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
@@ -43,6 +41,8 @@ fyne.io/fyne/v2 v2.4.5 h1:W6jpAEmLoBbKyBB+EXqI7GMJ7kLgHQWCa0wZHUV2VfQ=
|
|||||||
fyne.io/fyne/v2 v2.4.5/go.mod h1:SlOgbca0y80cRObu/JOhxIJdIgtoW7aCyqUVlTMgs0Y=
|
fyne.io/fyne/v2 v2.4.5/go.mod h1:SlOgbca0y80cRObu/JOhxIJdIgtoW7aCyqUVlTMgs0Y=
|
||||||
fyne.io/x/fyne v0.0.0-20240421102438-d5a080914907 h1:Ajr8gCMkVv6f7H2IPviMjfZCq40/+HrgWhAh/ZUOm/k=
|
fyne.io/x/fyne v0.0.0-20240421102438-d5a080914907 h1:Ajr8gCMkVv6f7H2IPviMjfZCq40/+HrgWhAh/ZUOm/k=
|
||||||
fyne.io/x/fyne v0.0.0-20240421102438-d5a080914907/go.mod h1:1pa3ZVIopRWNvfSG4ZrSkcZ3mJ8qoHPZv4PT8/zpn1o=
|
fyne.io/x/fyne v0.0.0-20240421102438-d5a080914907/go.mod h1:1pa3ZVIopRWNvfSG4ZrSkcZ3mJ8qoHPZv4PT8/zpn1o=
|
||||||
|
gitea.hevanto-it.com/hevanto/i18n v0.1.0 h1:SHsFugp1p+1a63MYrkXVAfgRp1zTSXWv3a6c/gU9Oy0=
|
||||||
|
gitea.hevanto-it.com/hevanto/i18n v0.1.0/go.mod h1:Ib85itweX6FuNHKFJNlMHglTq02TqaYdgvr4xDaQtQY=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package screen
|
package screen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/hevanto/ui/uiwidget"
|
"gitea.hevanto-it.com/hevanto/ui/uiwidget"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
|
@@ -3,7 +3,7 @@ package screen
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"bitbucket.org/hevanto/i18n"
|
"gitea.hevanto-it.com/hevanto/i18n"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -47,6 +47,11 @@ func (p *Padding) HasPadding() bool {
|
|||||||
return p.Top > 0 || p.Bottom > 0 || p.Left > 0 || p.Right > 0
|
return p.Top > 0 || p.Bottom > 0 || p.Left > 0 || p.Right > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ToolTip struct {
|
||||||
|
Content string `yaml:"content"`
|
||||||
|
Localized bool `yaml:"localized"`
|
||||||
|
}
|
||||||
|
|
||||||
// Element represents the yaml description of a ui element
|
// Element represents the yaml description of a ui element
|
||||||
type Element struct {
|
type Element struct {
|
||||||
ID string `yaml:"id"`
|
ID string `yaml:"id"`
|
||||||
@@ -97,6 +102,7 @@ type Element struct {
|
|||||||
Options map[string]any `yaml:"options"`
|
Options map[string]any `yaml:"options"`
|
||||||
Disabled bool `yaml:"disabled"`
|
Disabled bool `yaml:"disabled"`
|
||||||
Hidden bool `yaml:"hidden"`
|
Hidden bool `yaml:"hidden"`
|
||||||
|
ToolTip *ToolTip `yaml:"tooltip"`
|
||||||
|
|
||||||
// Properties shared by most widgets
|
// Properties shared by most widgets
|
||||||
Placeholder string `yaml:"placeholder"`
|
Placeholder string `yaml:"placeholder"`
|
||||||
|
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"bitbucket.org/hevanto/ui/uilayout"
|
"gitea.hevanto-it.com/hevanto/ui/uilayout"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package screen
|
package screen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/hevanto/ui/uilayout"
|
"gitea.hevanto-it.com/hevanto/ui/uilayout"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
)
|
)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package screen
|
package screen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/hevanto/ui/uilayout"
|
"gitea.hevanto-it.com/hevanto/ui/uilayout"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
)
|
)
|
||||||
|
@@ -133,8 +133,12 @@ func (s *Screen) Resize(sz fyne.Size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Screen) MinSize() fyne.Size {
|
||||||
|
return s.CanvasObject.MinSize()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Screen) CreateRenderer() fyne.WidgetRenderer {
|
func (s *Screen) CreateRenderer() fyne.WidgetRenderer {
|
||||||
return widget.NewSimpleRenderer(s.CanvasObject)
|
return widget.NewSimpleRenderer(s.AsContainer())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Screen) RegisterResizeCallback(cb func(fyne.Size)) {
|
func (s *Screen) RegisterResizeCallback(cb func(fyne.Size)) {
|
||||||
@@ -149,6 +153,42 @@ func (s *Screen) AsContainer() *fyne.Container {
|
|||||||
return s.CanvasObject.(*fyne.Container)
|
return s.CanvasObject.(*fyne.Container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DialogScreen struct {
|
||||||
|
*Screen
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDialogScreen(
|
||||||
|
filesystem embed.FS,
|
||||||
|
name string,
|
||||||
|
screenHandler ScreenHandler,
|
||||||
|
) (src *DialogScreen, err error) {
|
||||||
|
screen, err := New(filesystem, name, screenHandler)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
src = &DialogScreen{screen}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DialogScreen) Initialize() (obj fyne.CanvasObject, err error) {
|
||||||
|
if s.CanvasObject, err = s.rootElement.BuildUI(s.screenHandler); err != nil {
|
||||||
|
err = fmt.Errorf("failed to build screen: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obj = s
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DialogScreen) Move(p fyne.Position) {
|
||||||
|
c := fyne.CurrentApp().Driver().CanvasForObject(s.CanvasObject)
|
||||||
|
movePos := fyne.Position{
|
||||||
|
X: p.X / c.Scale(),
|
||||||
|
Y: p.Y / c.Scale(),
|
||||||
|
}
|
||||||
|
s.CanvasObject.Move(movePos)
|
||||||
|
//fmt.Printf("%+v\n", s.CanvasObject.Position());
|
||||||
|
}
|
||||||
|
|
||||||
type TemplateScreenHandler struct {
|
type TemplateScreenHandler struct {
|
||||||
localizer *i18n.Localizer
|
localizer *i18n.Localizer
|
||||||
elementsMap map[string]*UIElement
|
elementsMap map[string]*UIElement
|
||||||
|
@@ -7,7 +7,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"bitbucket.org/hevanto/ui/uiwidget"
|
"gitea.hevanto-it.com/hevanto/ui/uiwidget"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/data/binding"
|
"fyne.io/fyne/v2/data/binding"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
|
@@ -2,18 +2,34 @@ package ui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"bitbucket.org/hevanto/ui/screen"
|
"gitea.hevanto-it.com/hevanto/ui/screen"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/data/binding"
|
"fyne.io/fyne/v2/data/binding"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type screenType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
stScreen screenType = iota
|
||||||
|
stDialog
|
||||||
|
)
|
||||||
|
|
||||||
|
type ScreenDefinition interface {
|
||||||
|
fyne.Widget
|
||||||
|
Initialize() (fyne.CanvasObject, error)
|
||||||
|
RegisterResizeCallback(func(fyne.Size))
|
||||||
|
RegisterMoveCallback(func(fyne.Position))
|
||||||
|
AsContainer() *fyne.Container
|
||||||
|
}
|
||||||
|
|
||||||
// ScreenHandler represents the handler for a screen.
|
// ScreenHandler represents the handler for a screen.
|
||||||
//
|
//
|
||||||
// It provides:
|
// It provides:
|
||||||
@@ -24,7 +40,7 @@ import (
|
|||||||
// - List item templates and renderers
|
// - List item templates and renderers
|
||||||
// - User interaction handlers
|
// - User interaction handlers
|
||||||
type ScreenHandler struct {
|
type ScreenHandler struct {
|
||||||
screenDefinition *screen.Screen
|
screenDefinition ScreenDefinition
|
||||||
localizer *i18n.Localizer
|
localizer *i18n.Localizer
|
||||||
viewModel BaseViewModel
|
viewModel BaseViewModel
|
||||||
assetLoader func(string) (fs.File, error)
|
assetLoader func(string) (fs.File, error)
|
||||||
@@ -63,18 +79,48 @@ func NewScreenHandler(
|
|||||||
viewModel BaseViewModel,
|
viewModel BaseViewModel,
|
||||||
localizer *i18n.Localizer,
|
localizer *i18n.Localizer,
|
||||||
assetLoader func(string) (fs.File, error),
|
assetLoader func(string) (fs.File, error),
|
||||||
|
) (h *ScreenHandler, err error) {
|
||||||
|
return newScreenHandler(
|
||||||
|
stScreen, filesystem, screenName, viewModel, localizer, assetLoader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDialogScreenHandler(
|
||||||
|
filesystem embed.FS,
|
||||||
|
screenName string,
|
||||||
|
viewModel BaseViewModel,
|
||||||
|
localizer *i18n.Localizer,
|
||||||
|
assetLoader func(string) (fs.File, error),
|
||||||
|
) (h *ScreenHandler, err error) {
|
||||||
|
return newScreenHandler(
|
||||||
|
stDialog, filesystem, screenName, viewModel, localizer, assetLoader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newScreenHandler(
|
||||||
|
screenType screenType,
|
||||||
|
fileSystem embed.FS,
|
||||||
|
screenName string,
|
||||||
|
viewModel BaseViewModel,
|
||||||
|
localizer *i18n.Localizer,
|
||||||
|
assetLoader func(string) (fs.File, error),
|
||||||
) (h *ScreenHandler, err error) {
|
) (h *ScreenHandler, err error) {
|
||||||
h = new(ScreenHandler)
|
h = new(ScreenHandler)
|
||||||
|
|
||||||
h.viewModel = viewModel
|
h.viewModel = viewModel
|
||||||
h.localizer = localizer
|
h.localizer = localizer
|
||||||
|
|
||||||
def, err := screen.New(filesystem, screenName, h)
|
switch screenType {
|
||||||
|
case stScreen:
|
||||||
|
h.screenDefinition, err = screen.New(fileSystem, screenName, h)
|
||||||
|
case stDialog:
|
||||||
|
h.screenDefinition, err = screen.NewDialogScreen(fileSystem, screenName, h)
|
||||||
|
default:
|
||||||
|
err = errors.New("Unsupported screen type")
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("failure loading screen: %w", err)
|
err = fmt.Errorf("failure loading screen: %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.screenDefinition = def
|
|
||||||
h.assetLoader = assetLoader
|
h.assetLoader = assetLoader
|
||||||
|
|
||||||
h.exportedElements = make(map[string]*screen.UIElement)
|
h.exportedElements = make(map[string]*screen.UIElement)
|
||||||
@@ -93,7 +139,7 @@ func NewScreenHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ScreenDefinition returns the screen definition for the ScreenHandler.
|
// ScreenDefinition returns the screen definition for the ScreenHandler.
|
||||||
func (h *ScreenHandler) ScreenDefinition() *screen.Screen {
|
func (h *ScreenHandler) ScreenDefinition() ScreenDefinition {
|
||||||
return h.screenDefinition
|
return h.screenDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"bitbucket.org/hevanto/ui/uilayout"
|
"gitea.hevanto-it.com/hevanto/ui/uilayout"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
"fyne.io/fyne/v2/data/binding"
|
"fyne.io/fyne/v2/data/binding"
|
||||||
|
Reference in New Issue
Block a user