Added scroll container and minsize layout
This commit is contained in:
		
							
								
								
									
										93
									
								
								screen/container.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								screen/container.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | package screen | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"bitbucket.org/hevanto/ui/uiwidget" | ||||||
|  | 	"fyne.io/fyne/v2" | ||||||
|  | 	"fyne.io/fyne/v2/container" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Container string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	HScroll Container = "HScroll" | ||||||
|  | 	Scroll  Container = "Scroll" | ||||||
|  | 	VScroll Container = "VScroll" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (cnt Container) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||||
|  | 	switch cnt { | ||||||
|  | 	case HScroll: | ||||||
|  | 		c, err = cnt.buildHScrollContainer(e, s) | ||||||
|  | 	case Scroll: | ||||||
|  | 		c, err = cnt.buildScrollContainer(e, s) | ||||||
|  | 	case VScroll: | ||||||
|  | 		c, err = cnt.buildVScrollContainer(e, s) | ||||||
|  | 	default: | ||||||
|  | 		err = errors.New("invalid container") | ||||||
|  | 	} | ||||||
|  | 	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 (ctn Container) buildHScrollContainer(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||||
|  | 	if e.Content == nil { | ||||||
|  | 		err = errors.New("HScroll: no content defined") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	content, err := e.Content.BuildUI(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		err = fmt.Errorf("HScroll: failed to build content: %w", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	c = container.NewHScroll(content) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	content, err := e.Content.BuildUI(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		err = fmt.Errorf("Scroll: failed to build content: %w", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	c = container.NewScroll(content) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	content, err := e.Content.BuildUI(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		err = fmt.Errorf("VScroll: failed to build content: %w", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	c = container.NewScroll(content) | ||||||
|  | 	return | ||||||
|  | } | ||||||
| @@ -15,8 +15,9 @@ type Size struct { | |||||||
| type Element struct { | type Element struct { | ||||||
| 	ID string `yaml:"id"` | 	ID string `yaml:"id"` | ||||||
|  |  | ||||||
| 	Layout Layout `yaml:"layout"` | 	Container Container `yaml:"container"` | ||||||
| 	Widget Widget `yaml:"widget"` | 	Layout    Layout    `yaml:"layout"` | ||||||
|  | 	Widget    Widget    `yaml:"widget"` | ||||||
|  |  | ||||||
| 	// Border Layout Elements | 	// Border Layout Elements | ||||||
| 	Top    *Element   `yaml:"top"` | 	Top    *Element   `yaml:"top"` | ||||||
| @@ -27,6 +28,7 @@ type Element struct { | |||||||
|  |  | ||||||
| 	// Other Layout Elements | 	// Other Layout Elements | ||||||
| 	Children []*Element `yaml:"children"` | 	Children []*Element `yaml:"children"` | ||||||
|  | 	Content  *Element   `yaml:"content"` | ||||||
|  |  | ||||||
| 	// Form Element | 	// Form Element | ||||||
| 	Label *Element `yaml:"label"` | 	Label *Element `yaml:"label"` | ||||||
| @@ -38,6 +40,9 @@ type Element struct { | |||||||
| 	RowColumns  *int  `yaml:"rowColumns"` | 	RowColumns  *int  `yaml:"rowColumns"` | ||||||
| 	ElementSize *Size `yaml:"elementSize"` | 	ElementSize *Size `yaml:"elementSize"` | ||||||
|  |  | ||||||
|  | 	// MinSize configuration | ||||||
|  | 	MinSize *Size `yaml:"minSize"` | ||||||
|  |  | ||||||
| 	// Widget Properties | 	// Widget Properties | ||||||
| 	Text       string         `yaml:"text"` | 	Text       string         `yaml:"text"` | ||||||
| 	Localized  bool           `yaml:"localized"` | 	Localized  bool           `yaml:"localized"` | ||||||
| @@ -81,6 +86,13 @@ func (e *Element) BuildUI(s ScreenHandler) (obj fyne.CanvasObject, err error) { | |||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
|  | 	if e.Container != "" { | ||||||
|  | 		if 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 e.Layout != "" { | ||||||
| 		if obj, err = e.Layout.Build(e, s); err != nil { | 		if obj, err = e.Layout.Build(e, s); err != nil { | ||||||
| 			err = fmt.Errorf("failed to build layout element: %w", err) | 			err = fmt.Errorf("failed to build layout element: %w", err) | ||||||
|   | |||||||
| @@ -4,6 +4,8 @@ import ( | |||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"bitbucket.org/hevanto/ui/uilayout" | ||||||
|  | 	"bitbucket.org/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" | ||||||
| @@ -12,15 +14,16 @@ import ( | |||||||
| type Layout string | type Layout string | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	Border Layout = "Border" | 	Border  Layout = "Border" | ||||||
| 	Form   Layout = "Form" | 	Form    Layout = "Form" | ||||||
| 	Grid   Layout = "Grid" | 	Grid    Layout = "Grid" | ||||||
| 	HBox   Layout = "HBox" | 	HBox    Layout = "HBox" | ||||||
| 	Stack  Layout = "Stack" | 	MinSize Layout = "MinSize" | ||||||
| 	VBox   Layout = "VBox" | 	Stack   Layout = "Stack" | ||||||
|  | 	VBox    Layout = "VBox" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func (l Layout) Build(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | func (l Layout) Build(e *Element, s ScreenHandler) (c fyne.CanvasObject, err error) { | ||||||
| 	switch l { | 	switch l { | ||||||
| 	case Border: | 	case Border: | ||||||
| 		c, err = l.buildBorderLayout(e, s) | 		c, err = l.buildBorderLayout(e, s) | ||||||
| @@ -30,6 +33,8 @@ func (l Layout) Build(e *Element, s ScreenHandler) (c *fyne.Container, err error | |||||||
| 		c, err = l.buildGridLayout(e, s) | 		c, err = l.buildGridLayout(e, s) | ||||||
| 	case HBox: | 	case HBox: | ||||||
| 		c, err = l.buildHBoxLayout(e, s) | 		c, err = l.buildHBoxLayout(e, s) | ||||||
|  | 	case MinSize: | ||||||
|  | 		c, err = l.buildMinSizeLayout(e, s) | ||||||
| 	case Stack: | 	case Stack: | ||||||
| 		c, err = l.buildStackLayout(e, s) | 		c, err = l.buildStackLayout(e, s) | ||||||
| 	case VBox: | 	case VBox: | ||||||
| @@ -41,6 +46,15 @@ func (l Layout) Build(e *Element, s ScreenHandler) (c *fyne.Container, err error | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if e.Decorators != nil { | ||||||
|  | 		for _, dec := range e.Decorators { | ||||||
|  | 			switch dec { | ||||||
|  | 			case "Border": | ||||||
|  | 				c = uiwidget.NewWidgetBorder(c) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if e.Hidden { | 	if e.Hidden { | ||||||
| 		c.Hide() | 		c.Hide() | ||||||
| 	} | 	} | ||||||
| @@ -179,6 +193,29 @@ func (l Layout) buildHBoxLayout(e *Element, s ScreenHandler) (c *fyne.Container, | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (l Layout) buildMinSizeLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||||
|  | 	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("MinSizeLayout failed to create child element: %w", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		children = append(children, obj) | ||||||
|  | 	} | ||||||
|  | 	if e.MinSize == nil { | ||||||
|  | 		e.MinSize = &Size{ | ||||||
|  | 			Width:  0, | ||||||
|  | 			Height: 0, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	c = container.New( | ||||||
|  | 		uilayout.NewMinSizeLayout( | ||||||
|  | 			fyne.NewSize(e.MinSize.Width, e.MinSize.Height)), | ||||||
|  | 		children...) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
| func (l Layout) buildStackLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | func (l Layout) buildStackLayout(e *Element, s ScreenHandler) (c *fyne.Container, err error) { | ||||||
| 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | 	children := make([]fyne.CanvasObject, 0, len(e.Children)) | ||||||
| 	for _, child := range e.Children { | 	for _, child := range e.Children { | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								uilayout/minsize.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								uilayout/minsize.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | package uilayout | ||||||
|  |  | ||||||
|  | import "fyne.io/fyne/v2" | ||||||
|  |  | ||||||
|  | type MinSize struct { | ||||||
|  | 	minSize fyne.Size | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewMinSizeLayout(minSize fyne.Size) *MinSize { | ||||||
|  | 	return &MinSize{minSize: minSize} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *MinSize) MinSize(objects []fyne.CanvasObject) fyne.Size { | ||||||
|  | 	size := l.minSize | ||||||
|  | 	for _, o := range objects { | ||||||
|  | 		childSize := o.MinSize() | ||||||
|  | 		if size.Width < childSize.Width { | ||||||
|  | 			size.Width = childSize.Width | ||||||
|  | 		} | ||||||
|  | 		if size.Height < childSize.Height { | ||||||
|  | 			size.Height = childSize.Height | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return size | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *MinSize) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) { | ||||||
|  | 	pos := fyne.NewPos(0, 0) | ||||||
|  | 	for _, o := range objects { | ||||||
|  | 		o.Resize(containerSize) | ||||||
|  | 		o.Move(pos) | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Maarten Heremans
					Maarten Heremans