tcell/cell.go

140 lines
3.6 KiB
Go

// Copyright 2015 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tcell
import (
"github.com/mattn/go-runewidth"
)
// Cell represents a single character cell. This is primarily intended for
// use by Screen implementors.
type Cell struct {
Ch []rune
Dirty bool
Width uint8
Style Style
}
// ClearCells clears the entire set of cells, making them all whitespace with
// the provided attribute.
func ClearCells(c []Cell, style Style) {
for i := range c {
c[i].Ch = nil
c[i].Style = style
c[i].Width = 1
c[i].Dirty = true
}
}
// InvalidateCells marks all cells in the array dirty.
func InvalidateCells(c []Cell) {
for i := range c {
c[i].Dirty = true
}
}
// ResizeCells is used to create a new cells array, with different dimensions,
// while preserving the original contents. The returned array may be the same
// as the original, if we can reuse it. Hence, the old array should no longer
// be used by the caller after this call. The cells will be marked dirty so
// that they can be redrawn.
func ResizeCells(oldc []Cell, oldw, oldh, neww, newh int) []Cell {
if oldh == newh && oldw == neww {
return oldc
}
newc := oldc
// Probably are other conditions where we could reuse, but if there is
// any doubt at all, its easier & safest to just realloc the window.
if newh > oldh || neww > oldw {
newc = make([]Cell, neww*newh)
}
for row := 0; row < newh && row < oldh; row++ {
for col := 0; col < oldw && col < neww; col++ {
newc[(row*neww)+col] = oldc[(row*oldw)+col]
newc[(row*neww)+col].Dirty = true
}
}
return newc
}
// SetCell writes the contents into the cell. It ensures that at most one
// nonzero width rune is present in the Ch array (and if any zero width runes
// are present without a non-zero one, then a space is inserted), and updates
// the Dirty bit if the contents are different than they were.
func (c *Cell) SetCell(ch []rune, style Style) {
c.PutChars(ch)
c.PutStyle(style)
}
// PutChars is a handy way to write runes to the Cell, without changing its
// style. The first rune should be a printable non-zero width value, and
// subsequent values may be combining marks.
func (c *Cell) PutChars(ch []rune) {
var mainc rune
var width uint8
var compc []rune
width = 1
mainc = ' '
for _, r := range ch {
if r < ' ' {
// skip over non-printable control characters
continue
}
switch runewidth.RuneWidth(r) {
case 1:
mainc = r
width = 1
case 2:
mainc = r
width = 2
case 0:
compc = append(compc, r)
}
}
newch := append([]rune{mainc}, compc...)
if len(newch) != len(c.Ch) {
c.Dirty = true
} else {
for i := range newch {
if newch[i] != c.Ch[i] {
c.Dirty = true
}
}
}
c.Ch = newch
c.Width = width
}
// PutChar writes a single rune into the cells location. The rune should be a
// a normal (not combining) printable character.
func (c *Cell) PutChar(ch rune) {
c.PutChars([]rune{ch})
}
// PutStyle changes the style of the given Cell, without altering the character
// content.
func (c *Cell) PutStyle(style Style) {
if c.Style != style {
c.Style = style
c.Dirty = true
}
}