forked from fyne-io/fyne
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for clipping items within clipped items (scroll containers)
Fixes fyne-io#1682
- Loading branch information
1 parent
29f4dd4
commit f76b648
Showing
6 changed files
with
174 additions
and
25 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,81 @@ | ||
package internal | ||
|
||
import "fyne.io/fyne" | ||
|
||
// ClipStack keeps track of the areas that should be clipped when drawing a canvas. | ||
// If no clips are present then adding one will be added as-is. | ||
// Subsequent items pushed will be completely within the previous clip. | ||
type ClipStack struct { | ||
clips []*ClipItem | ||
} | ||
|
||
// Pop removes the current top clip and returns it. | ||
func (c *ClipStack) Pop() *ClipItem { | ||
if len(c.clips) == 0 { | ||
return nil | ||
} | ||
|
||
ret := c.clips[len(c.clips)-1] | ||
c.clips = c.clips[:len(c.clips)-1] | ||
return ret | ||
} | ||
|
||
// Length returns the number of items in this clip stack. 0 means no clip. | ||
func (c *ClipStack) Length() int { | ||
return len(c.clips) | ||
} | ||
|
||
// Push a new clip onto this stack at position and size specified. | ||
// The returned clip item is the result of calculating the intersection of the requested clip and it's parent. | ||
func (c *ClipStack) Push(p fyne.Position, s fyne.Size) *ClipItem { | ||
outer := c.Top() | ||
inner := outer.Intersect(p, s) | ||
|
||
c.clips = append(c.clips, inner) | ||
return inner | ||
} | ||
|
||
// Top returns the current clip item - it will always be within the bounds of any parent clips. | ||
func (c *ClipStack) Top() *ClipItem { | ||
if len(c.clips) == 0 { | ||
return nil | ||
} | ||
|
||
return c.clips[len(c.clips)-1] | ||
} | ||
|
||
// ClipItem represents a single clip in a clip stack, denoted by a size and position. | ||
type ClipItem struct { | ||
pos fyne.Position | ||
size fyne.Size | ||
} | ||
|
||
// Rect returns the position and size parameters of the clip. | ||
func (i *ClipItem) Rect() (fyne.Position, fyne.Size) { | ||
return i.pos, i.size | ||
} | ||
|
||
// Intersect returns a new clip item that is the intersection of the requested parameters and this clip. | ||
func (i *ClipItem) Intersect(p fyne.Position, s fyne.Size) *ClipItem { | ||
ret := &ClipItem{p, s} | ||
if i == nil { | ||
return ret | ||
} | ||
|
||
if ret.pos.X < i.pos.X { | ||
ret.pos.X = i.pos.X | ||
ret.size.Width -= i.pos.X - p.X | ||
} | ||
if ret.pos.Y < i.pos.Y { | ||
ret.pos.Y = i.pos.Y | ||
ret.size.Height -= i.pos.Y - p.Y | ||
} | ||
|
||
if p.X+s.Width > i.pos.X+i.size.Width { | ||
ret.size.Width = (i.pos.X + i.size.Width) - ret.pos.X | ||
} | ||
if p.Y+s.Height > i.pos.Y+i.size.Height { | ||
ret.size.Height = (i.pos.Y + i.size.Height) - ret.pos.Y | ||
} | ||
return ret | ||
} |
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,62 @@ | ||
package internal | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"fyne.io/fyne" | ||
) | ||
|
||
func TestClipStack_Intersect(t *testing.T) { | ||
p1 := fyne.NewPos(5, 25) | ||
s1 := fyne.NewSize(100, 100) | ||
c := &ClipStack{ | ||
clips: []*ClipItem{ | ||
{p1, s1}, | ||
}, | ||
} | ||
|
||
p2 := fyne.NewPos(25, 0) | ||
s2 := fyne.NewSize(50, 50) | ||
i := c.Push(p2, s2) | ||
|
||
assert.Equal(t, fyne.NewPos(25, 25), i.pos) | ||
assert.Equal(t, fyne.NewSize(50, 25), i.size) | ||
assert.Equal(t, 2, len(c.clips)) | ||
|
||
_ = c.Pop() | ||
p2 = fyne.NewPos(50, 50) | ||
s2 = fyne.NewSize(150, 50) | ||
i = c.Push(p2, s2) | ||
|
||
assert.Equal(t, fyne.NewPos(50, 50), i.pos) | ||
assert.Equal(t, fyne.NewSize(55, 50), i.size) | ||
assert.Equal(t, 2, len(c.clips)) | ||
} | ||
|
||
func TestClipStack_Pop(t *testing.T) { | ||
p := fyne.NewPos(5, 5) | ||
s := fyne.NewSize(100, 100) | ||
c := &ClipStack{ | ||
clips: []*ClipItem{ | ||
{p, s}, | ||
}, | ||
} | ||
|
||
i := c.Pop() | ||
assert.Equal(t, p, i.pos) | ||
assert.Equal(t, s, i.size) | ||
assert.Equal(t, 0, len(c.clips)) | ||
} | ||
|
||
func TestClipStack_Push(t *testing.T) { | ||
c := &ClipStack{} | ||
p := fyne.NewPos(5, 5) | ||
s := fyne.NewSize(100, 100) | ||
|
||
i := c.Push(p, s) | ||
assert.Equal(t, p, i.pos) | ||
assert.Equal(t, s, i.size) | ||
assert.Equal(t, 1, len(c.clips)) | ||
} |
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
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