2017-01-13 23:07:43 -07:00
|
|
|
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
|
2015-03-20 14:21:50 -06:00
|
|
|
// Use of this source code is governed by a MIT license that can
|
|
|
|
// be found in the LICENSE file.
|
|
|
|
|
2015-02-03 12:13:51 -07:00
|
|
|
package termui
|
|
|
|
|
2015-04-03 07:14:39 -06:00
|
|
|
import (
|
2019-01-23 21:12:10 -07:00
|
|
|
"fmt"
|
|
|
|
"math"
|
|
|
|
"reflect"
|
2015-04-03 07:14:39 -06:00
|
|
|
|
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-04-03 07:14:39 -06:00
|
|
|
)
|
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
|
2015-04-01 14:25:00 -06:00
|
|
|
}
|
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func MaxInt(x, y int) int {
|
|
|
|
if x > y {
|
|
|
|
return x
|
2015-02-03 12:13:51 -07:00
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return y
|
|
|
|
}
|
2015-04-01 14:25:00 -06:00
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func MinInt(x, y int) int {
|
|
|
|
if x < y {
|
|
|
|
return x
|
2015-03-12 01:57:14 -06:00
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return y
|
2015-04-01 14:25:00 -06:00
|
|
|
}
|
|
|
|
|
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 {
|
2015-04-01 14:25:00 -06:00
|
|
|
if w <= 0 {
|
|
|
|
return ""
|
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
if rw.StringWidth(s) > w {
|
|
|
|
return rw.Truncate(s, w, string(DOTS))
|
2015-04-01 14:25:00 -06:00
|
|
|
}
|
|
|
|
return s
|
2015-03-25 16:04:15 -06:00
|
|
|
}
|
|
|
|
|
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
|
2015-03-25 16:04:15 -06:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
2015-04-03 07:14:39 -06: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
|
|
|
|
}
|
2015-04-03 07:14:39 -06:00
|
|
|
}
|
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return max, nil
|
2015-04-03 07:14:39 -06:00
|
|
|
}
|
2015-04-21 07:56:10 -06:00
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func SelectColor(colors []Color, index int) Color {
|
|
|
|
return colors[index%len(colors)]
|
|
|
|
}
|
2015-04-21 07:56:10 -06:00
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func SelectStyle(styles []Style, index int) Style {
|
|
|
|
return styles[index%len(styles)]
|
|
|
|
}
|
2015-04-21 07:56:10 -06:00
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func CellsToString(cells []Cell) string {
|
|
|
|
runes := make([]rune, len(cells))
|
|
|
|
for i, cell := range cells {
|
|
|
|
runes[i] = cell.Rune
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return string(runes)
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func RoundFloat64(x float64) float64 {
|
|
|
|
return math.Floor(x + 0.5)
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func SumIntSlice(slice []int) int {
|
|
|
|
sum := 0
|
|
|
|
for _, val := range slice {
|
|
|
|
sum += val
|
|
|
|
}
|
|
|
|
return sum
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func SumFloat64Slice(data []float64) float64 {
|
|
|
|
sum := 0.0
|
|
|
|
for _, v := range data {
|
|
|
|
sum += v
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return sum
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func AbsInt(x int) int {
|
|
|
|
if x >= 0 {
|
|
|
|
return x
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return -x
|
|
|
|
}
|
2015-04-21 07:56:10 -06:00
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func MinFloat64(x, y float64) float64 {
|
|
|
|
if x < y {
|
|
|
|
return x
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return y
|
|
|
|
}
|
2015-04-21 07:56:10 -06:00
|
|
|
|
2019-01-23 21:12:10 -07:00
|
|
|
func MaxFloat64(x, y float64) float64 {
|
|
|
|
if x > y {
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
return y
|
2015-04-21 07:56:10 -06:00
|
|
|
}
|
2016-03-10 13:49:31 -07:00
|
|
|
|
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
|
|
|
}
|
2016-02-04 23:20:46 -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})
|
2016-02-04 23:20:46 -07:00
|
|
|
}
|
2019-01-23 21:12:10 -07:00
|
|
|
return cells
|
2016-02-04 23:20:46 -07:00
|
|
|
}
|