github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/io/pointer/pointer.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package pointer 4 5 import ( 6 "encoding/binary" 7 "fmt" 8 "image" 9 "strings" 10 "time" 11 12 "github.com/cybriq/giocore/f32" 13 "github.com/cybriq/giocore/internal/opconst" 14 "github.com/cybriq/giocore/io/event" 15 "github.com/cybriq/giocore/io/key" 16 "github.com/cybriq/giocore/op" 17 ) 18 19 // Event is a pointer event. 20 type Event struct { 21 Type Type 22 Source Source 23 // PointerID is the id for the pointer and can be used 24 // to track a particular pointer from Press to 25 // Release or Cancel. 26 PointerID ID 27 // Priority is the priority of the receiving handler 28 // for this event. 29 Priority Priority 30 // Time is when the event was received. The 31 // timestamp is relative to an undefined base. 32 Time time.Duration 33 // Buttons are the set of pressed mouse buttons for this event. 34 Buttons Buttons 35 // Position is the position of the event, relative to 36 // the current transformation, as set by op.TransformOp. 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 // AreaOp updates the hit area to the intersection of the current 46 // hit area and the area. The area is transformed before applying 47 // it. 48 type AreaOp struct { 49 kind areaKind 50 rect image.Rectangle 51 } 52 53 // CursorNameOp sets the cursor for the current area. 54 type CursorNameOp struct { 55 Name CursorName 56 } 57 58 // InputOp declares an input handler ready for pointer 59 // events. 60 type InputOp struct { 61 Tag event.Tag 62 // Grab, if set, request that the handler get 63 // Grabbed priority. 64 Grab bool 65 // Types is a bitwise-or of event types to receive. 66 Types Type 67 // ScrollBounds describe the maximum scrollable distances in both 68 // axes. Specifically, any Event e delivered to Tag will satisfy 69 // 70 // ScrollBounds.Min.X <= e.Scroll.X <= ScrollBounds.Max.X (horizontal axis) 71 // ScrollBounds.Min.Y <= e.Scroll.Y <= ScrollBounds.Max.Y (vertical axis) 72 ScrollBounds image.Rectangle 73 } 74 75 // PassOp sets the pass-through mode. 76 type PassOp struct { 77 Pass bool 78 } 79 80 type ID uint16 81 82 // Type of an Event. 83 type Type uint8 84 85 // Priority of an Event. 86 type Priority uint8 87 88 // Source of an Event. 89 type Source uint8 90 91 // Buttons is a set of mouse buttons 92 type Buttons uint8 93 94 // CursorName is the name of a cursor. 95 type CursorName string 96 97 // Must match app/internal/input.areaKind 98 type areaKind uint8 99 100 const ( 101 // CursorDefault is the default cursor. 102 CursorDefault CursorName = "" 103 // CursorText is the cursor for text. 104 CursorText CursorName = "text" 105 // CursorPointer is the cursor for a link. 106 CursorPointer CursorName = "pointer" 107 // CursorCrossHair is the cursor for precise location. 108 CursorCrossHair CursorName = "crosshair" 109 // CursorColResize is the cursor for vertical resize. 110 CursorColResize CursorName = "col-resize" 111 // CursorRowResize is the cursor for horizontal resize. 112 CursorRowResize CursorName = "row-resize" 113 // CursorGrab is the cursor for moving object in any direction. 114 CursorGrab CursorName = "grab" 115 // CursorNone hides the cursor. To show it again, use any other cursor. 116 CursorNone CursorName = "none" 117 ) 118 119 const ( 120 // A Cancel event is generated when the current gesture is 121 // interrupted by other handlers or the system. 122 Cancel Type = (1 << iota) >> 1 123 // Press of a pointer. 124 Press 125 // Release of a pointer. 126 Release 127 // Move of a pointer. 128 Move 129 // Drag of a pointer. 130 Drag 131 // Pointer enters an area watching for pointer input 132 Enter 133 // Pointer leaves an area watching for pointer input 134 Leave 135 // Scroll of a pointer. 136 Scroll 137 ) 138 139 const ( 140 // Mouse generated event. 141 Mouse Source = iota 142 // Touch generated event. 143 Touch 144 ) 145 146 const ( 147 // Shared priority is for handlers that 148 // are part of a matching set larger than 1. 149 Shared Priority = iota 150 // Foremost priority is like Shared, but the 151 // handler is the foremost of the matching set. 152 Foremost 153 // Grabbed is used for matching sets of size 1. 154 Grabbed 155 ) 156 157 const ( 158 // ButtonPrimary is the primary button, usually the left button for a 159 // right-handed user. 160 ButtonPrimary Buttons = 1 << iota 161 // ButtonSecondary is the secondary button, usually the right button for a 162 // right-handed user. 163 ButtonSecondary 164 // ButtonTertiary is the tertiary button, usually the middle button. 165 ButtonTertiary 166 ) 167 168 const ( 169 areaRect areaKind = iota 170 areaEllipse 171 ) 172 173 // Rect constructs a rectangular hit area. 174 func Rect(size image.Rectangle) AreaOp { 175 return AreaOp{ 176 kind: areaRect, 177 rect: size, 178 } 179 } 180 181 // Ellipse constructs an ellipsoid hit area. 182 func Ellipse(size image.Rectangle) AreaOp { 183 return AreaOp{ 184 kind: areaEllipse, 185 rect: size, 186 } 187 } 188 189 func (op AreaOp) Add(o *op.Ops) { 190 data := o.Write(opconst.TypeAreaLen) 191 data[0] = byte(opconst.TypeArea) 192 data[1] = byte(op.kind) 193 bo := binary.LittleEndian 194 bo.PutUint32(data[2:], uint32(op.rect.Min.X)) 195 bo.PutUint32(data[6:], uint32(op.rect.Min.Y)) 196 bo.PutUint32(data[10:], uint32(op.rect.Max.X)) 197 bo.PutUint32(data[14:], uint32(op.rect.Max.Y)) 198 } 199 200 func (op CursorNameOp) Add(o *op.Ops) { 201 data := o.Write1(opconst.TypeCursorLen, op.Name) 202 data[0] = byte(opconst.TypeCursor) 203 } 204 205 // Add panics if the scroll range does not contain zero. 206 func (op InputOp) Add(o *op.Ops) { 207 if op.Tag == nil { 208 panic("Tag must be non-nil") 209 } 210 if b := op.ScrollBounds; b.Min.X > 0 || b.Max.X < 0 || b.Min.Y > 0 || b.Max.Y < 0 { 211 panic(fmt.Errorf("invalid scroll range value %v", b)) 212 } 213 data := o.Write1(opconst.TypePointerInputLen, op.Tag) 214 data[0] = byte(opconst.TypePointerInput) 215 if op.Grab { 216 data[1] = 1 217 } 218 data[2] = byte(op.Types) 219 bo := binary.LittleEndian 220 bo.PutUint32(data[3:], uint32(op.ScrollBounds.Min.X)) 221 bo.PutUint32(data[7:], uint32(op.ScrollBounds.Min.Y)) 222 bo.PutUint32(data[11:], uint32(op.ScrollBounds.Max.X)) 223 bo.PutUint32(data[15:], uint32(op.ScrollBounds.Max.Y)) 224 } 225 226 func (op PassOp) Add(o *op.Ops) { 227 data := o.Write(opconst.TypePassLen) 228 data[0] = byte(opconst.TypePass) 229 if op.Pass { 230 data[1] = 1 231 } 232 } 233 234 func (t Type) String() string { 235 switch t { 236 case Press: 237 return "Press" 238 case Release: 239 return "Release" 240 case Cancel: 241 return "Cancel" 242 case Move: 243 return "Move" 244 case Drag: 245 return "Drag" 246 case Enter: 247 return "Enter" 248 case Leave: 249 return "Leave" 250 case Scroll: 251 return "Scroll" 252 default: 253 panic("unknown Type") 254 } 255 } 256 257 func (p Priority) String() string { 258 switch p { 259 case Shared: 260 return "Shared" 261 case Foremost: 262 return "Foremost" 263 case Grabbed: 264 return "Grabbed" 265 default: 266 panic("unknown priority") 267 } 268 } 269 270 func (s Source) String() string { 271 switch s { 272 case Mouse: 273 return "Mouse" 274 case Touch: 275 return "Touch" 276 default: 277 panic("unknown source") 278 } 279 } 280 281 // Contain reports whether the set b contains 282 // all of the buttons. 283 func (b Buttons) Contain(buttons Buttons) bool { 284 return b&buttons == buttons 285 } 286 287 func (b Buttons) String() string { 288 var strs []string 289 if b.Contain(ButtonPrimary) { 290 strs = append(strs, "ButtonPrimary") 291 } 292 if b.Contain(ButtonSecondary) { 293 strs = append(strs, "ButtonSecondary") 294 } 295 if b.Contain(ButtonTertiary) { 296 strs = append(strs, "ButtonTertiary") 297 } 298 return strings.Join(strs, "|") 299 } 300 301 func (c CursorName) String() string { 302 if c == CursorDefault { 303 return "default" 304 } 305 return string(c) 306 } 307 308 func (Event) ImplementsEvent() {}