termui/utils.go

231 lines
4.5 KiB
Go
Raw Normal View History

2017-01-13 23:07:43 -07:00
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
2022-08-28 10:46:41 -06:00
// Use of this source code is governed by a GPLv3 license that can
2015-03-20 14:21:50 -06:00
// be found in the LICENSE file.
2015-02-03 12:13:51 -07:00
package termui
import (
2019-01-23 21:12:10 -07:00
"fmt"
"math"
"reflect"
2018-09-06 15:48:09 -06:00
rw "github.com/mattn/go-runewidth"
2019-01-23 21:12:10 -07:00
wordwrap "github.com/mitchellh/go-wordwrap"
)
2015-02-03 18:56:49 -07:00
2019-01-24 05:11:20 -07:00
// InterfaceSlice takes an []interface{} represented as an interface{} and converts it
2019-01-23 21:12:10 -07:00
// https://stackoverflow.com/questions/12753805/type-converting-slices-of-interfaces-in-go
func InterfaceSlice(slice interface{}) []interface{} {
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
panic("InterfaceSlice() given a non-slice type")
}
2015-03-03 11:28:09 -07:00
2019-01-23 21:12:10 -07:00
ret := make([]interface{}, s.Len())
2015-02-03 12:13:51 -07:00
2019-01-23 21:12:10 -07:00
for i := 0; i < s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}
2015-02-03 12:13:51 -07:00
2019-01-23 21:12:10 -07:00
return ret
}
2019-01-24 05:11:20 -07:00
// TrimString trims a string to a max length and adds '…' to the end if it was trimmed.
2019-01-23 21:12:10 -07:00
func TrimString(s string, w int) string {
if w <= 0 {
return ""
}
2019-01-23 21:12:10 -07:00
if rw.StringWidth(s) > w {
2019-01-26 03:47:47 -07:00
return rw.Truncate(s, w, string(ELLIPSES))
}
return s
}
2019-01-26 03:47:47 -07:00
func SelectColor(colors []Color, index int) Color {
return colors[index%len(colors)]
}
func SelectStyle(styles []Style, index int) Style {
return styles[index%len(styles)]
}
// Math ------------------------------------------------------------------------
func SumIntSlice(slice []int) int {
sum := 0
for _, val := range slice {
sum += val
}
return sum
}
func SumFloat64Slice(data []float64) float64 {
sum := 0.0
for _, v := range data {
sum += v
}
return sum
}
2019-01-23 21:12:10 -07:00
func GetMaxIntFromSlice(slice []int) (int, error) {
if len(slice) == 0 {
return 0, fmt.Errorf("cannot get max value from empty slice")
}
var max int
for _, val := range slice {
if val > max {
max = val
}
}
return max, nil
}
2019-01-23 21:12:10 -07:00
func GetMaxFloat64FromSlice(slice []float64) (float64, error) {
if len(slice) == 0 {
return 0, fmt.Errorf("cannot get max value from empty slice")
}
var max float64
for _, val := range slice {
if val > max {
max = val
}
}
return max, nil
2015-02-03 12:13:51 -07:00
}
2019-01-23 21:12:10 -07:00
func GetMaxFloat64From2dSlice(slices [][]float64) (float64, error) {
if len(slices) == 0 {
return 0, fmt.Errorf("cannot get max value from empty slice")
}
var max float64
for _, slice := range slices {
for _, val := range slice {
if val > max {
max = val
}
}
}
2019-01-23 21:12:10 -07:00
return max, nil
}
2019-01-23 21:12:10 -07:00
func RoundFloat64(x float64) float64 {
return math.Floor(x + 0.5)
}
func FloorFloat64(x float64) float64 {
return math.Floor(x)
}
2019-01-23 21:12:10 -07:00
func AbsInt(x int) int {
if x >= 0 {
return x
}
2019-01-23 21:12:10 -07:00
return -x
}
2019-01-23 21:12:10 -07:00
func MinFloat64(x, y float64) float64 {
if x < y {
return x
}
2019-01-23 21:12:10 -07:00
return y
}
2019-01-23 21:12:10 -07:00
func MaxFloat64(x, y float64) float64 {
if x > y {
return x
}
return y
}
2016-03-10 13:49:31 -07:00
2019-01-26 03:47:47 -07:00
func MaxInt(x, y int) int {
if x > y {
return x
}
return y
}
func MinInt(x, y int) int {
if x < y {
return x
}
return y
}
// []Cell ----------------------------------------------------------------------
2019-01-24 05:11:20 -07:00
// WrapCells takes []Cell and inserts Cells containing '\n' wherever a linebreak should go.
2019-01-23 21:12:10 -07:00
func WrapCells(cells []Cell, width uint) []Cell {
str := CellsToString(cells)
wrapped := wordwrap.WrapString(str, width)
wrappedCells := []Cell{}
i := 0
for _, _rune := range wrapped {
if _rune == '\n' {
wrappedCells = append(wrappedCells, Cell{_rune, StyleClear})
} else {
wrappedCells = append(wrappedCells, Cell{_rune, cells[i].Style})
}
i++
2016-03-10 13:49:31 -07:00
}
2019-01-23 21:12:10 -07:00
return wrappedCells
2016-03-10 13:49:31 -07:00
}
2019-01-23 21:12:10 -07:00
func RunesToStyledCells(runes []rune, style Style) []Cell {
cells := []Cell{}
for _, _rune := range runes {
cells = append(cells, Cell{_rune, style})
}
2019-01-23 21:12:10 -07:00
return cells
}
2019-01-26 03:47:47 -07:00
func CellsToString(cells []Cell) string {
runes := make([]rune, len(cells))
for i, cell := range cells {
runes[i] = cell.Rune
}
return string(runes)
}
func TrimCells(cells []Cell, w int) []Cell {
s := CellsToString(cells)
s = TrimString(s, w)
runes := []rune(s)
2019-01-26 03:47:47 -07:00
newCells := []Cell{}
for i, r := range runes {
2019-01-26 03:47:47 -07:00
newCells = append(newCells, Cell{r, cells[i].Style})
}
return newCells
}
func SplitCells(cells []Cell, r rune) [][]Cell {
splitCells := [][]Cell{}
temp := []Cell{}
for _, cell := range cells {
if cell.Rune == r {
splitCells = append(splitCells, temp)
temp = []Cell{}
} else {
temp = append(temp, cell)
}
}
2019-01-26 06:20:41 -07:00
if len(temp) > 0 {
2019-01-26 03:47:47 -07:00
splitCells = append(splitCells, temp)
}
return splitCells
}
type CellWithX struct {
X int
Cell Cell
}
func BuildCellWithXArray(cells []Cell) []CellWithX {
cellWithXArray := make([]CellWithX, len(cells))
index := 0
for i, cell := range cells {
cellWithXArray[i] = CellWithX{X: index, Cell: cell}
index += rw.RuneWidth(cell.Rune)
}
return cellWithXArray
}