Add --height option

This commit is contained in:
Junegunn Choi
2017-01-08 01:30:31 +09:00
parent fd137a9e87
commit 1448d631a7
24 changed files with 1624 additions and 608 deletions

View File

@@ -33,9 +33,39 @@ import (
"unicode/utf8"
)
type ColorPair int16
type Attr C.uint
type WindowImpl C.WINDOW
type CursesWindow struct {
impl *C.WINDOW
top int
left int
width int
height int
}
func (w *CursesWindow) Top() int {
return w.top
}
func (w *CursesWindow) Left() int {
return w.left
}
func (w *CursesWindow) Width() int {
return w.width
}
func (w *CursesWindow) Height() int {
return w.height
}
func (w *CursesWindow) Refresh() {
C.wnoutrefresh(w.impl)
}
func (w *CursesWindow) FinishFill() {
// NO-OP
}
const (
Bold Attr = C.A_BOLD
@@ -51,31 +81,14 @@ const (
AttrRegular Attr = 0
)
// Pallete
const (
ColDefault ColorPair = iota
ColNormal
ColPrompt
ColMatch
ColCurrent
ColCurrentMatch
ColSpinner
ColInfo
ColCursor
ColSelected
ColHeader
ColBorder
ColUser // Should be the last entry
)
var (
_screen *C.SCREEN
_colorMap map[int]ColorPair
_colorMap map[int]int16
_colorFn func(ColorPair, Attr) (C.short, C.int)
)
func init() {
_colorMap = make(map[int]ColorPair)
_colorMap = make(map[int]int16)
if strings.HasPrefix(C.GoString(C.curses_version()), "ncurses 5") {
Italic = C.A_NORMAL
}
@@ -85,14 +98,14 @@ func (a Attr) Merge(b Attr) Attr {
return a | b
}
func DefaultTheme() *ColorTheme {
func (r *FullscreenRenderer) defaultTheme() *ColorTheme {
if C.tigetnum(C.CString("colors")) >= 256 {
return Dark256
}
return Default16
}
func Init(theme *ColorTheme, black bool, mouse bool) {
func (r *FullscreenRenderer) Init() {
C.setlocale(C.LC_ALL, C.CString(""))
tty := C.c_tty()
if tty == nil {
@@ -105,7 +118,7 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
os.Exit(2)
}
C.set_term(_screen)
if mouse {
if r.mouse {
C.mousemask(C.ALL_MOUSE_EVENTS, nil)
C.mouseinterval(0)
}
@@ -124,14 +137,14 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
}
C.set_escdelay(C.int(delay))
_color = theme != nil
if _color {
if r.theme != nil {
C.start_color()
InitTheme(theme, black)
initPairs(theme)
C.bkgd(C.chtype(C.COLOR_PAIR(C.int(ColNormal))))
initTheme(r.theme, r.defaultTheme(), r.forceBlack)
initPairs(r.theme)
C.bkgd(C.chtype(C.COLOR_PAIR(C.int(ColNormal.index()))))
_colorFn = attrColored
} else {
initTheme(r.theme, nil, r.forceBlack)
_colorFn = attrMono
}
@@ -145,39 +158,39 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
func initPairs(theme *ColorTheme) {
C.assume_default_colors(C.int(theme.Fg), C.int(theme.Bg))
initPair := func(group ColorPair, fg Color, bg Color) {
C.init_pair(C.short(group), C.short(fg), C.short(bg))
for _, pair := range []ColorPair{
ColNormal,
ColPrompt,
ColMatch,
ColCurrent,
ColCurrentMatch,
ColSpinner,
ColInfo,
ColCursor,
ColSelected,
ColHeader,
ColBorder} {
C.init_pair(C.short(pair.index()), C.short(pair.Fg()), C.short(pair.Bg()))
}
initPair(ColNormal, theme.Fg, theme.Bg)
initPair(ColPrompt, theme.Prompt, theme.Bg)
initPair(ColMatch, theme.Match, theme.Bg)
initPair(ColCurrent, theme.Current, theme.DarkBg)
initPair(ColCurrentMatch, theme.CurrentMatch, theme.DarkBg)
initPair(ColSpinner, theme.Spinner, theme.Bg)
initPair(ColInfo, theme.Info, theme.Bg)
initPair(ColCursor, theme.Cursor, theme.DarkBg)
initPair(ColSelected, theme.Selected, theme.DarkBg)
initPair(ColHeader, theme.Header, theme.Bg)
initPair(ColBorder, theme.Border, theme.Bg)
}
func Pause() {
func (r *FullscreenRenderer) Pause() {
C.endwin()
}
func Resume() bool {
func (r *FullscreenRenderer) Resume() bool {
return false
}
func Close() {
func (r *FullscreenRenderer) Close() {
C.endwin()
C.delscreen(_screen)
}
func NewWindow(top int, left int, width int, height int, border bool) *Window {
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, border bool) Window {
win := C.newwin(C.int(height), C.int(width), C.int(top), C.int(left))
if _color {
C.wbkgd(win, C.chtype(C.COLOR_PAIR(C.int(ColNormal))))
if r.theme != nil {
C.wbkgd(win, C.chtype(C.COLOR_PAIR(C.int(ColNormal.index()))))
}
if border {
pair, attr := _colorFn(ColBorder, 0)
@@ -188,66 +201,50 @@ func NewWindow(top int, left int, width int, height int, border bool) *Window {
C.wcolor_set(win, 0, nil)
}
return &Window{
impl: (*WindowImpl)(win),
Top: top,
Left: left,
Width: width,
Height: height,
return &CursesWindow{
impl: win,
top: top,
left: left,
width: width,
height: height,
}
}
func attrColored(pair ColorPair, a Attr) (C.short, C.int) {
return C.short(pair), C.int(a)
func attrColored(color ColorPair, a Attr) (C.short, C.int) {
return C.short(color.index()), C.int(a)
}
func attrMono(pair ColorPair, a Attr) (C.short, C.int) {
var attr C.int
switch pair {
case ColCurrent:
attr = C.A_REVERSE
case ColMatch:
attr = C.A_UNDERLINE
case ColCurrentMatch:
attr = C.A_UNDERLINE | C.A_REVERSE
}
if C.int(a)&C.A_BOLD == C.A_BOLD {
attr = attr | C.A_BOLD
}
return 0, attr
func attrMono(color ColorPair, a Attr) (C.short, C.int) {
return 0, C.int(attrFor(color, a))
}
func MaxX() int {
func (r *FullscreenRenderer) MaxX() int {
return int(C.COLS)
}
func MaxY() int {
func (r *FullscreenRenderer) MaxY() int {
return int(C.LINES)
}
func (w *Window) win() *C.WINDOW {
return (*C.WINDOW)(w.impl)
func (w *CursesWindow) Close() {
C.delwin(w.impl)
}
func (w *Window) Close() {
C.delwin(w.win())
func (w *CursesWindow) Enclose(y int, x int) bool {
return bool(C.wenclose(w.impl, C.int(y), C.int(x)))
}
func (w *Window) Enclose(y int, x int) bool {
return bool(C.wenclose(w.win(), C.int(y), C.int(x)))
func (w *CursesWindow) Move(y int, x int) {
C.wmove(w.impl, C.int(y), C.int(x))
}
func (w *Window) Move(y int, x int) {
C.wmove(w.win(), C.int(y), C.int(x))
}
func (w *Window) MoveAndClear(y int, x int) {
func (w *CursesWindow) MoveAndClear(y int, x int) {
w.Move(y, x)
C.wclrtoeol(w.win())
C.wclrtoeol(w.impl)
}
func (w *Window) Print(text string) {
C.waddstr(w.win(), C.CString(strings.Map(func(r rune) rune {
func (w *CursesWindow) Print(text string) {
C.waddstr(w.impl, C.CString(strings.Map(func(r rune) rune {
if r < 32 {
return -1
}
@@ -255,69 +252,74 @@ func (w *Window) Print(text string) {
}, text)))
}
func (w *Window) CPrint(pair ColorPair, attr Attr, text string) {
p, a := _colorFn(pair, attr)
C.wcolor_set(w.win(), p, nil)
C.wattron(w.win(), a)
func (w *CursesWindow) CPrint(color ColorPair, attr Attr, text string) {
p, a := _colorFn(color, attr)
C.wcolor_set(w.impl, p, nil)
C.wattron(w.impl, a)
w.Print(text)
C.wattroff(w.win(), a)
C.wcolor_set(w.win(), 0, nil)
C.wattroff(w.impl, a)
C.wcolor_set(w.impl, 0, nil)
}
func Clear() {
func (r *FullscreenRenderer) Clear() {
C.clear()
C.endwin()
}
func Refresh() {
func (r *FullscreenRenderer) Refresh() {
C.refresh()
}
func (w *Window) Erase() {
C.werase(w.win())
func (w *CursesWindow) Erase() {
C.werase(w.impl)
}
func (w *Window) X() int {
return int(C.c_getcurx(w.win()))
func (w *CursesWindow) X() int {
return int(C.c_getcurx(w.impl))
}
func DoesAutoWrap() bool {
func (r *FullscreenRenderer) DoesAutoWrap() bool {
return true
}
func (w *Window) Fill(str string) bool {
return C.waddstr(w.win(), C.CString(str)) == C.OK
func (w *CursesWindow) Fill(str string) bool {
return C.waddstr(w.impl, C.CString(str)) == C.OK
}
func (w *Window) CFill(str string, fg Color, bg Color, attr Attr) bool {
pair := PairFor(fg, bg)
C.wcolor_set(w.win(), C.short(pair), nil)
C.wattron(w.win(), C.int(attr))
func (w *CursesWindow) CFill(fg Color, bg Color, attr Attr, str string) bool {
index := ColorPair{fg, bg, -1}.index()
C.wcolor_set(w.impl, C.short(index), nil)
C.wattron(w.impl, C.int(attr))
ret := w.Fill(str)
C.wattroff(w.win(), C.int(attr))
C.wcolor_set(w.win(), 0, nil)
C.wattroff(w.impl, C.int(attr))
C.wcolor_set(w.impl, 0, nil)
return ret
}
func RefreshWindows(windows []*Window) {
func (r *FullscreenRenderer) RefreshWindows(windows []Window) {
for _, w := range windows {
C.wnoutrefresh(w.win())
w.Refresh()
}
C.doupdate()
}
func PairFor(fg Color, bg Color) ColorPair {
// ncurses does not support 24-bit colors
if fg.is24() || bg.is24() {
return ColDefault
func (p ColorPair) index() int16 {
if p.id >= 0 {
return p.id
}
key := (int(fg) << 8) + int(bg)
// ncurses does not support 24-bit colors
if p.is24() {
return ColDefault.index()
}
key := p.key()
if found, prs := _colorMap[key]; prs {
return found
}
id := ColorPair(len(_colorMap) + int(ColUser))
C.init_pair(C.short(id), C.short(fg), C.short(bg))
id := int16(len(_colorMap)) + ColUser.id
C.init_pair(C.short(id), C.short(p.Fg()), C.short(p.Bg()))
_colorMap[key] = id
return id
}
@@ -369,7 +371,7 @@ func escSequence() Event {
return Event{Invalid, 0, nil}
}
func GetChar() Event {
func (r *FullscreenRenderer) GetChar() Event {
c := C.getch()
switch c {
case C.ERR:
@@ -435,17 +437,17 @@ func GetChar() Event {
/* Cannot use BUTTON1_DOUBLE_CLICKED due to mouseinterval(0) */
if (me.bstate & C.BUTTON1_PRESSED) > 0 {
now := time.Now()
if now.Sub(_prevDownTime) < doubleClickDuration {
_clickY = append(_clickY, y)
if now.Sub(r.prevDownTime) < doubleClickDuration {
r.clickY = append(r.clickY, y)
} else {
_clickY = []int{y}
_prevDownTime = now
r.clickY = []int{y}
r.prevDownTime = now
}
return Event{Mouse, 0, &MouseEvent{y, x, 0, true, false, mod}}
} else if (me.bstate & C.BUTTON1_RELEASED) > 0 {
double := false
if len(_clickY) > 1 && _clickY[0] == _clickY[1] &&
time.Now().Sub(_prevDownTime) < doubleClickDuration {
if len(r.clickY) > 1 && r.clickY[0] == r.clickY[1] &&
time.Now().Sub(r.prevDownTime) < doubleClickDuration {
double = true
}
return Event{Mouse, 0, &MouseEvent{y, x, 0, false, double, mod}}