-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a borderlayout that positions items around the borders of the ava…
…ilable area
- Loading branch information
1 parent
5a0d95a
commit 0984f8b
Showing
2 changed files
with
168 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package layout | ||
|
||
import "github.com/fyne-io/fyne" | ||
import "github.com/fyne-io/fyne/theme" | ||
|
||
type borderLayout struct { | ||
top, bottom, left, right 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 *borderLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { | ||
var topSize, bottomSize, leftSize, rightSize fyne.Size | ||
if b.top != nil { | ||
b.top.Resize(fyne.NewSize(size.Width, b.top.MinSize().Height)) | ||
topSize = fyne.NewSize(size.Width, b.top.MinSize().Height+theme.Padding()) | ||
} | ||
if b.bottom != nil { | ||
b.bottom.Resize(fyne.NewSize(size.Width, b.bottom.MinSize().Height)) | ||
bottomSize = fyne.NewSize(size.Width, b.bottom.MinSize().Height+theme.Padding()) | ||
} | ||
if b.left != nil { | ||
b.left.Resize(fyne.NewSize(b.left.MinSize().Width, size.Height-topSize.Height-bottomSize.Height)) | ||
leftSize = fyne.NewSize(b.left.MinSize().Width+theme.Padding(), size.Height-topSize.Height-bottomSize.Height) | ||
} | ||
if b.right != nil { | ||
b.right.Resize(fyne.NewSize(b.right.MinSize().Width, size.Height-topSize.Height-bottomSize.Height)) | ||
rightSize = fyne.NewSize(b.right.MinSize().Width+theme.Padding(), size.Height-topSize.Height-bottomSize.Height) | ||
} | ||
|
||
middleSize := fyne.NewSize(size.Width-leftSize.Width-rightSize.Width, size.Height-topSize.Height-bottomSize.Height) | ||
for _, child := range objects { | ||
if child != b.top && child != b.bottom && child != b.left && child != b.right { | ||
child.Resize(middleSize) | ||
} | ||
} | ||
} | ||
|
||
// MinSize finds the smallest size that satisfies all the child objects. | ||
// For BorderLayout 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 *borderLayout) MinSize(objects []fyne.CanvasObject) fyne.Size { | ||
minSize := fyne.NewSize(0, 0) | ||
for _, child := range objects { | ||
if child != b.top && child != b.bottom && child != b.left && child != b.right { | ||
minSize = minSize.Union(child.MinSize()) | ||
} | ||
} | ||
|
||
if b.top != nil { | ||
minSize = minSize.Add(fyne.NewSize(0, b.top.MinSize().Height+theme.Padding())) | ||
} | ||
if b.bottom != nil { | ||
minSize = minSize.Add(fyne.NewSize(0, b.bottom.MinSize().Height+theme.Padding())) | ||
} | ||
if b.left != nil { | ||
minSize = minSize.Add(fyne.NewSize(b.left.MinSize().Width+theme.Padding(), 0)) | ||
} | ||
if b.right != nil { | ||
minSize = minSize.Add(fyne.NewSize(b.right.MinSize().Width+theme.Padding(), 0)) | ||
} | ||
|
||
return minSize | ||
} | ||
|
||
// NewBorderLayout creates a new BorderLayout instance with top, left, bottom | ||
// and right objects set. All other items in the container will fill the centre | ||
// space | ||
func NewBorderLayout(top, bottom, left, right fyne.CanvasObject) fyne.Layout { | ||
return &borderLayout{top, bottom, left, right} | ||
} |
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,95 @@ | ||
package layout | ||
|
||
import "testing" | ||
|
||
import "image/color" | ||
|
||
import "github.com/fyne-io/fyne" | ||
import "github.com/fyne-io/fyne/canvas" | ||
import "github.com/fyne-io/fyne/theme" | ||
|
||
import "github.com/stretchr/testify/assert" | ||
|
||
func TestBorderLayoutEmpty(t *testing.T) { | ||
size := fyne.NewSize(100, 100) | ||
|
||
obj := canvas.NewRectangle(color.RGBA{0, 0, 0, 0}) | ||
container := &fyne.Container{ | ||
Size: size, | ||
Objects: []fyne.CanvasObject{obj}, | ||
} | ||
|
||
NewBorderLayout(nil, nil, nil, nil).Layout(container.Objects, size) | ||
|
||
assert.Equal(t, obj.Size, size) | ||
} | ||
|
||
func TestBorderLayoutTopBottom(t *testing.T) { | ||
size := fyne.NewSize(100, 100) | ||
|
||
obj1 := canvas.NewRectangle(color.RGBA{0, 0, 0, 0}) | ||
obj2 := canvas.NewRectangle(color.RGBA{0, 0, 0, 0}) | ||
obj3 := canvas.NewRectangle(color.RGBA{0, 0, 0, 0}) | ||
|
||
container := &fyne.Container{ | ||
Size: size, | ||
Objects: []fyne.CanvasObject{obj1, obj2, obj3}, | ||
} | ||
|
||
NewBorderLayout(obj1, obj2, nil, nil).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) | ||
} | ||
|
||
func TestBorderLayoutLeftRight(t *testing.T) { | ||
size := fyne.NewSize(100, 100) | ||
|
||
obj1 := canvas.NewRectangle(color.RGBA{0, 0, 0, 0}) | ||
obj2 := canvas.NewRectangle(color.RGBA{0, 0, 0, 0}) | ||
obj3 := canvas.NewRectangle(color.RGBA{0, 0, 0, 0}) | ||
|
||
container := &fyne.Container{ | ||
Size: size, | ||
Objects: []fyne.CanvasObject{obj1, obj2, obj3}, | ||
} | ||
|
||
NewBorderLayout(nil, nil, obj1, obj2).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) | ||
} | ||
|
||
func TestBorderCenterLayoutMinSize(t *testing.T) { | ||
text := canvas.NewText("Padding", color.RGBA{0, 0xff, 0, 0}) | ||
minSize := text.MinSize() | ||
|
||
container := fyne.NewContainer(text) | ||
layoutMin := NewBorderLayout(nil, nil, nil, nil).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} | ||
|
||
func TestBorderTopBottomLayoutMinSize(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.RGBA{0, 0xff, 0, 0}) | ||
text2 := canvas.NewText("Padding", color.RGBA{0, 0xff, 0, 0}) | ||
text3 := canvas.NewText("Padding", color.RGBA{0, 0xff, 0, 0}) | ||
minSize := fyne.NewSize(text3.MinSize().Width, text1.MinSize().Height+text2.MinSize().Height+text3.MinSize().Height+theme.Padding()*2) | ||
|
||
container := fyne.NewContainer(text1, text2, text3) | ||
layoutMin := NewBorderLayout(text1, text2, nil, nil).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} | ||
|
||
func TestBorderLeftRightLayoutMinSize(t *testing.T) { | ||
text1 := canvas.NewText("Padding", color.RGBA{0, 0xff, 0, 0}) | ||
text2 := canvas.NewText("Padding", color.RGBA{0, 0xff, 0, 0}) | ||
text3 := canvas.NewText("Padding", color.RGBA{0, 0xff, 0, 0}) | ||
minSize := fyne.NewSize(text1.MinSize().Width+text2.MinSize().Width+text3.MinSize().Width+theme.Padding()*2, text3.MinSize().Height) | ||
|
||
container := fyne.NewContainer(text1, text2, text3) | ||
layoutMin := NewBorderLayout(nil, nil, text1, text2).MinSize(container.Objects) | ||
|
||
assert.Equal(t, minSize, layoutMin) | ||
} |