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