forked from joejulian/gio
all: [API] replace tag parameter of Source.Event with per-filter tags
Until now, every event has had a particular target. We're about to simplify key event delivery to match the first matching filter, so there is no longer a global meaning to the tag argument to Source.Event. Add fields to filters to specify their target tags. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+5
-4
@@ -44,7 +44,7 @@ func (h *Hover) Add(ops *op.Ops) {
|
|||||||
// Update state and report whether a pointer is inside the area.
|
// Update state and report whether a pointer is inside the area.
|
||||||
func (h *Hover) Update(q input.Source) bool {
|
func (h *Hover) Update(q input.Source) bool {
|
||||||
for {
|
for {
|
||||||
ev, ok := q.Event(h, pointer.Filter{Kinds: pointer.Enter | pointer.Leave})
|
ev, ok := q.Event(pointer.Filter{Target: h, Kinds: pointer.Enter | pointer.Leave})
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,7 @@ func (c *Click) Pressed() bool {
|
|||||||
// Update state and return the next click events, if any.
|
// Update state and return the next click events, if any.
|
||||||
func (c *Click) Update(q input.Source) (ClickEvent, bool) {
|
func (c *Click) Update(q input.Source) (ClickEvent, bool) {
|
||||||
for {
|
for {
|
||||||
evt, ok := q.Event(c, pointer.Filter{Kinds: pointer.Press | pointer.Release | pointer.Enter | pointer.Leave})
|
evt, ok := q.Event(pointer.Filter{Target: c, Kinds: pointer.Press | pointer.Release | pointer.Enter | pointer.Leave})
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -268,11 +268,12 @@ func (s *Scroll) Stop() {
|
|||||||
func (s *Scroll) Update(cfg unit.Metric, q input.Source, t time.Time, axis Axis, bounds image.Rectangle) int {
|
func (s *Scroll) Update(cfg unit.Metric, q input.Source, t time.Time, axis Axis, bounds image.Rectangle) int {
|
||||||
total := 0
|
total := 0
|
||||||
f := pointer.Filter{
|
f := pointer.Filter{
|
||||||
|
Target: s,
|
||||||
Kinds: pointer.Press | pointer.Drag | pointer.Release | pointer.Scroll,
|
Kinds: pointer.Press | pointer.Drag | pointer.Release | pointer.Scroll,
|
||||||
ScrollBounds: bounds,
|
ScrollBounds: bounds,
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
evt, ok := q.Event(s, f)
|
evt, ok := q.Event(f)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -372,7 +373,7 @@ func (d *Drag) Add(ops *op.Ops) {
|
|||||||
// Update state and return the next drag event, if any.
|
// Update state and return the next drag event, if any.
|
||||||
func (d *Drag) Update(cfg unit.Metric, q input.Source, axis Axis) (pointer.Event, bool) {
|
func (d *Drag) Update(cfg unit.Metric, q input.Source, axis Axis) (pointer.Event, bool) {
|
||||||
for {
|
for {
|
||||||
ev, ok := q.Event(d, pointer.Filter{Kinds: pointer.Press | pointer.Drag | pointer.Release})
|
ev, ok := q.Event(pointer.Filter{Target: d, Kinds: pointer.Press | pointer.Drag | pointer.Release})
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,6 +294,7 @@ func TestFocusScroll(t *testing.T) {
|
|||||||
filters := []event.Filter{
|
filters := []event.Filter{
|
||||||
key.FocusFilter{},
|
key.FocusFilter{},
|
||||||
pointer.Filter{
|
pointer.Filter{
|
||||||
|
Target: h,
|
||||||
Kinds: pointer.Scroll,
|
Kinds: pointer.Scroll,
|
||||||
ScrollBounds: image.Rect(-100, -100, 100, 100),
|
ScrollBounds: image.Rect(-100, -100, 100, 100),
|
||||||
},
|
},
|
||||||
@@ -322,7 +323,8 @@ func TestFocusClick(t *testing.T) {
|
|||||||
filters := []event.Filter{
|
filters := []event.Filter{
|
||||||
key.FocusFilter{},
|
key.FocusFilter{},
|
||||||
pointer.Filter{
|
pointer.Filter{
|
||||||
Kinds: pointer.Press | pointer.Release,
|
Target: h,
|
||||||
|
Kinds: pointer.Press | pointer.Release,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assertEventPointerTypeSequence(t, events(r, h, filters...), pointer.Cancel)
|
assertEventPointerTypeSequence(t, events(r, h, filters...), pointer.Cancel)
|
||||||
|
|||||||
@@ -19,6 +19,17 @@ import (
|
|||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestPointerNilTarget(t *testing.T) {
|
||||||
|
r := new(Router)
|
||||||
|
r.Event(pointer.Filter{Kinds: pointer.Press})
|
||||||
|
r.Frame(new(op.Ops))
|
||||||
|
r.Queue(pointer.Event{Kind: pointer.Press})
|
||||||
|
// Nil Targets should not receive events.
|
||||||
|
if _, ok := r.Event(pointer.Filter{Kinds: pointer.Press}); ok {
|
||||||
|
t.Errorf("nil target received event")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPointerWakeup(t *testing.T) {
|
func TestPointerWakeup(t *testing.T) {
|
||||||
handler := new(int)
|
handler := new(int)
|
||||||
var ops op.Ops
|
var ops op.Ops
|
||||||
@@ -55,9 +66,29 @@ func TestPointerDrag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func events(r *Router, h event.Tag, filters ...event.Filter) []event.Event {
|
func events(r *Router, h event.Tag, filters ...event.Filter) []event.Event {
|
||||||
|
// Hack to facilitate transition to per-filter tags.
|
||||||
|
for i, f := range filters {
|
||||||
|
switch f := f.(type) {
|
||||||
|
case key.Filter:
|
||||||
|
f.Target = h
|
||||||
|
filters[i] = f
|
||||||
|
case key.FocusFilter:
|
||||||
|
f.Target = h
|
||||||
|
filters[i] = f
|
||||||
|
case transfer.SourceFilter:
|
||||||
|
f.Target = h
|
||||||
|
filters[i] = f
|
||||||
|
case transfer.TargetFilter:
|
||||||
|
f.Target = h
|
||||||
|
filters[i] = f
|
||||||
|
case pointer.Filter:
|
||||||
|
f.Target = h
|
||||||
|
filters[i] = f
|
||||||
|
}
|
||||||
|
}
|
||||||
var events []event.Event
|
var events []event.Event
|
||||||
for {
|
for {
|
||||||
e, ok := r.Event(h, filters...)
|
e, ok := r.Event(filters...)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-32
@@ -35,30 +35,23 @@ type Router struct {
|
|||||||
queue keyQueue
|
queue keyQueue
|
||||||
}
|
}
|
||||||
cqueue clipboardQueue
|
cqueue clipboardQueue
|
||||||
|
|
||||||
// states is the list of pending state changes resulting from
|
// states is the list of pending state changes resulting from
|
||||||
// incoming events. The first element, if present, contains the state
|
// incoming events. The first element, if present, contains the state
|
||||||
// and events for the current frame.
|
// and events for the current frame.
|
||||||
changes []stateChange
|
changes []stateChange
|
||||||
|
reader ops.Reader
|
||||||
reader ops.Reader
|
|
||||||
|
|
||||||
// InvalidateCmd summary.
|
// InvalidateCmd summary.
|
||||||
wakeup bool
|
wakeup bool
|
||||||
wakeupTime time.Time
|
wakeupTime time.Time
|
||||||
|
|
||||||
// Changes queued for next call to Frame.
|
// Changes queued for next call to Frame.
|
||||||
commands []Command
|
commands []Command
|
||||||
|
|
||||||
// transfers is the pending transfer.DataEvent.Open functions.
|
// transfers is the pending transfer.DataEvent.Open functions.
|
||||||
transfers []io.ReadCloser
|
transfers []io.ReadCloser
|
||||||
|
|
||||||
// deferring is set if command execution and event delivery is deferred
|
// deferring is set if command execution and event delivery is deferred
|
||||||
// to the next frame.
|
// to the next frame.
|
||||||
deferring bool
|
deferring bool
|
||||||
|
// scratchFilters is for garbage-free construction of ephemeral filters.
|
||||||
// scratchFilter is for garbage-free construction of ephemeral filters.
|
scratchFilters []taggedFilter
|
||||||
scratchFilter filter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source implements the interface between a Router and user interface widgets.
|
// Source implements the interface between a Router and user interface widgets.
|
||||||
@@ -131,6 +124,12 @@ type filter struct {
|
|||||||
key keyFilter
|
key keyFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// taggedFilter is a filter for a particular tag.
|
||||||
|
type taggedFilter struct {
|
||||||
|
tag event.Tag
|
||||||
|
filter filter
|
||||||
|
}
|
||||||
|
|
||||||
// stateChange represents the new state and outgoing events
|
// stateChange represents the new state and outgoing events
|
||||||
// resulting from an incoming event.
|
// resulting from an incoming event.
|
||||||
type stateChange struct {
|
type stateChange struct {
|
||||||
@@ -173,51 +172,94 @@ func (s Source) Enabled() bool {
|
|||||||
return s.r != nil
|
return s.r != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event returns the next event for the handler tag that matches one
|
// Event returns the next event that matches at least one of filters.
|
||||||
// or more of filters.
|
func (s Source) Event(filters ...event.Filter) (event.Event, bool) {
|
||||||
func (s Source) Event(k event.Tag, filters ...event.Filter) (event.Event, bool) {
|
|
||||||
if !s.Enabled() {
|
if !s.Enabled() {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
return s.r.Event(k, filters...)
|
return s.r.Event(filters...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Router) Event(k event.Tag, filters ...event.Filter) (event.Event, bool) {
|
func (q *Router) Event(filters ...event.Filter) (event.Event, bool) {
|
||||||
h := q.stateFor(k)
|
// Merge filters into scratch filters.
|
||||||
q.scratchFilter.Reset()
|
q.scratchFilters = q.scratchFilters[:0]
|
||||||
// Record handler filters and add reset events.
|
|
||||||
for _, f := range filters {
|
for _, f := range filters {
|
||||||
q.scratchFilter.Add(f)
|
var t event.Tag
|
||||||
switch f.(type) {
|
switch f := f.(type) {
|
||||||
|
case key.Filter:
|
||||||
|
t = f.Target
|
||||||
|
case transfer.SourceFilter:
|
||||||
|
t = f.Target
|
||||||
|
case transfer.TargetFilter:
|
||||||
|
t = f.Target
|
||||||
case key.FocusFilter:
|
case key.FocusFilter:
|
||||||
|
t = f.Target
|
||||||
|
case pointer.Filter:
|
||||||
|
t = f.Target
|
||||||
|
}
|
||||||
|
if t == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var filter *filter
|
||||||
|
for i := range q.scratchFilters {
|
||||||
|
s := &q.scratchFilters[i]
|
||||||
|
if s.tag == t {
|
||||||
|
filter = &s.filter
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if filter == nil {
|
||||||
|
n := len(q.scratchFilters)
|
||||||
|
q.scratchFilters = append(q.scratchFilters, taggedFilter{tag: t})
|
||||||
|
filter = &q.scratchFilters[n].filter
|
||||||
|
}
|
||||||
|
filter.Add(f)
|
||||||
|
}
|
||||||
|
for _, tf := range q.scratchFilters {
|
||||||
|
h := q.stateFor(tf.tag)
|
||||||
|
h.filter.Merge(tf.filter)
|
||||||
|
h.nextFilter.Merge(tf.filter)
|
||||||
|
}
|
||||||
|
// Deliver reset event, if any.
|
||||||
|
for _, f := range filters {
|
||||||
|
switch f := f.(type) {
|
||||||
|
case key.FocusFilter:
|
||||||
|
if f.Target == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
h := q.stateFor(f.Target)
|
||||||
if reset, ok := h.key.ResetEvent(); ok {
|
if reset, ok := h.key.ResetEvent(); ok {
|
||||||
return reset, true
|
return reset, true
|
||||||
}
|
}
|
||||||
case pointer.Filter:
|
case pointer.Filter:
|
||||||
|
if f.Target == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
h := q.stateFor(f.Target)
|
||||||
if reset, ok := h.pointer.ResetEvent(); ok {
|
if reset, ok := h.pointer.ResetEvent(); ok {
|
||||||
return reset, true
|
return reset, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h.nextFilter.Merge(q.scratchFilter)
|
|
||||||
if !q.deferring {
|
if !q.deferring {
|
||||||
for i := range q.changes {
|
for i := range q.changes {
|
||||||
change := &q.changes[i]
|
change := &q.changes[i]
|
||||||
j := 0
|
for j, evt := range change.events {
|
||||||
for j < len(change.events) {
|
for _, tf := range q.scratchFilters {
|
||||||
evt := change.events[j]
|
if evt.tag == tf.tag && tf.filter.Matches(evt.event) {
|
||||||
if evt.tag != k || !q.scratchFilter.Matches(evt.event) {
|
change.events = append(change.events[:j], change.events[j+1:]...)
|
||||||
j++
|
// Fast forward state to last matched.
|
||||||
continue
|
q.collapseState(i)
|
||||||
|
return evt.event, true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
change.events = append(change.events[:j], change.events[j+1:]...)
|
|
||||||
// Fast forward state to last matched.
|
|
||||||
q.collapseState(i)
|
|
||||||
return evt.event, true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h.processedFilter.Merge(q.scratchFilter)
|
for _, tf := range q.scratchFilters {
|
||||||
|
h := q.stateFor(tf.tag)
|
||||||
|
h.processedFilter.Merge(tf.filter)
|
||||||
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,6 +733,9 @@ func (q *Router) EditorState() EditorState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (q *Router) stateFor(tag event.Tag) *handler {
|
func (q *Router) stateFor(tag event.Tag) *handler {
|
||||||
|
if tag == nil {
|
||||||
|
panic("internal error: nil tag")
|
||||||
|
}
|
||||||
s, ok := q.handlers[tag]
|
s, ok := q.handlers[tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
s = new(handler)
|
s = new(handler)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func TestNoFilterAllocs(t *testing.T) {
|
|||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
s.Event(nil, pointer.Filter{})
|
s.Event(pointer.Filter{})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if allocs := b.AllocsPerOp(); allocs != 0 {
|
if allocs := b.AllocsPerOp(); allocs != 0 {
|
||||||
|
|||||||
+8
-3
@@ -18,8 +18,9 @@ import (
|
|||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Filter matches [Event]s.
|
// Filter matches any [Event] that matches the parameters.
|
||||||
type Filter struct {
|
type Filter struct {
|
||||||
|
Target event.Tag
|
||||||
// Required is the set of modifiers that must be included in events matched.
|
// Required is the set of modifiers that must be included in events matched.
|
||||||
Required Modifiers
|
Required Modifiers
|
||||||
// Optional is the set of modifiers that may be included in events matched.
|
// Optional is the set of modifiers that may be included in events matched.
|
||||||
@@ -108,8 +109,12 @@ type EditEvent struct {
|
|||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
// FocusFilter matches [FocusEvent]s.
|
// FocusFilter matches any [FocusEvent], [EditEvent], [SnippetEvent],
|
||||||
type FocusFilter struct{}
|
// or [SelectionEvent] with the specified target.
|
||||||
|
type FocusFilter struct {
|
||||||
|
// Target is a tag specified in a previous event.Op.
|
||||||
|
Target event.Tag
|
||||||
|
}
|
||||||
|
|
||||||
// InputHint changes the on-screen-keyboard type. That hints the
|
// InputHint changes the on-screen-keyboard type. That hints the
|
||||||
// type of data that might be entered by the user.
|
// type of data that might be entered by the user.
|
||||||
|
|||||||
+7
-24
@@ -5,36 +5,19 @@ Package pointer implements pointer events and operations.
|
|||||||
A pointer is either a mouse controlled cursor or a touch
|
A pointer is either a mouse controlled cursor or a touch
|
||||||
object such as a finger.
|
object such as a finger.
|
||||||
|
|
||||||
The InputOp operation is used to declare a handler ready for pointer
|
The [event.Op] operation is used to declare a handler ready for pointer
|
||||||
events. Use an event.Queue to receive events.
|
events.
|
||||||
|
|
||||||
# Kinds
|
|
||||||
|
|
||||||
Only events that match a specified list of types are delivered to a handler.
|
|
||||||
|
|
||||||
For example, to receive Press, Drag, and Release events (but not Move, Enter,
|
|
||||||
Leave, or Scroll):
|
|
||||||
|
|
||||||
var ops op.Ops
|
|
||||||
var h *Handler = ...
|
|
||||||
|
|
||||||
pointer.InputOp{
|
|
||||||
Tag: h,
|
|
||||||
Kinds: pointer.Press | pointer.Drag | pointer.Release,
|
|
||||||
}.Add(ops)
|
|
||||||
|
|
||||||
Cancel events are always delivered.
|
|
||||||
|
|
||||||
# Hit areas
|
# Hit areas
|
||||||
|
|
||||||
Clip operations from package op/clip are used for specifying
|
Clip operations from package [op/clip] are used for specifying
|
||||||
hit areas where subsequent InputOps are active.
|
hit areas where handlers may receive events.
|
||||||
|
|
||||||
For example, to set up a handler with a rectangular hit area:
|
For example, to set up a handler with a rectangular hit area:
|
||||||
|
|
||||||
r := image.Rectangle{...}
|
r := image.Rectangle{...}
|
||||||
area := clip.Rect(r).Push(ops)
|
area := clip.Rect(r).Push(ops)
|
||||||
pointer.InputOp{Tag: h}.Add(ops)
|
event.Op{Tag: h}.Add(ops)
|
||||||
area.Pop()
|
area.Pop()
|
||||||
|
|
||||||
Note that hit areas behave similar to painting: the effective area of a stack
|
Note that hit areas behave similar to painting: the effective area of a stack
|
||||||
@@ -54,11 +37,11 @@ For example:
|
|||||||
var h1, h2 *Handler
|
var h1, h2 *Handler
|
||||||
|
|
||||||
area := clip.Rect(...).Push(ops)
|
area := clip.Rect(...).Push(ops)
|
||||||
pointer.InputOp{Tag: h1}.Add(Ops)
|
event.Op{Tag: h1}.Add(Ops)
|
||||||
area.Pop()
|
area.Pop()
|
||||||
|
|
||||||
area := clip.Rect(...).Push(ops)
|
area := clip.Rect(...).Push(ops)
|
||||||
pointer.InputOp{Tag: h2}.Add(ops)
|
event.Op{Tag: h2}.Add(ops)
|
||||||
area.Pop()
|
area.Pop()
|
||||||
|
|
||||||
implies a tree of two inner nodes, each with one pointer handler attached.
|
implies a tree of two inner nodes, each with one pointer handler attached.
|
||||||
|
|||||||
@@ -54,8 +54,11 @@ type PassStack struct {
|
|||||||
macroID uint32
|
macroID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter matches [Event]s.
|
// Filter matches every [Event] that target the Tag and whose kind is
|
||||||
|
// included in Kinds. Note that only tags specified in [event.Op] can
|
||||||
|
// be targeted by pointer events.
|
||||||
type Filter struct {
|
type Filter struct {
|
||||||
|
Target event.Tag
|
||||||
// Kinds is a bitwise-or of event types to match.
|
// Kinds is a bitwise-or of event types to match.
|
||||||
Kinds Kind
|
Kinds Kind
|
||||||
// ScrollBounds describe the maximum scrollable distances in both
|
// ScrollBounds describe the maximum scrollable distances in both
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ func (OfferCmd) ImplementsCommand() {}
|
|||||||
// as well as [InitiateEvent] and [CancelEvent].
|
// as well as [InitiateEvent] and [CancelEvent].
|
||||||
// Use multiple filters to offer multiple types.
|
// Use multiple filters to offer multiple types.
|
||||||
type SourceFilter struct {
|
type SourceFilter struct {
|
||||||
|
// Target is a tag included in a previous event.Op.
|
||||||
|
Target event.Tag
|
||||||
// Type is the MIME type supported by this source.
|
// Type is the MIME type supported by this source.
|
||||||
Type string
|
Type string
|
||||||
}
|
}
|
||||||
@@ -49,6 +51,8 @@ type SourceFilter struct {
|
|||||||
// TargetFilter filters for any [DataEvent] whose type matches a MIME type
|
// TargetFilter filters for any [DataEvent] whose type matches a MIME type
|
||||||
// as well as [CancelEvent]. Use multiple filters to accept multiple types.
|
// as well as [CancelEvent]. Use multiple filters to accept multiple types.
|
||||||
type TargetFilter struct {
|
type TargetFilter struct {
|
||||||
|
// Target is a tag included in a previous event.Op.
|
||||||
|
Target event.Tag
|
||||||
// Type is the MIME type accepted by this target.
|
// Type is the MIME type accepted by this target.
|
||||||
Type string
|
Type string
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -148,13 +148,16 @@ func (b *Clickable) Update(gtx layout.Context) (Click, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
filters := []event.Filter{
|
filters := []event.Filter{
|
||||||
key.FocusFilter{},
|
key.FocusFilter{Target: b},
|
||||||
}
|
}
|
||||||
if b.focused {
|
if b.focused {
|
||||||
filters = append(filters, key.Filter{Name: key.NameReturn}, key.Filter{Name: key.NameSpace})
|
filters = append(filters,
|
||||||
|
key.Filter{Target: b, Name: key.NameReturn},
|
||||||
|
key.Filter{Target: b, Name: key.NameSpace},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
e, ok := gtx.Event(b, filters...)
|
e, ok := gtx.Event(filters...)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ func (d *Draggable) Update(gtx layout.Context) (mime string, requested bool) {
|
|||||||
d.pos = pos
|
d.pos = pos
|
||||||
|
|
||||||
for {
|
for {
|
||||||
e, ok := gtx.Event(d, transfer.SourceFilter{Type: d.Type})
|
e, ok := gtx.Event(transfer.SourceFilter{Target: d, Type: d.Type})
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -35,7 +35,7 @@ func TestDraggable(t *testing.T) {
|
|||||||
stack.Pop()
|
stack.Pop()
|
||||||
|
|
||||||
drag.Update(gtx)
|
drag.Update(gtx)
|
||||||
r.Event(tgt, transfer.TargetFilter{Type: drag.Type})
|
r.Event(transfer.TargetFilter{Target: tgt, Type: drag.Type})
|
||||||
r.Frame(gtx.Ops)
|
r.Frame(gtx.Ops)
|
||||||
r.Queue(
|
r.Queue(
|
||||||
pointer.Event{
|
pointer.Event{
|
||||||
@@ -53,10 +53,10 @@ func TestDraggable(t *testing.T) {
|
|||||||
)
|
)
|
||||||
ofr := &offer{data: "hello"}
|
ofr := &offer{data: "hello"}
|
||||||
drag.Update(gtx)
|
drag.Update(gtx)
|
||||||
r.Event(tgt, transfer.TargetFilter{Type: drag.Type})
|
r.Event(transfer.TargetFilter{Target: tgt, Type: drag.Type})
|
||||||
drag.Offer(gtx, "file", ofr)
|
drag.Offer(gtx, "file", ofr)
|
||||||
|
|
||||||
e, ok := r.Event(tgt, transfer.TargetFilter{Type: drag.Type})
|
e, ok := r.Event(transfer.TargetFilter{Target: tgt, Type: drag.Type})
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected event")
|
t.Fatalf("expected event")
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ func TestDraggable(t *testing.T) {
|
|||||||
if ofr.closed {
|
if ofr.closed {
|
||||||
t.Error("offer closed prematurely")
|
t.Error("offer closed prematurely")
|
||||||
}
|
}
|
||||||
e, ok = r.Event(tgt, transfer.TargetFilter{Type: drag.Type})
|
e, ok = r.Event(transfer.TargetFilter{Target: tgt, Type: drag.Type})
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected event")
|
t.Fatalf("expected event")
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-23
@@ -337,50 +337,50 @@ func (e *Editor) processKey(gtx layout.Context) {
|
|||||||
if e.text.Changed() {
|
if e.text.Changed() {
|
||||||
e.events = append(e.events, ChangeEvent{})
|
e.events = append(e.events, ChangeEvent{})
|
||||||
}
|
}
|
||||||
filters := []event.Filter{key.FocusFilter{}, transfer.TargetFilter{Type: "application/text"}}
|
filters := []event.Filter{key.FocusFilter{Target: e}, transfer.TargetFilter{Target: e, Type: "application/text"}}
|
||||||
if e.focused {
|
if e.focused {
|
||||||
filters = append(filters,
|
filters = append(filters,
|
||||||
key.Filter{Name: key.NameEnter, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NameEnter, Optional: key.ModShift},
|
||||||
key.Filter{Name: key.NameReturn, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NameReturn, Optional: key.ModShift},
|
||||||
|
|
||||||
key.Filter{Name: "Z", Required: key.ModShortcut, Optional: key.ModShift},
|
key.Filter{Target: e, Name: "Z", Required: key.ModShortcut, Optional: key.ModShift},
|
||||||
key.Filter{Name: "C", Required: key.ModShortcut},
|
key.Filter{Target: e, Name: "C", Required: key.ModShortcut},
|
||||||
key.Filter{Name: "V", Required: key.ModShortcut},
|
key.Filter{Target: e, Name: "V", Required: key.ModShortcut},
|
||||||
key.Filter{Name: "X", Required: key.ModShortcut},
|
key.Filter{Target: e, Name: "X", Required: key.ModShortcut},
|
||||||
key.Filter{Name: "A", Required: key.ModShortcut},
|
key.Filter{Target: e, Name: "A", Required: key.ModShortcut},
|
||||||
|
|
||||||
key.Filter{Name: key.NameDeleteBackward, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameDeleteBackward, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameDeleteForward, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameDeleteForward, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
|
|
||||||
key.Filter{Name: key.NameHome, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NameHome, Optional: key.ModShift},
|
||||||
key.Filter{Name: key.NameEnd, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NameEnd, Optional: key.ModShift},
|
||||||
key.Filter{Name: key.NamePageDown, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NamePageDown, Optional: key.ModShift},
|
||||||
key.Filter{Name: key.NamePageUp, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NamePageUp, Optional: key.ModShift},
|
||||||
)
|
)
|
||||||
caret, _ := e.text.Selection()
|
caret, _ := e.text.Selection()
|
||||||
if caret > 0 {
|
if caret > 0 {
|
||||||
if gtx.Locale.Direction.Progression() == system.FromOrigin {
|
if gtx.Locale.Direction.Progression() == system.FromOrigin {
|
||||||
filters = append(filters,
|
filters = append(filters,
|
||||||
key.Filter{Name: key.NameLeftArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameLeftArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameUpArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameUpArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
filters = append(filters,
|
filters = append(filters,
|
||||||
key.Filter{Name: key.NameRightArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameRightArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameDownArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameDownArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if caret < e.text.Len() {
|
if caret < e.text.Len() {
|
||||||
if gtx.Locale.Direction.Progression() == system.FromOrigin {
|
if gtx.Locale.Direction.Progression() == system.FromOrigin {
|
||||||
filters = append(filters,
|
filters = append(filters,
|
||||||
key.Filter{Name: key.NameRightArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameRightArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameDownArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameDownArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
filters = append(filters,
|
filters = append(filters,
|
||||||
key.Filter{Name: key.NameLeftArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameLeftArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameUpArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameUpArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,7 +388,7 @@ func (e *Editor) processKey(gtx layout.Context) {
|
|||||||
// adjust keeps track of runes dropped because of MaxLen.
|
// adjust keeps track of runes dropped because of MaxLen.
|
||||||
var adjust int
|
var adjust int
|
||||||
for {
|
for {
|
||||||
ke, ok := gtx.Event(e, filters...)
|
ke, ok := gtx.Event(filters...)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -65,13 +65,16 @@ func (e *Enum) Update(gtx layout.Context) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
filters := []event.Filter{
|
filters := []event.Filter{
|
||||||
key.FocusFilter{},
|
key.FocusFilter{Target: &state.tag},
|
||||||
}
|
}
|
||||||
if e.focused && e.focus == state.key {
|
if e.focused && e.focus == state.key {
|
||||||
filters = append(filters, key.Filter{Name: key.NameReturn}, key.Filter{Name: key.NameSpace})
|
filters = append(filters,
|
||||||
|
key.Filter{Target: &state.tag, Name: key.NameReturn},
|
||||||
|
key.Filter{Target: &state.tag, Name: key.NameSpace},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
ev, ok := gtx.Event(&state.tag, filters...)
|
ev, ok := gtx.Event(filters...)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ func ExampleDraggable_Layout() {
|
|||||||
|
|
||||||
// Check for the received data.
|
// Check for the received data.
|
||||||
for {
|
for {
|
||||||
ev, ok := gtx.Event(&drop, transfer.TargetFilter{Type: mime})
|
ev, ok := gtx.Event(transfer.TargetFilter{Target: &drop, Type: mime})
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -302,27 +302,27 @@ func (e *Selectable) clickDragEvents(gtx layout.Context) []event.Event {
|
|||||||
|
|
||||||
func (e *Selectable) processKey(gtx layout.Context) {
|
func (e *Selectable) processKey(gtx layout.Context) {
|
||||||
filters := []event.Filter{
|
filters := []event.Filter{
|
||||||
key.FocusFilter{},
|
key.FocusFilter{Target: e},
|
||||||
}
|
}
|
||||||
if e.focused {
|
if e.focused {
|
||||||
filters = append(filters,
|
filters = append(filters,
|
||||||
key.Filter{Name: key.NameLeftArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameLeftArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameRightArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameRightArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameUpArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameUpArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
key.Filter{Name: key.NameDownArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
key.Filter{Target: e, Name: key.NameDownArrow, Optional: key.ModShortcutAlt | key.ModShift},
|
||||||
|
|
||||||
key.Filter{Name: key.NamePageUp, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NamePageUp, Optional: key.ModShift},
|
||||||
key.Filter{Name: key.NamePageDown, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NamePageDown, Optional: key.ModShift},
|
||||||
key.Filter{Name: key.NameEnd, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NameEnd, Optional: key.ModShift},
|
||||||
key.Filter{Name: key.NameHome, Optional: key.ModShift},
|
key.Filter{Target: e, Name: key.NameHome, Optional: key.ModShift},
|
||||||
|
|
||||||
key.Filter{Name: "C", Required: key.ModShortcut},
|
key.Filter{Target: e, Name: "C", Required: key.ModShortcut},
|
||||||
key.Filter{Name: "X", Required: key.ModShortcut},
|
key.Filter{Target: e, Name: "X", Required: key.ModShortcut},
|
||||||
key.Filter{Name: "A", Required: key.ModShortcut},
|
key.Filter{Target: e, Name: "A", Required: key.ModShortcut},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
ke, ok := gtx.Event(e, filters...)
|
ke, ok := gtx.Event(filters...)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user