github.com/Seikaijyu/gio@v0.0.1/io/router/pointer.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package router
     4  
     5  import (
     6  	"image"
     7  	"io"
     8  
     9  	"github.com/Seikaijyu/gio/f32"
    10  	f32internal "github.com/Seikaijyu/gio/internal/f32"
    11  	"github.com/Seikaijyu/gio/internal/ops"
    12  	"github.com/Seikaijyu/gio/io/event"
    13  	"github.com/Seikaijyu/gio/io/key"
    14  	"github.com/Seikaijyu/gio/io/pointer"
    15  	"github.com/Seikaijyu/gio/io/semantic"
    16  	"github.com/Seikaijyu/gio/io/system"
    17  	"github.com/Seikaijyu/gio/io/transfer"
    18  )
    19  
    20  type pointerQueue struct {
    21  	hitTree   []hitNode
    22  	areas     []areaNode
    23  	cursor    pointer.Cursor
    24  	handlers  map[event.Tag]*pointerHandler
    25  	pointers  []pointerInfo
    26  	transfers []io.ReadCloser // pending data transfers
    27  
    28  	scratch []event.Tag
    29  
    30  	semantic struct {
    31  		idsAssigned bool
    32  		lastID      SemanticID
    33  		// contentIDs maps semantic content to a list of semantic IDs
    34  		// previously assigned. It is used to maintain stable IDs across
    35  		// frames.
    36  		contentIDs map[semanticContent][]semanticID
    37  	}
    38  }
    39  
    40  type hitNode struct {
    41  	next int
    42  	area int
    43  
    44  	// For handler nodes.
    45  	tag  event.Tag
    46  	ktag event.Tag
    47  	pass bool
    48  }
    49  
    50  type pointerInfo struct {
    51  	id       pointer.ID
    52  	pressed  bool
    53  	handlers []event.Tag
    54  	// last tracks the last pointer event received,
    55  	// used while processing frame events.
    56  	last pointer.Event
    57  
    58  	// entered tracks the tags that contain the pointer.
    59  	entered []event.Tag
    60  
    61  	dataSource event.Tag // dragging source tag
    62  	dataTarget event.Tag // dragging target tag
    63  }
    64  
    65  type pointerHandler struct {
    66  	area      int
    67  	active    bool
    68  	wantsGrab bool
    69  	types     pointer.Kind
    70  	// min and max horizontal/vertical scroll
    71  	scrollRange image.Rectangle
    72  
    73  	sourceMimes []string
    74  	targetMimes []string
    75  	offeredMime string
    76  	data        io.ReadCloser
    77  }
    78  
    79  type areaOp struct {
    80  	kind areaKind
    81  	rect image.Rectangle
    82  }
    83  
    84  type areaNode struct {
    85  	trans f32.Affine2D
    86  	area  areaOp
    87  
    88  	cursor pointer.Cursor
    89  
    90  	// Tree indices, with -1 being the sentinel.
    91  	parent     int
    92  	firstChild int
    93  	lastChild  int
    94  	sibling    int
    95  
    96  	semantic struct {
    97  		valid   bool
    98  		id      SemanticID
    99  		content semanticContent
   100  	}
   101  	action system.Action
   102  }
   103  
   104  type areaKind uint8
   105  
   106  // collectState represents the state for pointerCollector.
   107  type collectState struct {
   108  	t f32.Affine2D
   109  	// nodePlusOne is the current node index, plus one to
   110  	// make the zero value collectState the initial state.
   111  	nodePlusOne int
   112  	pass        int
   113  }
   114  
   115  // pointerCollector tracks the state needed to update an pointerQueue
   116  // from pointer ops.
   117  type pointerCollector struct {
   118  	q         *pointerQueue
   119  	state     collectState
   120  	nodeStack []int
   121  }
   122  
   123  type semanticContent struct {
   124  	tag      event.Tag
   125  	label    string
   126  	desc     string
   127  	class    semantic.ClassOp
   128  	gestures SemanticGestures
   129  	selected bool
   130  	disabled bool
   131  }
   132  
   133  type semanticID struct {
   134  	id   SemanticID
   135  	used bool
   136  }
   137  
   138  const (
   139  	areaRect areaKind = iota
   140  	areaEllipse
   141  )
   142  
   143  func (c *pointerCollector) resetState() {
   144  	c.state = collectState{}
   145  	c.nodeStack = c.nodeStack[:0]
   146  	// Pop every node except the root.
   147  	if len(c.q.hitTree) > 0 {
   148  		c.state.nodePlusOne = 0 + 1
   149  	}
   150  }
   151  
   152  func (c *pointerCollector) setTrans(t f32.Affine2D) {
   153  	c.state.t = t
   154  }
   155  
   156  func (c *pointerCollector) clip(op ops.ClipOp) {
   157  	kind := areaRect
   158  	if op.Shape == ops.Ellipse {
   159  		kind = areaEllipse
   160  	}
   161  	c.pushArea(kind, op.Bounds)
   162  }
   163  
   164  func (c *pointerCollector) pushArea(kind areaKind, bounds image.Rectangle) {
   165  	parentID := c.currentArea()
   166  	areaID := len(c.q.areas)
   167  	areaOp := areaOp{kind: kind, rect: bounds}
   168  	if parentID != -1 {
   169  		parent := &c.q.areas[parentID]
   170  		if parent.firstChild == -1 {
   171  			parent.firstChild = areaID
   172  		}
   173  		if siblingID := parent.lastChild; siblingID != -1 {
   174  			c.q.areas[siblingID].sibling = areaID
   175  		}
   176  		parent.lastChild = areaID
   177  	}
   178  	an := areaNode{
   179  		trans:      c.state.t,
   180  		area:       areaOp,
   181  		parent:     parentID,
   182  		sibling:    -1,
   183  		firstChild: -1,
   184  		lastChild:  -1,
   185  	}
   186  
   187  	c.q.areas = append(c.q.areas, an)
   188  	c.nodeStack = append(c.nodeStack, c.state.nodePlusOne-1)
   189  	c.addHitNode(hitNode{
   190  		area: areaID,
   191  		pass: true,
   192  	})
   193  }
   194  
   195  func (c *pointerCollector) popArea() {
   196  	n := len(c.nodeStack)
   197  	c.state.nodePlusOne = c.nodeStack[n-1] + 1
   198  	c.nodeStack = c.nodeStack[:n-1]
   199  }
   200  
   201  func (c *pointerCollector) pass() {
   202  	c.state.pass++
   203  }
   204  
   205  func (c *pointerCollector) popPass() {
   206  	c.state.pass--
   207  }
   208  
   209  func (c *pointerCollector) currentArea() int {
   210  	if i := c.state.nodePlusOne - 1; i != -1 {
   211  		n := c.q.hitTree[i]
   212  		return n.area
   213  	}
   214  	return -1
   215  }
   216  
   217  func (c *pointerCollector) currentAreaBounds() image.Rectangle {
   218  	a := c.currentArea()
   219  	if a == -1 {
   220  		panic("no root area")
   221  	}
   222  	return c.q.areas[a].bounds()
   223  }
   224  
   225  func (c *pointerCollector) addHitNode(n hitNode) {
   226  	n.next = c.state.nodePlusOne - 1
   227  	c.q.hitTree = append(c.q.hitTree, n)
   228  	c.state.nodePlusOne = len(c.q.hitTree) - 1 + 1
   229  }
   230  
   231  // newHandler returns the current handler or a new one for tag.
   232  func (c *pointerCollector) newHandler(tag event.Tag, events *handlerEvents) *pointerHandler {
   233  	areaID := c.currentArea()
   234  	c.addHitNode(hitNode{
   235  		area: areaID,
   236  		tag:  tag,
   237  		pass: c.state.pass > 0,
   238  	})
   239  	h, ok := c.q.handlers[tag]
   240  	if !ok {
   241  		h = new(pointerHandler)
   242  		c.q.handlers[tag] = h
   243  		// Cancel handlers on (each) first appearance, but don't
   244  		// trigger redraw.
   245  		events.AddNoRedraw(tag, pointer.Event{Kind: pointer.Cancel})
   246  	}
   247  	h.active = true
   248  	h.area = areaID
   249  	return h
   250  }
   251  
   252  func (c *pointerCollector) keyInputOp(op key.InputOp) {
   253  	areaID := c.currentArea()
   254  	c.addHitNode(hitNode{
   255  		area: areaID,
   256  		ktag: op.Tag,
   257  		pass: true,
   258  	})
   259  }
   260  
   261  func (c *pointerCollector) actionInputOp(act system.Action) {
   262  	areaID := c.currentArea()
   263  	area := &c.q.areas[areaID]
   264  	area.action = act
   265  }
   266  
   267  func (c *pointerCollector) inputOp(op pointer.InputOp, events *handlerEvents) {
   268  	areaID := c.currentArea()
   269  	area := &c.q.areas[areaID]
   270  	area.semantic.content.tag = op.Tag
   271  	if op.Kinds&(pointer.Press|pointer.Release) != 0 {
   272  		area.semantic.content.gestures |= ClickGesture
   273  	}
   274  	if op.Kinds&pointer.Scroll != 0 {
   275  		area.semantic.content.gestures |= ScrollGesture
   276  	}
   277  	area.semantic.valid = area.semantic.content.gestures != 0
   278  	h := c.newHandler(op.Tag, events)
   279  	h.wantsGrab = h.wantsGrab || op.Grab
   280  	h.types = h.types | op.Kinds
   281  	h.scrollRange = op.ScrollBounds
   282  }
   283  
   284  func (c *pointerCollector) semanticLabel(lbl string) {
   285  	areaID := c.currentArea()
   286  	area := &c.q.areas[areaID]
   287  	area.semantic.valid = true
   288  	area.semantic.content.label = lbl
   289  }
   290  
   291  func (c *pointerCollector) semanticDesc(desc string) {
   292  	areaID := c.currentArea()
   293  	area := &c.q.areas[areaID]
   294  	area.semantic.valid = true
   295  	area.semantic.content.desc = desc
   296  }
   297  
   298  func (c *pointerCollector) semanticClass(class semantic.ClassOp) {
   299  	areaID := c.currentArea()
   300  	area := &c.q.areas[areaID]
   301  	area.semantic.valid = true
   302  	area.semantic.content.class = class
   303  }
   304  
   305  func (c *pointerCollector) semanticSelected(selected bool) {
   306  	areaID := c.currentArea()
   307  	area := &c.q.areas[areaID]
   308  	area.semantic.valid = true
   309  	area.semantic.content.selected = selected
   310  }
   311  
   312  func (c *pointerCollector) semanticEnabled(enabled bool) {
   313  	areaID := c.currentArea()
   314  	area := &c.q.areas[areaID]
   315  	area.semantic.valid = true
   316  	area.semantic.content.disabled = !enabled
   317  }
   318  
   319  func (c *pointerCollector) cursor(cursor pointer.Cursor) {
   320  	areaID := c.currentArea()
   321  	area := &c.q.areas[areaID]
   322  	area.cursor = cursor
   323  }
   324  
   325  func (c *pointerCollector) sourceOp(op transfer.SourceOp, events *handlerEvents) {
   326  	h := c.newHandler(op.Tag, events)
   327  	h.sourceMimes = append(h.sourceMimes, op.Type)
   328  }
   329  
   330  func (c *pointerCollector) targetOp(op transfer.TargetOp, events *handlerEvents) {
   331  	h := c.newHandler(op.Tag, events)
   332  	h.targetMimes = append(h.targetMimes, op.Type)
   333  }
   334  
   335  func (c *pointerCollector) offerOp(op transfer.OfferOp, events *handlerEvents) {
   336  	h := c.newHandler(op.Tag, events)
   337  	h.offeredMime = op.Type
   338  	h.data = op.Data
   339  }
   340  
   341  func (c *pointerCollector) reset() {
   342  	c.q.reset()
   343  	c.resetState()
   344  	c.ensureRoot()
   345  }
   346  
   347  // Ensure implicit root area for semantic descriptions to hang onto.
   348  func (c *pointerCollector) ensureRoot() {
   349  	if len(c.q.areas) > 0 {
   350  		return
   351  	}
   352  	c.pushArea(areaRect, image.Rect(-1e6, -1e6, 1e6, 1e6))
   353  	// Make it semantic to ensure a single semantic root.
   354  	c.q.areas[0].semantic.valid = true
   355  }
   356  
   357  func (q *pointerQueue) assignSemIDs() {
   358  	if q.semantic.idsAssigned {
   359  		return
   360  	}
   361  	q.semantic.idsAssigned = true
   362  	for i, a := range q.areas {
   363  		if a.semantic.valid {
   364  			q.areas[i].semantic.id = q.semanticIDFor(a.semantic.content)
   365  		}
   366  	}
   367  }
   368  
   369  func (q *pointerQueue) AppendSemantics(nodes []SemanticNode) []SemanticNode {
   370  	q.assignSemIDs()
   371  	nodes = q.appendSemanticChildren(nodes, 0)
   372  	nodes = q.appendSemanticArea(nodes, 0, 0)
   373  	return nodes
   374  }
   375  
   376  func (q *pointerQueue) appendSemanticArea(nodes []SemanticNode, parentID SemanticID, nodeIdx int) []SemanticNode {
   377  	areaIdx := nodes[nodeIdx].areaIdx
   378  	a := q.areas[areaIdx]
   379  	childStart := len(nodes)
   380  	nodes = q.appendSemanticChildren(nodes, a.firstChild)
   381  	childEnd := len(nodes)
   382  	for i := childStart; i < childEnd; i++ {
   383  		nodes = q.appendSemanticArea(nodes, a.semantic.id, i)
   384  	}
   385  	n := &nodes[nodeIdx]
   386  	n.ParentID = parentID
   387  	n.Children = nodes[childStart:childEnd]
   388  	return nodes
   389  }
   390  
   391  func (q *pointerQueue) appendSemanticChildren(nodes []SemanticNode, areaIdx int) []SemanticNode {
   392  	if areaIdx == -1 {
   393  		return nodes
   394  	}
   395  	a := q.areas[areaIdx]
   396  	if semID := a.semantic.id; semID != 0 {
   397  		cnt := a.semantic.content
   398  		nodes = append(nodes, SemanticNode{
   399  			ID: semID,
   400  			Desc: SemanticDesc{
   401  				Bounds:      a.bounds(),
   402  				Label:       cnt.label,
   403  				Description: cnt.desc,
   404  				Class:       cnt.class,
   405  				Gestures:    cnt.gestures,
   406  				Selected:    cnt.selected,
   407  				Disabled:    cnt.disabled,
   408  			},
   409  			areaIdx: areaIdx,
   410  		})
   411  	} else {
   412  		nodes = q.appendSemanticChildren(nodes, a.firstChild)
   413  	}
   414  	return q.appendSemanticChildren(nodes, a.sibling)
   415  }
   416  
   417  func (q *pointerQueue) semanticIDFor(content semanticContent) SemanticID {
   418  	ids := q.semantic.contentIDs[content]
   419  	for i, id := range ids {
   420  		if !id.used {
   421  			ids[i].used = true
   422  			return id.id
   423  		}
   424  	}
   425  	// No prior assigned ID; allocate a new one.
   426  	q.semantic.lastID++
   427  	id := semanticID{id: q.semantic.lastID, used: true}
   428  	if q.semantic.contentIDs == nil {
   429  		q.semantic.contentIDs = make(map[semanticContent][]semanticID)
   430  	}
   431  	q.semantic.contentIDs[content] = append(q.semantic.contentIDs[content], id)
   432  	return id.id
   433  }
   434  
   435  func (q *pointerQueue) ActionAt(pos f32.Point) (action system.Action, hasAction bool) {
   436  	q.hitTest(pos, func(n *hitNode) bool {
   437  		area := q.areas[n.area]
   438  		if area.action != 0 {
   439  			action = area.action
   440  			hasAction = true
   441  			return false
   442  		}
   443  		return true
   444  	})
   445  	return action, hasAction
   446  }
   447  
   448  func (q *pointerQueue) SemanticAt(pos f32.Point) (semID SemanticID, hasSemID bool) {
   449  	q.assignSemIDs()
   450  	q.hitTest(pos, func(n *hitNode) bool {
   451  		area := q.areas[n.area]
   452  		if area.semantic.id != 0 {
   453  			semID = area.semantic.id
   454  			hasSemID = true
   455  			return false
   456  		}
   457  		return true
   458  	})
   459  	return semID, hasSemID
   460  }
   461  
   462  // hitTest searches the hit tree for nodes matching pos. Any node matching pos will
   463  // have the onNode func invoked on it to allow the caller to extract whatever information
   464  // is necessary for further processing. onNode may return false to terminate the walk of
   465  // the hit tree, or true to continue. Providing this algorithm in this generic way
   466  // allows normal event routing and system action event routing to share the same traversal
   467  // logic even though they are interested in different aspects of hit nodes.
   468  func (q *pointerQueue) hitTest(pos f32.Point, onNode func(*hitNode) bool) pointer.Cursor {
   469  	// Track whether we're passing through hits.
   470  	pass := true
   471  	idx := len(q.hitTree) - 1
   472  	cursor := pointer.CursorDefault
   473  	for idx >= 0 {
   474  		n := &q.hitTree[idx]
   475  		hit, c := q.hit(n.area, pos)
   476  		if !hit {
   477  			idx--
   478  			continue
   479  		}
   480  		if cursor == pointer.CursorDefault {
   481  			cursor = c
   482  		}
   483  		pass = pass && n.pass
   484  		if pass {
   485  			idx--
   486  		} else {
   487  			idx = n.next
   488  		}
   489  		if !onNode(n) {
   490  			break
   491  		}
   492  	}
   493  	return cursor
   494  }
   495  
   496  func (q *pointerQueue) opHit(pos f32.Point) ([]event.Tag, pointer.Cursor) {
   497  	hits := q.scratch[:0]
   498  	cursor := q.hitTest(pos, func(n *hitNode) bool {
   499  		if n.tag != nil {
   500  			if _, exists := q.handlers[n.tag]; exists {
   501  				hits = addHandler(hits, n.tag)
   502  			}
   503  		}
   504  		return true
   505  	})
   506  	q.scratch = hits[:0]
   507  	return hits, cursor
   508  }
   509  
   510  func (q *pointerQueue) invTransform(areaIdx int, p f32.Point) f32.Point {
   511  	if areaIdx == -1 {
   512  		return p
   513  	}
   514  	return q.areas[areaIdx].trans.Invert().Transform(p)
   515  }
   516  
   517  func (q *pointerQueue) hit(areaIdx int, p f32.Point) (bool, pointer.Cursor) {
   518  	c := pointer.CursorDefault
   519  	for areaIdx != -1 {
   520  		a := &q.areas[areaIdx]
   521  		if c == pointer.CursorDefault {
   522  			c = a.cursor
   523  		}
   524  		p := a.trans.Invert().Transform(p)
   525  		if !a.area.Hit(p) {
   526  			return false, c
   527  		}
   528  		areaIdx = a.parent
   529  	}
   530  	return true, c
   531  }
   532  
   533  func (q *pointerQueue) reset() {
   534  	if q.handlers == nil {
   535  		q.handlers = make(map[event.Tag]*pointerHandler)
   536  	}
   537  	for _, h := range q.handlers {
   538  		// Reset handler.
   539  		h.active = false
   540  		h.wantsGrab = false
   541  		h.types = 0
   542  		h.sourceMimes = h.sourceMimes[:0]
   543  		h.targetMimes = h.targetMimes[:0]
   544  	}
   545  	q.hitTree = q.hitTree[:0]
   546  	q.areas = q.areas[:0]
   547  	q.semantic.idsAssigned = false
   548  	for k, ids := range q.semantic.contentIDs {
   549  		for i := len(ids) - 1; i >= 0; i-- {
   550  			if !ids[i].used {
   551  				ids = append(ids[:i], ids[i+1:]...)
   552  			} else {
   553  				ids[i].used = false
   554  			}
   555  		}
   556  		if len(ids) > 0 {
   557  			q.semantic.contentIDs[k] = ids
   558  		} else {
   559  			delete(q.semantic.contentIDs, k)
   560  		}
   561  	}
   562  	for _, rc := range q.transfers {
   563  		if rc != nil {
   564  			rc.Close()
   565  		}
   566  	}
   567  	q.transfers = nil
   568  }
   569  
   570  func (q *pointerQueue) Frame(events *handlerEvents) {
   571  	for k, h := range q.handlers {
   572  		if !h.active {
   573  			q.dropHandler(nil, k)
   574  			delete(q.handlers, k)
   575  		}
   576  		if h.wantsGrab {
   577  			for _, p := range q.pointers {
   578  				if !p.pressed {
   579  					continue
   580  				}
   581  				for i, k2 := range p.handlers {
   582  					if k2 == k {
   583  						// Drop other handlers that lost their grab.
   584  						dropped := q.scratch[:0]
   585  						dropped = append(dropped, p.handlers[:i]...)
   586  						dropped = append(dropped, p.handlers[i+1:]...)
   587  						for _, tag := range dropped {
   588  							q.dropHandler(events, tag)
   589  						}
   590  						break
   591  					}
   592  				}
   593  			}
   594  		}
   595  	}
   596  	for i := range q.pointers {
   597  		p := &q.pointers[i]
   598  		q.deliverEnterLeaveEvents(p, events, p.last)
   599  		q.deliverTransferDataEvent(p, events)
   600  	}
   601  }
   602  
   603  func (q *pointerQueue) dropHandler(events *handlerEvents, tag event.Tag) {
   604  	if events != nil {
   605  		events.Add(tag, pointer.Event{Kind: pointer.Cancel})
   606  	}
   607  	for i := range q.pointers {
   608  		p := &q.pointers[i]
   609  		for i := len(p.handlers) - 1; i >= 0; i-- {
   610  			if p.handlers[i] == tag {
   611  				p.handlers = append(p.handlers[:i], p.handlers[i+1:]...)
   612  			}
   613  		}
   614  		for i := len(p.entered) - 1; i >= 0; i-- {
   615  			if p.entered[i] == tag {
   616  				p.entered = append(p.entered[:i], p.entered[i+1:]...)
   617  			}
   618  		}
   619  	}
   620  }
   621  
   622  // pointerOf returns the pointerInfo index corresponding to the pointer in e.
   623  func (q *pointerQueue) pointerOf(e pointer.Event) int {
   624  	for i, p := range q.pointers {
   625  		if p.id == e.PointerID {
   626  			return i
   627  		}
   628  	}
   629  	q.pointers = append(q.pointers, pointerInfo{id: e.PointerID})
   630  	return len(q.pointers) - 1
   631  }
   632  
   633  // Deliver is like Push, but delivers an event to a particular area.
   634  func (q *pointerQueue) Deliver(areaIdx int, e pointer.Event, events *handlerEvents) {
   635  	var sx, sy = e.Scroll.X, e.Scroll.Y
   636  	idx := len(q.hitTree) - 1
   637  	// Locate first potential receiver.
   638  	for idx != -1 {
   639  		n := &q.hitTree[idx]
   640  		if n.area == areaIdx {
   641  			break
   642  		}
   643  		idx--
   644  	}
   645  	for idx != -1 {
   646  		n := &q.hitTree[idx]
   647  		idx = n.next
   648  		if n.tag == nil {
   649  			continue
   650  		}
   651  		h := q.handlers[n.tag]
   652  		if e.Kind&h.types == 0 {
   653  			continue
   654  		}
   655  		e := e
   656  		if e.Kind == pointer.Scroll {
   657  			if sx == 0 && sy == 0 {
   658  				break
   659  			}
   660  			// Distribute the scroll to the handler based on its ScrollRange.
   661  			sx, e.Scroll.X = setScrollEvent(sx, h.scrollRange.Min.X, h.scrollRange.Max.X)
   662  			sy, e.Scroll.Y = setScrollEvent(sy, h.scrollRange.Min.Y, h.scrollRange.Max.Y)
   663  		}
   664  		e.Position = q.invTransform(h.area, e.Position)
   665  		events.Add(n.tag, e)
   666  		if e.Kind != pointer.Scroll {
   667  			break
   668  		}
   669  	}
   670  }
   671  
   672  // SemanticArea returns the sematic content for area, and its parent area.
   673  func (q *pointerQueue) SemanticArea(areaIdx int) (semanticContent, int) {
   674  	for areaIdx != -1 {
   675  		a := &q.areas[areaIdx]
   676  		areaIdx = a.parent
   677  		if !a.semantic.valid {
   678  			continue
   679  		}
   680  		return a.semantic.content, areaIdx
   681  	}
   682  	return semanticContent{}, -1
   683  }
   684  
   685  func (q *pointerQueue) Push(e pointer.Event, events *handlerEvents) {
   686  	if e.Kind == pointer.Cancel {
   687  		q.pointers = q.pointers[:0]
   688  		for k := range q.handlers {
   689  			q.dropHandler(events, k)
   690  		}
   691  		return
   692  	}
   693  	pidx := q.pointerOf(e)
   694  	p := &q.pointers[pidx]
   695  	p.last = e
   696  
   697  	switch e.Kind {
   698  	case pointer.Press:
   699  		q.deliverEnterLeaveEvents(p, events, e)
   700  		p.pressed = true
   701  		q.deliverEvent(p, events, e)
   702  	case pointer.Move:
   703  		if p.pressed {
   704  			e.Kind = pointer.Drag
   705  		}
   706  		q.deliverEnterLeaveEvents(p, events, e)
   707  		q.deliverEvent(p, events, e)
   708  		if p.pressed {
   709  			q.deliverDragEvent(p, events)
   710  		}
   711  	case pointer.Release:
   712  		q.deliverEvent(p, events, e)
   713  		p.pressed = false
   714  		q.deliverEnterLeaveEvents(p, events, e)
   715  		q.deliverDropEvent(p, events)
   716  	case pointer.Scroll:
   717  		q.deliverEnterLeaveEvents(p, events, e)
   718  		q.deliverEvent(p, events, e)
   719  	default:
   720  		panic("unsupported pointer event type")
   721  	}
   722  
   723  	if !p.pressed && len(p.entered) == 0 {
   724  		// No longer need to track pointer.
   725  		q.pointers = append(q.pointers[:pidx], q.pointers[pidx+1:]...)
   726  	}
   727  }
   728  
   729  func (q *pointerQueue) deliverEvent(p *pointerInfo, events *handlerEvents, e pointer.Event) {
   730  	foremost := true
   731  	if p.pressed && len(p.handlers) == 1 {
   732  		e.Priority = pointer.Grabbed
   733  		foremost = false
   734  	}
   735  	var sx, sy = e.Scroll.X, e.Scroll.Y
   736  	for _, k := range p.handlers {
   737  		h := q.handlers[k]
   738  		if e.Kind == pointer.Scroll {
   739  			if sx == 0 && sy == 0 {
   740  				return
   741  			}
   742  			// Distribute the scroll to the handler based on its ScrollRange.
   743  			sx, e.Scroll.X = setScrollEvent(sx, h.scrollRange.Min.X, h.scrollRange.Max.X)
   744  			sy, e.Scroll.Y = setScrollEvent(sy, h.scrollRange.Min.Y, h.scrollRange.Max.Y)
   745  		}
   746  		if e.Kind&h.types == 0 {
   747  			continue
   748  		}
   749  		e := e
   750  		if foremost {
   751  			foremost = false
   752  			e.Priority = pointer.Foremost
   753  		}
   754  		e.Position = q.invTransform(h.area, e.Position)
   755  		events.Add(k, e)
   756  	}
   757  }
   758  
   759  func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, events *handlerEvents, e pointer.Event) {
   760  	var hits []event.Tag
   761  	if e.Source != pointer.Mouse && !p.pressed && e.Kind != pointer.Press {
   762  		// Consider non-mouse pointers leaving when they're released.
   763  	} else {
   764  		hits, q.cursor = q.opHit(e.Position)
   765  		if p.pressed {
   766  			// Filter out non-participating handlers,
   767  			// except potential transfer targets when a transfer has been initiated.
   768  			var hitsHaveTarget bool
   769  			if p.dataSource != nil {
   770  				transferSource := q.handlers[p.dataSource]
   771  				for _, hit := range hits {
   772  					if _, ok := firstMimeMatch(transferSource, q.handlers[hit]); ok {
   773  						hitsHaveTarget = true
   774  						break
   775  					}
   776  				}
   777  			}
   778  			for i := len(hits) - 1; i >= 0; i-- {
   779  				if _, found := searchTag(p.handlers, hits[i]); !found && !hitsHaveTarget {
   780  					hits = append(hits[:i], hits[i+1:]...)
   781  				}
   782  			}
   783  		} else {
   784  			p.handlers = append(p.handlers[:0], hits...)
   785  		}
   786  	}
   787  	// Deliver Leave events.
   788  	for _, k := range p.entered {
   789  		if _, found := searchTag(hits, k); found {
   790  			continue
   791  		}
   792  		h := q.handlers[k]
   793  		e.Kind = pointer.Leave
   794  
   795  		if e.Kind&h.types != 0 {
   796  			e := e
   797  			e.Position = q.invTransform(h.area, e.Position)
   798  			events.Add(k, e)
   799  		}
   800  	}
   801  	// Deliver Enter events.
   802  	for _, k := range hits {
   803  		h := q.handlers[k]
   804  		if _, found := searchTag(p.entered, k); found {
   805  			continue
   806  		}
   807  		e.Kind = pointer.Enter
   808  
   809  		if e.Kind&h.types != 0 {
   810  			e := e
   811  			e.Position = q.invTransform(h.area, e.Position)
   812  			events.Add(k, e)
   813  		}
   814  	}
   815  	p.entered = append(p.entered[:0], hits...)
   816  }
   817  
   818  func (q *pointerQueue) deliverDragEvent(p *pointerInfo, events *handlerEvents) {
   819  	if p.dataSource != nil {
   820  		return
   821  	}
   822  	// Identify the data source.
   823  	for _, k := range p.entered {
   824  		src := q.handlers[k]
   825  		if len(src.sourceMimes) == 0 {
   826  			continue
   827  		}
   828  		// One data source handler per pointer.
   829  		p.dataSource = k
   830  		// Notify all potential targets.
   831  		for k, tgt := range q.handlers {
   832  			if _, ok := firstMimeMatch(src, tgt); ok {
   833  				events.Add(k, transfer.InitiateEvent{})
   834  			}
   835  		}
   836  		break
   837  	}
   838  }
   839  
   840  func (q *pointerQueue) deliverDropEvent(p *pointerInfo, events *handlerEvents) {
   841  	if p.dataSource == nil {
   842  		return
   843  	}
   844  	// Request data from the source.
   845  	src := q.handlers[p.dataSource]
   846  	for _, k := range p.entered {
   847  		h := q.handlers[k]
   848  		if m, ok := firstMimeMatch(src, h); ok {
   849  			p.dataTarget = k
   850  			events.Add(p.dataSource, transfer.RequestEvent{Type: m})
   851  			return
   852  		}
   853  	}
   854  	// No valid target found, abort.
   855  	q.deliverTransferCancelEvent(p, events)
   856  }
   857  
   858  func (q *pointerQueue) deliverTransferDataEvent(p *pointerInfo, events *handlerEvents) {
   859  	if p.dataSource == nil {
   860  		return
   861  	}
   862  	src := q.handlers[p.dataSource]
   863  	if src.data == nil {
   864  		// Data not received yet.
   865  		return
   866  	}
   867  	if p.dataTarget == nil {
   868  		q.deliverTransferCancelEvent(p, events)
   869  		return
   870  	}
   871  	// Send the offered data to the target.
   872  	transferIdx := len(q.transfers)
   873  	events.Add(p.dataTarget, transfer.DataEvent{
   874  		Type: src.offeredMime,
   875  		Open: func() io.ReadCloser {
   876  			q.transfers[transferIdx] = nil
   877  			return src.data
   878  		},
   879  	})
   880  	q.transfers = append(q.transfers, src.data)
   881  	p.dataTarget = nil
   882  }
   883  
   884  func (q *pointerQueue) deliverTransferCancelEvent(p *pointerInfo, events *handlerEvents) {
   885  	events.Add(p.dataSource, transfer.CancelEvent{})
   886  	// Cancel all potential targets.
   887  	src := q.handlers[p.dataSource]
   888  	for k, h := range q.handlers {
   889  		if _, ok := firstMimeMatch(src, h); ok {
   890  			events.Add(k, transfer.CancelEvent{})
   891  		}
   892  	}
   893  	src.offeredMime = ""
   894  	src.data = nil
   895  	p.dataSource = nil
   896  	p.dataTarget = nil
   897  }
   898  
   899  // ClipFor clips r to the parents of area.
   900  func (q *pointerQueue) ClipFor(area int, r image.Rectangle) image.Rectangle {
   901  	a := &q.areas[area]
   902  	parent := a.parent
   903  	for parent != -1 {
   904  		a := &q.areas[parent]
   905  		r = r.Intersect(a.bounds())
   906  		parent = a.parent
   907  	}
   908  	return r
   909  }
   910  
   911  func searchTag(tags []event.Tag, tag event.Tag) (int, bool) {
   912  	for i, t := range tags {
   913  		if t == tag {
   914  			return i, true
   915  		}
   916  	}
   917  	return 0, false
   918  }
   919  
   920  // addHandler adds tag to the slice if not present.
   921  func addHandler(tags []event.Tag, tag event.Tag) []event.Tag {
   922  	for _, t := range tags {
   923  		if t == tag {
   924  			return tags
   925  		}
   926  	}
   927  	return append(tags, tag)
   928  }
   929  
   930  // firstMimeMatch returns the first type match between src and tgt.
   931  func firstMimeMatch(src, tgt *pointerHandler) (first string, matched bool) {
   932  	for _, m1 := range tgt.targetMimes {
   933  		for _, m2 := range src.sourceMimes {
   934  			if m1 == m2 {
   935  				return m1, true
   936  			}
   937  		}
   938  	}
   939  	return "", false
   940  }
   941  
   942  func (op *areaOp) Hit(pos f32.Point) bool {
   943  	pos = pos.Sub(f32internal.FPt(op.rect.Min))
   944  	size := f32internal.FPt(op.rect.Size())
   945  	switch op.kind {
   946  	case areaRect:
   947  		return 0 <= pos.X && pos.X < size.X &&
   948  			0 <= pos.Y && pos.Y < size.Y
   949  	case areaEllipse:
   950  		rx := size.X / 2
   951  		ry := size.Y / 2
   952  		xh := pos.X - rx
   953  		yk := pos.Y - ry
   954  		// The ellipse function works in all cases because
   955  		// 0/0 is not <= 1.
   956  		return (xh*xh)/(rx*rx)+(yk*yk)/(ry*ry) <= 1
   957  	default:
   958  		panic("invalid area kind")
   959  	}
   960  }
   961  
   962  func (a *areaNode) bounds() image.Rectangle {
   963  	return f32internal.Rectangle{
   964  		Min: a.trans.Transform(f32internal.FPt(a.area.rect.Min)),
   965  		Max: a.trans.Transform(f32internal.FPt(a.area.rect.Max)),
   966  	}.Round()
   967  }
   968  
   969  func setScrollEvent(scroll float32, min, max int) (left, scrolled float32) {
   970  	if v := float32(max); scroll > v {
   971  		return scroll - v, v
   972  	}
   973  	if v := float32(min); scroll < v {
   974  		return scroll - v, v
   975  	}
   976  	return 0, scroll
   977  }