pointer.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // SPDX-License-Identifier: Unlicense OR MIT
  2. package pointer
  3. import (
  4. "strings"
  5. "time"
  6. "gioui.org/f32"
  7. "gioui.org/internal/ops"
  8. "gioui.org/io/event"
  9. "gioui.org/io/key"
  10. "gioui.org/op"
  11. )
  12. // Event is a pointer event.
  13. type Event struct {
  14. Kind Kind
  15. Source Source
  16. // PointerID is the id for the pointer and can be used
  17. // to track a particular pointer from Press to
  18. // Release or Cancel.
  19. PointerID ID
  20. // Priority is the priority of the receiving handler
  21. // for this event.
  22. Priority Priority
  23. // Time is when the event was received. The
  24. // timestamp is relative to an undefined base.
  25. Time time.Duration
  26. // Buttons are the set of pressed mouse buttons for this event.
  27. Buttons Buttons
  28. // Position is the coordinates of the event in the local coordinate
  29. // system of the receiving tag. The transformation from global window
  30. // coordinates to local coordinates is performed by the inverse of
  31. // the effective transformation of the tag.
  32. Position f32.Point
  33. // Scroll is the scroll amount, if any.
  34. Scroll f32.Point
  35. // Modifiers is the set of active modifiers when
  36. // the mouse button was pressed.
  37. Modifiers key.Modifiers
  38. }
  39. // PassOp sets the pass-through mode. InputOps added while the pass-through
  40. // mode is set don't block events to siblings.
  41. type PassOp struct {
  42. }
  43. // PassStack represents a PassOp on the pass stack.
  44. type PassStack struct {
  45. ops *ops.Ops
  46. id ops.StackID
  47. macroID uint32
  48. }
  49. // Filter matches every [Event] that target the Tag and whose kind is
  50. // included in Kinds. Note that only tags specified in [event.Op] can
  51. // be targeted by pointer events.
  52. type Filter struct {
  53. Target event.Tag
  54. // Kinds is a bitwise-or of event types to match.
  55. Kinds Kind
  56. // ScrollX and ScrollY constrain the range of scrolling events delivered
  57. // to Target. Specifically, any Event e delivered to Tag will satisfy
  58. //
  59. // ScrollX.Min <= e.Scroll.X <= ScrollX.Max (horizontal axis)
  60. // ScrollY.Min <= e.Scroll.Y <= ScrollY.Max (vertical axis)
  61. ScrollX ScrollRange
  62. ScrollY ScrollRange
  63. }
  64. // ScrollRange describes the range of scrolling distances in an
  65. // axis.
  66. type ScrollRange struct {
  67. Min, Max int
  68. }
  69. // GrabCmd requests a pointer grab on the pointer identified by ID.
  70. type GrabCmd struct {
  71. Tag event.Tag
  72. ID ID
  73. }
  74. type ID uint16
  75. // Kind of an Event.
  76. type Kind uint
  77. // Priority of an Event.
  78. type Priority uint8
  79. // Source of an Event.
  80. type Source uint8
  81. // Buttons is a set of mouse buttons
  82. type Buttons uint8
  83. // Cursor denotes a pre-defined cursor shape. Its Add method adds an
  84. // operation that sets the cursor shape for the current clip area.
  85. type Cursor byte
  86. // The cursors correspond to CSS pointer naming.
  87. const (
  88. // CursorDefault is the default cursor.
  89. CursorDefault Cursor = iota
  90. // CursorNone hides the cursor. To show it again, use any other cursor.
  91. CursorNone
  92. // CursorText is for selecting and inserting text.
  93. CursorText
  94. // CursorVerticalText is for selecting and inserting vertical text.
  95. CursorVerticalText
  96. // CursorPointer is for a link.
  97. // Usually displayed as a pointing hand.
  98. CursorPointer
  99. // CursorCrosshair is for a precise location.
  100. CursorCrosshair
  101. // CursorAllScroll is for indicating scrolling in all directions.
  102. // Usually displayed as arrows to all four directions.
  103. CursorAllScroll
  104. // CursorColResize is for vertical resize.
  105. // Usually displayed as a vertical bar with arrows pointing east and west.
  106. CursorColResize
  107. // CursorRowResize is for horizontal resize.
  108. // Usually displayed as a horizontal bar with arrows pointing north and south.
  109. CursorRowResize
  110. // CursorGrab is for content that can be grabbed (dragged to be moved).
  111. // Usually displayed as an open hand.
  112. CursorGrab
  113. // CursorGrabbing is for content that is being grabbed (dragged to be moved).
  114. // Usually displayed as a closed hand.
  115. CursorGrabbing
  116. // CursorNotAllowed is shown when the request action cannot be carried out.
  117. // Usually displayed as a circle with a line through.
  118. CursorNotAllowed
  119. // CursorWait is shown when the program is busy and user cannot interact.
  120. // Usually displayed as a hourglass or the system equivalent.
  121. CursorWait
  122. // CursorProgress is shown when the program is busy, but the user can still interact.
  123. // Usually displayed as a default cursor with a hourglass.
  124. CursorProgress
  125. // CursorNorthWestResize is for top-left corner resizing.
  126. // Usually displayed as an arrow towards north-west.
  127. CursorNorthWestResize
  128. // CursorNorthEastResize is for top-right corner resizing.
  129. // Usually displayed as an arrow towards north-east.
  130. CursorNorthEastResize
  131. // CursorSouthWestResize is for bottom-left corner resizing.
  132. // Usually displayed as an arrow towards south-west.
  133. CursorSouthWestResize
  134. // CursorSouthEastResize is for bottom-right corner resizing.
  135. // Usually displayed as an arrow towards south-east.
  136. CursorSouthEastResize
  137. // CursorNorthSouth is for top-bottom resizing.
  138. // Usually displayed as a bi-directional arrow towards north-south.
  139. CursorNorthSouthResize
  140. // CursorEastWestResize is for left-right resizing.
  141. // Usually displayed as a bi-directional arrow towards east-west.
  142. CursorEastWestResize
  143. // CursorWestResize is for left resizing.
  144. // Usually displayed as an arrow towards west.
  145. CursorWestResize
  146. // CursorEastResize is for right resizing.
  147. // Usually displayed as an arrow towards east.
  148. CursorEastResize
  149. // CursorNorthResize is for top resizing.
  150. // Usually displayed as an arrow towards north.
  151. CursorNorthResize
  152. // CursorSouthResize is for bottom resizing.
  153. // Usually displayed as an arrow towards south.
  154. CursorSouthResize
  155. // CursorNorthEastSouthWestResize is for top-right to bottom-left diagonal resizing.
  156. // Usually displayed as a double ended arrow on the corresponding diagonal.
  157. CursorNorthEastSouthWestResize
  158. // CursorNorthWestSouthEastResize is for top-left to bottom-right diagonal resizing.
  159. // Usually displayed as a double ended arrow on the corresponding diagonal.
  160. CursorNorthWestSouthEastResize
  161. )
  162. const (
  163. // A Cancel event is generated when the current gesture is
  164. // interrupted by other handlers or the system.
  165. Cancel Kind = 1 << iota
  166. // Press of a pointer.
  167. Press
  168. // Release of a pointer.
  169. Release
  170. // Move of a pointer.
  171. Move
  172. // Drag of a pointer.
  173. Drag
  174. // Pointer enters an area watching for pointer input
  175. Enter
  176. // Pointer leaves an area watching for pointer input
  177. Leave
  178. // Scroll of a pointer.
  179. Scroll
  180. )
  181. const (
  182. // Mouse generated event.
  183. Mouse Source = iota
  184. // Touch generated event.
  185. Touch
  186. )
  187. const (
  188. // Shared priority is for handlers that
  189. // are part of a matching set larger than 1.
  190. Shared Priority = iota
  191. // Foremost priority is like Shared, but the
  192. // handler is the foremost of the matching set.
  193. Foremost
  194. // Grabbed is used for matching sets of size 1.
  195. Grabbed
  196. )
  197. const (
  198. // ButtonPrimary is the primary button, usually the left button for a
  199. // right-handed user.
  200. ButtonPrimary Buttons = 1 << iota
  201. // ButtonSecondary is the secondary button, usually the right button for a
  202. // right-handed user.
  203. ButtonSecondary
  204. // ButtonTertiary is the tertiary button, usually the middle button.
  205. ButtonTertiary
  206. )
  207. func (s ScrollRange) Union(s2 ScrollRange) ScrollRange {
  208. return ScrollRange{
  209. Min: min(s.Min, s2.Min),
  210. Max: max(s.Max, s2.Max),
  211. }
  212. }
  213. // Push the current pass mode to the pass stack and set the pass mode.
  214. func (p PassOp) Push(o *op.Ops) PassStack {
  215. id, mid := ops.PushOp(&o.Internal, ops.PassStack)
  216. data := ops.Write(&o.Internal, ops.TypePassLen)
  217. data[0] = byte(ops.TypePass)
  218. return PassStack{ops: &o.Internal, id: id, macroID: mid}
  219. }
  220. func (p PassStack) Pop() {
  221. ops.PopOp(p.ops, ops.PassStack, p.id, p.macroID)
  222. data := ops.Write(p.ops, ops.TypePopPassLen)
  223. data[0] = byte(ops.TypePopPass)
  224. }
  225. func (op Cursor) Add(o *op.Ops) {
  226. data := ops.Write(&o.Internal, ops.TypeCursorLen)
  227. data[0] = byte(ops.TypeCursor)
  228. data[1] = byte(op)
  229. }
  230. func (t Kind) String() string {
  231. if t == Cancel {
  232. return "Cancel"
  233. }
  234. var buf strings.Builder
  235. for tt := Kind(1); tt > 0; tt <<= 1 {
  236. if t&tt > 0 {
  237. if buf.Len() > 0 {
  238. buf.WriteByte('|')
  239. }
  240. buf.WriteString((t & tt).string())
  241. }
  242. }
  243. return buf.String()
  244. }
  245. func (t Kind) string() string {
  246. switch t {
  247. case Press:
  248. return "Press"
  249. case Release:
  250. return "Release"
  251. case Cancel:
  252. return "Cancel"
  253. case Move:
  254. return "Move"
  255. case Drag:
  256. return "Drag"
  257. case Enter:
  258. return "Enter"
  259. case Leave:
  260. return "Leave"
  261. case Scroll:
  262. return "Scroll"
  263. default:
  264. panic("unknown Type")
  265. }
  266. }
  267. func (p Priority) String() string {
  268. switch p {
  269. case Shared:
  270. return "Shared"
  271. case Foremost:
  272. return "Foremost"
  273. case Grabbed:
  274. return "Grabbed"
  275. default:
  276. panic("unknown priority")
  277. }
  278. }
  279. func (s Source) String() string {
  280. switch s {
  281. case Mouse:
  282. return "Mouse"
  283. case Touch:
  284. return "Touch"
  285. default:
  286. panic("unknown source")
  287. }
  288. }
  289. // Contain reports whether the set b contains
  290. // all of the buttons.
  291. func (b Buttons) Contain(buttons Buttons) bool {
  292. return b&buttons == buttons
  293. }
  294. func (b Buttons) String() string {
  295. var strs []string
  296. if b.Contain(ButtonPrimary) {
  297. strs = append(strs, "ButtonPrimary")
  298. }
  299. if b.Contain(ButtonSecondary) {
  300. strs = append(strs, "ButtonSecondary")
  301. }
  302. if b.Contain(ButtonTertiary) {
  303. strs = append(strs, "ButtonTertiary")
  304. }
  305. return strings.Join(strs, "|")
  306. }
  307. func (c Cursor) String() string {
  308. switch c {
  309. case CursorDefault:
  310. return "Default"
  311. case CursorNone:
  312. return "None"
  313. case CursorText:
  314. return "Text"
  315. case CursorVerticalText:
  316. return "VerticalText"
  317. case CursorPointer:
  318. return "Pointer"
  319. case CursorCrosshair:
  320. return "Crosshair"
  321. case CursorAllScroll:
  322. return "AllScroll"
  323. case CursorColResize:
  324. return "ColResize"
  325. case CursorRowResize:
  326. return "RowResize"
  327. case CursorGrab:
  328. return "Grab"
  329. case CursorGrabbing:
  330. return "Grabbing"
  331. case CursorNotAllowed:
  332. return "NotAllowed"
  333. case CursorWait:
  334. return "Wait"
  335. case CursorProgress:
  336. return "Progress"
  337. case CursorNorthWestResize:
  338. return "NorthWestResize"
  339. case CursorNorthEastResize:
  340. return "NorthEastResize"
  341. case CursorSouthWestResize:
  342. return "SouthWestResize"
  343. case CursorSouthEastResize:
  344. return "SouthEastResize"
  345. case CursorNorthSouthResize:
  346. return "NorthSouthResize"
  347. case CursorEastWestResize:
  348. return "EastWestResize"
  349. case CursorWestResize:
  350. return "WestResize"
  351. case CursorEastResize:
  352. return "EastResize"
  353. case CursorNorthResize:
  354. return "NorthResize"
  355. case CursorSouthResize:
  356. return "SouthResize"
  357. case CursorNorthEastSouthWestResize:
  358. return "NorthEastSouthWestResize"
  359. case CursorNorthWestSouthEastResize:
  360. return "NorthWestSouthEastResize"
  361. default:
  362. panic("unknown Type")
  363. }
  364. }
  365. func (Event) ImplementsEvent() {}
  366. func (GrabCmd) ImplementsCommand() {}
  367. func (Filter) ImplementsFilter() {}