forked from fyne-io/fyne
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This new container is a replacement for container.NewBorder but without the footguns. There is a center item instead of a slcie of objects that act like a Stack container. The center item can optionally be nil also.
- Loading branch information
Showing
3 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package layout | ||
|
||
import ( | ||
"fyne.io/fyne/v2" | ||
"fyne.io/fyne/v2/theme" | ||
) | ||
|
||
// NewEdge creates a new edge layout instance with top, bottom, left, right | ||
// and center objects set. | ||
func NewEdge(top, bottom, left, right, center fyne.CanvasObject) fyne.Layout { | ||
return edgeLayout{top: top, bottom: bottom, left: left, right: right, center: center} | ||
} | ||
|
||
// Declare conformity with Layout interface | ||
var _ fyne.Layout = (*borderLayout)(nil) | ||
|
||
type edgeLayout struct { | ||
top, bottom, left, right, center fyne.CanvasObject | ||
} | ||
|
||
// Layout is called to pack all child objects into a specified size. | ||
// For BorderLayout this arranges the top, bottom, left and right widgets at | ||
// the sides and any remaining widgets are maximised in the middle space. | ||
func (b edgeLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { | ||
padding := theme.Padding() | ||
var topSize, bottomSize, leftSize, rightSize fyne.Size | ||
if b.top != nil && b.top.Visible() { | ||
topHeight := b.top.MinSize().Height | ||
b.top.Resize(fyne.NewSize(size.Width, topHeight)) | ||
b.top.Move(fyne.NewPos(0, 0)) | ||
topSize = fyne.NewSize(size.Width, topHeight+padding) | ||
} | ||
if b.bottom != nil && b.bottom.Visible() { | ||
bottomHeight := b.bottom.MinSize().Height | ||
b.bottom.Resize(fyne.NewSize(size.Width, bottomHeight)) | ||
b.bottom.Move(fyne.NewPos(0, size.Height-bottomHeight)) | ||
bottomSize = fyne.NewSize(size.Width, bottomHeight+padding) | ||
} | ||
if b.left != nil && b.left.Visible() { | ||
leftWidth := b.left.MinSize().Width | ||
b.left.Resize(fyne.NewSize(leftWidth, size.Height-topSize.Height-bottomSize.Height)) | ||
b.left.Move(fyne.NewPos(0, topSize.Height)) | ||
leftSize = fyne.NewSize(leftWidth+padding, size.Height-topSize.Height-bottomSize.Height) | ||
} | ||
if b.right != nil && b.right.Visible() { | ||
rightWidth := b.right.MinSize().Width | ||
b.right.Resize(fyne.NewSize(rightWidth, size.Height-topSize.Height-bottomSize.Height)) | ||
b.right.Move(fyne.NewPos(size.Width-rightWidth, topSize.Height)) | ||
rightSize = fyne.NewSize(rightWidth+padding, size.Height-topSize.Height-bottomSize.Height) | ||
} | ||
if b.center != nil && b.center.Visible() { | ||
middleSize := fyne.NewSize(size.Width-leftSize.Width-rightSize.Width, size.Height-topSize.Height-bottomSize.Height) | ||
middlePos := fyne.NewPos(leftSize.Width, topSize.Height) | ||
b.center.Resize(middleSize) | ||
b.center.Move(middlePos) | ||
} | ||
} | ||
|
||
// MinSize finds the smallest size that satisfies all the child objects. | ||
// For the edge layout, this is determined by the MinSize height of the top and | ||
// plus the MinSize width of the left and right, plus any padding needed. | ||
// This is then added to the union of the MinSize for any remaining content. | ||
func (b edgeLayout) MinSize(objects []fyne.CanvasObject) fyne.Size { | ||
padding := theme.Padding() | ||
|
||
var minSize fyne.Size | ||
if b.center != nil && b.center.Visible() { | ||
minSize = b.center.MinSize() | ||
} | ||
|
||
if b.left != nil && b.left.Visible() { | ||
leftMin := b.left.MinSize() | ||
minHeight := fyne.Max(minSize.Height, leftMin.Height) | ||
minSize = fyne.NewSize(minSize.Width+leftMin.Width+padding, minHeight) | ||
} | ||
if b.right != nil && b.right.Visible() { | ||
rightMin := b.right.MinSize() | ||
minHeight := fyne.Max(minSize.Height, rightMin.Height) | ||
minSize = fyne.NewSize(minSize.Width+rightMin.Width+padding, minHeight) | ||
} | ||
|
||
if b.top != nil && b.top.Visible() { | ||
topMin := b.top.MinSize() | ||
minWidth := fyne.Max(minSize.Width, topMin.Width) | ||
minSize = fyne.NewSize(minWidth, minSize.Height+topMin.Height+padding) | ||
} | ||
if b.bottom != nil && b.bottom.Visible() { | ||
bottomMin := b.bottom.MinSize() | ||
minWidth := fyne.Max(minSize.Width, bottomMin.Width) | ||
minSize = fyne.NewSize(minWidth, minSize.Height+bottomMin.Height+padding) | ||
} | ||
|
||
return minSize | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
package layout_test | ||
|
||
import ( | ||
"image/color" | ||
"testing" | ||
|
||
"fyne.io/fyne/v2" | ||
"fyne.io/fyne/v2/canvas" | ||
"fyne.io/fyne/v2/container" | ||
"fyne.io/fyne/v2/layout" | ||
_ "fyne.io/fyne/v2/test" | ||
"fyne.io/fyne/v2/theme" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNewEdgeContainer(t *testing.T) { | ||
top := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
top.SetMinSize(fyne.NewSize(10, 10)) | ||
right := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
right.SetMinSize(fyne.NewSize(10, 10)) | ||
middle := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
|
||
c := container.NewEdge(top, nil, nil, right, middle) | ||
assert.Equal(t, 3, len(c.Objects)) | ||
|
||
c.Resize(fyne.NewSize(100, 100)) | ||
assert.Equal(t, float32(0), top.Position().X) | ||
assert.Equal(t, float32(0), top.Position().Y) | ||
assert.Equal(t, float32(90), right.Position().X) | ||
assert.Equal(t, 10+theme.Padding(), right.Position().Y) | ||
assert.Equal(t, float32(0), middle.Position().X) | ||
assert.Equal(t, 10+theme.Padding(), middle.Position().Y) | ||
assert.Equal(t, 90-theme.Padding(), middle.Size().Width) | ||
assert.Equal(t, 90-theme.Padding(), middle.Size().Height) | ||
} | ||
|
||
func TestEdgeayout_Size_Empty(t *testing.T) { | ||
size := fyne.NewSize(100, 100) | ||
|
||
obj := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
container := &fyne.Container{ | ||
Objects: []fyne.CanvasObject{obj}, | ||
} | ||
container.Resize(size) | ||
|
||
layout.NewEdge(nil, nil, nil, nil, obj).Layout(container.Objects, size) | ||
|
||
assert.Equal(t, obj.Size(), size) | ||
} | ||
|
||
func TestEdgeLayout_Size_TopBottom(t *testing.T) { | ||
size := fyne.NewSize(100, 100) | ||
|
||
obj1 := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
obj2 := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
obj3 := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
|
||
container := &fyne.Container{ | ||
Objects: []fyne.CanvasObject{obj1, obj2, obj3}, | ||
} | ||
container.Resize(size) | ||
|
||
layout.NewEdge(obj1, obj2, nil, nil, obj3).Layout(container.Objects, size) | ||
|
||
innerSize := fyne.NewSize(size.Width, size.Height-obj1.Size().Height-obj2.Size().Height-theme.Padding()*2) | ||
assert.Equal(t, innerSize, obj3.Size()) | ||
assert.Equal(t, fyne.NewPos(0, 0), obj1.Position()) | ||
assert.Equal(t, fyne.NewPos(0, size.Height-obj2.Size().Height), obj2.Position()) | ||
assert.Equal(t, fyne.NewPos(0, obj1.Size().Height+theme.Padding()), obj3.Position()) | ||
} | ||
|
||
func TestEdgeLayout_Size_LeftRight(t *testing.T) { | ||
size := fyne.NewSize(100, 100) | ||
|
||
obj1 := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
obj2 := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
obj3 := canvas.NewRectangle(color.NRGBA{0, 0, 0, 0}) | ||
|
||
container := &fyne.Container{ | ||
Objects: []fyne.CanvasObject{obj1, obj2, obj3}, | ||
} | ||
container.Resize(size) | ||
|
||
layout.NewEdge(nil, nil, obj1, obj2, obj3).Layout(container.Objects, size) | ||
|
||
innerSize := fyne.NewSize(size.Width-obj1.Size().Width-obj2.Size().Width-theme.Padding()*2, size.Height) | ||
assert.Equal(t, innerSize, obj3.Size()) | ||
assert.Equal(t, fyne.NewPos(0, 0), obj1.Position()) | ||
assert.Equal(t, fyne.NewPos(size.Width-obj2.Size().Width, 0), obj2.Position()) | ||
assert.Equal(t, fyne.NewPos(obj1.Size().Width+theme.Padding(), 0), obj3.Position()) | ||
} | ||
|
||
func TestEdgeLayout_MinSize_Center(t *testing.T) { | ||
text := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
minSize := text.MinSize() | ||
|
||
container := container.NewWithoutLayout(text) | ||
layoutMin := layout.NewEdge(nil, nil, nil, nil, text).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} | ||
|
||
func TestEdgeLayout_MinSize_TopBottom(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text2 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text3 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
minSize := fyne.NewSize(text3.MinSize().Width, text1.MinSize().Height+text2.MinSize().Height+text3.MinSize().Height+theme.Padding()*2) | ||
|
||
container := container.NewWithoutLayout(text1, text2, text3) | ||
layoutMin := layout.NewEdge(text1, text2, nil, nil, text3).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} | ||
|
||
func TestEdgeLayout_MinSize_TopBottomHidden(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text1.Hide() | ||
text2 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text2.Hide() | ||
text3 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
|
||
container := container.NewWithoutLayout(text1, text2, text3) | ||
layoutMin := layout.NewEdge(text1, text2, nil, nil, text3).MinSize(container.Objects) | ||
|
||
assert.Equal(t, text1.MinSize(), layoutMin) | ||
} | ||
|
||
func TestEdgeLayout_MinSize_TopOnly(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
minSize := fyne.NewSize(text1.MinSize().Width, text1.MinSize().Height+theme.Padding()) | ||
|
||
container := container.NewWithoutLayout(text1) | ||
layoutMin := layout.NewEdge(text1, nil, nil, nil, nil).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} | ||
|
||
func TestEdgeLayout_MinSize_LeftRight(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text2 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text3 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
minSize := fyne.NewSize(text1.MinSize().Width+text2.MinSize().Width+text3.MinSize().Width+theme.Padding()*2, text3.MinSize().Height) | ||
|
||
container := container.NewWithoutLayout(text1, text2, text3) | ||
layoutMin := layout.NewEdge(nil, nil, text1, text2, text3).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} | ||
|
||
func TestEdgeLayout_MinSize_LeftRightHidden(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text1.Hide() | ||
text2 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
text2.Hide() | ||
text3 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
|
||
container := container.NewWithoutLayout(text1, text2, text3) | ||
layoutMin := layout.NewEdge(nil, nil, text1, text2, text3).MinSize(container.Objects) | ||
|
||
assert.Equal(t, text3.MinSize(), layoutMin) | ||
} | ||
|
||
func TestEdgeLayout_MinSize_LeftOnly(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.NRGBA{0, 0xff, 0, 0}) | ||
minSize := fyne.NewSize(text1.MinSize().Width+theme.Padding(), text1.MinSize().Height) | ||
|
||
container := container.NewWithoutLayout(text1) | ||
layoutMin := layout.NewEdge(nil, nil, text1, nil, nil).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} |