-
Notifications
You must be signed in to change notification settings - Fork 0
/
hittest.red
79 lines (74 loc) · 2.32 KB
/
hittest.red
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Red [
title: "Hittest facilities for Draw-based widgets"
author: @hiiamboris
license: BSD-3
]
;-- requires export
exports: [hittest]
into-map: function [
map [block!] xy [planar!] child [object! (space? child) none!]
/only list [block!] "Only try to enter selected spaces"
][
either child [
#debug events [#assert [find/same map child]] ;-- may fail, but still worth seeing it
;; geom=none possible if e.g. hittest on 'up' event uses drag-path of 'down' event
;; and some code of 'down' event replaces part of the tree;
;; also %hovering.red on tree modification uses a no longer valid path
xy: either geom: select/same/only map child [xy - geom/offset][(0,0)]
reduce [child xy]
][
either list [
foreach child list [
box: select/same map child
#assert [box/size "map should not contain infinite sizes"]
if within? xy o: box/offset box/size [
return reduce [child xy - o]
]
]
][
foreach [child box] map [
#assert [box/size "map should not contain infinite sizes"]
if within? xy o: box/offset box/size [
return reduce [child xy - o]
]
]
]
none
]
]
;; has to be fast, for on-over events
hittest: function [
"Map a certain point deeply into the tree of spaces"
space [object! (space? space) block! path!]
"Top space in the tree (host/space usually), or path of spaces to follow"
;; path/block is required for dragging, as we need to follow the same path as at the time of click
xy [planar!] "Point in that top space"
/into "Append into a given buffer"
path: (make [] 16) [block! path!]
][
unless object? template: space [ ;-- follow given path until it ends
forall template [ ;@@ use for-each
set [space: _: child:] template
repend path [space xy]
#assert [xy] ;-- forced into and map should always return the pair, if child is not none
set [child xy] case [
into: select space 'into [into/force xy child]
map: select space 'map [into-map map xy child]
]
template: next template
]
space: child ;-- continue forth from the child (if lands on any)
]
if object? space [
while [all [space xy inside? space]] [
repend path [space xy]
#assert [xy]
set [space xy] case [
into: select space 'into [into xy]
map: select space 'map [into-map map xy none]
]
]
]
new-line/all path no
]
export exports