forked from joejulian/gio
io/pointer: [API] split scroll bounds into two separate axes
A single image.Rectangle for the scroll bounds introduced a subtle issue with zero area rectangles (see #572). To avoid that and similar issues, split the bounds into two separate one-dimensional ranges. Fixes: https://todo.sr.ht/~eliasnaur/gio/572 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -251,9 +251,10 @@ func TestFocusScroll(t *testing.T) {
|
||||
filters := []event.Filter{
|
||||
key.FocusFilter{Target: h},
|
||||
pointer.Filter{
|
||||
Target: h,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollBounds: image.Rect(-100, -100, 100, 100),
|
||||
Target: h,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollX: pointer.ScrollRange{Min: -100, Max: +100},
|
||||
ScrollY: pointer.ScrollRange{Min: -100, Max: +100},
|
||||
},
|
||||
}
|
||||
events(r, -1, filters...)
|
||||
|
||||
+7
-5
@@ -72,7 +72,7 @@ type pointerHandler struct {
|
||||
type pointerFilter struct {
|
||||
kinds pointer.Kind
|
||||
// min and max horizontal/vertical scroll
|
||||
scrollRange image.Rectangle
|
||||
scrollX, scrollY pointer.ScrollRange
|
||||
|
||||
sourceMimes []string
|
||||
targetMimes []string
|
||||
@@ -297,7 +297,8 @@ func (p *pointerFilter) Add(f event.Filter) {
|
||||
p.targetMimes = append(p.targetMimes, f.Type)
|
||||
case pointer.Filter:
|
||||
p.kinds = p.kinds | f.Kinds
|
||||
p.scrollRange = p.scrollRange.Union(f.ScrollBounds)
|
||||
p.scrollX = p.scrollX.Union(f.ScrollX)
|
||||
p.scrollY = p.scrollY.Union(f.ScrollY)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +326,8 @@ func (p *pointerFilter) Matches(e event.Event) bool {
|
||||
|
||||
func (p *pointerFilter) Merge(p2 pointerFilter) {
|
||||
p.kinds = p.kinds | p2.kinds
|
||||
p.scrollRange = p.scrollRange.Union(p2.scrollRange)
|
||||
p.scrollX = p.scrollX.Union(p2.scrollX)
|
||||
p.scrollY = p.scrollY.Union(p2.scrollY)
|
||||
p.sourceMimes = append(p.sourceMimes, p2.sourceMimes...)
|
||||
p.targetMimes = append(p.targetMimes, p2.targetMimes...)
|
||||
}
|
||||
@@ -333,8 +335,8 @@ func (p *pointerFilter) Merge(p2 pointerFilter) {
|
||||
// clampScroll splits a scroll distance in the remaining scroll and the
|
||||
// scroll accepted by the filter.
|
||||
func (p *pointerFilter) clampScroll(scroll f32.Point) (left, scrolled f32.Point) {
|
||||
left.X, scrolled.X = clampSplit(scroll.X, p.scrollRange.Min.X, p.scrollRange.Max.X)
|
||||
left.Y, scrolled.Y = clampSplit(scroll.Y, p.scrollRange.Min.Y, p.scrollRange.Max.Y)
|
||||
left.X, scrolled.X = clampSplit(scroll.X, p.scrollX.Min, p.scrollX.Max)
|
||||
left.Y, scrolled.Y = clampSplit(scroll.Y, p.scrollY.Min, p.scrollY.Max)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -300,9 +300,9 @@ func TestPointerPriority(t *testing.T) {
|
||||
r1 := clip.Rect(image.Rect(0, 0, 100, 100)).Push(&ops)
|
||||
f1 := func(t event.Tag) event.Filter {
|
||||
return pointer.Filter{
|
||||
Target: t,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollBounds: image.Rectangle{Max: image.Point{X: 100}},
|
||||
Target: t,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollX: pointer.ScrollRange{Max: 100},
|
||||
}
|
||||
}
|
||||
events(&r, -1, f1(handler1))
|
||||
@@ -311,9 +311,9 @@ func TestPointerPriority(t *testing.T) {
|
||||
r2 := clip.Rect(image.Rect(0, 0, 100, 50)).Push(&ops)
|
||||
f2 := func(t event.Tag) event.Filter {
|
||||
return pointer.Filter{
|
||||
Target: t,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollBounds: image.Rectangle{Max: image.Point{X: 20}},
|
||||
Target: t,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollX: pointer.ScrollRange{Max: 20},
|
||||
}
|
||||
}
|
||||
events(&r, -1, f2(handler2))
|
||||
@@ -324,9 +324,10 @@ func TestPointerPriority(t *testing.T) {
|
||||
r3 := clip.Rect(image.Rect(0, 100, 100, 200)).Push(&ops)
|
||||
f3 := func(t event.Tag) event.Filter {
|
||||
return pointer.Filter{
|
||||
Target: t,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollBounds: image.Rectangle{Min: image.Point{X: -20, Y: -40}},
|
||||
Target: t,
|
||||
Kinds: pointer.Scroll,
|
||||
ScrollX: pointer.ScrollRange{Min: -20},
|
||||
ScrollY: pointer.ScrollRange{Min: -40},
|
||||
}
|
||||
}
|
||||
events(&r, -1, f3(handler3))
|
||||
|
||||
+19
-6
@@ -3,7 +3,6 @@
|
||||
package pointer
|
||||
|
||||
import (
|
||||
"image"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -61,12 +60,19 @@ type Filter struct {
|
||||
Target event.Tag
|
||||
// Kinds is a bitwise-or of event types to match.
|
||||
Kinds Kind
|
||||
// ScrollBounds describe the maximum scrollable distances in both
|
||||
// axes. Specifically, any Event e delivered to Tag will satisfy
|
||||
// ScrollX and ScrollY constrain the range of scrolling events delivered
|
||||
// to Target. Specifically, any Event e delivered to Tag will satisfy
|
||||
//
|
||||
// ScrollBounds.Min.X <= e.Scroll.X <= ScrollBounds.Max.X (horizontal axis)
|
||||
// ScrollBounds.Min.Y <= e.Scroll.Y <= ScrollBounds.Max.Y (vertical axis)
|
||||
ScrollBounds image.Rectangle
|
||||
// ScrollX.Min <= e.Scroll.X <= ScrollX.Max (horizontal axis)
|
||||
// ScrollY.Min <= e.Scroll.Y <= ScrollY.Max (vertical axis)
|
||||
ScrollX ScrollRange
|
||||
ScrollY ScrollRange
|
||||
}
|
||||
|
||||
// ScrollRange describes the range of scrolling distances in an
|
||||
// axis.
|
||||
type ScrollRange struct {
|
||||
Min, Max int
|
||||
}
|
||||
|
||||
// GrabCmd requests a pointer grab on the pointer identified by ID.
|
||||
@@ -219,6 +225,13 @@ const (
|
||||
ButtonTertiary
|
||||
)
|
||||
|
||||
func (s ScrollRange) Union(s2 ScrollRange) ScrollRange {
|
||||
return ScrollRange{
|
||||
Min: min(s.Min, s2.Min),
|
||||
Max: max(s.Max, s2.Max),
|
||||
}
|
||||
}
|
||||
|
||||
// Push the current pass mode to the pass stack and set the pass mode.
|
||||
func (p PassOp) Push(o *op.Ops) PassStack {
|
||||
id, mid := ops.PushOp(&o.Internal, ops.PassStack)
|
||||
|
||||
Reference in New Issue
Block a user