mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 18:35:34 +00:00
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
|
nextStateID int
|
||||||
|
|
||||||
macroStack stack
|
macroStack stack
|
||||||
stacks [3]stack
|
stacks [4]stack
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpType byte
|
type OpType byte
|
||||||
@@ -45,6 +45,8 @@ const (
|
|||||||
TypeLinearGradient
|
TypeLinearGradient
|
||||||
TypeArea
|
TypeArea
|
||||||
TypePopArea
|
TypePopArea
|
||||||
|
TypePass
|
||||||
|
TypePopPass
|
||||||
TypePointerInput
|
TypePointerInput
|
||||||
TypeClipboardRead
|
TypeClipboardRead
|
||||||
TypeClipboardWrite
|
TypeClipboardWrite
|
||||||
@@ -88,6 +90,7 @@ const (
|
|||||||
ClipStack StackKind = iota
|
ClipStack StackKind = iota
|
||||||
AreaStack
|
AreaStack
|
||||||
TransStack
|
TransStack
|
||||||
|
PassStack
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -102,8 +105,10 @@ const (
|
|||||||
TypePaintLen = 1
|
TypePaintLen = 1
|
||||||
TypeColorLen = 1 + 4
|
TypeColorLen = 1 + 4
|
||||||
TypeLinearGradientLen = 1 + 8*2 + 4*2
|
TypeLinearGradientLen = 1 + 8*2 + 4*2
|
||||||
TypeAreaLen = 1 + 1 + 1 + 4*4
|
TypeAreaLen = 1 + 1 + 4*4
|
||||||
TypePopAreaLen = 1
|
TypePopAreaLen = 1
|
||||||
|
TypePassLen = 1
|
||||||
|
TypePopPassLen = 1
|
||||||
TypePointerInputLen = 1 + 1 + 1 + 2*4 + 2*4
|
TypePointerInputLen = 1 + 1 + 1 + 2*4 + 2*4
|
||||||
TypeClipboardReadLen = 1
|
TypeClipboardReadLen = 1
|
||||||
TypeClipboardWriteLen = 1
|
TypeClipboardWriteLen = 1
|
||||||
@@ -313,6 +318,8 @@ func (t OpType) Size() int {
|
|||||||
TypeLinearGradientLen,
|
TypeLinearGradientLen,
|
||||||
TypeAreaLen,
|
TypeAreaLen,
|
||||||
TypePopAreaLen,
|
TypePopAreaLen,
|
||||||
|
TypePassLen,
|
||||||
|
TypePopPassLen,
|
||||||
TypePointerInputLen,
|
TypePointerInputLen,
|
||||||
TypeClipboardReadLen,
|
TypeClipboardReadLen,
|
||||||
TypeClipboardWriteLen,
|
TypeClipboardWriteLen,
|
||||||
@@ -370,6 +377,10 @@ func (t OpType) String() string {
|
|||||||
return "Area"
|
return "Area"
|
||||||
case TypePopArea:
|
case TypePopArea:
|
||||||
return "PopArea"
|
return "PopArea"
|
||||||
|
case TypePass:
|
||||||
|
return "Pass"
|
||||||
|
case TypePopPass:
|
||||||
|
return "PopPass"
|
||||||
case TypePointerInput:
|
case TypePointerInput:
|
||||||
return "PointerInput"
|
return "PointerInput"
|
||||||
case TypeClipboardRead:
|
case TypeClipboardRead:
|
||||||
|
|||||||
+32
-14
@@ -42,14 +42,9 @@ type Event struct {
|
|||||||
Modifiers key.Modifiers
|
Modifiers key.Modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
// AreaOp updates the hit area to the intersection of the current
|
// AreaOp pushes the current hit area to the stack and updates it to the
|
||||||
// hit area and the area. The area is transformed before applying
|
// intersection of the current hit area and the transformed area.
|
||||||
// it.
|
|
||||||
type AreaOp struct {
|
type AreaOp struct {
|
||||||
// PassThrough areas and their children don't block events to siblings
|
|
||||||
// them.
|
|
||||||
PassThrough bool
|
|
||||||
|
|
||||||
kind areaKind
|
kind areaKind
|
||||||
rect image.Rectangle
|
rect image.Rectangle
|
||||||
}
|
}
|
||||||
@@ -61,6 +56,18 @@ type AreaStack struct {
|
|||||||
macroID int
|
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.
|
// CursorNameOp sets the cursor for the current area.
|
||||||
type CursorNameOp struct {
|
type CursorNameOp struct {
|
||||||
Name CursorName
|
Name CursorName
|
||||||
@@ -204,14 +211,11 @@ func (a AreaOp) add(o *op.Ops, push bool) {
|
|||||||
data := o.Internal.Write(ops.TypeAreaLen)
|
data := o.Internal.Write(ops.TypeAreaLen)
|
||||||
data[0] = byte(ops.TypeArea)
|
data[0] = byte(ops.TypeArea)
|
||||||
data[1] = byte(a.kind)
|
data[1] = byte(a.kind)
|
||||||
if a.PassThrough {
|
|
||||||
data[2] = 1
|
|
||||||
}
|
|
||||||
bo := binary.LittleEndian
|
bo := binary.LittleEndian
|
||||||
bo.PutUint32(data[3:], uint32(a.rect.Min.X))
|
bo.PutUint32(data[2:], uint32(a.rect.Min.X))
|
||||||
bo.PutUint32(data[7:], uint32(a.rect.Min.Y))
|
bo.PutUint32(data[6:], uint32(a.rect.Min.Y))
|
||||||
bo.PutUint32(data[11:], uint32(a.rect.Max.X))
|
bo.PutUint32(data[10:], uint32(a.rect.Max.X))
|
||||||
bo.PutUint32(data[15:], uint32(a.rect.Max.Y))
|
bo.PutUint32(data[14:], uint32(a.rect.Max.Y))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o AreaStack) Pop() {
|
func (o AreaStack) Pop() {
|
||||||
@@ -220,6 +224,20 @@ func (o AreaStack) Pop() {
|
|||||||
data[0] = byte(ops.TypePopArea)
|
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) {
|
func (op CursorNameOp) Add(o *op.Ops) {
|
||||||
data := o.Internal.Write1(ops.TypeCursorLen, op.Name)
|
data := o.Internal.Write1(ops.TypeCursorLen, op.Name)
|
||||||
data[0] = byte(ops.TypeCursor)
|
data[0] = byte(ops.TypeCursor)
|
||||||
|
|||||||
+10
-8
@@ -64,7 +64,6 @@ type pointerHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type areaOp struct {
|
type areaOp struct {
|
||||||
pass bool
|
|
||||||
kind areaKind
|
kind areaKind
|
||||||
rect f32.Rectangle
|
rect f32.Rectangle
|
||||||
}
|
}
|
||||||
@@ -82,7 +81,7 @@ type areaKind uint8
|
|||||||
type collectState struct {
|
type collectState struct {
|
||||||
t f32.Affine2D
|
t f32.Affine2D
|
||||||
node int
|
node int
|
||||||
pass bool
|
pass int
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -122,7 +121,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
|
|||||||
n := q.hitTree[i]
|
n := q.hitTree[i]
|
||||||
area = n.area
|
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.nodeStack = append(q.nodeStack, state.node)
|
||||||
q.hitTree = append(q.hitTree, hitNode{
|
q.hitTree = append(q.hitTree, hitNode{
|
||||||
next: state.node,
|
next: state.node,
|
||||||
@@ -133,6 +132,10 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents) {
|
|||||||
n := len(q.nodeStack)
|
n := len(q.nodeStack)
|
||||||
state.node = q.nodeStack[n-1]
|
state.node = q.nodeStack[n-1]
|
||||||
q.nodeStack = q.nodeStack[:n-1]
|
q.nodeStack = q.nodeStack[:n-1]
|
||||||
|
case ops.TypePass:
|
||||||
|
state.pass++
|
||||||
|
case ops.TypePopPass:
|
||||||
|
state.pass--
|
||||||
case ops.TypeTransform:
|
case ops.TypeTransform:
|
||||||
dop, push := ops.DecodeTransform(encOp.Data)
|
dop, push := ops.DecodeTransform(encOp.Data)
|
||||||
if push {
|
if push {
|
||||||
@@ -480,18 +483,17 @@ func (op *areaOp) Decode(d []byte) {
|
|||||||
}
|
}
|
||||||
rect := f32.Rectangle{
|
rect := f32.Rectangle{
|
||||||
Min: f32.Point{
|
Min: f32.Point{
|
||||||
X: opDecodeFloat32(d[3:]),
|
X: opDecodeFloat32(d[2:]),
|
||||||
Y: opDecodeFloat32(d[7:]),
|
Y: opDecodeFloat32(d[6:]),
|
||||||
},
|
},
|
||||||
Max: f32.Point{
|
Max: f32.Point{
|
||||||
X: opDecodeFloat32(d[11:]),
|
X: opDecodeFloat32(d[10:]),
|
||||||
Y: opDecodeFloat32(d[15:]),
|
Y: opDecodeFloat32(d[14:]),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
*op = areaOp{
|
*op = areaOp{
|
||||||
kind: areaKind(d[1]),
|
kind: areaKind(d[1]),
|
||||||
rect: rect,
|
rect: rect,
|
||||||
pass: d[2] != 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,9 @@ func ExampleClickable_passthrough() {
|
|||||||
// widget lays out two buttons on top of each other.
|
// widget lays out two buttons on top of each other.
|
||||||
widget := func() {
|
widget := func() {
|
||||||
button1.Layout(gtx)
|
button1.Layout(gtx)
|
||||||
area := pointer.Rect(image.Rectangle{Max: gtx.Constraints.Max})
|
|
||||||
// button2 completely covers button1, but pass-through allows pointer
|
// button2 completely covers button1, but pass-through allows pointer
|
||||||
// events to pass through to button1.
|
// events to pass through to button1.
|
||||||
area.PassThrough = true
|
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||||
defer area.Push(gtx.Ops).Pop()
|
|
||||||
button2.Layout(gtx)
|
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
|
// Stack a normal clickable area on top of the draggable area
|
||||||
// to capture non-dragging clicks.
|
// to capture non-dragging clicks.
|
||||||
pointerArea.PassThrough = true
|
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||||
defer pointerArea.Push(gtx.Ops).Pop()
|
defer pointerArea.Push(gtx.Ops).Pop()
|
||||||
s.Scrollbar.AddTrack(gtx.Ops)
|
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.
|
// Add the indicator pointer hit area.
|
||||||
area := pointer.Rect(image.Rectangle{Max: indicatorDims})
|
area := pointer.Rect(image.Rectangle{Max: indicatorDims})
|
||||||
area.PassThrough = true
|
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||||
defer area.Push(gtx.Ops).Pop()
|
defer area.Push(gtx.Ops).Pop()
|
||||||
s.Scrollbar.AddIndicator(gtx.Ops)
|
s.Scrollbar.AddIndicator(gtx.Ops)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user