app: add support for system cursors

Signed-off-by: pierre <pierre.curto@gmail.com>
This commit is contained in:
pierre
2020-12-02 16:50:56 +01:00
committed by Elias Naur
parent 951d45a2c6
commit 69cc2c795c
15 changed files with 297 additions and 18 deletions
+2
View File
@@ -3,6 +3,8 @@ image: freebsd/11.x
packages: packages:
- libX11 - libX11
- libxkbcommon - libxkbcommon
- libXcursor
- libXfixes
- wayland - wayland
- mesa-libs - mesa-libs
- xorg-vfbserver - xorg-vfbserver
+6 -1
View File
@@ -22,6 +22,7 @@ import android.view.Choreographer;
import android.view.KeyCharacterMap; import android.view.KeyCharacterMap;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.WindowInsets; import android.view.WindowInsets;
@@ -36,7 +37,6 @@ import android.view.inputmethod.EditorInfo;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
public final class GioView extends SurfaceView implements Choreographer.FrameCallback { public final class GioView extends SurfaceView implements Choreographer.FrameCallback {
private final static Object initLock = new Object();
private static boolean jniLoaded; private static boolean jniLoaded;
private final SurfaceHolder.Callback surfCallbacks; private final SurfaceHolder.Callback surfCallbacks;
@@ -124,6 +124,11 @@ public final class GioView extends SurfaceView implements Choreographer.FrameCal
return true; return true;
} }
private void setCursor(Context ctx, int id) {
PointerIcon pointerIcon = PointerIcon.getSystemIcon(ctx, id);
GioView.this.setPointerIcon(pointerIcon);
}
private void dispatchMotionEvent(MotionEvent event) { private void dispatchMotionEvent(MotionEvent event) {
for (int j = 0; j < event.getHistorySize(); j++) { for (int j = 0; j < event.getHistorySize(); j++) {
long time = event.getHistoricalEventTime(j); long time = event.getHistoricalEventTime(j);
+28
View File
@@ -80,6 +80,7 @@ type window struct {
mshowTextInput C.jmethodID mshowTextInput C.jmethodID
mhideTextInput C.jmethodID mhideTextInput C.jmethodID
mpostFrameCallback C.jmethodID mpostFrameCallback C.jmethodID
msetCursor C.jmethodID
} }
// ViewEvent is sent whenever the Window's underlying Android view // ViewEvent is sent whenever the Window's underlying Android view
@@ -202,6 +203,7 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
mshowTextInput: getMethodID(env, class, "showTextInput", "()V"), mshowTextInput: getMethodID(env, class, "showTextInput", "()V"),
mhideTextInput: getMethodID(env, class, "hideTextInput", "()V"), mhideTextInput: getMethodID(env, class, "hideTextInput", "()V"),
mpostFrameCallback: getMethodID(env, class, "postFrameCallback", "()V"), mpostFrameCallback: getMethodID(env, class, "postFrameCallback", "()V"),
msetCursor: getMethodID(env, class, "setCursor", "(Landroid/content/Context;I)V"),
} }
wopts := <-mainWindow.out wopts := <-mainWindow.out
w.callbacks = wopts.window w.callbacks = wopts.window
@@ -649,6 +651,32 @@ func (w *window) ReadClipboard() {
}) })
} }
func (w *window) SetCursor(name pointer.CursorName) {
var curID int
switch name {
default:
fallthrough
case pointer.CursorDefault:
curID = 1000 // TYPE_ARROW
case pointer.CursorText:
curID = 1008 // TYPE_TEXT
case pointer.CursorPointer:
curID = 1002 // TYPE_HAND
case pointer.CursorCrossHair:
curID = 1007 // TYPE_CROSSHAIR
case pointer.CursorColResize:
curID = 1014 // TYPE_HORIZONTAL_DOUBLE_ARROW
case pointer.CursorRowResize:
curID = 1015 // TYPE_VERTICAL_DOUBLE_ARROW
case pointer.CursorNone:
curID = 0 // TYPE_NULL
}
runOnMain(func(env *C.JNIEnv) {
callVoidMethod(env, w.view, w.msetCursor,
jvalue(android.appCtx), jvalue(curID))
})
}
// Close the window. Not implemented for Android. // Close the window. Not implemented for Android.
func (w *window) Close() {} func (w *window) Close() {}
+43
View File
@@ -13,6 +13,9 @@ __attribute__ ((visibility ("hidden"))) void gio_releaseDisplayLink(CFTypeRef dl
__attribute__ ((visibility ("hidden"))) int gio_startDisplayLink(CFTypeRef dl); __attribute__ ((visibility ("hidden"))) int gio_startDisplayLink(CFTypeRef dl);
__attribute__ ((visibility ("hidden"))) int gio_stopDisplayLink(CFTypeRef dl); __attribute__ ((visibility ("hidden"))) int gio_stopDisplayLink(CFTypeRef dl);
__attribute__ ((visibility ("hidden"))) void gio_setDisplayLinkDisplay(CFTypeRef dl, uint64_t did); __attribute__ ((visibility ("hidden"))) void gio_setDisplayLinkDisplay(CFTypeRef dl, uint64_t did);
__attribute__ ((visibility ("hidden"))) void gio_hideCursor();
__attribute__ ((visibility ("hidden"))) void gio_showCursor();
__attribute__ ((visibility ("hidden"))) void gio_setCursor(NSUInteger curID);
*/ */
import "C" import "C"
import ( import (
@@ -22,6 +25,8 @@ import (
"time" "time"
"unicode/utf16" "unicode/utf16"
"unsafe" "unsafe"
"gioui.org/io/pointer"
) )
// displayLink is the state for a display link (CVDisplayLinkRef on macOS, // displayLink is the state for a display link (CVDisplayLinkRef on macOS,
@@ -169,3 +174,41 @@ func gio_onFrameCallback(dl C.CFTypeRef) {
} }
} }
} }
// windowSetCursor updates the cursor from the current one to a new one
// and returns the new one.
func windowSetCursor(from, to pointer.CursorName) pointer.CursorName {
if from == to {
return to
}
var curID int
switch to {
default:
to = pointer.CursorDefault
fallthrough
case pointer.CursorDefault:
curID = 1
case pointer.CursorText:
curID = 2
case pointer.CursorPointer:
curID = 3
case pointer.CursorCrossHair:
curID = 4
case pointer.CursorColResize:
curID = 5
case pointer.CursorRowResize:
curID = 6
case pointer.CursorNone:
runOnMain(func() {
C.gio_hideCursor()
})
return to
}
runOnMain(func() {
if from == pointer.CursorNone {
C.gio_showCursor()
}
C.gio_setCursor(C.NSUInteger(curID))
})
return to
}
+40
View File
@@ -20,3 +20,43 @@ void gio_nsstringGetCharacters(CFTypeRef cstr, unichar *chars, NSUInteger loc, N
NSString *str = (__bridge NSString *)cstr; NSString *str = (__bridge NSString *)cstr;
[str getCharacters:chars range:NSMakeRange(loc, length)]; [str getCharacters:chars range:NSMakeRange(loc, length)];
} }
void gio_hideCursor() {
@autoreleasepool {
[NSCursor hide];
}
}
void gio_showCursor() {
@autoreleasepool {
[NSCursor unhide];
}
}
void gio_setCursor(NSUInteger curID) {
@autoreleasepool {
switch (curID) {
case 1:
[NSCursor.arrowCursor set];
break;
case 2:
[NSCursor.IBeamCursor set];
break;
case 3:
[NSCursor.pointingHandCursor set];
break;
case 4:
[NSCursor.crosshairCursor set];
break;
case 5:
[NSCursor.resizeLeftRightCursor set];
break;
case 6:
[NSCursor.resizeUpDownCursor set];
break;
default:
[NSCursor.arrowCursor set];
break;
}
}
}
+5
View File
@@ -51,6 +51,7 @@ type window struct {
layer C.CFTypeRef layer C.CFTypeRef
visible atomic.Value visible atomic.Value
cursor pointer.CursorName
pointerMap []C.CFTypeRef pointerMap []C.CFTypeRef
} }
@@ -249,6 +250,10 @@ func (w *window) SetAnimating(anim bool) {
} }
} }
func (w *window) SetCursor(name pointer.CursorName) {
w.cursor = windowSetCursor(w.cursor, name)
}
func (w *window) onKeyCommand(name string) { func (w *window) onKeyCommand(name string) {
w.w.Event(key.Event{ w.w.Event(key.Event{
Name: name, Name: name,
+5
View File
@@ -426,6 +426,11 @@ func (w *window) WriteClipboard(s string) {
w.clipboard.Call("writeText", s) w.clipboard.Call("writeText", s)
} }
func (w *window) SetCursor(name pointer.CursorName) {
style := w.cnv.Get("style")
style.Set("cursor", string(name))
}
func (w *window) ShowTextInput(show bool) { func (w *window) ShowTextInput(show bool) {
// Run in a goroutine to avoid a deadlock if the // Run in a goroutine to avoid a deadlock if the
// focus change result in an event. // focus change result in an event.
+7 -1
View File
@@ -58,6 +58,7 @@ type window struct {
w Callbacks w Callbacks
stage system.Stage stage system.Stage
displayLink *displayLink displayLink *displayLink
cursor pointer.CursorName
scale float32 scale float32
} }
@@ -74,7 +75,7 @@ var launched = make(chan struct{})
// cascadeTopLeftFromPoint. // cascadeTopLeftFromPoint.
var nextTopLeft C.NSPoint var nextTopLeft C.NSPoint
// mustView is like lookoupView, except that it panics // mustView is like lookupView, except that it panics
// if the view isn't mapped. // if the view isn't mapped.
func mustView(view C.CFTypeRef) *window { func mustView(view C.CFTypeRef) *window {
w, ok := lookupView(view) w, ok := lookupView(view)
@@ -122,6 +123,10 @@ func (w *window) WriteClipboard(s string) {
}) })
} }
func (w *window) SetCursor(name pointer.CursorName) {
w.cursor = windowSetCursor(w.cursor, name)
}
func (w *window) ShowTextInput(show bool) {} func (w *window) ShowTextInput(show bool) {}
func (w *window) SetAnimating(anim bool) { func (w *window) SetAnimating(anim bool) {
@@ -227,6 +232,7 @@ func gio_onDraw(view C.CFTypeRef) {
func gio_onFocus(view C.CFTypeRef, focus C.BOOL) { func gio_onFocus(view C.CFTypeRef, focus C.BOOL) {
w := mustView(view) w := mustView(view)
w.w.Event(key.FocusEvent{Focus: focus == C.YES}) w.w.Event(key.FocusEvent{Focus: focus == C.YES})
w.SetCursor(w.cursor)
} }
//export gio_onChangeScreen //export gio_onChangeScreen
+45 -10
View File
@@ -764,16 +764,7 @@ func gio_onPointerEnter(data unsafe.Pointer, pointer *C.struct_wl_pointer, seria
s.serial = serial s.serial = serial
w := callbackLoad(unsafe.Pointer(surf)).(*window) w := callbackLoad(unsafe.Pointer(surf)).(*window)
s.pointerFocus = w s.pointerFocus = w
// Get images[0]. w.setCursor(pointer, serial)
img := *w.cursor.cursor.images
buf := C.wl_cursor_image_get_buffer(img)
if buf == nil {
return
}
C.wl_pointer_set_cursor(pointer, serial, w.cursor.surf, C.int32_t(img.hotspot_x), C.int32_t(img.hotspot_y))
C.wl_surface_attach(w.cursor.surf, buf, 0, 0)
C.wl_surface_damage(w.cursor.surf, 0, 0, C.int32_t(img.width), C.int32_t(img.height))
C.wl_surface_commit(w.cursor.surf)
w.lastPos = f32.Point{X: fromFixed(x), Y: fromFixed(y)} w.lastPos = f32.Point{X: fromFixed(x), Y: fromFixed(y)}
} }
@@ -917,6 +908,50 @@ func (w *window) WriteClipboard(s string) {
w.disp.wakeup() w.disp.wakeup()
} }
func (w *window) SetCursor(name pointer.CursorName) {
if name == pointer.CursorNone {
C.wl_pointer_set_cursor(w.disp.seat.pointer, w.serial, nil, 0, 0)
return
}
switch name {
default:
fallthrough
case pointer.CursorDefault:
name = "left_ptr"
case pointer.CursorText:
name = "xterm"
case pointer.CursorPointer:
name = "hand1"
case pointer.CursorCrossHair:
name = "crosshair"
case pointer.CursorRowResize:
name = "top_side"
case pointer.CursorColResize:
name = "left_side"
}
cname := C.CString(string(name))
defer C.free(unsafe.Pointer(cname))
c := C.wl_cursor_theme_get_cursor(w.cursor.theme, cname)
if c == nil {
return
}
w.cursor.cursor = c
w.setCursor(w.disp.seat.pointer, w.serial)
}
func (w *window) setCursor(pointer *C.struct_wl_pointer, serial C.uint32_t) {
// Get images[0].
img := *w.cursor.cursor.images
buf := C.wl_cursor_image_get_buffer(img)
if buf == nil {
return
}
C.wl_pointer_set_cursor(pointer, serial, w.cursor.surf, C.int32_t(img.hotspot_x), C.int32_t(img.hotspot_y))
C.wl_surface_attach(w.cursor.surf, buf, 0, 0)
C.wl_surface_damage(w.cursor.surf, 0, 0, C.int32_t(img.width), C.int32_t(img.height))
C.wl_surface_commit(w.cursor.surf)
}
func (w *window) resetFling() { func (w *window) resetFling() {
w.fling.start = false w.fling.start = false
w.fling.anim = fling.Animation{} w.fling.anim = fling.Animation{}
+39 -3
View File
@@ -45,6 +45,7 @@ type window struct {
height int height int
stage system.Stage stage system.Stage
pointerBtns pointer.Buttons pointerBtns pointer.Buttons
cursor syscall.Handle
mu sync.Mutex mu sync.Mutex
animating bool animating bool
@@ -105,6 +106,9 @@ func NewWindow(window Callbacks, opts *Options) error {
windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT) windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT)
windows.SetForegroundWindow(w.hwnd) windows.SetForegroundWindow(w.hwnd)
windows.SetFocus(w.hwnd) windows.SetFocus(w.hwnd)
// Since the window class for the cursor is null,
// set it here to show the cursor.
w.SetCursor(pointer.CursorDefault)
if err := w.loop(); err != nil { if err := w.loop(); err != nil {
panic(err) panic(err)
} }
@@ -120,17 +124,16 @@ func initResources() error {
return err return err
} }
resources.handle = hInst resources.handle = hInst
curs, err := windows.LoadCursor(windows.IDC_ARROW) c, err := loadCursor(pointer.CursorDefault)
if err != nil { if err != nil {
return err return err
} }
resources.cursor = curs resources.cursor = c
wcls := windows.WndClassEx{ wcls := windows.WndClassEx{
CbSize: uint32(unsafe.Sizeof(windows.WndClassEx{})), CbSize: uint32(unsafe.Sizeof(windows.WndClassEx{})),
Style: windows.CS_HREDRAW | windows.CS_VREDRAW | windows.CS_OWNDC, Style: windows.CS_HREDRAW | windows.CS_VREDRAW | windows.CS_OWNDC,
LpfnWndProc: syscall.NewCallback(windowProc), LpfnWndProc: syscall.NewCallback(windowProc),
HInstance: hInst, HInstance: hInst,
HCursor: curs,
LpszClassName: syscall.StringToUTF16Ptr("GioWindow"), LpszClassName: syscall.StringToUTF16Ptr("GioWindow"),
} }
cls, err := windows.RegisterClassEx(&wcls) cls, err := windows.RegisterClassEx(&wcls)
@@ -299,6 +302,8 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
Y: w.minmax.maxHeight + w.deltas.height, Y: w.minmax.maxHeight + w.deltas.height,
} }
} }
case windows.WM_SETCURSOR:
windows.SetCursor(w.cursor)
} }
return windows.DefWindowProc(hwnd, msg, wParam, lParam) return windows.DefWindowProc(hwnd, msg, wParam, lParam)
@@ -552,6 +557,37 @@ func (w *window) writeClipboard(s string) error {
return nil return nil
} }
func (w *window) SetCursor(name pointer.CursorName) {
c, err := loadCursor(name)
if err != nil {
c = resources.cursor
}
w.cursor = c
}
func loadCursor(name pointer.CursorName) (syscall.Handle, error) {
var curID uint16
switch name {
default:
fallthrough
case pointer.CursorDefault:
return resources.cursor, nil
case pointer.CursorText:
curID = windows.IDC_IBEAM
case pointer.CursorPointer:
curID = windows.IDC_HAND
case pointer.CursorCrossHair:
curID = windows.IDC_CROSS
case pointer.CursorColResize:
curID = windows.IDC_SIZEWE
case pointer.CursorRowResize:
curID = windows.IDC_SIZENS
case pointer.CursorNone:
return 0, nil
}
return windows.LoadCursor(curID)
}
func (w *window) ShowTextInput(show bool) {} func (w *window) ShowTextInput(show bool) {}
func (w *window) HDC() syscall.Handle { func (w *window) HDC() syscall.Handle {
+26 -2
View File
@@ -7,8 +7,8 @@ package window
/* /*
#cgo openbsd CFLAGS: -I/usr/X11R6/include -I/usr/local/include #cgo openbsd CFLAGS: -I/usr/X11R6/include -I/usr/local/include
#cgo openbsd LDFLAGS: -L/usr/X11R6/lib -L/usr/local/lib #cgo openbsd LDFLAGS: -L/usr/X11R6/lib -L/usr/local/lib
#cgo freebsd openbsd LDFLAGS: -lX11 -lxkbcommon -lxkbcommon-x11 -lX11-xcb #cgo freebsd openbsd LDFLAGS: -lX11 -lxkbcommon -lxkbcommon-x11 -lX11-xcb -lXcursor -lXfixes
#cgo linux pkg-config: x11 xkbcommon xkbcommon-x11 x11-xcb #cgo linux pkg-config: x11 xkbcommon xkbcommon-x11 x11-xcb xcursor xfixes
#include <stdlib.h> #include <stdlib.h>
#include <locale.h> #include <locale.h>
@@ -18,6 +18,8 @@ package window
#include <X11/Xresource.h> #include <X11/Xresource.h>
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#include <X11/Xlib-xcb.h> #include <X11/Xlib-xcb.h>
#include <X11/extensions/Xfixes.h>
#include <X11/Xcursor/Xcursor.h>
#include <xkbcommon/xkbcommon-x11.h> #include <xkbcommon/xkbcommon-x11.h>
*/ */
@@ -87,6 +89,7 @@ type x11Window struct {
write *string write *string
content []byte content []byte
} }
cursor pointer.CursorName
} }
func (w *x11Window) SetAnimating(anim bool) { func (w *x11Window) SetAnimating(anim bool) {
@@ -112,6 +115,27 @@ func (w *x11Window) WriteClipboard(s string) {
w.wakeup() w.wakeup()
} }
func (w *x11Window) SetCursor(name pointer.CursorName) {
if name == pointer.CursorNone {
w.cursor = name
C.XFixesHideCursor(w.x, w.xw)
return
}
if w.cursor == pointer.CursorNone {
C.XFixesShowCursor(w.x, w.xw)
}
cname := C.CString(string(name))
defer C.free(unsafe.Pointer(cname))
c := C.XcursorLibraryLoadCursor(w.x, cname)
if c == 0 {
name = pointer.CursorDefault
}
w.cursor = name
// If c if null (i.e. name was not found),
// XDefineCursor will use the default cursor.
C.XDefineCursor(w.x, w.xw, c)
}
func (w *x11Window) ShowTextInput(show bool) {} func (w *x11Window) ShowTextInput(show bool) {}
// Close the window. // Close the window.
+4
View File
@@ -9,6 +9,7 @@ import (
"gioui.org/gpu/backend" "gioui.org/gpu/backend"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/pointer"
"gioui.org/io/system" "gioui.org/io/system"
"gioui.org/unit" "gioui.org/unit"
) )
@@ -60,6 +61,9 @@ type Driver interface {
// WriteClipboard requests a clipboard write. // WriteClipboard requests a clipboard write.
WriteClipboard(s string) WriteClipboard(s string)
// SetCursor updates the current cursor to name.
SetCursor(name pointer.CursorName)
// Close the window. // Close the window.
Close() Close()
} }
+12 -1
View File
@@ -61,7 +61,12 @@ const (
CW_USEDEFAULT = -2147483648 CW_USEDEFAULT = -2147483648
IDC_ARROW = 32512 IDC_ARROW = 32512
IDC_IBEAM = 32513
IDC_HAND = 32649
IDC_CROSS = 32515
IDC_SIZENS = 32645
IDC_SIZEWE = 32644
INFINITE = 0xFFFFFFFF INFINITE = 0xFFFFFFFF
@@ -146,6 +151,7 @@ const (
WM_PAINT = 0x000F WM_PAINT = 0x000F
WM_CLOSE = 0x0010 WM_CLOSE = 0x0010
WM_QUIT = 0x0012 WM_QUIT = 0x0012
WM_SETCURSOR = 0x0020
WM_SETFOCUS = 0x0007 WM_SETFOCUS = 0x0007
WM_KILLFOCUS = 0x0008 WM_KILLFOCUS = 0x0008
WM_SHOWWINDOW = 0x0018 WM_SHOWWINDOW = 0x0018
@@ -227,6 +233,7 @@ var (
_ScreenToClient = user32.NewProc("ScreenToClient") _ScreenToClient = user32.NewProc("ScreenToClient")
_ShowWindow = user32.NewProc("ShowWindow") _ShowWindow = user32.NewProc("ShowWindow")
_SetCapture = user32.NewProc("SetCapture") _SetCapture = user32.NewProc("SetCapture")
_SetCursor = user32.NewProc("SetCursor")
_SetClipboardData = user32.NewProc("SetClipboardData") _SetClipboardData = user32.NewProc("SetClipboardData")
_SetForegroundWindow = user32.NewProc("SetForegroundWindow") _SetForegroundWindow = user32.NewProc("SetForegroundWindow")
_SetFocus = user32.NewProc("SetFocus") _SetFocus = user32.NewProc("SetFocus")
@@ -514,6 +521,10 @@ func SetClipboardData(format uint32, mem syscall.Handle) error {
return nil return nil
} }
func SetCursor(h syscall.Handle) {
_SetCursor.Call(uintptr(h))
}
func SetTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error { func SetTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error {
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc) r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc)
if r == 0 { if r == 0 {
+8
View File
@@ -10,6 +10,7 @@ import (
"gioui.org/app/internal/window" "gioui.org/app/internal/window"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/pointer"
"gioui.org/io/profile" "gioui.org/io/profile"
"gioui.org/io/router" "gioui.org/io/router"
"gioui.org/io/system" "gioui.org/io/system"
@@ -209,6 +210,13 @@ func (w *Window) WriteClipboard(s string) {
}) })
} }
// SetCursorName changes the current window cursor to name.
func (w *Window) SetCursorName(name pointer.CursorName) {
go w.driverDo(func() {
w.driver.SetCursor(name)
})
}
// Close the window. The window's event loop should exit when it receives // Close the window. The window's event loop should exit when it receives
// system.DestroyEvent. // system.DestroyEvent.
// //
+27
View File
@@ -79,9 +79,29 @@ type Source uint8
// Buttons is a set of mouse buttons // Buttons is a set of mouse buttons
type Buttons uint8 type Buttons uint8
// CursorName is the name of a cursor.
type CursorName string
// Must match app/internal/input.areaKind // Must match app/internal/input.areaKind
type areaKind uint8 type areaKind uint8
const (
// CursorDefault is the default cursor.
CursorDefault CursorName = ""
// CursorText is the cursor for text.
CursorText CursorName = "text"
// CursorPointer is the cursor for a link.
CursorPointer CursorName = "pointer"
// CursorCrossHair is the cursor for precise location.
CursorCrossHair CursorName = "crosshair"
// CursorColResize is the cursor for vertical resize.
CursorColResize CursorName = "col-resize"
// CursorRowResize is the cursor for horizontal resize.
CursorRowResize CursorName = "row-resize"
// CursorNone hides the cursor. To show it again, use any other cursor.
CursorNone CursorName = "none"
)
const ( const (
// A Cancel event is generated when the current gesture is // A Cancel event is generated when the current gesture is
// interrupted by other handlers or the system. // interrupted by other handlers or the system.
@@ -242,4 +262,11 @@ func (b Buttons) String() string {
return strings.Join(strs, "|") return strings.Join(strs, "|")
} }
func (c CursorName) String() string {
if c == CursorDefault {
return "default"
}
return string(c)
}
func (Event) ImplementsEvent() {} func (Event) ImplementsEvent() {}