listbox: implement horizontal scrolling
Implement horizontal scrolling for selected lines that are longer than dialog width. The following keys can be used: Ctrl-a, Home jump to beginning of line Ctrl-e, End jump to end of line Left move one character back Right move one character forward Ctrl+b move one word back Ctrl+w move one word forward Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
8153f59188
commit
b860a64622
2 changed files with 64 additions and 1 deletions
|
@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
- `:pipe -m git am -3` on patch series when `Message-Id` headers have not been
|
- `:pipe -m git am -3` on patch series when `Message-Id` headers have not been
|
||||||
generated by `git send-email`.
|
generated by `git send-email`.
|
||||||
|
- Overflowing text in header editors while composing can now be scrolled
|
||||||
|
horizontally.
|
||||||
|
|
||||||
## [0.13.0](https://git.sr.ht/~rjarry/aerc/refs/0.13.0) - 2022-10-20
|
## [0.13.0](https://git.sr.ht/~rjarry/aerc/refs/0.13.0) - 2022-10-20
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"git.sr.ht/~rjarry/aerc/lib/ui"
|
"git.sr.ht/~rjarry/aerc/lib/ui"
|
||||||
"git.sr.ht/~rjarry/aerc/logging"
|
"git.sr.ht/~rjarry/aerc/logging"
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
|
"github.com/mattn/go-runewidth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListBox struct {
|
type ListBox struct {
|
||||||
|
@ -17,6 +18,7 @@ type ListBox struct {
|
||||||
lines []string
|
lines []string
|
||||||
selected string
|
selected string
|
||||||
cursorPos int
|
cursorPos int
|
||||||
|
horizPos int
|
||||||
jump int
|
jump int
|
||||||
showCursor bool
|
showCursor bool
|
||||||
showFilter bool
|
showFilter bool
|
||||||
|
@ -109,6 +111,17 @@ func (lb *ListBox) moveCursor(delta int) {
|
||||||
}
|
}
|
||||||
lb.selected = list[lb.cursorPos]
|
lb.selected = list[lb.cursorPos]
|
||||||
lb.showCursor = true
|
lb.showCursor = true
|
||||||
|
lb.horizPos = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lb *ListBox) moveHorizontal(delta int) {
|
||||||
|
lb.horizPos += delta
|
||||||
|
if lb.horizPos > len(lb.selected) {
|
||||||
|
lb.horizPos = len(lb.selected)
|
||||||
|
}
|
||||||
|
if lb.horizPos < 0 {
|
||||||
|
lb.horizPos = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lb *ListBox) filtered() []string {
|
func (lb *ListBox) filtered() []string {
|
||||||
|
@ -157,10 +170,22 @@ func (lb *ListBox) drawBox(ctx *ui.Context) {
|
||||||
y := 0
|
y := 0
|
||||||
for i := lb.Scroll(); i < len(list) && y < h; i++ {
|
for i := lb.Scroll(); i < len(list) && y < h; i++ {
|
||||||
style := defaultStyle
|
style := defaultStyle
|
||||||
|
line := runewidth.Truncate(list[i], w-1, "❯")
|
||||||
if lb.selected == list[i] && lb.showCursor {
|
if lb.selected == list[i] && lb.showCursor {
|
||||||
style = selectedStyle
|
style = selectedStyle
|
||||||
|
if len(list[i]) > w {
|
||||||
|
if len(list[i])-lb.horizPos < w {
|
||||||
|
lb.horizPos = len(list[i]) - w + 1
|
||||||
}
|
}
|
||||||
ctx.Printf(1, y, style, list[i])
|
rest := list[i][lb.horizPos:]
|
||||||
|
line = runewidth.Truncate(rest,
|
||||||
|
w-1, "❯")
|
||||||
|
if lb.horizPos > 0 && len(line) > 0 {
|
||||||
|
line = "❮" + line[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.Printf(1, y, style, line)
|
||||||
y += 1
|
y += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +216,42 @@ func (lb *ListBox) Invalidate() {
|
||||||
func (lb *ListBox) Event(event tcell.Event) bool {
|
func (lb *ListBox) Event(event tcell.Event) bool {
|
||||||
if event, ok := event.(*tcell.EventKey); ok {
|
if event, ok := event.(*tcell.EventKey); ok {
|
||||||
switch event.Key() {
|
switch event.Key() {
|
||||||
|
case tcell.KeyLeft:
|
||||||
|
lb.moveHorizontal(-1)
|
||||||
|
lb.Invalidate()
|
||||||
|
return true
|
||||||
|
case tcell.KeyRight:
|
||||||
|
lb.moveHorizontal(+1)
|
||||||
|
lb.Invalidate()
|
||||||
|
return true
|
||||||
|
case tcell.KeyCtrlB:
|
||||||
|
line := lb.selected[:lb.horizPos]
|
||||||
|
fds := strings.Fields(line)
|
||||||
|
if len(fds) > 1 {
|
||||||
|
lb.moveHorizontal(
|
||||||
|
strings.LastIndex(line,
|
||||||
|
fds[len(fds)-1]) - lb.horizPos - 1)
|
||||||
|
} else {
|
||||||
|
lb.horizPos = 0
|
||||||
|
}
|
||||||
|
lb.Invalidate()
|
||||||
|
return true
|
||||||
|
case tcell.KeyCtrlW:
|
||||||
|
line := lb.selected[lb.horizPos+1:]
|
||||||
|
fds := strings.Fields(line)
|
||||||
|
if len(fds) > 1 {
|
||||||
|
lb.moveHorizontal(strings.Index(line, fds[1]))
|
||||||
|
}
|
||||||
|
lb.Invalidate()
|
||||||
|
return true
|
||||||
|
case tcell.KeyCtrlA, tcell.KeyHome:
|
||||||
|
lb.horizPos = 0
|
||||||
|
lb.Invalidate()
|
||||||
|
return true
|
||||||
|
case tcell.KeyCtrlE, tcell.KeyEnd:
|
||||||
|
lb.horizPos = len(lb.selected)
|
||||||
|
lb.Invalidate()
|
||||||
|
return true
|
||||||
case tcell.KeyCtrlP, tcell.KeyUp:
|
case tcell.KeyCtrlP, tcell.KeyUp:
|
||||||
lb.moveCursor(-1)
|
lb.moveCursor(-1)
|
||||||
lb.Invalidate()
|
lb.Invalidate()
|
||||||
|
|
Loading…
Reference in a new issue