1// Copyright 2019 Graham Clark. All rights reserved. Use of this source 2// code is governed by the MIT license that can be found in the LICENSE 3// file. 4 5package gowid 6 7//====================================================================== 8 9// Cell represents a single element of terminal output. The empty value 10// is a blank cell with default colors, style, and a 'blank' rune. It is 11// closely tied to TCell's underlying cell representation - colors are 12// TCell-specific, so are translated from anything more general before a 13// Cell is instantiated. 14type Cell struct { 15 codePoint rune 16 fg TCellColor 17 bg TCellColor 18 style StyleAttrs 19} 20 21// MakeCell returns a Cell initialized with the supplied run (char to display), 22// foreground color, background color and style attributes. Each color can specify 23// "default" meaning whatever the terminal default foreground/background is, or 24// "none" meaning no preference, allowing it to be overridden when laid on top 25// of another Cell during the render process. 26func MakeCell(codePoint rune, fg TCellColor, bg TCellColor, Attr StyleAttrs) Cell { 27 return Cell{ 28 codePoint: codePoint, 29 fg: fg, 30 bg: bg, 31 style: Attr, 32 } 33} 34 35// MergeUnder returns a Cell representing the receiver merged "underneath" the 36// Cell argument provided. This means the argument's rune value will be used 37// unless it is "empty", and the cell's color and styling come from the 38// argument's value in a similar fashion. 39func (c Cell) MergeUnder(upper Cell) Cell { 40 res := c 41 if upper.codePoint != 0 { 42 res.codePoint = upper.codePoint 43 } 44 return res.MergeDisplayAttrsUnder(upper) 45} 46 47// MergeDisplayAttrsUnder returns a Cell representing the receiver Cell with the 48// argument Cell's color and styling applied, if they are explicitly set. 49func (c Cell) MergeDisplayAttrsUnder(upper Cell) Cell { 50 res := c 51 ufg, ubg, ust := upper.GetDisplayAttrs() 52 if ubg != ColorNone { 53 res = res.WithBackgroundColor(ubg) 54 } 55 if ufg != ColorNone { 56 res = res.WithForegroundColor(ufg) 57 } 58 res.style = res.style.MergeUnder(ust) 59 return res 60} 61 62// GetDisplayAttrs returns the receiver Cell's foreground and background color 63// and styling. 64func (c Cell) GetDisplayAttrs() (x TCellColor, y TCellColor, z StyleAttrs) { 65 x = c.ForegroundColor() 66 y = c.BackgroundColor() 67 z = c.Style() 68 return 69} 70 71// HasRune returns true if the Cell actively specifies a rune to display; otherwise 72// false, meaning there it is "empty", and a Cell layered underneath it will have its 73// rune displayed. 74func (c Cell) HasRune() bool { 75 return c.codePoint != 0 76} 77 78// Rune will return a rune that can be displayed, if this Cell is being rendered in some 79// fashion. If the Cell is empty, then a space rune is returned. 80func (c Cell) Rune() rune { 81 if !c.HasRune() { 82 return ' ' 83 } else { 84 return c.codePoint 85 } 86} 87 88// WithRune returns a Cell equal to the receiver Cell but that will render the supplied 89// rune instead. 90func (c Cell) WithRune(r rune) Cell { 91 c.codePoint = r 92 return c 93} 94 95// BackgroundColor returns the background color of the receiver Cell. 96func (c Cell) BackgroundColor() TCellColor { 97 return c.bg 98} 99 100// ForegroundColor returns the foreground color of the receiver Cell. 101func (c Cell) ForegroundColor() TCellColor { 102 return c.fg 103} 104 105// Style returns the style of the receiver Cell. 106func (c Cell) Style() StyleAttrs { 107 return c.style 108} 109 110// WithRune returns a Cell equal to the receiver Cell but that will render no 111// rune instead i.e. it is "empty". 112func (c Cell) WithNoRune() Cell { 113 c.codePoint = 0 114 return c 115} 116 117// WithBackgroundColor returns a Cell equal to the receiver Cell but that 118// will render with the supplied background color instead. Note that this color 119// can be set to "none" by passing the value gowid.ColorNone, meaning allow 120// Cells layered underneath to determine the background color. 121func (c Cell) WithBackgroundColor(a TCellColor) Cell { 122 c.bg = a 123 return c 124} 125 126// WithForegroundColor returns a Cell equal to the receiver Cell but that 127// will render with the supplied foreground color instead. Note that this color 128// can be set to "none" by passing the value gowid.ColorNone, meaning allow 129// Cells layered underneath to determine the background color. 130func (c Cell) WithForegroundColor(a TCellColor) Cell { 131 c.fg = a 132 return c 133} 134 135// WithStyle returns a Cell equal to the receiver Cell but that will render 136// with the supplied style (e.g. underline) instead. Note that this style 137// can be set to "none" by passing the value gowid.AttrNone, meaning allow 138// Cells layered underneath to determine the style. 139func (c Cell) WithStyle(attr StyleAttrs) Cell { 140 c.style = attr 141 return c 142} 143 144//====================================================================== 145 146// CellFromRune returns a Cell with the supplied rune and with default 147// coloring and styling. 148func CellFromRune(r rune) Cell { 149 return MakeCell(r, ColorNone, ColorNone, StyleNone) 150} 151 152// CellsFromString is a utility function to turn a string into an array 153// of Cells. Note that each Cell has no color or style set. 154func CellsFromString(s string) []Cell { 155 res := make([]Cell, 0, len(s)) // overcommits, counts chars and not runes, but minimizes reallocations. 156 for _, r := range s { 157 if r != ' ' { 158 res = append(res, CellFromRune(r)) 159 } else { 160 res = append(res, Cell{}) 161 } 162 } 163 return res 164} 165 166//====================================================================== 167// Local Variables: 168// mode: Go 169// fill-column: 110 170// End: 171