Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions internal/action/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,32 @@ func (h *BufPane) ScrollReachedEnd() bool {
// MousePress is the event that should happen when a normal click happens
// This is almost always bound to left click
func (h *BufPane) MousePress(e *tcell.EventMouse) bool {
// Scrollbar hit-test
// Intercept clicks on the scrollbar before any buffer/cursor handling.
if bw, ok := h.BWindow.(*display.BufWindow); ok {
mx, my := e.Position()
sbX := bw.ScrollBarX()
if sbX >= 0 && mx == sbX {
trackStart, trackEnd := bw.ScrollBarTrackBounds()
if my >= trackStart && my <= trackEnd {
thumbStart, thumbEnd := bw.ScrollBarBounds()
if my >= thumbStart && my <= thumbEnd {
// Click lands on the thumb: start a drag.
bw.BeginScrollDrag(my, thumbStart)
} else {
// Click on the track outside the thumb: page scroll.
if my < thumbStart {
h.ScrollUp(h.BufView().Height)
} else {
h.ScrollDown(h.BufView().Height)
h.ScrollAdjust()
}
}
return true
}
}
}

b := h.Buf
mx, my := e.Position()
// ignore click on the status line
Expand Down Expand Up @@ -109,6 +135,18 @@ func (h *BufPane) MousePress(e *tcell.EventMouse) bool {
}

func (h *BufPane) MouseDrag(e *tcell.EventMouse) bool {
if bw, ok := h.BWindow.(*display.BufWindow); ok && bw.IsScrollDragging() {
_, my := e.Position()
// Subtract the intra-thumb offset
effectiveY := my - bw.ScrollDragOffset()
targetLine := bw.ScrollPosFromMouse(effectiveY)
v := h.GetView()
v.StartLine = display.SLoc{targetLine, 0}
h.SetView(v)
h.ScrollAdjust()
return true
}

mx, my := e.Position()
// ignore drag on the status line
if my >= h.BufView().Y+h.BufView().Height {
Expand All @@ -130,6 +168,11 @@ func (h *BufPane) MouseDrag(e *tcell.EventMouse) bool {
}

func (h *BufPane) MouseRelease(e *tcell.EventMouse) bool {
if bw, ok := h.BWindow.(*display.BufWindow); ok && bw.IsScrollDragging() {
bw.EndScrollDrag()
return true
}

// We could finish the selection based on the release location as in the
// commented out code below, to allow text selections even in a terminal
// that doesn't support mouse motion events. But when the mouse click is
Expand Down
70 changes: 70 additions & 0 deletions internal/display/bufwindow.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ type BufWindow struct {
hasMessage bool
maxLineNumLength int
drawDivider bool

scrollDragging bool
// Y delta between the mouse click position and the top of the thumb.
scrollDragOffset int
}

// NewBufWindow creates a new window at a location in the screen with a width and height
Expand Down Expand Up @@ -893,6 +897,72 @@ func (w *BufWindow) displayScrollBar() {
}
}

func (w *BufWindow) ScrollBarX() int {
if !w.Buf.Settings["scrollbar"].(bool) || w.Buf.LinesNum() <= w.Height {
return -1
}
return w.X + w.Width - 1
}

// returns the (inclusive) screen Y range [thumbStart, thumbEnd]
// of the scrollbar thumb, or (-1,-1) when the scrollbar is not visible.
func (w *BufWindow) ScrollBarBounds() (int, int) {
if !w.Buf.Settings["scrollbar"].(bool) || w.Buf.LinesNum() <= w.Height {
return -1, -1
}
barsize := int(float64(w.Height) / float64(w.Buf.LinesNum()) * float64(w.Height))
if barsize < 1 {
barsize = 1
}
barstart := w.Y + int(float64(w.StartLine.Line)/float64(w.Buf.LinesNum())*float64(w.Height))
barend := util.Min(barstart+barsize, w.Y+w.bufHeight) - 1
return barstart, barend
}

// returns the screen Y range [start, end] of the full
// scrollbar track column (excluding the status line).
func (w *BufWindow) ScrollBarTrackBounds() (int, int) {
if !w.Buf.Settings["scrollbar"].(bool) || w.Buf.LinesNum() <= w.Height {
return -1, -1
}
return w.Y, w.Y + w.bufHeight - 1
}

func (w *BufWindow) ScrollPosFromMouse(screenY int) int {
trackStart, trackEnd := w.ScrollBarTrackBounds()
trackH := trackEnd - trackStart + 1
if trackH <= 0 {
return 0
}
ratio := float64(screenY-trackStart) / float64(trackH)
line := int(ratio * float64(w.Buf.LinesNum()))
if line < 0 {
line = 0
}
if line >= w.Buf.LinesNum() {
line = w.Buf.LinesNum() - 1
}
return line
}

func (w *BufWindow) BeginScrollDrag(dragY, thumbStart int) {
w.scrollDragging = true
w.scrollDragOffset = dragY - thumbStart
}

func (w *BufWindow) EndScrollDrag() {
w.scrollDragging = false
w.scrollDragOffset = 0
}

func (w *BufWindow) IsScrollDragging() bool {
return w.scrollDragging
}

func (w *BufWindow) ScrollDragOffset() int {
return w.scrollDragOffset
}

// Display displays the buffer and the statusline
func (w *BufWindow) Display() {
w.updateDisplayInfo()
Expand Down