2
0
mirror of https://github.com/rivo/tview.git synced 2024-11-15 06:12:46 +00:00

Merge pull request #126 from benweidig/fix_borders

Refactored semigraphics and configurable borders
This commit is contained in:
rivo 2018-06-15 23:09:46 +02:00 committed by GitHub
commit e643d10b36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 383 additions and 152 deletions

45
borders.go Normal file
View File

@ -0,0 +1,45 @@
package tview
// Borders defines various borders used when primitives are drawn.
// These may be changed to accommodate a different look and feel.
var Borders = struct {
Horizontal rune
Vertical rune
TopLeft rune
TopRight rune
BottomLeft rune
BottomRight rune
LeftT rune
RightT rune
TopT rune
BottomT rune
Cross rune
HorizontalFocus rune
VerticalFocus rune
TopLeftFocus rune
TopRightFocus rune
BottomLeftFocus rune
BottomRightFocus rune
}{
Horizontal: BoxDrawingsLightHorizontal,
Vertical: BoxDrawingsLightVertical,
TopLeft: BoxDrawingsLightDownAndRight,
TopRight: BoxDrawingsLightDownAndLeft,
BottomLeft: BoxDrawingsLightUpAndRight,
BottomRight: BoxDrawingsLightUpAndLeft,
LeftT: BoxDrawingsLightVerticalAndRight,
RightT: BoxDrawingsLightVerticalAndLeft,
TopT: BoxDrawingsLightDownAndHorizontal,
BottomT: BoxDrawingsLightUpAndHorizontal,
Cross: BoxDrawingsLightVerticalAndHorizontal,
HorizontalFocus: BoxDrawingsDoubleHorizontal,
VerticalFocus: BoxDrawingsDoubleVertical,
TopLeftFocus: BoxDrawingsDoubleDownAndRight,
TopRightFocus: BoxDrawingsDoubleDownAndLeft,
BottomLeftFocus: BoxDrawingsDoubleUpAndRight,
BottomRightFocus: BoxDrawingsDoubleUpAndLeft,
}

34
box.go
View File

@ -236,27 +236,27 @@ func (b *Box) Draw(screen tcell.Screen) {
border := background.Foreground(b.borderColor) border := background.Foreground(b.borderColor)
var vertical, horizontal, topLeft, topRight, bottomLeft, bottomRight rune var vertical, horizontal, topLeft, topRight, bottomLeft, bottomRight rune
if b.focus.HasFocus() { if b.focus.HasFocus() {
vertical = GraphicsDbVertBar horizontal = Borders.HorizontalFocus
horizontal = GraphicsDbHorBar vertical = Borders.VerticalFocus
topLeft = GraphicsDbTopLeftCorner topLeft = Borders.TopLeftFocus
topRight = GraphicsDbTopRightCorner topRight = Borders.TopRightFocus
bottomLeft = GraphicsDbBottomLeftCorner bottomLeft = Borders.BottomLeftFocus
bottomRight = GraphicsDbBottomRightCorner bottomRight = Borders.BottomRightFocus
} else { } else {
vertical = GraphicsHoriBar horizontal = Borders.Horizontal
horizontal = GraphicsVertBar vertical = Borders.Vertical
topLeft = GraphicsTopLeftCorner topLeft = Borders.TopLeft
topRight = GraphicsTopRightCorner topRight = Borders.TopRight
bottomLeft = GraphicsBottomLeftCorner bottomLeft = Borders.BottomLeft
bottomRight = GraphicsBottomRightCorner bottomRight = Borders.BottomRight
} }
for x := b.x + 1; x < b.x+b.width-1; x++ { for x := b.x + 1; x < b.x+b.width-1; x++ {
screen.SetContent(x, b.y, vertical, nil, border) screen.SetContent(x, b.y, horizontal, nil, border)
screen.SetContent(x, b.y+b.height-1, vertical, nil, border) screen.SetContent(x, b.y+b.height-1, horizontal, nil, border)
} }
for y := b.y + 1; y < b.y+b.height-1; y++ { for y := b.y + 1; y < b.y+b.height-1; y++ {
screen.SetContent(b.x, y, horizontal, nil, border) screen.SetContent(b.x, y, vertical, nil, border)
screen.SetContent(b.x+b.width-1, y, horizontal, nil, border) screen.SetContent(b.x+b.width-1, y, vertical, nil, border)
} }
screen.SetContent(b.x, b.y, topLeft, nil, border) screen.SetContent(b.x, b.y, topLeft, nil, border)
screen.SetContent(b.x+b.width-1, b.y, topRight, nil, border) screen.SetContent(b.x+b.width-1, b.y, topRight, nil, border)
@ -269,7 +269,7 @@ func (b *Box) Draw(screen tcell.Screen) {
if StringWidth(b.title)-printed > 0 && printed > 0 { if StringWidth(b.title)-printed > 0 && printed > 0 {
_, _, style, _ := screen.GetContent(b.x+b.width-2, b.y) _, _, style, _ := screen.GetContent(b.x+b.width-2, b.y)
fg, _, _ := style.Decompose() fg, _, _ := style.Decompose()
Print(screen, string(GraphicsEllipsis), b.x+b.width-2, b.y, 1, AlignLeft, fg) Print(screen, string(SemigraphicsHorizontalEllipsis), b.x+b.width-2, b.y, 1, AlignLeft, fg)
} }
} }
} }

