mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 18:35:34 +00:00
io/input: merge pointer and key filters
Refactor the pointer and key filter unions into the handler state struct. This is a preparation for replacing calls to filtersMatches with queries to the filter union. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+24
-19
@@ -46,11 +46,6 @@ type keyHandler struct {
|
|||||||
hint key.InputHint
|
hint key.InputHint
|
||||||
orderPlusOne int
|
orderPlusOne int
|
||||||
dirOrder int
|
dirOrder int
|
||||||
// filter are the key filters accumulated in the previous frame,
|
|
||||||
// used for routing events in the current frame.
|
|
||||||
filter keyFilter
|
|
||||||
// nextFilter is the filter accumulator for the current frame.
|
|
||||||
nextFilter keyFilter
|
|
||||||
trans f32.Affine2D
|
trans f32.Affine2D
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +92,6 @@ func (q *keyQueue) InputHint(handlers map[event.Tag]*handler, state keyState) (k
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k *keyHandler) Reset() {
|
func (k *keyHandler) Reset() {
|
||||||
k.filter, k.nextFilter = k.nextFilter, k.filter
|
|
||||||
k.nextFilter = keyFilter{}
|
|
||||||
k.visible = false
|
k.visible = false
|
||||||
k.orderPlusOne = 0
|
k.orderPlusOne = 0
|
||||||
k.hint = key.HintAny
|
k.hint = key.HintAny
|
||||||
@@ -119,7 +112,7 @@ func (k *keyHandler) ResetEvent() (event.Event, bool) {
|
|||||||
|
|
||||||
func (q *keyQueue) Frame(handlers map[event.Tag]*handler, state keyState) keyState {
|
func (q *keyQueue) Frame(handlers map[event.Tag]*handler, state keyState) keyState {
|
||||||
if state.focus != nil {
|
if state.focus != nil {
|
||||||
if h, ok := handlers[state.focus]; !ok || !h.key.isFocusable() {
|
if h, ok := handlers[state.focus]; !ok || !h.filter.key.focusable || !h.key.visible {
|
||||||
// Remove focus from the handler that is no longer focusable.
|
// Remove focus from the handler that is no longer focusable.
|
||||||
state.focus = nil
|
state.focus = nil
|
||||||
state.state = TextInputClose
|
state.state = TextInputClose
|
||||||
@@ -260,12 +253,17 @@ func (q *keyQueue) AreaFor(k *keyHandler) int {
|
|||||||
return q.dirOrder[order].area
|
return q.dirOrder[order].area
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *keyHandler) Accepts(e key.Event) bool {
|
func (k *keyFilter) Matches(e event.Event) bool {
|
||||||
for _, f := range k.filter.filters {
|
switch e := e.(type) {
|
||||||
|
case key.Event:
|
||||||
|
for _, f := range k.filters {
|
||||||
if keyFilterMatch(f, e) {
|
if keyFilterMatch(f, e) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case key.FocusEvent, key.SnippetEvent, key.EditEvent, key.SelectionEvent:
|
||||||
|
return k.focusable
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +282,7 @@ func keyFilterMatch(f key.Filter, e key.Event) bool {
|
|||||||
|
|
||||||
func (q *keyQueue) Focus(handlers map[event.Tag]*handler, state keyState, focus event.Tag) (keyState, []taggedEvent) {
|
func (q *keyQueue) Focus(handlers map[event.Tag]*handler, state keyState, focus event.Tag) (keyState, []taggedEvent) {
|
||||||
if focus != nil {
|
if focus != nil {
|
||||||
if h, exists := handlers[focus]; !exists || !h.key.isFocusable() {
|
if h, exists := handlers[focus]; !exists || !h.filter.key.focusable || !h.key.visible {
|
||||||
focus = nil
|
focus = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,16 +313,23 @@ func (s keyState) softKeyboard(show bool) keyState {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *keyHandler) Filter(f key.Filter) {
|
func (k *keyFilter) Add(f event.Filter) {
|
||||||
k.nextFilter.filters = append(k.nextFilter.filters, f)
|
switch f := f.(type) {
|
||||||
|
case key.FocusFilter:
|
||||||
|
k.focusable = true
|
||||||
|
case key.Filter:
|
||||||
|
for _, f2 := range k.filters {
|
||||||
|
if f == f2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k.filters = append(k.filters, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *keyHandler) isFocusable() bool {
|
func (k *keyFilter) Merge(k2 keyFilter) {
|
||||||
return k.filter.focusable && k.visible
|
k.focusable = k.focusable || k2.focusable
|
||||||
}
|
k.filters = append(k.filters, k2.filters...)
|
||||||
|
|
||||||
func (k *keyHandler) Focusable() {
|
|
||||||
k.nextFilter.focusable = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *keyQueue) inputOp(tag event.Tag, state *keyHandler, t f32.Affine2D, area int, bounds image.Rectangle) {
|
func (q *keyQueue) inputOp(tag event.Tag, state *keyHandler, t f32.Affine2D, area int, bounds image.Rectangle) {
|
||||||
|
|||||||
+95
-62
@@ -66,12 +66,6 @@ type pointerHandler struct {
|
|||||||
// setup tracks whether the handler has received
|
// setup tracks whether the handler has received
|
||||||
// the pointer.Cancel event that resets its state.
|
// the pointer.Cancel event that resets its state.
|
||||||
setup bool
|
setup bool
|
||||||
// filter is the combined filter of every filter the handler has
|
|
||||||
// asked for through event handling in the previous frame. It is
|
|
||||||
// used for routing events in the current frame.
|
|
||||||
filter pointerFilter
|
|
||||||
// prevFilter is the filter being built in the current frame.
|
|
||||||
nextFilter pointerFilter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pointerFilter represents the union of a set of pointer filters.
|
// pointerFilter represents the union of a set of pointer filters.
|
||||||
@@ -249,8 +243,6 @@ func (c *pointerCollector) newHandler(tag event.Tag, state *pointerHandler) {
|
|||||||
|
|
||||||
func (s *pointerHandler) Reset() {
|
func (s *pointerHandler) Reset() {
|
||||||
s.areaPlusOne = 0
|
s.areaPlusOne = 0
|
||||||
s.filter = s.nextFilter
|
|
||||||
s.nextFilter = pointerFilter{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *pointerCollector) actionInputOp(act system.Action) {
|
func (c *pointerCollector) actionInputOp(act system.Action) {
|
||||||
@@ -287,9 +279,73 @@ func (c *pointerCollector) inputOp(tag event.Tag, state *pointerHandler) {
|
|||||||
c.newHandler(tag, state)
|
c.newHandler(tag, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pointerHandler) Filter(tag event.Tag, f pointer.Filter) {
|
func (p *pointerFilter) Add(f event.Filter) {
|
||||||
s.nextFilter.kinds = s.nextFilter.kinds | f.Kinds
|
switch f := f.(type) {
|
||||||
s.nextFilter.scrollRange = s.nextFilter.scrollRange.Union(f.ScrollBounds)
|
case transfer.SourceFilter:
|
||||||
|
for _, m := range p.sourceMimes {
|
||||||
|
if m == f.Type {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.sourceMimes = append(p.sourceMimes, f.Type)
|
||||||
|
case transfer.TargetFilter:
|
||||||
|
for _, m := range p.targetMimes {
|
||||||
|
if m == f.Type {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.targetMimes = append(p.targetMimes, f.Type)
|
||||||
|
case pointer.Filter:
|
||||||
|
p.kinds = p.kinds | f.Kinds
|
||||||
|
p.scrollRange = p.scrollRange.Union(f.ScrollBounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pointerFilter) Matches(e event.Event) bool {
|
||||||
|
switch e := e.(type) {
|
||||||
|
case pointer.Event:
|
||||||
|
return e.Kind&p.kinds == e.Kind
|
||||||
|
case transfer.CancelEvent, transfer.InitiateEvent:
|
||||||
|
return len(p.sourceMimes) > 0 || len(p.targetMimes) > 0
|
||||||
|
case transfer.RequestEvent:
|
||||||
|
for _, t := range p.sourceMimes {
|
||||||
|
if t == e.Type {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case transfer.DataEvent:
|
||||||
|
for _, t := range p.targetMimes {
|
||||||
|
if t == e.Type {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pointerFilter) Merge(p2 pointerFilter) {
|
||||||
|
p.kinds = p.kinds | p2.kinds
|
||||||
|
p.scrollRange = p.scrollRange.Union(p2.scrollRange)
|
||||||
|
p.sourceMimes = append(p.sourceMimes, p2.sourceMimes...)
|
||||||
|
p.targetMimes = append(p.targetMimes, p2.targetMimes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func clampSplit(v float32, min, max int) (float32, float32) {
|
||||||
|
if m := float32(max); v > m {
|
||||||
|
return v - m, m
|
||||||
|
}
|
||||||
|
if m := float32(min); v < m {
|
||||||
|
return v - m, m
|
||||||
|
}
|
||||||
|
return 0, v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pointerHandler) ResetEvent() (event.Event, bool) {
|
func (s *pointerHandler) ResetEvent() (event.Event, bool) {
|
||||||
@@ -341,14 +397,6 @@ func (c *pointerCollector) cursor(cursor pointer.Cursor) {
|
|||||||
area.cursor = cursor
|
area.cursor = cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pointerHandler) SourceFilter(tag event.Tag, f transfer.SourceFilter) {
|
|
||||||
s.nextFilter.sourceMimes = append(s.nextFilter.sourceMimes, f.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *pointerHandler) TargetFilter(tag event.Tag, f transfer.TargetFilter) {
|
|
||||||
s.nextFilter.targetMimes = append(s.nextFilter.targetMimes, f.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *pointerQueue) offerData(handlers map[event.Tag]*handler, state pointerState, req transfer.OfferCmd) (pointerState, []taggedEvent) {
|
func (q *pointerQueue) offerData(handlers map[event.Tag]*handler, state pointerState, req transfer.OfferCmd) (pointerState, []taggedEvent) {
|
||||||
var evts []taggedEvent
|
var evts []taggedEvent
|
||||||
for i, p := range state.pointers {
|
for i, p := range state.pointers {
|
||||||
@@ -572,10 +620,10 @@ func (q *pointerQueue) Frame(handlers map[event.Tag]*handler, state pointerState
|
|||||||
for _, h := range handlers {
|
for _, h := range handlers {
|
||||||
if h.pointer.areaPlusOne != 0 {
|
if h.pointer.areaPlusOne != 0 {
|
||||||
area := &q.areas[h.pointer.areaPlusOne-1]
|
area := &q.areas[h.pointer.areaPlusOne-1]
|
||||||
if h.pointer.filter.kinds&(pointer.Press|pointer.Release) != 0 {
|
if h.filter.pointer.kinds&(pointer.Press|pointer.Release) != 0 {
|
||||||
area.semantic.content.gestures |= ClickGesture
|
area.semantic.content.gestures |= ClickGesture
|
||||||
}
|
}
|
||||||
if h.pointer.filter.kinds&pointer.Scroll != 0 {
|
if h.filter.pointer.kinds&pointer.Scroll != 0 {
|
||||||
area.semantic.content.gestures |= ScrollGesture
|
area.semantic.content.gestures |= ScrollGesture
|
||||||
}
|
}
|
||||||
area.semantic.valid = area.semantic.content.gestures != 0
|
area.semantic.valid = area.semantic.content.gestures != 0
|
||||||
@@ -630,7 +678,7 @@ func (s pointerState) pointerOf(e pointer.Event) (pointerState, int) {
|
|||||||
|
|
||||||
// Deliver is like Push, but delivers an event to a particular area.
|
// Deliver is like Push, but delivers an event to a particular area.
|
||||||
func (q *pointerQueue) Deliver(handlers map[event.Tag]*handler, areaIdx int, e pointer.Event) []taggedEvent {
|
func (q *pointerQueue) Deliver(handlers map[event.Tag]*handler, areaIdx int, e pointer.Event) []taggedEvent {
|
||||||
var sx, sy = e.Scroll.X, e.Scroll.Y
|
scroll := e.Scroll
|
||||||
idx := len(q.hitTree) - 1
|
idx := len(q.hitTree) - 1
|
||||||
// Locate first potential receiver.
|
// Locate first potential receiver.
|
||||||
for idx != -1 {
|
for idx != -1 {
|
||||||
@@ -645,18 +693,15 @@ func (q *pointerQueue) Deliver(handlers map[event.Tag]*handler, areaIdx int, e p
|
|||||||
n := &q.hitTree[idx]
|
n := &q.hitTree[idx]
|
||||||
idx = n.next
|
idx = n.next
|
||||||
h, ok := handlers[n.tag]
|
h, ok := handlers[n.tag]
|
||||||
if !ok || e.Kind&h.pointer.filter.kinds == 0 {
|
if !ok || !h.filter.pointer.Matches(e) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f := h.pointer.filter
|
|
||||||
e := e
|
e := e
|
||||||
if e.Kind == pointer.Scroll {
|
if e.Kind == pointer.Scroll {
|
||||||
if sx == 0 && sy == 0 {
|
if scroll == (f32.Point{}) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Distribute the scroll to the handler based on its ScrollRange.
|
scroll, e.Scroll = h.filter.pointer.clampScroll(scroll)
|
||||||
sx, e.Scroll.X = setScrollEvent(sx, f.scrollRange.Min.X, f.scrollRange.Max.X)
|
|
||||||
sy, e.Scroll.Y = setScrollEvent(sy, f.scrollRange.Min.Y, f.scrollRange.Max.Y)
|
|
||||||
}
|
}
|
||||||
e.Position = q.invTransform(h.pointer.areaPlusOne-1, e.Position)
|
e.Position = q.invTransform(h.pointer.areaPlusOne-1, e.Position)
|
||||||
evts = append(evts, taggedEvent{tag: n.tag, event: e})
|
evts = append(evts, taggedEvent{tag: n.tag, event: e})
|
||||||
@@ -739,23 +784,21 @@ func (q *pointerQueue) deliverEvent(handlers map[event.Tag]*handler, p pointerIn
|
|||||||
e.Priority = pointer.Grabbed
|
e.Priority = pointer.Grabbed
|
||||||
foremost = false
|
foremost = false
|
||||||
}
|
}
|
||||||
var sx, sy = e.Scroll.X, e.Scroll.Y
|
scroll := e.Scroll
|
||||||
for _, k := range p.handlers {
|
for _, k := range p.handlers {
|
||||||
h, ok := handlers[k]
|
h, ok := handlers[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f := h.pointer.filter
|
f := h.filter.pointer
|
||||||
|
if !f.Matches(e) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if e.Kind == pointer.Scroll {
|
if e.Kind == pointer.Scroll {
|
||||||
if sx == 0 && sy == 0 {
|
if scroll == (f32.Point{}) {
|
||||||
return evts
|
return evts
|
||||||
}
|
}
|
||||||
// Distribute the scroll to the handler based on its ScrollRange.
|
scroll, e.Scroll = f.clampScroll(scroll)
|
||||||
sx, e.Scroll.X = setScrollEvent(sx, f.scrollRange.Min.X, f.scrollRange.Max.X)
|
|
||||||
sy, e.Scroll.Y = setScrollEvent(sy, f.scrollRange.Min.Y, f.scrollRange.Max.Y)
|
|
||||||
}
|
|
||||||
if e.Kind&f.kinds == 0 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
e := e
|
e := e
|
||||||
if foremost {
|
if foremost {
|
||||||
@@ -774,9 +817,9 @@ func (q *pointerQueue) deliverEnterLeaveEvents(handlers map[event.Tag]*handler,
|
|||||||
if e.Source != pointer.Mouse && !p.pressed && e.Kind != pointer.Press {
|
if e.Source != pointer.Mouse && !p.pressed && e.Kind != pointer.Press {
|
||||||
// Consider non-mouse pointers leaving when they're released.
|
// Consider non-mouse pointers leaving when they're released.
|
||||||
} else {
|
} else {
|
||||||
var transSrc *pointerHandler
|
var transSrc *pointerFilter
|
||||||
if p.dataSource != nil {
|
if p.dataSource != nil {
|
||||||
transSrc = &handlers[p.dataSource].pointer
|
transSrc = &handlers[p.dataSource].filter.pointer
|
||||||
}
|
}
|
||||||
cursor = q.hitTest(e.Position, func(n *hitNode) bool {
|
cursor = q.hitTest(e.Position, func(n *hitNode) bool {
|
||||||
h, ok := handlers[n.tag]
|
h, ok := handlers[n.tag]
|
||||||
@@ -792,7 +835,7 @@ func (q *pointerQueue) deliverEnterLeaveEvents(handlers map[event.Tag]*handler,
|
|||||||
add = true
|
add = true
|
||||||
}
|
}
|
||||||
if transSrc != nil {
|
if transSrc != nil {
|
||||||
if _, ok := firstMimeMatch(transSrc, &h.pointer); ok {
|
if _, ok := firstMimeMatch(transSrc, &h.filter.pointer); ok {
|
||||||
add = true
|
add = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -820,7 +863,7 @@ func (q *pointerQueue) deliverEnterLeaveEvents(handlers map[event.Tag]*handler,
|
|||||||
e := e
|
e := e
|
||||||
e.Kind = pointer.Leave
|
e.Kind = pointer.Leave
|
||||||
|
|
||||||
if e.Kind&h.pointer.filter.kinds != 0 {
|
if h.filter.pointer.Matches(e) {
|
||||||
e.Position = q.invTransform(h.pointer.areaPlusOne-1, e.Position)
|
e.Position = q.invTransform(h.pointer.areaPlusOne-1, e.Position)
|
||||||
evts = append(evts, taggedEvent{tag: k, event: e})
|
evts = append(evts, taggedEvent{tag: k, event: e})
|
||||||
}
|
}
|
||||||
@@ -838,7 +881,7 @@ func (q *pointerQueue) deliverEnterLeaveEvents(handlers map[event.Tag]*handler,
|
|||||||
e := e
|
e := e
|
||||||
e.Kind = pointer.Enter
|
e.Kind = pointer.Enter
|
||||||
|
|
||||||
if e.Kind&h.pointer.filter.kinds != 0 {
|
if h.filter.pointer.Matches(e) {
|
||||||
e.Position = q.invTransform(h.pointer.areaPlusOne-1, e.Position)
|
e.Position = q.invTransform(h.pointer.areaPlusOne-1, e.Position)
|
||||||
evts = append(evts, taggedEvent{tag: k, event: e})
|
evts = append(evts, taggedEvent{tag: k, event: e})
|
||||||
}
|
}
|
||||||
@@ -853,15 +896,15 @@ func (q *pointerQueue) deliverDragEvent(handlers map[event.Tag]*handler, p point
|
|||||||
}
|
}
|
||||||
// Identify the data source.
|
// Identify the data source.
|
||||||
for _, k := range p.entered {
|
for _, k := range p.entered {
|
||||||
src := &handlers[k].pointer
|
src := &handlers[k].filter.pointer
|
||||||
if len(src.filter.sourceMimes) == 0 {
|
if len(src.sourceMimes) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// One data source handler per pointer.
|
// One data source handler per pointer.
|
||||||
p.dataSource = k
|
p.dataSource = k
|
||||||
// Notify all potential targets.
|
// Notify all potential targets.
|
||||||
for k, tgt := range handlers {
|
for k, tgt := range handlers {
|
||||||
if _, ok := firstMimeMatch(src, &tgt.pointer); ok {
|
if _, ok := firstMimeMatch(src, &tgt.filter.pointer); ok {
|
||||||
evts = append(evts, taggedEvent{tag: k, event: transfer.InitiateEvent{}})
|
evts = append(evts, taggedEvent{tag: k, event: transfer.InitiateEvent{}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -875,10 +918,10 @@ func (q *pointerQueue) deliverDropEvent(handlers map[event.Tag]*handler, p point
|
|||||||
return p, evts
|
return p, evts
|
||||||
}
|
}
|
||||||
// Request data from the source.
|
// Request data from the source.
|
||||||
src := &handlers[p.dataSource].pointer
|
src := &handlers[p.dataSource].filter.pointer
|
||||||
for _, k := range p.entered {
|
for _, k := range p.entered {
|
||||||
h := handlers[k]
|
h := handlers[k]
|
||||||
if m, ok := firstMimeMatch(src, &h.pointer); ok {
|
if m, ok := firstMimeMatch(src, &h.filter.pointer); ok {
|
||||||
p.dataTarget = k
|
p.dataTarget = k
|
||||||
evts = append(evts, taggedEvent{tag: p.dataSource, event: transfer.RequestEvent{Type: m}})
|
evts = append(evts, taggedEvent{tag: p.dataSource, event: transfer.RequestEvent{Type: m}})
|
||||||
return p, evts
|
return p, evts
|
||||||
@@ -891,9 +934,9 @@ func (q *pointerQueue) deliverDropEvent(handlers map[event.Tag]*handler, p point
|
|||||||
func (q *pointerQueue) deliverTransferCancelEvent(handlers map[event.Tag]*handler, p pointerInfo, evts []taggedEvent) (pointerInfo, []taggedEvent) {
|
func (q *pointerQueue) deliverTransferCancelEvent(handlers map[event.Tag]*handler, p pointerInfo, evts []taggedEvent) (pointerInfo, []taggedEvent) {
|
||||||
evts = append(evts, taggedEvent{tag: p.dataSource, event: transfer.CancelEvent{}})
|
evts = append(evts, taggedEvent{tag: p.dataSource, event: transfer.CancelEvent{}})
|
||||||
// Cancel all potential targets.
|
// Cancel all potential targets.
|
||||||
src := &handlers[p.dataSource].pointer
|
src := &handlers[p.dataSource].filter.pointer
|
||||||
for k, h := range handlers {
|
for k, h := range handlers {
|
||||||
if _, ok := firstMimeMatch(src, &h.pointer); ok {
|
if _, ok := firstMimeMatch(src, &h.filter.pointer); ok {
|
||||||
evts = append(evts, taggedEvent{tag: k, event: transfer.CancelEvent{}})
|
evts = append(evts, taggedEvent{tag: k, event: transfer.CancelEvent{}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -934,9 +977,9 @@ func addHandler(tags []event.Tag, tag event.Tag) []event.Tag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// firstMimeMatch returns the first type match between src and tgt.
|
// firstMimeMatch returns the first type match between src and tgt.
|
||||||
func firstMimeMatch(src, tgt *pointerHandler) (first string, matched bool) {
|
func firstMimeMatch(src, tgt *pointerFilter) (first string, matched bool) {
|
||||||
for _, m1 := range tgt.filter.targetMimes {
|
for _, m1 := range tgt.targetMimes {
|
||||||
for _, m2 := range src.filter.sourceMimes {
|
for _, m2 := range src.sourceMimes {
|
||||||
if m1 == m2 {
|
if m1 == m2 {
|
||||||
return m1, true
|
return m1, true
|
||||||
}
|
}
|
||||||
@@ -971,13 +1014,3 @@ func (a *areaNode) bounds() image.Rectangle {
|
|||||||
Max: a.trans.Transform(f32internal.FPt(a.area.rect.Max)),
|
Max: a.trans.Transform(f32internal.FPt(a.area.rect.Max)),
|
||||||
}.Round()
|
}.Round()
|
||||||
}
|
}
|
||||||
|
|
||||||
func setScrollEvent(scroll float32, min, max int) (left, scrolled float32) {
|
|
||||||
if v := float32(max); scroll > v {
|
|
||||||
return scroll - v, v
|
|
||||||
}
|
|
||||||
if v := float32(min); scroll < v {
|
|
||||||
return scroll - v, v
|
|
||||||
}
|
|
||||||
return 0, scroll
|
|
||||||
}
|
|
||||||
|
|||||||
+56
-57
@@ -53,6 +53,9 @@ type Router struct {
|
|||||||
|
|
||||||
// transfers is the pending transfer.DataEvent.Open functions.
|
// transfers is the pending transfer.DataEvent.Open functions.
|
||||||
transfers []io.ReadCloser
|
transfers []io.ReadCloser
|
||||||
|
|
||||||
|
// scratchFilter is for garbage-free construction of ephemeral filters.
|
||||||
|
scratchFilter filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source implements the interface between a Router and user interface widgets.
|
// Source implements the interface between a Router and user interface widgets.
|
||||||
@@ -109,6 +112,18 @@ type handler struct {
|
|||||||
active bool
|
active bool
|
||||||
pointer pointerHandler
|
pointer pointerHandler
|
||||||
key keyHandler
|
key keyHandler
|
||||||
|
// filter the handler has asked for through event handling
|
||||||
|
// in the previous frame. It is used for routing events in the
|
||||||
|
// current frame.
|
||||||
|
filter filter
|
||||||
|
// prevFilter is the filter being built in the current frame.
|
||||||
|
nextFilter filter
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter is the union of a set of [io/event.Filters].
|
||||||
|
type filter struct {
|
||||||
|
pointer pointerFilter
|
||||||
|
key keyFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateChange represents the new state and outgoing events
|
// stateChange represents the new state and outgoing events
|
||||||
@@ -164,27 +179,22 @@ func (s Source) Events(k event.Tag, filters ...event.Filter) []event.Event {
|
|||||||
func (q *Router) Events(k event.Tag, filters ...event.Filter) []event.Event {
|
func (q *Router) Events(k event.Tag, filters ...event.Filter) []event.Event {
|
||||||
var events []event.Event
|
var events []event.Event
|
||||||
h := q.stateFor(k)
|
h := q.stateFor(k)
|
||||||
|
q.scratchFilter.Reset()
|
||||||
// Record handler filters and add reset events.
|
// Record handler filters and add reset events.
|
||||||
for _, f := range filters {
|
for _, f := range filters {
|
||||||
switch f := f.(type) {
|
q.scratchFilter.Add(f)
|
||||||
case key.Filter:
|
switch f.(type) {
|
||||||
h.key.Filter(f)
|
|
||||||
case key.FocusFilter:
|
case key.FocusFilter:
|
||||||
h.key.Focusable()
|
|
||||||
if reset, ok := h.key.ResetEvent(); ok {
|
if reset, ok := h.key.ResetEvent(); ok {
|
||||||
events = append(events, reset)
|
events = append(events, reset)
|
||||||
}
|
}
|
||||||
case pointer.Filter:
|
case pointer.Filter:
|
||||||
h.pointer.Filter(k, f)
|
|
||||||
if reset, ok := h.pointer.ResetEvent(); ok {
|
if reset, ok := h.pointer.ResetEvent(); ok {
|
||||||
events = append(events, reset)
|
events = append(events, reset)
|
||||||
}
|
}
|
||||||
case transfer.SourceFilter:
|
|
||||||
h.pointer.SourceFilter(k, f)
|
|
||||||
case transfer.TargetFilter:
|
|
||||||
h.pointer.TargetFilter(k, f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
h.nextFilter.Merge(q.scratchFilter)
|
||||||
// Accumulate events from state changes until there are no more
|
// Accumulate events from state changes until there are no more
|
||||||
// matching events.
|
// matching events.
|
||||||
matchedIdx := 0
|
matchedIdx := 0
|
||||||
@@ -193,7 +203,7 @@ func (q *Router) Events(k event.Tag, filters ...event.Filter) []event.Event {
|
|||||||
j := 0
|
j := 0
|
||||||
for j < len(change.events) {
|
for j < len(change.events) {
|
||||||
evt := change.events[j]
|
evt := change.events[j]
|
||||||
if evt.tag != k || !filtersMatches(filters, evt.event) {
|
if evt.tag != k || !q.scratchFilter.Matches(evt.event) {
|
||||||
j++
|
j++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -237,6 +247,8 @@ func (q *Router) Frame(frame *op.Ops) {
|
|||||||
q.changes = append(q.changes[:0], stateChange{state: state})
|
q.changes = append(q.changes[:0], stateChange{state: state})
|
||||||
}
|
}
|
||||||
for _, h := range q.handlers {
|
for _, h := range q.handlers {
|
||||||
|
h.filter, h.nextFilter = h.nextFilter, h.filter
|
||||||
|
h.nextFilter.Reset()
|
||||||
h.pointer.Reset()
|
h.pointer.Reset()
|
||||||
h.key.Reset()
|
h.key.Reset()
|
||||||
}
|
}
|
||||||
@@ -276,6 +288,38 @@ func (q *Router) Queue(events ...event.Event) bool {
|
|||||||
return matched
|
return matched
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *filter) Reset() {
|
||||||
|
*f = filter{
|
||||||
|
key: keyFilter{
|
||||||
|
// Re-use filter slice storage.
|
||||||
|
filters: f.key.filters[:0],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) Add(flt event.Filter) {
|
||||||
|
switch flt := flt.(type) {
|
||||||
|
case key.Filter:
|
||||||
|
f.key.Add(flt)
|
||||||
|
case key.FocusFilter:
|
||||||
|
f.key.Add(flt)
|
||||||
|
case pointer.Filter:
|
||||||
|
f.pointer.Add(flt)
|
||||||
|
case transfer.SourceFilter, transfer.TargetFilter:
|
||||||
|
f.pointer.Add(flt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge f2 into f.
|
||||||
|
func (f *filter) Merge(f2 filter) {
|
||||||
|
f.key.Merge(f2.key)
|
||||||
|
f.pointer.Merge(f2.pointer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) Matches(e event.Event) bool {
|
||||||
|
return f.key.Matches(e) || f.pointer.Matches(e)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *Router) processEvent(e event.Event) bool {
|
func (q *Router) processEvent(e event.Event) bool {
|
||||||
state := q.lastState()
|
state := q.lastState()
|
||||||
switch e := e.(type) {
|
switch e := e.(type) {
|
||||||
@@ -428,7 +472,7 @@ func rangeNorm(r key.Range) key.Range {
|
|||||||
func (q *Router) queueKeyEvent(state keyState, e key.Event) []taggedEvent {
|
func (q *Router) queueKeyEvent(state keyState, e key.Event) []taggedEvent {
|
||||||
f := state.focus
|
f := state.focus
|
||||||
var evts []taggedEvent
|
var evts []taggedEvent
|
||||||
if f != nil && q.handlers[f].key.Accepts(e) {
|
if f != nil && q.handlers[f].filter.key.Matches(e) {
|
||||||
evts = append(evts, taggedEvent{tag: f, event: e})
|
evts = append(evts, taggedEvent{tag: f, event: e})
|
||||||
return evts
|
return evts
|
||||||
}
|
}
|
||||||
@@ -451,7 +495,7 @@ func (q *Router) queueKeyEvent(state keyState, e key.Event) []taggedEvent {
|
|||||||
if n.tag == nil {
|
if n.tag == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if q.handlers[n.tag].key.Accepts(e) {
|
if q.handlers[n.tag].filter.key.Matches(e) {
|
||||||
evts = append(evts, taggedEvent{tag: n.tag, event: e})
|
evts = append(evts, taggedEvent{tag: n.tag, event: e})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -724,51 +768,6 @@ func (q *Router) WakeupTime() (time.Time, bool) {
|
|||||||
return q.wakeupTime, q.wakeup
|
return q.wakeupTime, q.wakeup
|
||||||
}
|
}
|
||||||
|
|
||||||
func filtersMatches(filters []event.Filter, e event.Event) bool {
|
|
||||||
switch e := e.(type) {
|
|
||||||
case key.Event:
|
|
||||||
for _, f := range filters {
|
|
||||||
if f, ok := f.(key.Filter); ok {
|
|
||||||
if keyFilterMatch(f, e) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case key.FocusEvent, key.SnippetEvent, key.EditEvent, key.SelectionEvent:
|
|
||||||
for _, f := range filters {
|
|
||||||
if _, ok := f.(key.FocusFilter); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case pointer.Event:
|
|
||||||
for _, f := range filters {
|
|
||||||
if f, ok := f.(pointer.Filter); ok && f.Kinds&e.Kind == e.Kind {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case transfer.CancelEvent, transfer.InitiateEvent:
|
|
||||||
for _, f := range filters {
|
|
||||||
switch f.(type) {
|
|
||||||
case transfer.SourceFilter, transfer.TargetFilter:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case transfer.RequestEvent:
|
|
||||||
for _, f := range filters {
|
|
||||||
if f, ok := f.(transfer.SourceFilter); ok && f.Type == e.Type {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case transfer.DataEvent:
|
|
||||||
for _, f := range filters {
|
|
||||||
if f, ok := f.(transfer.TargetFilter); ok && f.Type == e.Type {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeInvalidateOp(d []byte) op.InvalidateOp {
|
func decodeInvalidateOp(d []byte) op.InvalidateOp {
|
||||||
bo := binary.LittleEndian
|
bo := binary.LittleEndian
|
||||||
if ops.OpType(d[0]) != ops.TypeInvalidate {
|
if ops.OpType(d[0]) != ops.TypeInvalidate {
|
||||||
|
|||||||
Reference in New Issue
Block a user