mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 14:18:26 +02:00
Use hand pointer when hovering over buttons in ask kitten
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"kitty/tools/cli/markup"
|
"kitty/tools/cli/markup"
|
||||||
|
"kitty/tools/tty"
|
||||||
"kitty/tools/tui/loop"
|
"kitty/tools/tui/loop"
|
||||||
"kitty/tools/utils"
|
"kitty/tools/utils"
|
||||||
"kitty/tools/utils/style"
|
"kitty/tools/utils/style"
|
||||||
@@ -60,13 +61,16 @@ func extra_for(width, screen_width int) int {
|
|||||||
return max(0, screen_width-width)/2 + 1
|
return max(0, screen_width-width)/2 + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var debugprintln = tty.DebugPrintln
|
||||||
|
var _ = debugprintln
|
||||||
|
|
||||||
func GetChoices(o *Options) (response string, err error) {
|
func GetChoices(o *Options) (response string, err error) {
|
||||||
response = ""
|
response = ""
|
||||||
lp, err := loop.New()
|
lp, err := loop.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
lp.MouseTrackingMode(loop.BUTTONS_ONLY_MOUSE_TRACKING)
|
lp.MouseTrackingMode(loop.FULL_MOUSE_TRACKING)
|
||||||
|
|
||||||
prefix_style_pat := regexp.MustCompile("^(?:\x1b\\[[^m]*?m)+")
|
prefix_style_pat := regexp.MustCompile("^(?:\x1b\\[[^m]*?m)+")
|
||||||
choice_order := make([]Choice, 0, len(o.Choices))
|
choice_order := make([]Choice, 0, len(o.Choices))
|
||||||
@@ -398,16 +402,31 @@ func GetChoices(o *Options) (response string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lp.OnMouseEvent = func(ev *loop.MouseEvent) error {
|
lp.OnMouseEvent = func(ev *loop.MouseEvent) error {
|
||||||
if ev.Event_type == loop.MOUSE_CLICK {
|
on_letter := ""
|
||||||
for letter, ranges := range clickable_ranges {
|
for letter, ranges := range clickable_ranges {
|
||||||
for _, r := range ranges {
|
for _, r := range ranges {
|
||||||
if r.has_point(ev.Cell.X, ev.Cell.Y) {
|
if r.has_point(ev.Cell.X, ev.Cell.Y) {
|
||||||
response = letter
|
on_letter = letter
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if on_letter != "" {
|
||||||
|
if s, has_shape := lp.CurrentPointerShape(); !has_shape && s != loop.POINTER_POINTER {
|
||||||
|
lp.PushPointerShape(loop.POINTER_POINTER)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, has_shape := lp.CurrentPointerShape(); has_shape {
|
||||||
|
lp.PopPointerShape()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ev.Event_type == loop.MOUSE_CLICK {
|
||||||
|
if on_letter != "" {
|
||||||
|
response = on_letter
|
||||||
lp.Quit(0)
|
lp.Quit(0)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if hidden_text != "" && replacement_range.has_point(ev.Cell.X, ev.Cell.Y) {
|
if hidden_text != "" && replacement_range.has_point(ev.Cell.X, ev.Cell.Y) {
|
||||||
unhide()
|
unhide()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1741,6 +1741,7 @@ def set_pointer_shape(screen: Screen, value: str, os_window_id: int = 0) -> str:
|
|||||||
value = value[1:]
|
value = value[1:]
|
||||||
if op in '=>':
|
if op in '=>':
|
||||||
for v in value.split(','):
|
for v in value.split(','):
|
||||||
|
if v:
|
||||||
screen.change_pointer_shape(op, v)
|
screen.change_pointer_shape(op, v)
|
||||||
if os_window_id and current_focused_os_window_id() == os_window_id:
|
if os_window_id and current_focused_os_window_id() == os_window_id:
|
||||||
update_pointer_shape(os_window_id)
|
update_pointer_shape(os_window_id)
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ type Loop struct {
|
|||||||
style_cache map[string]func(...any) string
|
style_cache map[string]func(...any) string
|
||||||
style_ctx style.Context
|
style_ctx style.Context
|
||||||
atomic_update_active bool
|
atomic_update_active bool
|
||||||
|
pointer_shapes []PointerShape
|
||||||
|
|
||||||
// Suspend the loop restoring terminal state, and run the provided function. When it returns terminal state is
|
// Suspend the loop restoring terminal state, and run the provided function. When it returns terminal state is
|
||||||
// put back to what it was before suspending unless the function returns an error or an error occurs saving/restoring state.
|
// put back to what it was before suspending unless the function returns an error or an error occurs saving/restoring state.
|
||||||
@@ -449,3 +450,48 @@ func (self *Loop) CopyTextToPrimarySelection(text string) {
|
|||||||
func (self *Loop) CopyTextToClipboard(text string) {
|
func (self *Loop) CopyTextToClipboard(text string) {
|
||||||
self.copy_text_to(text, "c")
|
self.copy_text_to(text, "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Loop) PushPointerShape(s PointerShape) {
|
||||||
|
self.pointer_shapes = append(self.pointer_shapes, s)
|
||||||
|
self.QueueWriteString("\x1b]22;" + s.String() + "\x1b\\")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Loop) PopPointerShape() {
|
||||||
|
if len(self.pointer_shapes) > 0 {
|
||||||
|
self.pointer_shapes = self.pointer_shapes[:len(self.pointer_shapes)-1]
|
||||||
|
self.QueueWriteString("\x1b]22;<\x1b\\")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Loop) ClearPointerShapes() (ans []PointerShape) {
|
||||||
|
ans = self.pointer_shapes
|
||||||
|
for i := len(self.pointer_shapes) - 1; i >= 0; i-- {
|
||||||
|
self.QueueWriteString("\x1b]22;<\x1b\\")
|
||||||
|
}
|
||||||
|
self.pointer_shapes = nil
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Loop) SetPointerShapes(ps []PointerShape) {
|
||||||
|
self.pointer_shapes = ps
|
||||||
|
if len(ps) > 0 {
|
||||||
|
s := strings.Builder{}
|
||||||
|
s.WriteString("\x1b]22;>")
|
||||||
|
for i, x := range ps {
|
||||||
|
s.WriteString(x.String())
|
||||||
|
if i+1 < len(ps) {
|
||||||
|
s.WriteByte(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.WriteString("\x1b\\")
|
||||||
|
self.QueueWriteString(s.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Loop) CurrentPointerShape() (ans PointerShape, has_shape bool) {
|
||||||
|
if len(self.pointer_shapes) > 0 {
|
||||||
|
has_shape = true
|
||||||
|
ans = self.pointer_shapes[len(self.pointer_shapes)-1]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ func (self *Loop) run() (err error) {
|
|||||||
self.QueueWriteString(finalizer)
|
self.QueueWriteString(finalizer)
|
||||||
}
|
}
|
||||||
if needs_reset_escape_codes {
|
if needs_reset_escape_codes {
|
||||||
|
self.ClearPointerShapes()
|
||||||
self.QueueWriteString(self.terminal_options.ResetStateEscapeCodes())
|
self.QueueWriteString(self.terminal_options.ResetStateEscapeCodes())
|
||||||
}
|
}
|
||||||
// flush queued data and wait for it to be written for a timeout, then wait for writer to shutdown
|
// flush queued data and wait for it to be written for a timeout, then wait for writer to shutdown
|
||||||
@@ -365,6 +366,7 @@ func (self *Loop) run() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.SuspendAndRun = func(run func() error) (err error) {
|
self.SuspendAndRun = func(run func() error) (err error) {
|
||||||
|
ps := self.ClearPointerShapes()
|
||||||
write_id := self.QueueWriteString(self.terminal_options.ResetStateEscapeCodes())
|
write_id := self.QueueWriteString(self.terminal_options.ResetStateEscapeCodes())
|
||||||
needs_reset_escape_codes = false
|
needs_reset_escape_codes = false
|
||||||
if err = self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second); err != nil {
|
if err = self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second); err != nil {
|
||||||
@@ -386,11 +388,13 @@ func (self *Loop) run() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
write_id = self.QueueWriteString(self.terminal_options.SetStateEscapeCodes())
|
write_id = self.QueueWriteString(self.terminal_options.SetStateEscapeCodes())
|
||||||
|
self.SetPointerShapes(ps)
|
||||||
needs_reset_escape_codes = true
|
needs_reset_escape_codes = true
|
||||||
return self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second)
|
return self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.on_SIGTSTP = func() error {
|
self.on_SIGTSTP = func() error {
|
||||||
|
ps := self.ClearPointerShapes()
|
||||||
write_id := self.QueueWriteString(self.terminal_options.ResetStateEscapeCodes())
|
write_id := self.QueueWriteString(self.terminal_options.ResetStateEscapeCodes())
|
||||||
needs_reset_escape_codes = false
|
needs_reset_escape_codes = false
|
||||||
err := self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second)
|
err := self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second)
|
||||||
@@ -406,6 +410,7 @@ func (self *Loop) run() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
write_id = self.QueueWriteString(self.terminal_options.SetStateEscapeCodes())
|
write_id = self.QueueWriteString(self.terminal_options.SetStateEscapeCodes())
|
||||||
|
self.SetPointerShapes(ps)
|
||||||
needs_reset_escape_codes = true
|
needs_reset_escape_codes = true
|
||||||
err = self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second)
|
err = self.wait_for_write_to_complete(write_id, self.tty_write_channel, write_done_channel, 2*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user