Files
gio-patched/ui/pointer/pointer.go
T
Elias Naur f44ccec043 ui/pointer: simplify pointer pass through
Get rid of the confused LayerOp and the transparent property from
AreaOp. Add an explicit PassOp to specify whether pointer events
pass-through the current area.

Let AreaOp swallow events even when no handlers are active for the
area. That behaviour is less surprising and allow clients to disable
a widget by keeping its areas but leave out its handlers.

Simplify the pointer.HitResult enum to just a bool: hit or no hit.

Finally, simplify the pointer queue by tracking parent areas and
node with indices.
2019-07-10 22:43:03 +02:00

217 lines
3.3 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package pointer
import (
"encoding/binary"
"image"
"time"
"gioui.org/ui"
"gioui.org/ui/f32"
"gioui.org/ui/internal/ops"
)
type Event struct {
Type Type
Source Source
PointerID ID
Priority Priority
Time time.Duration
Hit bool
Position f32.Point
Scroll f32.Point
}
type AreaOp struct {
kind areaKind
size image.Point
}
type HandlerOp struct {
Key Key
Grab bool
}
// PassOp change the current event pass-through
// setting.
type PassOp struct {
Pass bool
}
type Key interface{}
type ID uint16
type Type uint8
type Priority uint8
type Source uint8
type areaKind uint8
const (
Cancel Type = iota
Press
Release
Move
)
const (
Mouse Source = iota
Touch
)
const (
Shared Priority = iota
Foremost
Grabbed
)
const (
areaRect areaKind = iota
areaEllipse
)
func AreaRect(size image.Point) AreaOp {
return AreaOp{
kind: areaRect,
size: size,
}
}
func AreaEllipse(size image.Point) AreaOp {
return AreaOp{
kind: areaEllipse,
size: size,
}
}
func (op AreaOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypeAreaLen)
data[0] = byte(ops.TypeArea)
data[1] = byte(op.kind)
bo := binary.LittleEndian
bo.PutUint32(data[2:], uint32(op.size.X))
bo.PutUint32(data[6:], uint32(op.size.Y))
o.Write(data)
}
func (op *AreaOp) Decode(d []byte) {
if ops.OpType(d[0]) != ops.TypeArea {
panic("invalid op")
}
bo := binary.LittleEndian
size := image.Point{
X: int(bo.Uint32(d[2:])),
Y: int(bo.Uint32(d[6:])),
}
*op = AreaOp{
kind: areaKind(d[1]),
size: size,
}
}
func (op *AreaOp) Hit(pos f32.Point) bool {
switch op.kind {
case areaRect:
if 0 <= pos.X && pos.X < float32(op.size.X) &&
0 <= pos.Y && pos.Y < float32(op.size.Y) {
return true
} else {
return false
}
case areaEllipse:
rx := float32(op.size.X) / 2
ry := float32(op.size.Y) / 2
rx2 := rx * rx
ry2 := ry * ry
xh := pos.X - rx
yk := pos.Y - ry
if xh*xh*ry2+yk*yk*rx2 <= rx2*ry2 {
return true
} else {
return false
}
default:
panic("invalid area kind")
}
}
func (h HandlerOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypePointerHandlerLen)
data[0] = byte(ops.TypePointerHandler)
if h.Grab {
data[1] = 1
}
o.Write(data, h.Key)
}
func (h *HandlerOp) Decode(d []byte, refs []interface{}) {
if ops.OpType(d[0]) != ops.TypePointerHandler {
panic("invalid op")
}
*h = HandlerOp{
Grab: d[1] != 0,
Key: refs[0].(Key),
}
}
func (op PassOp) Add(o *ui.Ops) {
data := make([]byte, ops.TypePassLen)
data[0] = byte(ops.TypePass)
if op.Pass {
data[1] = 1
}
o.Write(data)
}
func (op *PassOp) Decode(d []byte) {
if ops.OpType(d[0]) != ops.TypePass {
panic("invalid op")
}
*op = PassOp{
Pass: d[1] != 0,
}
}
func (t Type) String() string {
switch t {
case Press:
return "Press"
case Release:
return "Release"
case Cancel:
return "Cancel"
case Move:
return "Move"
default:
panic("unknown Type")
}
}
func (p Priority) String() string {
switch p {
case Shared:
return "Shared"
case Foremost:
return "Foremost"
case Grabbed:
return "Grabbed"
default:
panic("unknown priority")
}
}
func (s Source) String() string {
switch s {
case Mouse:
return "Mouse"
case Touch:
return "Touch"
default:
panic("unknown source")
}
}
func (Event) ImplementsEvent() {}
func (Event) ImplementsInputEvent() {}