View File

@ -87,7 +87,7 @@ const tableBasic = `[green]func[white] [yellow]main[white]() {
const tableSeparator = `[green]func[white] [yellow]main[white]() { const tableSeparator = `[green]func[white] [yellow]main[white]() {
table := tview.[yellow]NewTable[white](). table := tview.[yellow]NewTable[white]().
[yellow]SetFixed[white]([red]1[white], [red]1[white]). [yellow]SetFixed[white]([red]1[white], [red]1[white]).
[yellow]SetSeparator[white](tview.GraphicsVertBar) [yellow]SetSeparator[white](Borders.Vertical)
[yellow]for[white] row := [red]0[white]; row < [red]40[white]; row++ { [yellow]for[white] row := [red]0[white]; row < [red]40[white]; row++ {
[yellow]for[white] column := [red]0[white]; column < [red]7[white]; column++ { [yellow]for[white] column := [red]0[white]; column < [red]7[white]; column++ {
color := tcell.ColorWhite color := tcell.ColorWhite
@ -295,7 +295,7 @@ func Table(nextSlide func()) (title string, content tview.Primitive) {
separator := func() { separator := func() {
table.SetBorders(false). table.SetBorders(false).
SetSelectable(false, false). SetSelectable(false, false).
SetSeparator(tview.GraphicsVertBar) SetSeparator(tview.Borders.Vertical)
code.Clear() code.Clear()
fmt.Fprint(code, tableSeparator) fmt.Fprint(code, tableSeparator)
} }

16
grid.go
View File

@ -590,11 +590,11 @@ func (g *Grid) Draw(screen tcell.Screen) {
} }
by := item.y - 1 by := item.y - 1
if by >= 0 && by < height { if by >= 0 && by < height {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsHoriBar, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.Horizontal, g.bordersColor)
} }
by = item.y + item.h by = item.y + item.h
if by >= 0 && by < height { if by >= 0 && by < height {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsHoriBar, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.Horizontal, g.bordersColor)
} }
} }
for by := item.y; by < item.y+item.h; by++ { // Left/right lines. for by := item.y; by < item.y+item.h; by++ { // Left/right lines.
@ -603,28 +603,28 @@ func (g *Grid) Draw(screen tcell.Screen) {
} }
bx := item.x - 1 bx := item.x - 1
if bx >= 0 && bx < width { if bx >= 0 && bx < width {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsVertBar, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.Vertical, g.bordersColor)
} }
bx = item.x + item.w bx = item.x + item.w
if bx >= 0 && bx < width { if bx >= 0 && bx < width {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsVertBar, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.Vertical, g.bordersColor)
} }
} }
bx, by := item.x-1, item.y-1 // Top-left corner. bx, by := item.x-1, item.y-1 // Top-left corner.
if bx >= 0 && bx < width && by >= 0 && by < height { if bx >= 0 && bx < width && by >= 0 && by < height {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsTopLeftCorner, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.TopLeft, g.bordersColor)
} }
bx, by = item.x+item.w, item.y-1 // Top-right corner. bx, by = item.x+item.w, item.y-1 // Top-right corner.
if bx >= 0 && bx < width && by >= 0 && by < height { if bx >= 0 && bx < width && by >= 0 && by < height {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsTopRightCorner, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.TopRight, g.bordersColor)
} }
bx, by = item.x-1, item.y+item.h // Bottom-left corner. bx, by = item.x-1, item.y+item.h // Bottom-left corner.
if bx >= 0 && bx < width && by >= 0 && by < height { if bx >= 0 && bx < width && by >= 0 && by < height {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsBottomLeftCorner, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.BottomLeft, g.bordersColor)
} }
bx, by = item.x+item.w, item.y+item.h // Bottom-right corner. bx, by = item.x+item.w, item.y+item.h // Bottom-right corner.
if bx >= 0 && bx < width && by >= 0 && by < height { if bx >= 0 && bx < width && by >= 0 && by < height {
PrintJoinedBorder(screen, x+bx, y+by, GraphicsBottomRightCorner, g.bordersColor) PrintJoinedSemigraphics(screen, x+bx, y+by, Borders.BottomRight, g.bordersColor)
} }
} }
} }

296
semigraphics.go Normal file
View File

@ -0,0 +1,296 @@
package tview
import "github.com/gdamore/tcell"
// Semigraphics provides an easy way to access unicode characters for drawing.
//
// Named like the unicode characters, 'Semigraphics'-prefix used if unicode block
// isn't prefixed itself.
const (
// Block: General Punctation U+2000-U+206F (http://unicode.org/charts/PDF/U2000.pdf)
SemigraphicsHorizontalEllipsis rune = '\u2026' // …
// Block: Box Drawing U+2500-U+257F (http://unicode.org/charts/PDF/U2500.pdf)
BoxDrawingsLightHorizontal rune = '\u2500' // ─
BoxDrawingsHeavyHorizontal rune = '\u2501' // ━
BoxDrawingsLightVertical rune = '\u2502' // │
BoxDrawingsHeavyVertical rune = '\u2503' // ┃
BoxDrawingsLightTripleDashHorizontal rune = '\u2504' // ┄
BoxDrawingsHeavyTripleDashHorizontal rune = '\u2505' // ┅
BoxDrawingsLightTripleDashVertical rune = '\u2506' // ┆
BoxDrawingsHeavyTripleDashVertical rune = '\u2507' // ┇
BoxDrawingsLightQuadrupleDashHorizontal rune = '\u2508' // ┈
BoxDrawingsHeavyQuadrupleDashHorizontal rune = '\u2509' // ┉
BoxDrawingsLightQuadrupleDashVertical rune = '\u250a' // ┊
BoxDrawingsHeavyQuadrupleDashVertical rune = '\u250b' // ┋
BoxDrawingsLightDownAndRight rune = '\u250c' // ┌
BoxDrawingsDownLighAndRightHeavy rune = '\u250d' // ┍
BoxDrawingsDownHeavyAndRightLight rune = '\u250e' // ┎
BoxDrawingsHeavyDownAndRight rune = '\u250f' // ┏
BoxDrawingsLightDownAndLeft rune = '\u2510' // ┐
BoxDrawingsDownLighAndLeftHeavy rune = '\u2511' // ┑
BoxDrawingsDownHeavyAndLeftLight rune = '\u2512' // ┒
BoxDrawingsHeavyDownAndLeft rune = '\u2513' // ┓
BoxDrawingsLightUpAndRight rune = '\u2514' // └
BoxDrawingsUpLightAndRightHeavy rune = '\u2515' // ┕
BoxDrawingsUpHeavyAndRightLight rune = '\u2516' // ┖
BoxDrawingsHeavyUpAndRight rune = '\u2517' // ┗
BoxDrawingsLightUpAndLeft rune = '\u2518' // ┘
BoxDrawingsUpLightAndLeftHeavy rune = '\u2519' // ┙
BoxDrawingsUpHeavyAndLeftLight rune = '\u251a' // ┚
BoxDrawingsHeavyUpAndLeft rune = '\u251b' // ┛
BoxDrawingsLightVerticalAndRight rune = '\u251c' // ├
BoxDrawingsVerticalLightAndRightHeavy rune = '\u251d' // ┝
BoxDrawingsUpHeavyAndRightDownLight rune = '\u251e' // ┞
BoxDrawingsDownHeacyAndRightUpLight rune = '\u251f' // ┟
BoxDrawingsVerticalHeavyAndRightLight rune = '\u2520' // ┠
BoxDrawingsDownLightAnbdRightUpHeavy rune = '\u2521' // ┡
BoxDrawingsUpLightAndRightDownHeavy rune = '\u2522' // ┢
BoxDrawingsHeavyVerticalAndRight rune = '\u2523' // ┣
BoxDrawingsLightVerticalAndLeft rune = '\u2524' // ┤
BoxDrawingsVerticalLightAndLeftHeavy rune = '\u2525' // ┥
BoxDrawingsUpHeavyAndLeftDownLight rune = '\u2526' // ┦
BoxDrawingsDownHeavyAndLeftUpLight rune = '\u2527' // ┧
BoxDrawingsVerticalheavyAndLeftLight rune = '\u2528' // ┨
BoxDrawingsDownLightAndLeftUpHeavy rune = '\u2529' // ┨
BoxDrawingsUpLightAndLeftDownHeavy rune = '\u252a' // ┪
BoxDrawingsHeavyVerticalAndLeft rune = '\u252b' // ┫
BoxDrawingsLightDownAndHorizontal rune = '\u252c' // ┬
BoxDrawingsLeftHeavyAndRightDownLight rune = '\u252d' // ┭
BoxDrawingsRightHeavyAndLeftDownLight rune = '\u252e' // ┮
BoxDrawingsDownLightAndHorizontalHeavy rune = '\u252f' // ┯
BoxDrawingsDownHeavyAndHorizontalLight rune = '\u2530' // ┰
BoxDrawingsRightLightAndLeftDownHeavy rune = '\u2531' // ┱
BoxDrawingsLeftLightAndRightDownHeavy rune = '\u2532' // ┲
BoxDrawingsHeavyDownAndHorizontal rune = '\u2533' // ┳
BoxDrawingsLightUpAndHorizontal rune = '\u2534' // ┴
BoxDrawingsLeftHeavyAndRightUpLight rune = '\u2535' // ┵
BoxDrawingsRightHeavyAndLeftUpLight rune = '\u2536' // ┶
BoxDrawingsUpLightAndHorizontalHeavy rune = '\u2537' // ┷
BoxDrawingsUpHeavyAndHorizontalLight rune = '\u2538' // ┸
BoxDrawingsRightLightAndLeftUpHeavy rune = '\u2539' // ┹
BoxDrawingsLeftLightAndRightUpHeavy rune = '\u253a' // ┺
BoxDrawingsHeavyUpAndHorizontal rune = '\u253b' // ┻
BoxDrawingsLightVerticalAndHorizontal rune = '\u253c' // ┼
BoxDrawingsLeftHeavyAndRightVerticalLight rune = '\u253d' // ┽
BoxDrawingsRightHeavyAndLeftVerticalLight rune = '\u253e' // ┾
BoxDrawingsVerticalLightAndHorizontalHeavy rune = '\u253f' // ┿
BoxDrawingsUpHeavyAndDownHorizontalLight rune = '\u2540' // ╀
BoxDrawingsDownHeavyAndUpHorizontalLight rune = '\u2541' // ╁
BoxDrawingsVerticalHeavyAndHorizontalLight rune = '\u2542' // ╂
BoxDrawingsLeftUpHeavyAndRightDownLight rune = '\u2543' // ╃
BoxDrawingsRightUpHeavyAndLeftDownLight rune = '\u2544' // ╄
BoxDrawingsLeftDownHeavyAndRightUpLight rune = '\u2545' // ╅
BoxDrawingsRightDownHeavyAndLeftUpLight rune = '\u2546' // ╆
BoxDrawingsDownLightAndUpHorizontalHeavy rune = '\u2547' // ╇
BoxDrawingsUpLightAndDownHorizontalHeavy rune = '\u2548' // ╈
BoxDrawingsRightLightAndLeftVerticalHeavy rune = '\u2549' // ╉
BoxDrawingsLeftLightAndRightVerticalHeavy rune = '\u254a' // ╊
BoxDrawingsHeavyVerticalAndHorizontal rune = '\u254b' // ╋
BoxDrawingsLightDoubleDashHorizontal rune = '\u254c' // ╌
BoxDrawingsHeavyDoubleDashHorizontal rune = '\u254d' // ╍
BoxDrawingsLightDoubleDashVertical rune = '\u254e' // ╎
BoxDrawingsHeavyDoubleDashVertical rune = '\u254f' // ╏
BoxDrawingsDoubleHorizontal rune = '\u2550' // ═
BoxDrawingsDoubleVertical rune = '\u2551' // ║
BoxDrawingsDownSingleAndRightDouble rune = '\u2552' // ╒
BoxDrawingsDownDoubleAndRightSingle rune = '\u2553' // ╓
BoxDrawingsDoubleDownAndRight rune = '\u2554' // ╔
BoxDrawingsDownSingleAndLeftDouble rune = '\u2555' // ╕
BoxDrawingsDownDoubleAndLeftSingle rune = '\u2556' // ╖
BoxDrawingsDoubleDownAndLeft rune = '\u2557' // ╗
BoxDrawingsUpSingleAndRightDouble rune = '\u2558' // ╘
BoxDrawingsUpDoubleAndRightSingle rune = '\u2559' // ╙
BoxDrawingsDoubleUpAndRight rune = '\u255a' // ╚
BoxDrawingsUpSingleAndLeftDouble rune = '\u255b' // ╛
BoxDrawingsUpDobuleAndLeftSingle rune = '\u255c' // ╜
BoxDrawingsDoubleUpAndLeft rune = '\u255d' // ╝
BoxDrawingsVerticalSingleAndRightDouble rune = '\u255e' // ╞
BoxDrawingsVerticalDoubleAndRightSingle rune = '\u255f' // ╟
BoxDrawingsDoubleVerticalAndRight rune = '\u2560' // ╠
BoxDrawingsVerticalSingleAndLeftDouble rune = '\u2561' // ╡
BoxDrawingsVerticalDoubleAndLeftSingle rune = '\u2562' // ╢
BoxDrawingsDoubleVerticalAndLeft rune = '\u2563' // ╣
BoxDrawingsDownSingleAndHorizontalDouble rune = '\u2564' // ╤
BoxDrawingsDownDoubleAndHorizontalSingle rune = '\u2565' // ╥
BoxDrawingsDoubleDownAndHorizontal rune = '\u2566' // ╦
BoxDrawingsUpSingleAndHorizontalDouble rune = '\u2567' // ╧
BoxDrawingsUpDoubleAndHorizontalSingle rune = '\u2568' // ╨
BoxDrawingsDoubleUpAndHorizontal rune = '\u2569' // ╩
BoxDrawingsVerticalSingleAndHorizontalDouble rune = '\u256a' // ╪
BoxDrawingsVerticalDoubleAndHorizontalSingle rune = '\u256b' // ╫
BoxDrawingsDoubleVerticalAndHorizontal rune = '\u256c' // ╬
BoxDrawingsLightArcDownAndRight rune = '\u256d' // ╭
BoxDrawingsLightArcDownAndLeft rune = '\u256e' // ╮
BoxDrawingsLightArcUpAndLeft rune = '\u256f' // ╯
BoxDrawingsLightArcUpAndRight rune = '\u2570' // ╰
BoxDrawingsLightDiagonalUpperRightToLowerLeft rune = '\u2571' //
BoxDrawingsLightDiagonalUpperLeftToLowerRight rune = '\u2572' // ╲
BoxDrawingsLightDiagonalCross rune = '\u2573' //
BoxDrawingsLightLeft rune = '\u2574' // ╴
BoxDrawingsLightUp rune = '\u2575' // ╵
BoxDrawingsLightRight rune = '\u2576' // ╶
BoxDrawingsLightDown rune = '\u2577' // ╷
BoxDrawingsHeavyLeft rune = '\u2578' // ╸
BoxDrawingsHeavyUp rune = '\u2579' // ╹
BoxDrawingsHeavyRight rune = '\u257a' // ╺
BoxDrawingsHeavyDown rune = '\u257b' // ╻
BoxDrawingsLightLeftAndHeavyRight rune = '\u257c' // ╼
BoxDrawingsLightUpAndHeavyDown rune = '\u257d' // ╽
BoxDrawingsHeavyLeftAndLightRight rune = '\u257e' // ╾
BoxDrawingsHeavyUpAndLightDown rune = '\u257f' // ╿
)
// SemigraphicJoints is a map for joining semigraphic (or otherwise) runes.
// So far only light lines are supported but if you want to change the border
// styling you need to provide the joints, too.
// The matching will be sorted ascending by rune value, so you don't need to
// provide all rune combinations,
// e.g. (─) + (│) = (┼) will also match (│) + (─) = (┼)
var SemigraphicJoints = map[string]rune{
// (─) + (│) = (┼)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightVertical}): BoxDrawingsLightVerticalAndHorizontal,
// (─) + (┌) = (┬)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightDownAndRight}): BoxDrawingsLightDownAndHorizontal,
// (─) + (┐) = (┬)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightDownAndLeft}): BoxDrawingsLightDownAndHorizontal,
// (─) + (└) = (┴)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightUpAndRight}): BoxDrawingsLightUpAndHorizontal,
// (─) + (┘) = (┴)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightUpAndLeft}): BoxDrawingsLightUpAndHorizontal,
// (─) + (├) = (┼)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightVerticalAndRight}): BoxDrawingsLightVerticalAndHorizontal,
// (─) + (┤) = (┼)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightVerticalAndLeft}): BoxDrawingsLightVerticalAndHorizontal,
// (─) + (┬) = (┬)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightDownAndHorizontal,
// (─) + (┴) = (┴)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightUpAndHorizontal,
// (─) + (┼) = (┼)
string([]rune{BoxDrawingsLightHorizontal, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (│) + (┌) = (├)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightDownAndRight}): BoxDrawingsLightVerticalAndRight,
// (│) + (┐) = (┤)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightDownAndLeft}): BoxDrawingsLightVerticalAndLeft,
// (│) + (└) = (├)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightUpAndRight}): BoxDrawingsLightVerticalAndRight,
// (│) + (┘) = (┤)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightUpAndLeft}): BoxDrawingsLightVerticalAndLeft,
// (│) + (├) = (├)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightVerticalAndRight}): BoxDrawingsLightVerticalAndRight,
// (│) + (┤) = (┤)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightVerticalAndLeft}): BoxDrawingsLightVerticalAndLeft,
// (│) + (┬) = (┼)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (│) + (┴) = (┼)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (│) + (┼) = (┼)
string([]rune{BoxDrawingsLightVertical, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┌) + (┐) = (┬)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightDownAndLeft}): BoxDrawingsLightDownAndHorizontal,
// (┌) + (└) = (├)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightUpAndRight}): BoxDrawingsLightVerticalAndRight,
// (┌) + (┘) = (┼)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightUpAndLeft}): BoxDrawingsLightVerticalAndHorizontal,
// (┌) + (├) = (├)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightVerticalAndRight}): BoxDrawingsLightVerticalAndRight,
// (┌) + (┤) = (┼)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightVerticalAndLeft}): BoxDrawingsLightVerticalAndHorizontal,
// (┌) + (┬) = (┬)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightDownAndHorizontal,
// (┌) + (┴) = (┼)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┌) + (┴) = (┼)
string([]rune{BoxDrawingsLightDownAndRight, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┐) + (└) = (┼)
string([]rune{BoxDrawingsLightDownAndLeft, BoxDrawingsLightUpAndRight}): BoxDrawingsLightVerticalAndHorizontal,
// (┐) + (┘) = (┤)
string([]rune{BoxDrawingsLightDownAndLeft, BoxDrawingsLightUpAndLeft}): BoxDrawingsLightVerticalAndLeft,
// (┐) + (├) = (┼)
string([]rune{BoxDrawingsLightDownAndLeft, BoxDrawingsLightVerticalAndRight}): BoxDrawingsLightVerticalAndHorizontal,
// (┐) + (┤) = (┤)
string([]rune{BoxDrawingsLightDownAndLeft, BoxDrawingsLightVerticalAndLeft}): BoxDrawingsLightVerticalAndLeft,
// (┐) + (┬) = (┬)
string([]rune{BoxDrawingsLightDownAndLeft, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightDownAndHorizontal,
// (┐) + (┴) = (┼)
string([]rune{BoxDrawingsLightDownAndLeft, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┐) + (┼) = (┼)
string([]rune{BoxDrawingsLightDownAndLeft, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (└) + (┘) = (┴)
string([]rune{BoxDrawingsLightUpAndRight, BoxDrawingsLightUpAndLeft}): BoxDrawingsLightUpAndHorizontal,
// (└) + (├) = (├)
string([]rune{BoxDrawingsLightUpAndRight, BoxDrawingsLightVerticalAndRight}): BoxDrawingsLightVerticalAndRight,
// (└) + (┤) = (┼)
string([]rune{BoxDrawingsLightUpAndRight, BoxDrawingsLightVerticalAndLeft}): BoxDrawingsLightVerticalAndHorizontal,
// (└) + (┬) = (┼)
string([]rune{BoxDrawingsLightUpAndRight, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (└) + (┴) = (┴)
string([]rune{BoxDrawingsLightUpAndRight, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightUpAndHorizontal,
// (└) + (┼) = (┼)
string([]rune{BoxDrawingsLightUpAndRight, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┘) + (├) = (┼)
string([]rune{BoxDrawingsLightUpAndLeft, BoxDrawingsLightVerticalAndRight}): BoxDrawingsLightVerticalAndHorizontal,
// (┘) + (┤) = (┤)
string([]rune{BoxDrawingsLightUpAndLeft, BoxDrawingsLightVerticalAndLeft}): BoxDrawingsLightVerticalAndLeft,
// (┘) + (┬) = (┼)
string([]rune{BoxDrawingsLightUpAndLeft, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┘) + (┴) = (┴)
string([]rune{BoxDrawingsLightUpAndLeft, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightUpAndHorizontal,
// (┘) + (┼) = (┼)
string([]rune{BoxDrawingsLightUpAndLeft, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (├) + (┤) = (┼)
string([]rune{BoxDrawingsLightVerticalAndRight, BoxDrawingsLightVerticalAndLeft}): BoxDrawingsLightVerticalAndHorizontal,
// (├) + (┬) = (┼)
string([]rune{BoxDrawingsLightVerticalAndRight, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (├) + (┴) = (┼)
string([]rune{BoxDrawingsLightVerticalAndRight, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (├) + (┼) = (┼)
string([]rune{BoxDrawingsLightVerticalAndRight, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┤) + (┬) = (┼)
string([]rune{BoxDrawingsLightVerticalAndLeft, BoxDrawingsLightDownAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┤) + (┴) = (┼)
string([]rune{BoxDrawingsLightVerticalAndLeft, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┤) + (┼) = (┼)
string([]rune{BoxDrawingsLightVerticalAndLeft, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┬) + (┴) = (┼)
string([]rune{BoxDrawingsLightDownAndHorizontal, BoxDrawingsLightUpAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┬) + (┼) = (┼)
string([]rune{BoxDrawingsLightDownAndHorizontal, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
// (┴) + (┼) = (┼)
string([]rune{BoxDrawingsLightUpAndHorizontal, BoxDrawingsLightVerticalAndHorizontal}): BoxDrawingsLightVerticalAndHorizontal,
}
// PrintJoinedSemigraphics prints a semigraphics rune into the screen at the given
// position with the given color, joining it with any existing semigraphics
// rune. Background colors are preserved. At this point, only regular single
// line borders are supported.
func PrintJoinedSemigraphics(screen tcell.Screen, x, y int, ch rune, color tcell.Color) {
previous, _, style, _ := screen.GetContent(x, y)
style = style.Foreground(color)
// What's the resulting rune?
var result rune
if ch == previous {
result = ch
} else {
if ch < previous {
previous, ch = ch, previous
}
result = SemigraphicJoints[string([]rune{previous, ch})]
}
if result == 0 {
result = ch
}
// We only print something if we have something.
screen.SetContent(x, y, result, nil, style)
}

View File

@ -278,7 +278,7 @@ func (t *Table) SetBordersColor(color tcell.Color) *Table {
// SetSeparator sets the character used to fill the space between two // SetSeparator sets the character used to fill the space between two
// neighboring cells. This is a space character ' ' per default but you may // neighboring cells. This is a space character ' ' per default but you may
// want to set it to GraphicsVertBar (or any other rune) if the column // want to set it to Borders.Vertical (or any other rune) if the column
// separation should be more visible. If cell borders are activated, this is // separation should be more visible. If cell borders are activated, this is
// ignored. // ignored.
// //
@ -668,24 +668,24 @@ ColumnLoop:
// Draw borders. // Draw borders.
rowY *= 2 rowY *= 2
for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ { for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
drawBorder(columnX+pos+1, rowY, GraphicsHoriBar) drawBorder(columnX+pos+1, rowY, Borders.Horizontal)
} }
ch := GraphicsCross ch := Borders.Cross
if columnIndex == 0 { if columnIndex == 0 {
if rowY == 0 { if rowY == 0 {
ch = GraphicsTopLeftCorner ch = Borders.TopLeft
} else { } else {
ch = GraphicsLeftT ch = Borders.LeftT
} }
} else if rowY == 0 { } else if rowY == 0 {
ch = GraphicsTopT ch = Borders.TopT
} }
drawBorder(columnX, rowY, ch) drawBorder(columnX, rowY, ch)
rowY++ rowY++
if rowY >= height { if rowY >= height {
break // No space for the text anymore. break // No space for the text anymore.
} }
drawBorder(columnX, rowY, GraphicsVertBar) drawBorder(columnX, rowY, Borders.Vertical)
} else if columnIndex > 0 { } else if columnIndex > 0 {
// Draw separator. // Draw separator.
drawBorder(columnX, rowY, t.separator) drawBorder(columnX, rowY, t.separator)
@ -706,18 +706,18 @@ ColumnLoop:
_, printed := printWithStyle(screen, cell.Text, x+columnX+1, y+rowY, finalWidth, cell.Align, tcell.StyleDefault.Foreground(cell.Color)|tcell.Style(cell.Attributes)) _, printed := printWithStyle(screen, cell.Text, x+columnX+1, y+rowY, finalWidth, cell.Align, tcell.StyleDefault.Foreground(cell.Color)|tcell.Style(cell.Attributes))
if StringWidth(cell.Text)-printed > 0 && printed > 0 { if StringWidth(cell.Text)-printed > 0 && printed > 0 {
_, _, style, _ := screen.GetContent(x+columnX+1+finalWidth-1, y+rowY) _, _, style, _ := screen.GetContent(x+columnX+1+finalWidth-1, y+rowY)
printWithStyle(screen, string(GraphicsEllipsis), x+columnX+1+finalWidth-1, y+rowY, 1, AlignLeft, style) printWithStyle(screen, string(SemigraphicsHorizontalEllipsis), x+columnX+1+finalWidth-1, y+rowY, 1, AlignLeft, style)
} }
} }
// Draw bottom border. // Draw bottom border.
if rowY := 2 * len(rows); t.borders && rowY < height { if rowY := 2 * len(rows); t.borders && rowY < height {
for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ { for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
drawBorder(columnX+pos+1, rowY, GraphicsHoriBar) drawBorder(columnX+pos+1, rowY, Borders.Horizontal)
} }
ch := GraphicsBottomT ch := Borders.BottomT
if columnIndex == 0 { if columnIndex == 0 {
ch = GraphicsBottomLeftCorner ch = Borders.BottomLeft
} }
drawBorder(columnX, rowY, ch) drawBorder(columnX, rowY, ch)
} }
@ -730,16 +730,16 @@ ColumnLoop:
for rowY := range rows { for rowY := range rows {
rowY *= 2 rowY *= 2
if rowY+1 < height { if rowY+1 < height {
drawBorder(columnX, rowY+1, GraphicsVertBar) drawBorder(columnX, rowY+1, Borders.Vertical)
} }
ch := GraphicsRightT ch := Borders.RightT
if rowY == 0 { if rowY == 0 {
ch = GraphicsTopRightCorner ch = Borders.TopRight
} }
drawBorder(columnX, rowY, ch) drawBorder(columnX, rowY, ch)
} }
if rowY := 2 * len(rows); rowY < height { if rowY := 2 * len(rows); rowY < height {
drawBorder(columnX, rowY, GraphicsBottomRightCorner) drawBorder(columnX, rowY, Borders.BottomRight)
} }
} }

110
util.go
View File

@ -19,90 +19,6 @@ const (
AlignRight AlignRight
) )
// Semigraphical runes.
const (
GraphicsHoriBar = '\u2500'
GraphicsVertBar = '\u2502'
GraphicsTopLeftCorner = '\u250c'
GraphicsTopRightCorner = '\u2510'
GraphicsBottomLeftCorner = '\u2514'
GraphicsBottomRightCorner = '\u2518'
GraphicsLeftT = '\u251c'
GraphicsRightT = '\u2524'
GraphicsTopT = '\u252c'
GraphicsBottomT = '\u2534'
GraphicsCross = '\u253c'
GraphicsDbVertBar = '\u2550'
GraphicsDbHorBar = '\u2551'
GraphicsDbTopLeftCorner = '\u2554'
GraphicsDbTopRightCorner = '\u2557'
GraphicsDbBottomRightCorner = '\u255d'
GraphicsDbBottomLeftCorner = '\u255a'
GraphicsEllipsis = '\u2026'
)
// joints maps combinations of two graphical runes to the rune that results
// when joining the two in the same screen cell. The keys of this map are
// two-rune strings where the value of the first rune is lower than the value
// of the second rune. Identical runes are not contained.
var joints = map[string]rune{
"\u2500\u2502": GraphicsCross,
"\u2500\u250c": GraphicsTopT,
"\u2500\u2510": GraphicsTopT,
"\u2500\u2514": GraphicsBottomT,
"\u2500\u2518": GraphicsBottomT,
"\u2500\u251c": GraphicsCross,
"\u2500\u2524": GraphicsCross,
"\u2500\u252c": GraphicsTopT,
"\u2500\u2534": GraphicsBottomT,
"\u2500\u253c": GraphicsCross,
"\u2502\u250c": GraphicsLeftT,
"\u2502\u2510": GraphicsRightT,
"\u2502\u2514": GraphicsLeftT,
"\u2502\u2518": GraphicsRightT,
"\u2502\u251c": GraphicsLeftT,
"\u2502\u2524": GraphicsRightT,
"\u2502\u252c": GraphicsCross,
"\u2502\u2534": GraphicsCross,
"\u2502\u253c": GraphicsCross,
"\u250c\u2510": GraphicsTopT,
"\u250c\u2514": GraphicsLeftT,
"\u250c\u2518": GraphicsCross,
"\u250c\u251c": GraphicsLeftT,
"\u250c\u2524": GraphicsCross,
"\u250c\u252c": GraphicsTopT,
"\u250c\u2534": GraphicsCross,
"\u250c\u253c": GraphicsCross,
"\u2510\u2514": GraphicsCross,
"\u2510\u2518": GraphicsRightT,
"\u2510\u251c": GraphicsCross,
"\u2510\u2524": GraphicsRightT,
"\u2510\u252c": GraphicsTopT,
"\u2510\u2534": GraphicsCross,
"\u2510\u253c": GraphicsCross,
"\u2514\u2518": GraphicsBottomT,
"\u2514\u251c": GraphicsLeftT,
"\u2514\u2524": GraphicsCross,
"\u2514\u252c": GraphicsCross,
"\u2514\u2534": GraphicsBottomT,
"\u2514\u253c": GraphicsCross,
"\u2518\u251c": GraphicsCross,
"\u2518\u2524": GraphicsRightT,
"\u2518\u252c": GraphicsCross,
"\u2518\u2534": GraphicsBottomT,
"\u2518\u253c": GraphicsCross,
"\u251c\u2524": GraphicsCross,
"\u251c\u252c": GraphicsCross,
"\u251c\u2534": GraphicsCross,
"\u251c\u253c": GraphicsCross,
"\u2524\u252c": GraphicsCross,
"\u2524\u2534": GraphicsCross,
"\u2524\u253c": GraphicsCross,
"\u252c\u2534": GraphicsCross,
"\u252c\u253c": GraphicsCross,
"\u2534\u253c": GraphicsCross,
}
// Common regular expressions. // Common regular expressions.
var ( var (
colorPattern = regexp.MustCompile(`\[([a-zA-Z]+|#[0-9a-zA-Z]{6}|\-)?(:([a-zA-Z]+|#[0-9a-zA-Z]{6}|\-)?(:([lbdru]+|\-)?)?)?\]`) colorPattern = regexp.MustCompile(`\[([a-zA-Z]+|#[0-9a-zA-Z]{6}|\-)?(:([a-zA-Z]+|#[0-9a-zA-Z]{6}|\-)?(:([lbdru]+|\-)?)?)?\]`)
@ -607,32 +523,6 @@ func WordWrap(text string, width int) (lines []string) {
return return
} }
// PrintJoinedBorder prints a border graphics rune into the screen at the given
// position with the given color, joining it with any existing border graphics
// rune. Background colors are preserved. At this point, only regular single
// line borders are supported.
func PrintJoinedBorder(screen tcell.Screen, x, y int, ch rune, color tcell.Color) {
previous, _, style, _ := screen.GetContent(x, y)
style = style.Foreground(color)
// What's the resulting rune?
var result rune
if ch == previous {
result = ch
} else {
if ch < previous {
previous, ch = ch, previous
}
result = joints[string(previous)+string(ch)]
}
if result == 0 {
result = ch
}
// We only print something if we have something.
screen.SetContent(x, y, result, nil, style)
}
// Escape escapes the given text such that color and/or region tags are not // Escape escapes the given text such that color and/or region tags are not
// recognized and substituted by the print functions of this package. For // recognized and substituted by the print functions of this package. For
// example, to include a tag-like string in a box title or in a TextView: // example, to include a tag-like string in a box title or in a TextView: