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() {}