forked from joejulian/gio
io/pointer: re-introduce PassOp
A previous change merged PassOp with AreaOp under the assumption that
the pass mode would be set on a particular area. That assumption turns
out not to hold, so this change brings back PassOp as an independent
stack operation.
This is an API change: replace AreaOp{Pass: true} with a separate
pointer.PassOp operation.
Fixes gio#288
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+13
-2
@@ -23,7 +23,7 @@ type Ops struct {
|
||||
nextStateID int
|
||||
|
||||
macroStack stack
|
||||
stacks [3]stack
|
||||
stacks [4]stack
|
||||
}
|
||||
|
||||
type OpType byte
|
||||
@@ -45,6 +45,8 @@ const (
|
||||
TypeLinearGradient
|
||||
TypeArea
|
||||
TypePopArea
|
||||
TypePass
|
||||
TypePopPass
|
||||
TypePointerInput
|
||||
TypeClipboardRead
|
||||
TypeClipboardWrite
|
||||
@@ -88,6 +90,7 @@ const (
|
||||
ClipStack StackKind = iota
|
||||
AreaStack
|
||||
TransStack
|
||||
PassStack
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -102,8 +105,10 @@ const (
|
||||
TypePaintLen = 1
|
||||
TypeColorLen = 1 + 4
|
||||
TypeLinearGradientLen = 1 + 8*2 + 4*2
|
||||
TypeAreaLen = 1 + 1 + 1 + 4*4
|
||||
TypeAreaLen = 1 + 1 + 4*4
|
||||
TypePopAreaLen = 1
|
||||
TypePassLen = 1
|
||||
TypePopPassLen = 1
|
||||
TypePointerInputLen = 1 + 1 + 1 + 2*4 + 2*4
|
||||
TypeClipboardReadLen = 1
|
||||
TypeClipboardWriteLen = 1
|
||||
@@ -313,6 +318,8 @@ func (t OpType) Size() int {
|
||||
TypeLinearGradientLen,
|
||||
TypeAreaLen,
|
||||
TypePopAreaLen,
|
||||
TypePassLen,
|
||||
TypePopPassLen,
|
||||
TypePointerInputLen,
|
||||
TypeClipboardReadLen,
|
||||
TypeClipboardWriteLen,
|
||||
@@ -370,6 +377,10 @@ func (t OpType) String() string {
|
||||
return "Area"
|
||||
case TypePopArea:
|
||||
return "PopArea"
|
||||
case TypePass:
|
||||
return "Pass"
|
||||
case TypePopPass:
|
||||
return "PopPass"
|
||||
case TypePointerInput:
|
||||
return "PointerInput"
|
||||
case TypeClipboardRead:
|
||||
|
||||
+32
-14
@@ -42,14 +42,9 @@ type Event struct {
|
||||
Modifiers key.Modifiers
|
||||
}
|
||||
|
||||
// AreaOp updates the hit area to the intersection of the current
|
||||
// hit area and the area. The area is transformed before applying
|
||||
// it.
|
||||
// AreaOp pushes the current hit area to the stack and updates it to the
|
||||
// intersection of the current hit area and the transformed area.
|
||||
type AreaOp struct {
|
||||
// PassThrough areas and their children don't block events to siblings
|
||||
// them.
|
||||
PassThrough bool
|
||||
|
||||
kind areaKind
|
||||
rect image.Rectangle
|
||||
}
|
||||
@@ -61,6 +56,18 @@ type AreaStack struct {
|
||||
macroID int
|
||||
}
|
||||
|
||||
// PassOp sets the pass-through mode. AreaOps added while the pass-through
|
||||
// mode is set don't block events to siblings.
|
||||
type PassOp struct {
|
||||
}
|
||||
|
||||
// PassStack represents a PassOp on the pass stack.
|
||||
type PassStack struct {
|
||||
ops *ops.Ops
|
||||
id ops.StackID
|
||||
macroID int
|
||||
}
|
||||
|
||||
// CursorNameOp sets the cursor for the current area.
|
||||
type CursorNameOp struct {
|
||||
Name CursorName
|
||||
@@ -204,14 +211,11 @@ func (a AreaOp) add(o *op.Ops, push bool) {
|
||||
data := o.Internal.Write(ops.TypeAreaLen)
|
||||
data[0] = byte(ops.TypeArea)
|
||||
data[1] = byte(a.kind)
|
||||
if a.PassThrough {
|
||||
data[2] = 1
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
bo.PutUint32(data[3:], uint32(a.rect.Min.X))
|
||||
bo.PutUint32(data[7:], uint32(a.rect.Min.Y))
|
||||
bo.PutUint32(data[11:], uint32(a.rect.Max.X))
|
||||
bo.PutUint32(data[15:], uint32(a.rect.Max.Y))
|
||||
bo.PutUint32(data[2:], uint32(a.rect.Min.X))
|
||||
bo.PutUint32(data[6:], uint32(a.rect.Min.Y))
|
||||
bo.PutUint32(data[10:], uint32(a.rect.Max.X))
|
||||
bo.PutUint32(data[14:], uint32(a.rect.Max.Y))
|
||||
}
|
||||
|
||||
func (o AreaStack) Pop() {
|
||||
@@ -220,6 +224,20 @@ func (o AreaStack) Pop() {
|
||||
data[0] = byte(ops.TypePopArea)
|
||||
}
|
||||
|
||||
// Push the current pass mode to the pass stack and set the pass mode.
|
||||
func (p PassOp) Push(o *op.Ops) PassStack {
|
||||
id, mid := o.Internal.PushOp(ops.PassStack)
|
||||
data := o.Internal.Write(ops.TypePassLen)
|
||||
data[0] = byte(ops.TypePass)
|
||||
return PassStack{ops: &o.Internal, id: id, macroID: mid}
|
||||
}
|
||||
|
||||
func (p PassStack) Pop() {
|
||||
p.ops.PopOp(ops.PassStack, p.id, p.macroID)
|
||||
data := p.ops.Write(ops.TypePopPassLen)
|
||||
data[0] = byte(ops.TypePopPass)
|
||||
}
|
||||
|
||||
func (op CursorNameOp) Add(o *op.Ops) {
|
||||
data := o.Internal.Write1(ops.TypeCursorLen, op.Name)
|
||||
data[0] = byte(ops.TypeCursor)
|
||||
|
||||
+10
-8
@@ -64,7 +64,6 @@ type pointerHandler struct {
|
||||
}
|
||||
|
||||
type areaOp struct {
|
||||
pass bool
|
||||
kind areaKind
|
||||
rect f32.Rectangle
|
||||
}
|
||||
@@ -82,7 +81,7 @@ type areaKind uint8
|
||||
type collectState struct {
|
||||
t f32.Affine2D
|
||||
node int
|
||||
pass bool
|
||||
pass int
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -122,7 +121,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
|
||||
n := q.hitTree[i]
|
||||
area = n.area
|
||||
}
|
||||
q.areas = append(q.areas, areaNode{trans: state.t, next: area, area: op, pass: op.pass})
|
||||
q.areas = append(q.areas, areaNode{trans: state.t, next: area, area: op, pass: state.pass > 0})
|
||||
q.nodeStack = append(q.nodeStack, state.node)
|
||||
q.hitTree = append(q.hitTree, hitNode{
|
||||
next: state.node,
|
||||
@@ -133,6 +132,10 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
|
||||
n := len(q.nodeStack)
|
||||
state.node = q.nodeStack[n-1]
|
||||
q.nodeStack = q.nodeStack[:n-1]
|
||||
case ops.TypePass:
|
||||
state.pass++
|
||||
case ops.TypePopPass:
|
||||
state.pass--
|
||||
case ops.TypeTransform:
|
||||
dop, push := ops.DecodeTransform(encOp.Data)
|
||||
if push {
|
||||
@@ -480,18 +483,17 @@ func (op *areaOp) Decode(d []byte) {
|
||||
}
|
||||
rect := f32.Rectangle{
|
||||
Min: f32.Point{
|
||||
X: opDecodeFloat32(d[3:]),
|
||||
Y: opDecodeFloat32(d[7:]),
|
||||
X: opDecodeFloat32(d[2:]),
|
||||
Y: opDecodeFloat32(d[6:]),
|
||||
},
|
||||
Max: f32.Point{
|
||||
X: opDecodeFloat32(d[11:]),
|
||||
Y: opDecodeFloat32(d[15:]),
|
||||
X: opDecodeFloat32(d[10:]),
|
||||
Y: opDecodeFloat32(d[14:]),
|
||||
},
|
||||
}
|
||||
*op = areaOp{
|
||||
kind: areaKind(d[1]),
|
||||
rect: rect,
|
||||
pass: d[2] != 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,9 @@ func ExampleClickable_passthrough() {
|
||||
// widget lays out two buttons on top of each other.
|
||||
widget := func() {
|
||||
button1.Layout(gtx)
|
||||
area := pointer.Rect(image.Rectangle{Max: gtx.Constraints.Max})
|
||||
// button2 completely covers button1, but pass-through allows pointer
|
||||
// events to pass through to button1.
|
||||
area.PassThrough = true
|
||||
defer area.Push(gtx.Ops).Pop()
|
||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||
button2.Layout(gtx)
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
||||
|
||||
// Stack a normal clickable area on top of the draggable area
|
||||
// to capture non-dragging clicks.
|
||||
pointerArea.PassThrough = true
|
||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||
defer pointerArea.Push(gtx.Ops).Pop()
|
||||
s.Scrollbar.AddTrack(gtx.Ops)
|
||||
|
||||
@@ -206,7 +206,7 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
||||
|
||||
// Add the indicator pointer hit area.
|
||||
area := pointer.Rect(image.Rectangle{Max: indicatorDims})
|
||||
area.PassThrough = true
|
||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||
defer area.Push(gtx.Ops).Pop()
|
||||
s.Scrollbar.AddIndicator(gtx.Ops)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user