2022-03-29 12:20:33 +00:00
|
|
|
//go:build tcell || windows
|
2016-10-24 03:45:45 +00:00
|
|
|
|
|
|
|
package tui
|
|
|
|
|
|
|
|
import (
|
2017-06-03 10:47:53 +00:00
|
|
|
"os"
|
2016-10-24 03:45:45 +00:00
|
|
|
"time"
|
|
|
|
|
2022-08-20 21:23:03 +00:00
|
|
|
"github.com/gdamore/tcell/v2"
|
|
|
|
"github.com/gdamore/tcell/v2/encoding"
|
2023-03-25 01:23:05 +00:00
|
|
|
"github.com/junegunn/fzf/src/util"
|
2016-11-06 17:15:34 +00:00
|
|
|
|
2024-01-27 13:18:43 +00:00
|
|
|
"github.com/rivo/uniseg"
|
2016-10-24 03:45:45 +00:00
|
|
|
)
|
|
|
|
|
2020-10-30 17:53:10 +00:00
|
|
|
func HasFullscreenRenderer() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-01-15 16:22:02 +00:00
|
|
|
var DefaultBorderShape BorderShape = BorderSharp
|
|
|
|
|
2022-08-20 21:23:03 +00:00
|
|
|
func asTcellColor(color Color) tcell.Color {
|
2022-09-26 05:09:38 +00:00
|
|
|
if color == colDefault {
|
|
|
|
return tcell.ColorDefault
|
|
|
|
}
|
|
|
|
|
2022-08-20 21:23:03 +00:00
|
|
|
value := uint64(tcell.ColorValid) + uint64(color)
|
|
|
|
if color.is24() {
|
|
|
|
value = value | uint64(tcell.ColorIsRGB)
|
|
|
|
}
|
|
|
|
return tcell.Color(value)
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (p ColorPair) style() tcell.Style {
|
|
|
|
style := tcell.StyleDefault
|
2022-08-20 21:23:03 +00:00
|
|
|
return style.Foreground(asTcellColor(p.Fg())).Background(asTcellColor(p.Bg()))
|
2017-01-07 16:30:31 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2022-08-20 21:23:03 +00:00
|
|
|
type Attr int32
|
2017-01-07 16:30:31 +00:00
|
|
|
|
|
|
|
type TcellWindow struct {
|
2017-02-04 12:51:22 +00:00
|
|
|
color bool
|
2020-03-05 11:15:15 +00:00
|
|
|
preview bool
|
2017-02-04 12:51:22 +00:00
|
|
|
top int
|
|
|
|
left int
|
|
|
|
width int
|
|
|
|
height int
|
2019-12-12 14:03:17 +00:00
|
|
|
normal ColorPair
|
2017-02-04 12:51:22 +00:00
|
|
|
lastX int
|
|
|
|
lastY int
|
|
|
|
moveCursor bool
|
|
|
|
borderStyle BorderStyle
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Top() int {
|
|
|
|
return w.top
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Left() int {
|
|
|
|
return w.left
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Width() int {
|
|
|
|
return w.width
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *TcellWindow) Height() int {
|
|
|
|
return w.height
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *TcellWindow) Refresh() {
|
|
|
|
if w.moveCursor {
|
|
|
|
_screen.ShowCursor(w.left+w.lastX, w.top+w.lastY)
|
|
|
|
w.moveCursor = false
|
|
|
|
}
|
|
|
|
w.lastX = 0
|
|
|
|
w.lastY = 0
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) FinishFill() {
|
|
|
|
// NO-OP
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2022-08-20 21:23:03 +00:00
|
|
|
Bold Attr = Attr(tcell.AttrBold)
|
|
|
|
Dim = Attr(tcell.AttrDim)
|
|
|
|
Blink = Attr(tcell.AttrBlink)
|
|
|
|
Reverse = Attr(tcell.AttrReverse)
|
|
|
|
Underline = Attr(tcell.AttrUnderline)
|
|
|
|
StrikeThrough = Attr(tcell.AttrStrikeThrough)
|
|
|
|
Italic = Attr(tcell.AttrItalic)
|
2016-10-24 03:45:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-10-25 10:29:37 +00:00
|
|
|
AttrUndefined = Attr(0)
|
|
|
|
AttrRegular = Attr(1 << 7)
|
|
|
|
AttrClear = Attr(1 << 8)
|
2016-10-24 03:45:45 +00:00
|
|
|
)
|
|
|
|
|
2023-11-10 03:55:18 +00:00
|
|
|
func (r *FullscreenRenderer) PassThrough(str string) {
|
|
|
|
// No-op
|
2023-11-12 13:08:08 +00:00
|
|
|
// https://github.com/gdamore/tcell/pull/650#issuecomment-1806442846
|
2023-10-07 09:20:27 +00:00
|
|
|
}
|
|
|
|
|
2022-09-07 16:01:22 +00:00
|
|
|
func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) defaultTheme() *ColorTheme {
|
2016-10-24 03:45:45 +00:00
|
|
|
if _screen.Colors() >= 256 {
|
|
|
|
return Dark256
|
|
|
|
}
|
|
|
|
return Default16
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
_colorToAttribute = []tcell.Color{
|
|
|
|
tcell.ColorBlack,
|
|
|
|
tcell.ColorRed,
|
|
|
|
tcell.ColorGreen,
|
|
|
|
tcell.ColorYellow,
|
|
|
|
tcell.ColorBlue,
|
|
|
|
tcell.ColorDarkMagenta,
|
|
|
|
tcell.ColorLightCyan,
|
|
|
|
tcell.ColorWhite,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func (c Color) Style() tcell.Color {
|
|
|
|
if c <= colDefault {
|
|
|
|
return tcell.ColorDefault
|
|
|
|
} else if c >= colBlack && c <= colWhite {
|
|
|
|
return _colorToAttribute[int(c)]
|
|
|
|
} else {
|
|
|
|
return tcell.Color(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a Attr) Merge(b Attr) Attr {
|
|
|
|
return a | b
|
|
|
|
}
|
|
|
|
|
2021-10-01 14:59:02 +00:00
|
|
|
// handle the following as private members of FullscreenRenderer instance
|
|
|
|
// they are declared here to prevent introducing tcell library in non-windows builds
|
2016-10-24 03:45:45 +00:00
|
|
|
var (
|
2021-10-01 14:59:02 +00:00
|
|
|
_screen tcell.Screen
|
|
|
|
_prevMouseButton tcell.ButtonMask
|
2024-02-01 07:25:53 +00:00
|
|
|
_initialResize bool = true
|
2016-10-24 03:45:45 +00:00
|
|
|
)
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) initScreen() {
|
2016-10-24 03:45:45 +00:00
|
|
|
s, e := tcell.NewScreen()
|
|
|
|
if e != nil {
|
2017-01-11 14:01:56 +00:00
|
|
|
errorExit(e.Error())
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
if e = s.Init(); e != nil {
|
2017-01-11 14:01:56 +00:00
|
|
|
errorExit(e.Error())
|
2016-11-06 17:15:34 +00:00
|
|
|
}
|
2017-01-07 16:30:31 +00:00
|
|
|
if r.mouse {
|
2016-11-06 17:15:34 +00:00
|
|
|
s.EnableMouse()
|
|
|
|
} else {
|
|
|
|
s.DisableMouse()
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
_screen = s
|
2016-11-06 17:15:34 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) Init() {
|
2017-06-03 10:47:53 +00:00
|
|
|
if os.Getenv("TERM") == "cygwin" {
|
|
|
|
os.Setenv("TERM", "")
|
|
|
|
}
|
2016-11-06 17:15:34 +00:00
|
|
|
encoding.Register()
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
r.initScreen()
|
|
|
|
initTheme(r.theme, r.defaultTheme(), r.forceBlack)
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2023-11-01 16:35:36 +00:00
|
|
|
func (r *FullscreenRenderer) Top() int {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) MaxX() int {
|
2016-10-24 03:45:45 +00:00
|
|
|
ncols, _ := _screen.Size()
|
|
|
|
return int(ncols)
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) MaxY() int {
|
2016-10-24 03:45:45 +00:00
|
|
|
_, nlines := _screen.Size()
|
|
|
|
return int(nlines)
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) X() int {
|
|
|
|
return w.lastX
|
2016-12-04 17:13:47 +00:00
|
|
|
}
|
|
|
|
|
2017-07-19 13:46:16 +00:00
|
|
|
func (w *TcellWindow) Y() int {
|
|
|
|
return w.lastY
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) Clear() {
|
2016-11-06 17:15:34 +00:00
|
|
|
_screen.Sync()
|
2016-10-24 03:45:45 +00:00
|
|
|
_screen.Clear()
|
|
|
|
}
|
|
|
|
|
2023-01-15 16:22:02 +00:00
|
|
|
func (r *FullscreenRenderer) NeedScrollbarRedraw() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-01-24 06:59:54 +00:00
|
|
|
func (r *FullscreenRenderer) ShouldEmitResizeEvent() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) Refresh() {
|
2016-10-24 03:45:45 +00:00
|
|
|
// noop
|
|
|
|
}
|
|
|
|
|
2023-11-10 03:55:18 +00:00
|
|
|
// TODO: Pixel width and height not implemented
|
2023-10-25 15:22:28 +00:00
|
|
|
func (r *FullscreenRenderer) Size() TermSize {
|
2023-11-10 03:55:18 +00:00
|
|
|
cols, lines := _screen.Size()
|
|
|
|
return TermSize{lines, cols, 0, 0}
|
2023-10-22 16:01:47 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) GetChar() Event {
|
2016-10-24 03:45:45 +00:00
|
|
|
ev := _screen.PollEvent()
|
|
|
|
switch ev := ev.(type) {
|
|
|
|
case *tcell.EventResize:
|
2024-02-01 07:25:53 +00:00
|
|
|
// Ignore the first resize event
|
|
|
|
// https://github.com/gdamore/tcell/blob/v2.7.0/TUTORIAL.md?plain=1#L18
|
|
|
|
if _initialResize {
|
|
|
|
_initialResize = false
|
|
|
|
return Event{Invalid, 0, nil}
|
|
|
|
}
|
2016-11-22 16:58:46 +00:00
|
|
|
return Event{Resize, 0, nil}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
|
|
|
// process mouse events:
|
|
|
|
case *tcell.EventMouse:
|
2021-09-21 15:52:39 +00:00
|
|
|
// mouse down events have zeroed buttons, so we can't use them
|
|
|
|
// mouse up event consists of two events, 1. (main) event with modifier and other metadata, 2. event with zeroed buttons
|
|
|
|
// so mouse click is three consecutive events, but the first and last are indistinguishable from movement events (with released buttons)
|
|
|
|
// dragging has same structure, it only repeats the middle (main) event appropriately
|
2016-10-24 03:45:45 +00:00
|
|
|
x, y := ev.Position()
|
|
|
|
mod := ev.Modifiers() != 0
|
2021-09-21 15:52:39 +00:00
|
|
|
|
|
|
|
// since we dont have mouse down events (unlike LightRenderer), we need to track state in prevButton
|
2021-10-01 14:59:02 +00:00
|
|
|
prevButton, button := _prevMouseButton, ev.Buttons()
|
|
|
|
_prevMouseButton = button
|
2021-09-21 15:52:39 +00:00
|
|
|
drag := prevButton == button
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case button&tcell.WheelDown != 0:
|
2017-11-30 17:11:20 +00:00
|
|
|
return Event{Mouse, 0, &MouseEvent{y, x, -1, false, false, false, mod}}
|
2021-09-21 15:52:39 +00:00
|
|
|
case button&tcell.WheelUp != 0:
|
2017-11-30 17:11:20 +00:00
|
|
|
return Event{Mouse, 0, &MouseEvent{y, x, +1, false, false, false, mod}}
|
2023-01-02 16:21:40 +00:00
|
|
|
case button&tcell.Button1 != 0:
|
|
|
|
double := false
|
|
|
|
if !drag {
|
|
|
|
// all potential double click events put their coordinates in the clicks array
|
|
|
|
// double click event has two conditions, temporal and spatial, the first is checked here
|
|
|
|
now := time.Now()
|
|
|
|
if now.Sub(r.prevDownTime) < doubleClickDuration {
|
|
|
|
r.clicks = append(r.clicks, [2]int{x, y})
|
|
|
|
} else {
|
|
|
|
r.clicks = [][2]int{{x, y}}
|
|
|
|
}
|
|
|
|
r.prevDownTime = now
|
|
|
|
|
|
|
|
// detect double clicks (also check for spatial condition)
|
|
|
|
n := len(r.clicks)
|
|
|
|
double = n > 1 && r.clicks[n-2][0] == r.clicks[n-1][0] && r.clicks[n-2][1] == r.clicks[n-1][1]
|
|
|
|
if double {
|
|
|
|
// make sure two consecutive double clicks require four clicks
|
|
|
|
r.clicks = [][2]int{}
|
|
|
|
}
|
2021-09-21 15:52:39 +00:00
|
|
|
}
|
|
|
|
// fire single or double click event
|
|
|
|
return Event{Mouse, 0, &MouseEvent{y, x, 0, true, !double, double, mod}}
|
2023-01-02 16:21:40 +00:00
|
|
|
case button&tcell.Button2 != 0:
|
2021-09-21 15:52:39 +00:00
|
|
|
return Event{Mouse, 0, &MouseEvent{y, x, 0, false, true, false, mod}}
|
2023-01-02 16:21:40 +00:00
|
|
|
default:
|
2016-10-24 03:45:45 +00:00
|
|
|
// double and single taps on Windows don't quite work due to
|
|
|
|
// the console acting on the events and not allowing us
|
|
|
|
// to consume them.
|
2017-11-30 17:11:20 +00:00
|
|
|
left := button&tcell.Button1 != 0
|
|
|
|
down := left || button&tcell.Button3 != 0
|
2016-10-24 03:45:45 +00:00
|
|
|
double := false
|
|
|
|
|
2017-11-30 17:11:20 +00:00
|
|
|
return Event{Mouse, 0, &MouseEvent{y, x, 0, left, down, double, mod}}
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// process keyboard:
|
|
|
|
case *tcell.EventKey:
|
2020-11-24 10:36:58 +00:00
|
|
|
mods := ev.Modifiers()
|
2021-09-21 09:09:04 +00:00
|
|
|
none := mods == tcell.ModNone
|
2020-11-24 10:36:58 +00:00
|
|
|
alt := (mods & tcell.ModAlt) > 0
|
2021-09-19 21:48:31 +00:00
|
|
|
ctrl := (mods & tcell.ModCtrl) > 0
|
2020-11-24 10:36:58 +00:00
|
|
|
shift := (mods & tcell.ModShift) > 0
|
2021-09-19 21:48:31 +00:00
|
|
|
ctrlAlt := ctrl && alt
|
2020-11-24 10:36:58 +00:00
|
|
|
altShift := alt && shift
|
2021-09-19 21:48:31 +00:00
|
|
|
|
2020-12-29 16:59:18 +00:00
|
|
|
keyfn := func(r rune) Event {
|
2017-04-27 17:36:36 +00:00
|
|
|
if alt {
|
2020-12-29 16:59:18 +00:00
|
|
|
return CtrlAltKey(r)
|
2017-04-27 17:36:36 +00:00
|
|
|
}
|
2020-12-29 16:59:18 +00:00
|
|
|
return EventType(CtrlA.Int() - 'a' + int(r)).AsEvent()
|
2017-04-27 17:36:36 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
switch ev.Key() {
|
2021-09-19 19:37:37 +00:00
|
|
|
// section 1: Ctrl+(Alt)+[a-z]
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlA:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('a')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlB:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('b')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlC:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('c')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlD:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('d')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlE:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('e')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlF:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('f')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlG:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('g')
|
2017-04-27 17:36:36 +00:00
|
|
|
case tcell.KeyCtrlH:
|
2021-09-21 09:09:04 +00:00
|
|
|
switch ev.Rune() {
|
|
|
|
case 0:
|
|
|
|
if ctrl {
|
|
|
|
return Event{BSpace, 0, nil}
|
|
|
|
}
|
|
|
|
case rune(tcell.KeyCtrlH):
|
|
|
|
switch {
|
|
|
|
case ctrl:
|
|
|
|
return keyfn('h')
|
|
|
|
case alt:
|
|
|
|
return Event{AltBS, 0, nil}
|
|
|
|
case none, shift:
|
|
|
|
return Event{BSpace, 0, nil}
|
|
|
|
}
|
|
|
|
}
|
2017-04-27 17:36:36 +00:00
|
|
|
case tcell.KeyCtrlI:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('i')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlJ:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('j')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlK:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('k')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlL:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('l')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlM:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('m')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlN:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('n')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlO:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('o')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlP:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('p')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlQ:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('q')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlR:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('r')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlS:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('s')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlT:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('t')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlU:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('u')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlV:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('v')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlW:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('w')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlX:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('x')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlY:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('y')
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyCtrlZ:
|
2020-12-29 16:59:18 +00:00
|
|
|
return keyfn('z')
|
2021-09-19 19:37:37 +00:00
|
|
|
// section 2: Ctrl+[ \]_]
|
2017-01-27 17:54:47 +00:00
|
|
|
case tcell.KeyCtrlSpace:
|
|
|
|
return Event{CtrlSpace, 0, nil}
|
2019-11-14 13:39:25 +00:00
|
|
|
case tcell.KeyCtrlBackslash:
|
|
|
|
return Event{CtrlBackSlash, 0, nil}
|
|
|
|
case tcell.KeyCtrlRightSq:
|
|
|
|
return Event{CtrlRightBracket, 0, nil}
|
2021-09-20 18:19:11 +00:00
|
|
|
case tcell.KeyCtrlCarat:
|
|
|
|
return Event{CtrlCaret, 0, nil}
|
2019-11-14 13:39:25 +00:00
|
|
|
case tcell.KeyCtrlUnderscore:
|
|
|
|
return Event{CtrlSlash, 0, nil}
|
2021-09-19 19:37:37 +00:00
|
|
|
// section 3: (Alt)+Backspace2
|
2017-04-28 13:58:08 +00:00
|
|
|
case tcell.KeyBackspace2:
|
2016-11-06 17:15:34 +00:00
|
|
|
if alt {
|
|
|
|
return Event{AltBS, 0, nil}
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{BSpace, 0, nil}
|
|
|
|
|
2021-09-19 19:37:37 +00:00
|
|
|
// section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyUp:
|
2020-11-24 10:36:58 +00:00
|
|
|
if altShift {
|
|
|
|
return Event{AltSUp, 0, nil}
|
|
|
|
}
|
|
|
|
if shift {
|
|
|
|
return Event{SUp, 0, nil}
|
|
|
|
}
|
2018-04-12 08:39:28 +00:00
|
|
|
if alt {
|
|
|
|
return Event{AltUp, 0, nil}
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{Up, 0, nil}
|
|
|
|
case tcell.KeyDown:
|
2020-11-24 10:36:58 +00:00
|
|
|
if altShift {
|
|
|
|
return Event{AltSDown, 0, nil}
|
|
|
|
}
|
|
|
|
if shift {
|
|
|
|
return Event{SDown, 0, nil}
|
|
|
|
}
|
2018-04-12 08:39:28 +00:00
|
|
|
if alt {
|
|
|
|
return Event{AltDown, 0, nil}
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{Down, 0, nil}
|
|
|
|
case tcell.KeyLeft:
|
2020-11-24 10:36:58 +00:00
|
|
|
if altShift {
|
|
|
|
return Event{AltSLeft, 0, nil}
|
|
|
|
}
|
|
|
|
if shift {
|
|
|
|
return Event{SLeft, 0, nil}
|
|
|
|
}
|
2018-04-12 08:39:28 +00:00
|
|
|
if alt {
|
|
|
|
return Event{AltLeft, 0, nil}
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{Left, 0, nil}
|
|
|
|
case tcell.KeyRight:
|
2020-11-24 10:36:58 +00:00
|
|
|
if altShift {
|
|
|
|
return Event{AltSRight, 0, nil}
|
|
|
|
}
|
|
|
|
if shift {
|
|
|
|
return Event{SRight, 0, nil}
|
|
|
|
}
|
2018-04-12 08:39:28 +00:00
|
|
|
if alt {
|
|
|
|
return Event{AltRight, 0, nil}
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{Right, 0, nil}
|
|
|
|
|
2021-09-19 19:37:37 +00:00
|
|
|
// section 5: (Insert|Home|Delete|End|PgUp|PgDn|BackTab|F1-F12)
|
2020-02-23 16:43:19 +00:00
|
|
|
case tcell.KeyInsert:
|
|
|
|
return Event{Insert, 0, nil}
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyHome:
|
|
|
|
return Event{Home, 0, nil}
|
|
|
|
case tcell.KeyDelete:
|
2023-05-21 09:40:05 +00:00
|
|
|
if ctrl {
|
|
|
|
return Event{CtrlDelete, 0, nil}
|
|
|
|
}
|
|
|
|
if shift {
|
|
|
|
return Event{SDelete, 0, nil}
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{Del, 0, nil}
|
|
|
|
case tcell.KeyEnd:
|
|
|
|
return Event{End, 0, nil}
|
2016-11-06 17:15:34 +00:00
|
|
|
case tcell.KeyPgUp:
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{PgUp, 0, nil}
|
2016-11-06 17:15:34 +00:00
|
|
|
case tcell.KeyPgDn:
|
|
|
|
return Event{PgDn, 0, nil}
|
|
|
|
case tcell.KeyBacktab:
|
|
|
|
return Event{BTab, 0, nil}
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyF1:
|
|
|
|
return Event{F1, 0, nil}
|
|
|
|
case tcell.KeyF2:
|
|
|
|
return Event{F2, 0, nil}
|
|
|
|
case tcell.KeyF3:
|
|
|
|
return Event{F3, 0, nil}
|
|
|
|
case tcell.KeyF4:
|
|
|
|
return Event{F4, 0, nil}
|
|
|
|
case tcell.KeyF5:
|
|
|
|
return Event{F5, 0, nil}
|
|
|
|
case tcell.KeyF6:
|
|
|
|
return Event{F6, 0, nil}
|
|
|
|
case tcell.KeyF7:
|
|
|
|
return Event{F7, 0, nil}
|
|
|
|
case tcell.KeyF8:
|
|
|
|
return Event{F8, 0, nil}
|
|
|
|
case tcell.KeyF9:
|
|
|
|
return Event{F9, 0, nil}
|
|
|
|
case tcell.KeyF10:
|
|
|
|
return Event{F10, 0, nil}
|
|
|
|
case tcell.KeyF11:
|
2016-11-19 13:40:28 +00:00
|
|
|
return Event{F11, 0, nil}
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyF12:
|
2016-11-19 13:40:28 +00:00
|
|
|
return Event{F12, 0, nil}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2021-09-19 21:48:31 +00:00
|
|
|
// section 6: (Ctrl+Alt)+'rune'
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyRune:
|
2016-11-06 17:15:34 +00:00
|
|
|
r := ev.Rune()
|
2021-09-19 21:48:31 +00:00
|
|
|
|
|
|
|
switch {
|
2021-09-20 17:48:53 +00:00
|
|
|
// translate native key events to ascii control characters
|
|
|
|
case r == ' ' && ctrl:
|
|
|
|
return Event{CtrlSpace, 0, nil}
|
2021-09-19 21:48:31 +00:00
|
|
|
// handle AltGr characters
|
|
|
|
case ctrlAlt:
|
|
|
|
return Event{Rune, r, nil} // dropping modifiers
|
|
|
|
// simple characters (possibly with modifier)
|
|
|
|
case alt:
|
2020-12-29 16:59:18 +00:00
|
|
|
return AltKey(r)
|
2021-09-19 21:48:31 +00:00
|
|
|
default:
|
|
|
|
return Event{Rune, r, nil}
|
2016-11-06 17:15:34 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2021-09-19 19:37:37 +00:00
|
|
|
// section 7: Esc
|
2016-10-24 03:45:45 +00:00
|
|
|
case tcell.KeyEsc:
|
|
|
|
return Event{ESC, 0, nil}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-19 19:37:37 +00:00
|
|
|
// section 8: Invalid
|
2016-10-24 03:45:45 +00:00
|
|
|
return Event{Invalid, 0, nil}
|
|
|
|
}
|
|
|
|
|
2018-09-27 02:10:49 +00:00
|
|
|
func (r *FullscreenRenderer) Pause(clear bool) {
|
|
|
|
if clear {
|
|
|
|
_screen.Fini()
|
|
|
|
}
|
2016-11-06 17:15:34 +00:00
|
|
|
}
|
|
|
|
|
2020-05-17 17:33:37 +00:00
|
|
|
func (r *FullscreenRenderer) Resume(clear bool, sigcont bool) {
|
2018-09-27 02:10:49 +00:00
|
|
|
if clear {
|
|
|
|
r.initScreen()
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) Close() {
|
2016-10-24 03:45:45 +00:00
|
|
|
_screen.Fini()
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (r *FullscreenRenderer) RefreshWindows(windows []Window) {
|
2016-10-24 03:45:45 +00:00
|
|
|
// TODO
|
|
|
|
for _, w := range windows {
|
2017-01-07 16:30:31 +00:00
|
|
|
w.Refresh()
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
_screen.Show()
|
|
|
|
}
|
|
|
|
|
2019-12-12 14:03:17 +00:00
|
|
|
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
|
|
|
|
normal := ColNormal
|
|
|
|
if preview {
|
|
|
|
normal = ColPreview
|
|
|
|
}
|
2022-11-06 05:35:20 +00:00
|
|
|
w := &TcellWindow{
|
2020-10-25 10:29:37 +00:00
|
|
|
color: r.theme.Colored,
|
2020-03-05 11:15:15 +00:00
|
|
|
preview: preview,
|
2017-02-04 12:51:22 +00:00
|
|
|
top: top,
|
|
|
|
left: left,
|
|
|
|
width: width,
|
|
|
|
height: height,
|
2019-12-12 14:03:17 +00:00
|
|
|
normal: normal,
|
2017-02-04 12:51:22 +00:00
|
|
|
borderStyle: borderStyle}
|
2023-01-21 16:56:29 +00:00
|
|
|
w.drawBorder(false)
|
2022-11-06 05:35:20 +00:00
|
|
|
return w
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Close() {
|
2016-10-24 03:45:45 +00:00
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
2019-12-12 14:03:17 +00:00
|
|
|
func fill(x, y, w, h int, n ColorPair, r rune) {
|
2016-10-24 03:45:45 +00:00
|
|
|
for ly := 0; ly <= h; ly++ {
|
|
|
|
for lx := 0; lx <= w; lx++ {
|
2019-12-12 14:03:17 +00:00
|
|
|
_screen.SetContent(x+lx, y+ly, r, nil, n.style())
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Erase() {
|
2023-10-22 16:01:47 +00:00
|
|
|
w.drawBorder(false)
|
2023-01-04 01:09:39 +00:00
|
|
|
fill(w.left-1, w.top, w.width+1, w.height-1, w.normal, ' ')
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 12:00:07 +00:00
|
|
|
func (w *TcellWindow) EraseMaybe() bool {
|
|
|
|
w.Erase()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Enclose(y int, x int) bool {
|
|
|
|
return x >= w.left && x < (w.left+w.width) &&
|
|
|
|
y >= w.top && y < (w.top+w.height)
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Move(y int, x int) {
|
|
|
|
w.lastX = x
|
|
|
|
w.lastY = y
|
|
|
|
w.moveCursor = true
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) MoveAndClear(y int, x int) {
|
2016-10-24 03:45:45 +00:00
|
|
|
w.Move(y, x)
|
2017-01-07 16:30:31 +00:00
|
|
|
for i := w.lastX; i < w.width; i++ {
|
2019-12-12 14:03:17 +00:00
|
|
|
_screen.SetContent(i+w.left, w.lastY+w.top, rune(' '), nil, w.normal.style())
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
2017-01-07 16:30:31 +00:00
|
|
|
w.lastX = x
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
func (w *TcellWindow) Print(text string) {
|
2020-10-25 10:29:37 +00:00
|
|
|
w.printString(text, w.normal)
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2020-10-25 10:29:37 +00:00
|
|
|
func (w *TcellWindow) printString(text string, pair ColorPair) {
|
2016-10-24 03:45:45 +00:00
|
|
|
lx := 0
|
2020-10-25 10:29:37 +00:00
|
|
|
a := pair.Attr()
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2020-10-25 10:29:37 +00:00
|
|
|
style := pair.style()
|
|
|
|
if a&AttrClear == 0 {
|
|
|
|
style = style.
|
2016-11-08 16:45:06 +00:00
|
|
|
Reverse(a&Attr(tcell.AttrReverse) != 0).
|
2020-10-25 10:29:37 +00:00
|
|
|
Underline(a&Attr(tcell.AttrUnderline) != 0).
|
2022-08-20 21:23:03 +00:00
|
|
|
StrikeThrough(a&Attr(tcell.AttrStrikeThrough) != 0).
|
2020-10-25 10:29:37 +00:00
|
|
|
Italic(a&Attr(tcell.AttrItalic) != 0).
|
|
|
|
Blink(a&Attr(tcell.AttrBlink) != 0).
|
|
|
|
Dim(a&Attr(tcell.AttrDim) != 0)
|
2016-11-08 16:45:06 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2021-05-14 02:43:32 +00:00
|
|
|
gr := uniseg.NewGraphemes(text)
|
|
|
|
for gr.Next() {
|
2023-03-25 01:23:05 +00:00
|
|
|
st := style
|
2021-05-14 02:43:32 +00:00
|
|
|
rs := gr.Runes()
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2021-05-14 02:43:32 +00:00
|
|
|
if len(rs) == 1 {
|
|
|
|
r := rs[0]
|
2023-03-25 01:23:05 +00:00
|
|
|
if r == '\r' {
|
|
|
|
st = style.Dim(true)
|
|
|
|
rs[0] = '␍'
|
2021-05-14 02:43:32 +00:00
|
|
|
} else if r == '\n' {
|
2023-03-25 01:23:05 +00:00
|
|
|
st = style.Dim(true)
|
|
|
|
rs[0] = '␊'
|
|
|
|
} else if r < rune(' ') { // ignore control characters
|
2016-10-24 03:45:45 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2021-05-14 02:43:32 +00:00
|
|
|
var xPos = w.left + w.lastX + lx
|
|
|
|
var yPos = w.top + w.lastY
|
|
|
|
if xPos < (w.left+w.width) && yPos < (w.top+w.height) {
|
2023-03-25 01:23:05 +00:00
|
|
|
_screen.SetContent(xPos, yPos, rs[0], rs[1:], st)
|
2021-05-14 02:43:32 +00:00
|
|
|
}
|
2023-03-25 01:23:05 +00:00
|
|
|
lx += util.StringWidth(string(rs))
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
2017-01-07 16:30:31 +00:00
|
|
|
w.lastX += lx
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2020-10-25 10:29:37 +00:00
|
|
|
func (w *TcellWindow) CPrint(pair ColorPair, text string) {
|
|
|
|
w.printString(text, pair)
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2020-10-25 12:43:53 +00:00
|
|
|
func (w *TcellWindow) fillString(text string, pair ColorPair) FillReturn {
|
2016-10-24 03:45:45 +00:00
|
|
|
lx := 0
|
2020-10-25 12:43:53 +00:00
|
|
|
a := pair.Attr()
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2016-11-08 16:45:06 +00:00
|
|
|
var style tcell.Style
|
2017-01-07 16:30:31 +00:00
|
|
|
if w.color {
|
2016-11-08 16:45:06 +00:00
|
|
|
style = pair.style()
|
|
|
|
} else {
|
2019-12-12 14:03:17 +00:00
|
|
|
style = w.normal.style()
|
2016-11-08 16:45:06 +00:00
|
|
|
}
|
|
|
|
style = style.
|
2016-10-24 03:45:45 +00:00
|
|
|
Blink(a&Attr(tcell.AttrBlink) != 0).
|
|
|
|
Bold(a&Attr(tcell.AttrBold) != 0).
|
|
|
|
Dim(a&Attr(tcell.AttrDim) != 0).
|
|
|
|
Reverse(a&Attr(tcell.AttrReverse) != 0).
|
2020-10-25 10:29:37 +00:00
|
|
|
Underline(a&Attr(tcell.AttrUnderline) != 0).
|
2022-08-20 21:23:03 +00:00
|
|
|
StrikeThrough(a&Attr(tcell.AttrStrikeThrough) != 0).
|
2020-10-25 10:29:37 +00:00
|
|
|
Italic(a&Attr(tcell.AttrItalic) != 0)
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2021-05-14 02:43:32 +00:00
|
|
|
gr := uniseg.NewGraphemes(text)
|
2023-03-25 01:23:05 +00:00
|
|
|
Loop:
|
2021-05-14 02:43:32 +00:00
|
|
|
for gr.Next() {
|
2023-03-25 01:23:05 +00:00
|
|
|
st := style
|
2021-05-14 02:43:32 +00:00
|
|
|
rs := gr.Runes()
|
2023-03-25 01:23:05 +00:00
|
|
|
if len(rs) == 1 {
|
|
|
|
r := rs[0]
|
|
|
|
switch r {
|
|
|
|
case '\r':
|
|
|
|
st = style.Dim(true)
|
|
|
|
rs[0] = '␍'
|
|
|
|
case '\n':
|
|
|
|
w.lastY++
|
|
|
|
w.lastX = 0
|
|
|
|
lx = 0
|
|
|
|
continue Loop
|
|
|
|
}
|
2021-05-14 02:43:32 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2021-05-14 02:43:32 +00:00
|
|
|
// word wrap:
|
|
|
|
xPos := w.left + w.lastX + lx
|
|
|
|
if xPos >= (w.left + w.width) {
|
|
|
|
w.lastY++
|
|
|
|
w.lastX = 0
|
|
|
|
lx = 0
|
|
|
|
xPos = w.left
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2021-05-14 02:43:32 +00:00
|
|
|
yPos := w.top + w.lastY
|
|
|
|
if yPos >= (w.top + w.height) {
|
|
|
|
return FillSuspend
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
2021-05-14 02:43:32 +00:00
|
|
|
|
2023-03-25 01:23:05 +00:00
|
|
|
_screen.SetContent(xPos, yPos, rs[0], rs[1:], st)
|
|
|
|
lx += util.StringWidth(string(rs))
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
2017-01-07 16:30:31 +00:00
|
|
|
w.lastX += lx
|
2020-10-25 12:43:53 +00:00
|
|
|
if w.lastX == w.width {
|
|
|
|
w.lastY++
|
|
|
|
w.lastX = 0
|
|
|
|
return FillNextLine
|
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2017-01-11 13:13:40 +00:00
|
|
|
return FillContinue
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 13:13:40 +00:00
|
|
|
func (w *TcellWindow) Fill(str string) FillReturn {
|
2020-10-25 12:43:53 +00:00
|
|
|
return w.fillString(str, w.normal)
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 13:13:40 +00:00
|
|
|
func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn {
|
2017-09-09 04:50:07 +00:00
|
|
|
if fg == colDefault {
|
2019-12-12 14:03:17 +00:00
|
|
|
fg = w.normal.Fg()
|
2017-09-09 04:50:07 +00:00
|
|
|
}
|
|
|
|
if bg == colDefault {
|
2019-12-12 14:03:17 +00:00
|
|
|
bg = w.normal.Bg()
|
2017-09-09 04:50:07 +00:00
|
|
|
}
|
2020-10-25 12:43:53 +00:00
|
|
|
return w.fillString(str, NewColorPair(fg, bg, a))
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
|
|
|
|
2023-10-22 16:01:47 +00:00
|
|
|
func (w *TcellWindow) DrawBorder() {
|
|
|
|
w.drawBorder(false)
|
|
|
|
}
|
|
|
|
|
2023-01-21 16:56:29 +00:00
|
|
|
func (w *TcellWindow) DrawHBorder() {
|
|
|
|
w.drawBorder(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
|
2020-10-26 13:33:41 +00:00
|
|
|
shape := w.borderStyle.shape
|
|
|
|
if shape == BorderNone {
|
2019-03-28 17:11:03 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-01-07 16:30:31 +00:00
|
|
|
left := w.left
|
|
|
|
right := left + w.width
|
|
|
|
top := w.top
|
|
|
|
bot := top + w.height
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2016-11-08 16:45:06 +00:00
|
|
|
var style tcell.Style
|
2017-01-07 16:30:31 +00:00
|
|
|
if w.color {
|
2020-03-05 11:15:15 +00:00
|
|
|
if w.preview {
|
2019-12-12 14:03:17 +00:00
|
|
|
style = ColPreviewBorder.style()
|
|
|
|
} else {
|
|
|
|
style = ColBorder.style()
|
|
|
|
}
|
2016-11-08 16:45:06 +00:00
|
|
|
} else {
|
2019-12-12 14:03:17 +00:00
|
|
|
style = w.normal.style()
|
2016-11-08 16:45:06 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
|
2024-01-20 17:52:28 +00:00
|
|
|
hw := runeWidth(w.borderStyle.top)
|
2020-10-26 13:33:41 +00:00
|
|
|
switch shape {
|
2023-06-10 05:48:29 +00:00
|
|
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderHorizontal, BorderTop:
|
2023-01-16 10:34:28 +00:00
|
|
|
max := right - 2*hw
|
|
|
|
if shape == BorderHorizontal || shape == BorderTop {
|
|
|
|
max = right - hw
|
|
|
|
}
|
|
|
|
// tcell has an issue displaying two overlapping wide runes
|
|
|
|
// e.g. SetContent( HH )
|
|
|
|
// SetContent( TR )
|
|
|
|
// ==================
|
|
|
|
// ( HH ) => TR is ignored
|
|
|
|
for x := left; x <= max; x += hw {
|
2023-05-20 09:24:23 +00:00
|
|
|
_screen.SetContent(x, top, w.borderStyle.top, nil, style)
|
2020-10-26 13:33:41 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|
2020-10-26 13:33:41 +00:00
|
|
|
switch shape {
|
2023-06-10 05:48:29 +00:00
|
|
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderHorizontal, BorderBottom:
|
2023-01-16 10:34:28 +00:00
|
|
|
max := right - 2*hw
|
|
|
|
if shape == BorderHorizontal || shape == BorderBottom {
|
|
|
|
max = right - hw
|
|
|
|
}
|
|
|
|
for x := left; x <= max; x += hw {
|
2023-05-20 09:24:23 +00:00
|
|
|
_screen.SetContent(x, bot-1, w.borderStyle.bottom, nil, style)
|
2020-10-26 13:33:41 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-21 16:56:29 +00:00
|
|
|
if !onlyHorizontal {
|
|
|
|
switch shape {
|
2023-06-10 05:48:29 +00:00
|
|
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderVertical, BorderLeft:
|
2023-01-21 16:56:29 +00:00
|
|
|
for y := top; y < bot; y++ {
|
2023-05-20 09:24:23 +00:00
|
|
|
_screen.SetContent(left, y, w.borderStyle.left, nil, style)
|
2023-01-21 16:56:29 +00:00
|
|
|
}
|
2020-10-26 13:33:41 +00:00
|
|
|
}
|
2023-01-21 16:56:29 +00:00
|
|
|
switch shape {
|
2023-06-10 05:48:29 +00:00
|
|
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderVertical, BorderRight:
|
2024-01-20 17:52:28 +00:00
|
|
|
vw := runeWidth(w.borderStyle.right)
|
2023-01-21 16:56:29 +00:00
|
|
|
for y := top; y < bot; y++ {
|
2023-05-20 09:24:23 +00:00
|
|
|
_screen.SetContent(right-vw, y, w.borderStyle.right, nil, style)
|
2023-01-21 16:56:29 +00:00
|
|
|
}
|
2017-02-04 12:51:22 +00:00
|
|
|
}
|
2020-10-26 13:33:41 +00:00
|
|
|
}
|
|
|
|
switch shape {
|
2023-06-10 05:48:29 +00:00
|
|
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble:
|
2019-03-28 17:11:03 +00:00
|
|
|
_screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
|
2024-01-20 17:52:28 +00:00
|
|
|
_screen.SetContent(right-runeWidth(w.borderStyle.topRight), top, w.borderStyle.topRight, nil, style)
|
2019-03-28 17:11:03 +00:00
|
|
|
_screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
|
2024-01-20 17:52:28 +00:00
|
|
|
_screen.SetContent(right-runeWidth(w.borderStyle.bottomRight), bot-1, w.borderStyle.bottomRight, nil, style)
|
2017-02-04 12:51:22 +00:00
|
|
|
}
|
2016-10-24 03:45:45 +00:00
|
|
|
}
|