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