event.mx raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  // Event system types ported from gioui.org/io/{event,key,pointer,clipboard,system,transfer,semantic}.
   4  // All sub-packages merged into package gio with prefixed names to avoid collisions.
   5  
   6  package gio
   7  
   8  import (
   9  	"bytes"
  10  	"io"
  11  	"time"
  12  )
  13  
  14  // ---------------------------------------------------------------------------
  15  // event - core interfaces
  16  // ---------------------------------------------------------------------------
  17  
  18  // Tag is the stable identifier for an event handler.
  19  // For a handler h, the tag is typically &h.
  20  type Tag any
  21  
  22  // Event is the marker interface for events.
  23  type Event interface {
  24  	ImplementsEvent()
  25  }
  26  
  27  // Filter represents a filter for Event types.
  28  type Filter interface {
  29  	ImplementsFilter()
  30  }
  31  
  32  // InputCommand represents a request such as moving the focus or reading the clipboard.
  33  type InputCommand interface {
  34  	ImplementsCommand()
  35  }
  36  
  37  // EventOp declares a tag for input routing at the current transformation
  38  // and clip area hierarchy. It panics if tag is nil.
  39  func EventOp(o *OpList, tag Tag) {
  40  	if tag == nil {
  41  		panic("Tag must be non-nil")
  42  	}
  43  	data := WriteOps1(&o.Internal, TypeInputLen, tag)
  44  	data[0] = byte(TypeInput)
  45  }
  46  
  47  // ---------------------------------------------------------------------------
  48  // key - key events, names, modifiers
  49  // ---------------------------------------------------------------------------
  50  
  51  // KeyFilter matches any KeyEvent that matches the parameters.
  52  type KeyFilter struct {
  53  	// Focus is the tag that must be focused for the filter to match. It has no
  54  	// effect if it is nil.
  55  	Focus Tag
  56  	// Required is the set of modifiers that must be included in events matched.
  57  	Required Modifiers
  58  	// Optional is the set of modifiers that may be included in events matched.
  59  	Optional Modifiers
  60  	// Name of the key to be matched. As a special case, the empty Name matches
  61  	// every key not matched by any other filter.
  62  	Name KeyName
  63  }
  64  
  65  // KeyInputHintOp describes the type of text expected by a tag.
  66  type KeyInputHintOp struct {
  67  	Tag  Tag
  68  	Hint InputHint
  69  }
  70  
  71  // SoftKeyboardCmd shows or hides the on-screen keyboard, if available.
  72  type SoftKeyboardCmd struct {
  73  	Show bool
  74  }
  75  
  76  // SelectionCmd updates the selection for an input handler.
  77  type SelectionCmd struct {
  78  	Tag Tag
  79  	KeyRange
  80  	Caret
  81  }
  82  
  83  // SnippetCmd updates the content snippet for an input handler.
  84  type SnippetCmd struct {
  85  	Tag Tag
  86  	Snippet
  87  }
  88  
  89  // KeyRange represents a range of text, such as an editor's selection.
  90  // Start and End are in runes.
  91  type KeyRange struct {
  92  	Start int
  93  	End   int
  94  }
  95  
  96  // Snippet represents a snippet of text content used for communicating between
  97  // an editor and an input method.
  98  type Snippet struct {
  99  	KeyRange
 100  	Text string
 101  }
 102  
 103  // Caret represents the position of a caret.
 104  type Caret struct {
 105  	// Pos is the intersection point of the caret and its baseline.
 106  	Pos Point
 107  	// Ascent is the length of the caret above its baseline.
 108  	Ascent float32
 109  	// Descent is the length of the caret below its baseline.
 110  	Descent float32
 111  }
 112  
 113  // SelectionEvent is generated when an input method changes the selection.
 114  type SelectionEvent KeyRange
 115  
 116  // SnippetEvent is generated when the snippet range is updated by an input method.
 117  type SnippetEvent KeyRange
 118  
 119  // KeyFocusEvent is generated when a handler gains or loses focus.
 120  type KeyFocusEvent struct {
 121  	Focus bool
 122  }
 123  
 124  // KeyEvent is generated when a key is pressed. For text input use KeyEditEvent.
 125  type KeyEvent struct {
 126  	// Name of the key.
 127  	Name KeyName
 128  	// Modifiers is the set of active modifiers when the key was pressed.
 129  	Modifiers Modifiers
 130  	// State is the state of the key when the event was fired.
 131  	State KeyState
 132  }
 133  
 134  // KeyEditEvent requests an edit by an input method.
 135  type KeyEditEvent struct {
 136  	// Range specifies the range to replace with Text.
 137  	Range KeyRange
 138  	Text  string
 139  }
 140  
 141  // KeyFocusFilter matches any KeyFocusEvent, KeyEditEvent, SnippetEvent,
 142  // or SelectionEvent with the specified target.
 143  type KeyFocusFilter struct {
 144  	// Target is a tag specified in a previous EventOp.
 145  	Target Tag
 146  }
 147  
 148  // InputHint changes the on-screen-keyboard type. That hints the type of data
 149  // that might be entered by the user.
 150  type InputHint uint8
 151  
 152  const (
 153  	// HintAny hints that any input is expected.
 154  	HintAny InputHint = iota
 155  	// HintText hints that text input is expected. It may activate auto-correction and suggestions.
 156  	HintText
 157  	// HintNumeric hints that numeric input is expected. It may activate shortcuts for 0-9, "." and ",".
 158  	HintNumeric
 159  	// HintEmail hints that email input is expected. It may activate shortcuts for common email characters, such as "@" and ".com".
 160  	HintEmail
 161  	// HintURL hints that URL input is expected. It may activate shortcuts for common URL fragments such as "/" and ".com".
 162  	HintURL
 163  	// HintTelephone hints that telephone number input is expected. It may activate shortcuts for 0-9, "#" and "*".
 164  	HintTelephone
 165  	// HintPassword hints that password input is expected. It may disable autocorrection and enable password autofill.
 166  	HintPassword
 167  )
 168  
 169  // KeyState is the state of a key during an event.
 170  type KeyState uint8
 171  
 172  const (
 173  	// KeyPress is the state of a pressed key.
 174  	KeyPress KeyState = iota
 175  	// KeyRelease is the state of a key that has been released.
 176  	KeyRelease
 177  )
 178  
 179  // Modifiers
 180  type Modifiers uint32
 181  
 182  const (
 183  	// ModCtrl is the ctrl modifier key.
 184  	ModCtrl Modifiers = 1 << iota
 185  	// ModCommand is the command modifier key found on Apple keyboards.
 186  	ModCommand
 187  	// ModShift is the shift modifier key.
 188  	ModShift
 189  	// ModAlt is the alt modifier key, or the option key on Apple keyboards.
 190  	ModAlt
 191  	// ModSuper is the "logo" modifier key, often represented by a Windows logo.
 192  	ModSuper
 193  )
 194  
 195  // ModShortcut is the platform's shortcut modifier (WASM: always Ctrl).
 196  const ModShortcut = ModCtrl
 197  
 198  // ModShortcutAlt is the platform's alternative shortcut modifier (WASM: always Ctrl).
 199  const ModShortcutAlt = ModCtrl
 200  
 201  // KeyName is the identifier for a keyboard key.
 202  //
 203  // For letters, the upper case form is used, via unicode.ToUpper.
 204  // The shift modifier is taken into account, all other modifiers are ignored.
 205  // For example, the "shift-1" and "ctrl-shift-1" combinations both give the
 206  // Name "!" with the US keyboard layout.
 207  type KeyName string
 208  
 209  const (
 210  	KeyNameLeftArrow      KeyName = "\xe2\x86\x90"
 211  	KeyNameRightArrow     KeyName = "\xe2\x86\x92"
 212  	KeyNameUpArrow        KeyName = "\xe2\x86\x91"
 213  	KeyNameDownArrow      KeyName = "\xe2\x86\x93"
 214  	KeyNameReturn         KeyName = "\xe2\x8f\x8e"
 215  	KeyNameEnter          KeyName = "\xe2\x8c\xa4"
 216  	KeyNameEscape         KeyName = "\xe2\x8e\x8b"
 217  	KeyNameHome           KeyName = "\xe2\x87\xb1"
 218  	KeyNameEnd            KeyName = "\xe2\x87\xb2"
 219  	KeyNameDeleteBackward KeyName = "\xe2\x8c\xab"
 220  	KeyNameDeleteForward  KeyName = "\xe2\x8c\xa6"
 221  	KeyNamePageUp         KeyName = "\xe2\x87\x9e"
 222  	KeyNamePageDown       KeyName = "\xe2\x87\x9f"
 223  	KeyNameTab            KeyName = "Tab"
 224  	KeyNameSpace          KeyName = "Space"
 225  	KeyNameCtrl           KeyName = "Ctrl"
 226  	KeyNameShift          KeyName = "Shift"
 227  	KeyNameAlt            KeyName = "Alt"
 228  	KeyNameSuper          KeyName = "Super"
 229  	KeyNameCommand        KeyName = "\xe2\x8c\x98"
 230  	KeyNameF1             KeyName = "F1"
 231  	KeyNameF2             KeyName = "F2"
 232  	KeyNameF3             KeyName = "F3"
 233  	KeyNameF4             KeyName = "F4"
 234  	KeyNameF5             KeyName = "F5"
 235  	KeyNameF6             KeyName = "F6"
 236  	KeyNameF7             KeyName = "F7"
 237  	KeyNameF8             KeyName = "F8"
 238  	KeyNameF9             KeyName = "F9"
 239  	KeyNameF10            KeyName = "F10"
 240  	KeyNameF11            KeyName = "F11"
 241  	KeyNameF12            KeyName = "F12"
 242  	KeyNameBack           KeyName = "Back"
 243  )
 244  
 245  type FocusDirection int
 246  
 247  const (
 248  	FocusRight FocusDirection = iota
 249  	FocusLeft
 250  	FocusUp
 251  	FocusDown
 252  	FocusForward
 253  	FocusBackward
 254  )
 255  
 256  // Contain reports whether m contains all modifiers in m2.
 257  func (m Modifiers) Contain(m2 Modifiers) bool {
 258  	return m&m2 == m2
 259  }
 260  
 261  // FocusCmd requests to set or clear the keyboard focus.
 262  type FocusCmd struct {
 263  	// Tag is the new focus. The focus is cleared if Tag is nil, or if Tag
 264  	// has no EventOp references.
 265  	Tag Tag
 266  }
 267  
 268  func (h KeyInputHintOp) Add(o *OpList) {
 269  	if h.Tag == nil {
 270  		panic("Tag must be non-nil")
 271  	}
 272  	data := WriteOps1(&o.Internal, TypeKeyInputHintLen, h.Tag)
 273  	data[0] = byte(TypeKeyInputHint)
 274  	data[1] = byte(h.Hint)
 275  }
 276  
 277  func (KeyEditEvent) ImplementsEvent()    {}
 278  func (KeyEvent) ImplementsEvent()        {}
 279  func (KeyFocusEvent) ImplementsEvent()   {}
 280  func (SnippetEvent) ImplementsEvent()    {}
 281  func (SelectionEvent) ImplementsEvent()  {}
 282  
 283  func (FocusCmd) ImplementsCommand()        {}
 284  func (SoftKeyboardCmd) ImplementsCommand() {}
 285  func (SelectionCmd) ImplementsCommand()    {}
 286  func (SnippetCmd) ImplementsCommand()      {}
 287  
 288  func (KeyFilter) ImplementsFilter()      {}
 289  func (KeyFocusFilter) ImplementsFilter() {}
 290  
 291  func (m Modifiers) String() string {
 292  	var parts []string
 293  	if m.Contain(ModCtrl) {
 294  		parts = append(parts, string(KeyNameCtrl))
 295  	}
 296  	if m.Contain(ModCommand) {
 297  		parts = append(parts, string(KeyNameCommand))
 298  	}
 299  	if m.Contain(ModShift) {
 300  		parts = append(parts, string(KeyNameShift))
 301  	}
 302  	if m.Contain(ModAlt) {
 303  		parts = append(parts, string(KeyNameAlt))
 304  	}
 305  	if m.Contain(ModSuper) {
 306  		parts = append(parts, string(KeyNameSuper))
 307  	}
 308  	return bytes.Join(parts, "-")
 309  }
 310  
 311  func (s KeyState) String() string {
 312  	switch s {
 313  	case KeyPress:
 314  		return "Press"
 315  	case KeyRelease:
 316  		return "Release"
 317  	default:
 318  		panic("invalid KeyState")
 319  	}
 320  }
 321  
 322  // ---------------------------------------------------------------------------
 323  // pointer - pointer events, cursor types
 324  // ---------------------------------------------------------------------------
 325  
 326  // PointerEvent is a pointer event.
 327  type PointerEvent struct {
 328  	Kind   PointerKind
 329  	Source PointerSource
 330  	// PointerID is the id for the pointer and can be used to track a particular
 331  	// pointer from Press to Release.
 332  	PointerID PointerID
 333  	// Priority is the priority of the receiving handler for this event.
 334  	Priority PointerPriority
 335  	// Time is when the event was received. The timestamp is relative to an
 336  	// undefined base.
 337  	Time time.Duration
 338  	// Buttons are the set of pressed mouse buttons for this event.
 339  	Buttons PointerButtons
 340  	// Position is the coordinates of the event in the local coordinate system
 341  	// of the receiving tag.
 342  	Position Point
 343  	// Scroll is the scroll amount, if any.
 344  	Scroll Point
 345  	// Modifiers is the set of active modifiers when the mouse button was pressed.
 346  	Modifiers Modifiers
 347  }
 348  
 349  // PassOp sets the pass-through mode. InputOps added while the pass-through
 350  // mode is set don't block events to siblings.
 351  type PassOp struct{}
 352  
 353  // PassStack represents a PassOp on the pass stack.
 354  type PassStack struct {
 355  	ops     *Ops
 356  	id      StackID
 357  	macroID uint32
 358  }
 359  
 360  // PointerFilter matches every PointerEvent that targets the Tag and whose kind
 361  // is included in Kinds.
 362  type PointerFilter struct {
 363  	Target Tag
 364  	// Kinds is a bitwise-or of event types to match.
 365  	Kinds PointerKind
 366  	// ScrollX and ScrollY constrain the range of scrolling events delivered
 367  	// to Target.
 368  	ScrollX ScrollRange
 369  	ScrollY ScrollRange
 370  }
 371  
 372  // ScrollRange describes the range of scrolling distances in an axis.
 373  type ScrollRange struct {
 374  	Min, Max int
 375  }
 376  
 377  // GrabCmd requests a pointer grab on the pointer identified by ID.
 378  type GrabCmd struct {
 379  	Tag Tag
 380  	ID  PointerID
 381  }
 382  
 383  type PointerID uint16
 384  
 385  // PointerKind of a PointerEvent.
 386  type PointerKind uint
 387  
 388  // PointerPriority of a PointerEvent.
 389  type PointerPriority uint8
 390  
 391  // PointerSource of a PointerEvent.
 392  type PointerSource uint8
 393  
 394  // PointerButtons is a set of mouse buttons.
 395  type PointerButtons uint8
 396  
 397  // Cursor denotes a pre-defined cursor shape. Its Add method adds an operation
 398  // that sets the cursor shape for the current clip area.
 399  type Cursor byte
 400  
 401  // The cursors correspond to CSS pointer naming.
 402  const (
 403  	CursorDefault                  Cursor = iota
 404  	CursorNone
 405  	CursorText
 406  	CursorVerticalText
 407  	CursorPointer
 408  	CursorCrosshair
 409  	CursorAllScroll
 410  	CursorColResize
 411  	CursorRowResize
 412  	CursorGrab
 413  	CursorGrabbing
 414  	CursorNotAllowed
 415  	CursorWait
 416  	CursorProgress
 417  	CursorNorthWestResize
 418  	CursorNorthEastResize
 419  	CursorSouthWestResize
 420  	CursorSouthEastResize
 421  	CursorNorthSouthResize
 422  	CursorEastWestResize
 423  	CursorWestResize
 424  	CursorEastResize
 425  	CursorNorthResize
 426  	CursorSouthResize
 427  	CursorNorthEastSouthWestResize
 428  	CursorNorthWestSouthEastResize
 429  )
 430  
 431  const (
 432  	// Cancel is generated when the current gesture is interrupted.
 433  	PointerCancel PointerKind = 1 << iota
 434  	// PointerPress of a pointer.
 435  	PointerPress
 436  	// PointerRelease of a pointer.
 437  	PointerRelease
 438  	// PointerMove of a pointer.
 439  	PointerMove
 440  	// PointerDrag of a pointer.
 441  	PointerDrag
 442  	// PointerEnter - pointer enters an area watching for pointer input.
 443  	PointerEnter
 444  	// PointerLeave - pointer leaves an area watching for pointer input.
 445  	PointerLeave
 446  	// PointerScroll of a pointer.
 447  	PointerScroll
 448  )
 449  
 450  const (
 451  	// Mouse generated event.
 452  	Mouse PointerSource = iota
 453  	// Touch generated event.
 454  	Touch
 455  )
 456  
 457  const (
 458  	// Shared priority is for handlers that are part of a matching set larger than 1.
 459  	Shared PointerPriority = iota
 460  	// Grabbed is used for matching sets of size 1.
 461  	Grabbed
 462  )
 463  
 464  const (
 465  	// ButtonPrimary is the primary button, usually the left button for a
 466  	// right-handed user.
 467  	ButtonPrimary PointerButtons = 1 << iota
 468  	// ButtonSecondary is the secondary button, usually the right button for a
 469  	// right-handed user.
 470  	ButtonSecondary
 471  	// ButtonTertiary is the tertiary button, usually the middle button.
 472  	ButtonTertiary
 473  	// ButtonQuaternary is the fourth button, usually used for browser
 474  	// navigation (backward).
 475  	ButtonQuaternary
 476  	// ButtonQuinary is the fifth button, usually used for browser
 477  	// navigation (forward).
 478  	ButtonQuinary
 479  )
 480  
 481  func (s ScrollRange) Union(s2 ScrollRange) ScrollRange {
 482  	return ScrollRange{
 483  		Min: min(s.Min, s2.Min),
 484  		Max: max(s.Max, s2.Max),
 485  	}
 486  }
 487  
 488  // Push the current pass mode to the pass stack and set the pass mode.
 489  func (p PassOp) Push(o *OpList) PassStack {
 490  	id, mid := PushOp(&o.Internal, PassStackKind)
 491  	data := WriteOps(&o.Internal, TypePassLen)
 492  	data[0] = byte(TypePass)
 493  	return PassStack{ops: &o.Internal, id: id, macroID: mid}
 494  }
 495  
 496  func (p PassStack) Pop() {
 497  	PopOp(p.ops, PassStackKind, p.id, p.macroID)
 498  	data := WriteOps(p.ops, TypePopPassLen)
 499  	data[0] = byte(TypePopPass)
 500  }
 501  
 502  func (c Cursor) Add(o *OpList) {
 503  	data := WriteOps(&o.Internal, TypeCursorLen)
 504  	data[0] = byte(TypeCursor)
 505  	data[1] = byte(c)
 506  }
 507  
 508  func (t PointerKind) String() string {
 509  	if t == PointerCancel {
 510  		return "Cancel"
 511  	}
 512  	var buf []byte
 513  	for tt := PointerKind(1); tt > 0; tt <<= 1 {
 514  		if t&tt > 0 {
 515  			if len(buf) > 0 {
 516  				buf = append(buf, '|')
 517  			}
 518  			buf = append(buf, (t & tt).string()...)
 519  		}
 520  	}
 521  	return buf
 522  }
 523  
 524  func (t PointerKind) string() string {
 525  	switch t {
 526  	case PointerPress:
 527  		return "Press"
 528  	case PointerRelease:
 529  		return "Release"
 530  	case PointerCancel:
 531  		return "Cancel"
 532  	case PointerMove:
 533  		return "Move"
 534  	case PointerDrag:
 535  		return "Drag"
 536  	case PointerEnter:
 537  		return "Enter"
 538  	case PointerLeave:
 539  		return "Leave"
 540  	case PointerScroll:
 541  		return "Scroll"
 542  	default:
 543  		panic("unknown PointerKind")
 544  	}
 545  }
 546  
 547  func (p PointerPriority) String() string {
 548  	switch p {
 549  	case Shared:
 550  		return "Shared"
 551  	case Grabbed:
 552  		return "Grabbed"
 553  	default:
 554  		panic("unknown priority")
 555  	}
 556  }
 557  
 558  func (s PointerSource) String() string {
 559  	switch s {
 560  	case Mouse:
 561  		return "Mouse"
 562  	case Touch:
 563  		return "Touch"
 564  	default:
 565  		panic("unknown source")
 566  	}
 567  }
 568  
 569  // Contain reports whether the set b contains all of the buttons.
 570  func (b PointerButtons) Contain(buttons PointerButtons) bool {
 571  	return b&buttons == buttons
 572  }
 573  
 574  func (b PointerButtons) String() string {
 575  	var parts []string
 576  	if b.Contain(ButtonPrimary) {
 577  		parts = append(parts, "ButtonPrimary")
 578  	}
 579  	if b.Contain(ButtonSecondary) {
 580  		parts = append(parts, "ButtonSecondary")
 581  	}
 582  	if b.Contain(ButtonTertiary) {
 583  		parts = append(parts, "ButtonTertiary")
 584  	}
 585  	if b.Contain(ButtonQuaternary) {
 586  		parts = append(parts, "ButtonQuaternary")
 587  	}
 588  	if b.Contain(ButtonQuinary) {
 589  		parts = append(parts, "ButtonQuinary")
 590  	}
 591  	return bytes.Join(parts, "|")
 592  }
 593  
 594  func (c Cursor) String() string {
 595  	switch c {
 596  	case CursorDefault:
 597  		return "Default"
 598  	case CursorNone:
 599  		return "None"
 600  	case CursorText:
 601  		return "Text"
 602  	case CursorVerticalText:
 603  		return "VerticalText"
 604  	case CursorPointer:
 605  		return "Pointer"
 606  	case CursorCrosshair:
 607  		return "Crosshair"
 608  	case CursorAllScroll:
 609  		return "AllScroll"
 610  	case CursorColResize:
 611  		return "ColResize"
 612  	case CursorRowResize:
 613  		return "RowResize"
 614  	case CursorGrab:
 615  		return "Grab"
 616  	case CursorGrabbing:
 617  		return "Grabbing"
 618  	case CursorNotAllowed:
 619  		return "NotAllowed"
 620  	case CursorWait:
 621  		return "Wait"
 622  	case CursorProgress:
 623  		return "Progress"
 624  	case CursorNorthWestResize:
 625  		return "NorthWestResize"
 626  	case CursorNorthEastResize:
 627  		return "NorthEastResize"
 628  	case CursorSouthWestResize:
 629  		return "SouthWestResize"
 630  	case CursorSouthEastResize:
 631  		return "SouthEastResize"
 632  	case CursorNorthSouthResize:
 633  		return "NorthSouthResize"
 634  	case CursorEastWestResize:
 635  		return "EastWestResize"
 636  	case CursorWestResize:
 637  		return "WestResize"
 638  	case CursorEastResize:
 639  		return "EastResize"
 640  	case CursorNorthResize:
 641  		return "NorthResize"
 642  	case CursorSouthResize:
 643  		return "SouthResize"
 644  	case CursorNorthEastSouthWestResize:
 645  		return "NorthEastSouthWestResize"
 646  	case CursorNorthWestSouthEastResize:
 647  		return "NorthWestSouthEastResize"
 648  	default:
 649  		panic("unknown Cursor")
 650  	}
 651  }
 652  
 653  func (PointerEvent) ImplementsEvent() {}
 654  
 655  func (GrabCmd) ImplementsCommand() {}
 656  
 657  func (PointerFilter) ImplementsFilter() {}
 658  
 659  // ---------------------------------------------------------------------------
 660  // clipboard - clipboard events
 661  // ---------------------------------------------------------------------------
 662  
 663  // ClipboardWriteCmd copies data to the clipboard.
 664  type ClipboardWriteCmd struct {
 665  	Type string
 666  	Data io.ReadCloser
 667  }
 668  
 669  // ClipboardReadCmd requests clipboard contents, delivered to the handler
 670  // through a TransferDataEvent.
 671  type ClipboardReadCmd struct {
 672  	Tag Tag
 673  }
 674  
 675  func (ClipboardWriteCmd) ImplementsCommand() {}
 676  func (ClipboardReadCmd) ImplementsCommand()  {}
 677  
 678  // ---------------------------------------------------------------------------
 679  // system - system actions, decoration, locale
 680  // ---------------------------------------------------------------------------
 681  
 682  // ActionInputOp makes the current clip area available for system gestures.
 683  type ActionInputOp SystemAction
 684  
 685  // SystemAction is a set of window decoration actions.
 686  type SystemAction uint
 687  
 688  const (
 689  	ActionMinimize SystemAction = 1 << iota
 690  	ActionMaximize
 691  	ActionUnmaximize
 692  	ActionFullscreen
 693  	ActionRaise
 694  	ActionCenter
 695  	ActionClose
 696  	ActionMove
 697  )
 698  
 699  func (a ActionInputOp) Add(o *OpList) {
 700  	data := WriteOps(&o.Internal, TypeActionInputLen)
 701  	data[0] = byte(TypeActionInput)
 702  	data[1] = byte(a)
 703  }
 704  
 705  func (a SystemAction) String() string {
 706  	var buf []byte
 707  	for b := SystemAction(1); a != 0; b <<= 1 {
 708  		if a&b != 0 {
 709  			if len(buf) > 0 {
 710  				buf = append(buf, '|')
 711  			}
 712  			buf = append(buf, b.string()...)
 713  			a &^= b
 714  		}
 715  	}
 716  	return buf
 717  }
 718  
 719  func (a SystemAction) string() string {
 720  	switch a {
 721  	case ActionMinimize:
 722  		return "ActionMinimize"
 723  	case ActionMaximize:
 724  		return "ActionMaximize"
 725  	case ActionUnmaximize:
 726  		return "ActionUnmaximize"
 727  	case ActionClose:
 728  		return "ActionClose"
 729  	case ActionMove:
 730  		return "ActionMove"
 731  	case ActionFullscreen:
 732  		return "ActionFullscreen"
 733  	case ActionRaise:
 734  		return "ActionRaise"
 735  	case ActionCenter:
 736  		return "ActionCenter"
 737  	}
 738  	return ""
 739  }
 740  
 741  // Locale provides language information for the current system.
 742  type Locale struct {
 743  	// Language is the BCP-47 tag for the primary language of the system.
 744  	Language string
 745  	// Direction indicates the primary direction of text and layout flow.
 746  	Direction TextDirection
 747  }
 748  
 749  const (
 750  	axisShift = iota
 751  	progressionShift
 752  )
 753  
 754  // TextDirection defines a direction for text flow.
 755  type TextDirection byte
 756  
 757  const (
 758  	// LTR is left-to-right text.
 759  	LTR TextDirection = TextDirection(Horizontal<<axisShift) | TextDirection(FromOrigin<<progressionShift)
 760  	// RTL is right-to-left text.
 761  	RTL TextDirection = TextDirection(Horizontal<<axisShift) | TextDirection(TowardOrigin<<progressionShift)
 762  )
 763  
 764  // Axis returns the axis of the text layout.
 765  func (d TextDirection) Axis() TextAxis {
 766  	return TextAxis((d & (1 << axisShift)) >> axisShift)
 767  }
 768  
 769  // Progression returns the way that the text flows relative to the origin.
 770  func (d TextDirection) Progression() TextProgression {
 771  	return TextProgression((d & (1 << progressionShift)) >> progressionShift)
 772  }
 773  
 774  func (d TextDirection) String() string {
 775  	switch d {
 776  	case RTL:
 777  		return "RTL"
 778  	default:
 779  		return "LTR"
 780  	}
 781  }
 782  
 783  // TextAxis defines the layout axis of text.
 784  type TextAxis byte
 785  
 786  const (
 787  	// Horizontal indicates text that flows along the X axis.
 788  	Horizontal TextAxis = iota
 789  	// Vertical indicates text that flows along the Y axis.
 790  	Vertical
 791  )
 792  
 793  // TextProgression indicates how text flows along an axis relative to the
 794  // origin. The origin is the upper-left corner of coordinate space.
 795  type TextProgression byte
 796  
 797  const (
 798  	// FromOrigin indicates text that flows along its axis away from the origin.
 799  	FromOrigin TextProgression = iota
 800  	// TowardOrigin indicates text that flows along its axis towards the origin.
 801  	TowardOrigin
 802  )
 803  
 804  // ---------------------------------------------------------------------------
 805  // transfer - data transfer operations
 806  // ---------------------------------------------------------------------------
 807  
 808  // TransferOfferCmd is used by data sources as a response to a TransferRequestEvent.
 809  type TransferOfferCmd struct {
 810  	Tag  Tag
 811  	Type string
 812  	Data io.ReadCloser
 813  }
 814  
 815  func (TransferOfferCmd) ImplementsCommand() {}
 816  
 817  // TransferSourceFilter filters for any TransferRequestEvent that match a MIME
 818  // type as well as TransferInitiateEvent and TransferCancelEvent.
 819  type TransferSourceFilter struct {
 820  	Target Tag
 821  	Type   string
 822  }
 823  
 824  // TransferTargetFilter filters for any TransferDataEvent whose type matches a
 825  // MIME type as well as TransferCancelEvent.
 826  type TransferTargetFilter struct {
 827  	Target Tag
 828  	Type   string
 829  }
 830  
 831  // TransferRequestEvent requests data from a data source. The source must
 832  // respond with a TransferOfferCmd.
 833  type TransferRequestEvent struct {
 834  	Type string
 835  }
 836  
 837  func (TransferRequestEvent) ImplementsEvent() {}
 838  
 839  // TransferInitiateEvent is sent to a data source when a drag-and-drop
 840  // transfer gesture is initiated. Potential data targets also receive the event.
 841  type TransferInitiateEvent struct{}
 842  
 843  func (TransferInitiateEvent) ImplementsEvent() {}
 844  
 845  // TransferCancelEvent is sent to data sources and targets to cancel the
 846  // effects of a TransferInitiateEvent.
 847  type TransferCancelEvent struct{}
 848  
 849  func (TransferCancelEvent) ImplementsEvent() {}
 850  
 851  // TransferDataEvent is sent to the target receiving the transfer.
 852  type TransferDataEvent struct {
 853  	Type string
 854  	// Open returns the transfer data. It is only valid to call Open in the
 855  	// frame the TransferDataEvent is received. The caller must close the return
 856  	// value after use.
 857  	Open func() io.ReadCloser
 858  }
 859  
 860  func (TransferDataEvent) ImplementsEvent() {}
 861  
 862  func (TransferSourceFilter) ImplementsFilter() {}
 863  func (TransferTargetFilter) ImplementsFilter() {}
 864  
 865  // ---------------------------------------------------------------------------
 866  // semantic - accessibility data
 867  // ---------------------------------------------------------------------------
 868  
 869  // SemanticLabelOp provides the content of a textual component.
 870  type SemanticLabelOp string
 871  
 872  // SemanticDescriptionOp describes a component.
 873  type SemanticDescriptionOp string
 874  
 875  // SemanticClassOp provides the component class.
 876  type SemanticClassOp int
 877  
 878  const (
 879  	SemanticUnknown SemanticClassOp = iota
 880  	SemanticButton
 881  	SemanticCheckBox
 882  	SemanticEditor
 883  	SemanticRadioButton
 884  	SemanticSwitch
 885  )
 886  
 887  // SemanticSelectedOp describes the selected state for components that have
 888  // boolean state.
 889  type SemanticSelectedOp bool
 890  
 891  // SemanticEnabledOp describes the enabled state.
 892  type SemanticEnabledOp bool
 893  
 894  func (l SemanticLabelOp) Add(o *OpList) {
 895  	data := WriteOps1String(&o.Internal, TypeSemanticLabelLen, string(l))
 896  	data[0] = byte(TypeSemanticLabel)
 897  }
 898  
 899  func (d SemanticDescriptionOp) Add(o *OpList) {
 900  	data := WriteOps1String(&o.Internal, TypeSemanticDescLen, string(d))
 901  	data[0] = byte(TypeSemanticDesc)
 902  }
 903  
 904  func (c SemanticClassOp) Add(o *OpList) {
 905  	data := WriteOps(&o.Internal, TypeSemanticClassLen)
 906  	data[0] = byte(TypeSemanticClass)
 907  	data[1] = byte(c)
 908  }
 909  
 910  func (s SemanticSelectedOp) Add(o *OpList) {
 911  	data := WriteOps(&o.Internal, TypeSemanticSelectedLen)
 912  	data[0] = byte(TypeSemanticSelected)
 913  	if s {
 914  		data[1] = 1
 915  	}
 916  }
 917  
 918  func (e SemanticEnabledOp) Add(o *OpList) {
 919  	data := WriteOps(&o.Internal, TypeSemanticEnabledLen)
 920  	data[0] = byte(TypeSemanticEnabled)
 921  	if e {
 922  		data[1] = 1
 923  	}
 924  }
 925  
 926  func (c SemanticClassOp) String() string {
 927  	switch c {
 928  	case SemanticUnknown:
 929  		return "Unknown"
 930  	case SemanticButton:
 931  		return "Button"
 932  	case SemanticCheckBox:
 933  		return "CheckBox"
 934  	case SemanticEditor:
 935  		return "Editor"
 936  	case SemanticRadioButton:
 937  		return "RadioButton"
 938  	case SemanticSwitch:
 939  		return "Switch"
 940  	default:
 941  		panic("invalid SemanticClassOp")
 942  	}
 943  }
 944