From 0b743464fbe5ce903f0f4559e71a3adbd78c118a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 4 May 2024 09:45:57 +0530 Subject: [PATCH] Work on supporting mouse interactions via simple hyperlinks --- tools/cmd/list_fonts/main.go | 1 + tools/cmd/list_fonts/ui.go | 6 +++ tools/tui/mouse.go | 76 ++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/tools/cmd/list_fonts/main.go b/tools/cmd/list_fonts/main.go index c6dc11891..fd9206500 100644 --- a/tools/cmd/list_fonts/main.go +++ b/tools/cmd/list_fonts/main.go @@ -70,6 +70,7 @@ func main() (rc int, err error) { lp.SetCursorVisible(true) return `` } + lp.OnMouseEvent = h.on_mouse_event lp.OnResize = func(_, _ loop.ScreenSize) error { return h.draw_screen() } diff --git a/tools/cmd/list_fonts/ui.go b/tools/cmd/list_fonts/ui.go index b0e422548..001b57866 100644 --- a/tools/cmd/list_fonts/ui.go +++ b/tools/cmd/list_fonts/ui.go @@ -5,6 +5,7 @@ import ( "strings" "sync" + "kitty/tools/tui" "kitty/tools/tui/loop" "kitty/tools/tui/readline" "kitty/tools/utils" @@ -30,6 +31,7 @@ type handler struct { state State err_mutex sync.Mutex err_in_worker_thread error + mouse_state tui.MouseState // Listing rl *readline.Readline @@ -278,6 +280,10 @@ func (h *handler) on_wakeup() (err error) { return h.draw_screen() } +func (h *handler) on_mouse_event(event *loop.MouseEvent) (err error) { + return h.mouse_state.UpdateState(event) +} + func (h *handler) on_key_event(event *loop.KeyEvent) (err error) { if event.MatchesPressOrRepeat("ctrl+c") { event.Handled = true diff --git a/tools/tui/mouse.go b/tools/tui/mouse.go index 41b894af3..2b414e7da 100644 --- a/tools/tui/mouse.go +++ b/tools/tui/mouse.go @@ -201,3 +201,79 @@ func (ms *MouseSelection) DragScroll(ev *loop.MouseEvent, lp *loop.Loop, callbac } ms.drag_scroll.mouse_event = *ev } + +type CellRegion struct { + TopLeft, BottomRight struct{ X, Y int } + Hovered bool + Id string + OnClick []func(id string) error +} + +func (c CellRegion) Contains(x, y int) bool { // 0-based + if c.TopLeft.Y > y || c.BottomRight.Y < y { + return false + } + return (y > c.TopLeft.Y || (y == c.TopLeft.Y && x >= c.TopLeft.X)) && (y < c.BottomRight.Y || (y == c.BottomRight.Y && x <= c.BottomRight.X)) +} + +type MouseState struct { + Cell, Pixel struct{ X, Y int } + Pressed struct{ Left, Right, Middle, Fourth, Fifth, Sixth, Seventh bool } + + regions []*CellRegion +} + +func (m *MouseState) AddCellRegion(id string, start_x, start_y, end_x, end_y int, on_click ...func(id string) error) *CellRegion { + cr := CellRegion{TopLeft: struct{ X, Y int }{start_x, start_y}, BottomRight: struct{ X, Y int }{end_x, end_y}, Id: id, OnClick: on_click} + m.regions = append(m.regions, &cr) + cr.Hovered = cr.Contains(m.Cell.X, m.Cell.Y) + return &cr +} + +func (m *MouseState) ClearCellRegions() { + m.regions = nil +} + +func (m *MouseState) UpdateState(ev *loop.MouseEvent) error { + m.Cell = ev.Cell + m.Pixel = ev.Pixel + if ev.Event_type == loop.MOUSE_PRESS || ev.Event_type == loop.MOUSE_RELEASE { + pressed := ev.Event_type == loop.MOUSE_PRESS + if ev.Buttons&loop.LEFT_MOUSE_BUTTON != 0 { + m.Pressed.Left = pressed + } + if ev.Buttons&loop.RIGHT_MOUSE_BUTTON != 0 { + m.Pressed.Right = pressed + } + if ev.Buttons&loop.MIDDLE_MOUSE_BUTTON != 0 { + m.Pressed.Middle = pressed + } + if ev.Buttons&loop.FOURTH_MOUSE_BUTTON != 0 { + m.Pressed.Fourth = pressed + } + if ev.Buttons&loop.FIFTH_MOUSE_BUTTON != 0 { + m.Pressed.Fifth = pressed + } + if ev.Buttons&loop.SIXTH_MOUSE_BUTTON != 0 { + m.Pressed.Sixth = pressed + } + if ev.Buttons&loop.SEVENTH_MOUSE_BUTTON != 0 { + m.Pressed.Seventh = pressed + } + } + for _, r := range m.regions { + if r.Contains(m.Cell.X, m.Cell.Y) { + r.Hovered = true + if ev.Event_type == loop.MOUSE_CLICK { + for _, f := range r.OnClick { + if err := f(r.Id); err != nil { + return err + } + } + } + } else { + r.Hovered = false + } + } + return nil +}