mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-20 22:21:13 +02:00
Implemented a new component based on `tview.Table` that shows all available block devices as a table. Had to stop using standard form control, because it doesn't really handle multiline elements. Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
211 lines
4.1 KiB
Go
211 lines
4.1 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package components
|
|
|
|
import (
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/rivo/tview"
|
|
)
|
|
|
|
var (
|
|
backgroundColor = tcell.Color235
|
|
textNormalColor = tcell.ColorIvory
|
|
selectedTextColor = tview.Styles.PrimaryTextColor
|
|
selectedBackgroundColor = tview.Styles.ContrastBackgroundColor
|
|
)
|
|
|
|
// NewTable creates new table.
|
|
func NewTable() *Table {
|
|
t := &Table{
|
|
Table: tview.NewTable(),
|
|
selectedRow: -1,
|
|
hoveredRow: -1,
|
|
rows: [][]interface{}{},
|
|
}
|
|
|
|
hasFocus := false
|
|
|
|
t.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) {
|
|
changed := hasFocus != t.HasFocus()
|
|
if !changed {
|
|
return x, y, width, height
|
|
}
|
|
|
|
hasFocus = t.HasFocus()
|
|
|
|
if hasFocus {
|
|
if t.selectedRow != -1 {
|
|
t.HoverRow(t.selectedRow)
|
|
} else {
|
|
t.HoverRow(1)
|
|
}
|
|
} else {
|
|
t.HoverRow(-1)
|
|
}
|
|
|
|
return x, y, width, height
|
|
})
|
|
|
|
t.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
|
|
// nolint:exhaustive
|
|
switch e.Key() {
|
|
case tcell.KeyUp:
|
|
if t.hoveredRow > 0 {
|
|
t.HoverRow(t.hoveredRow - 1)
|
|
}
|
|
case tcell.KeyDown:
|
|
if t.hoveredRow < t.GetRowCount() {
|
|
t.HoverRow(t.hoveredRow + 1)
|
|
}
|
|
case tcell.KeyEnter:
|
|
if t.hoveredRow != -1 {
|
|
t.SelectRow(t.hoveredRow)
|
|
}
|
|
}
|
|
|
|
return e
|
|
})
|
|
|
|
return t
|
|
}
|
|
|
|
// Table list of choices represented in table format.
|
|
type Table struct {
|
|
*tview.Table
|
|
selectedRow int
|
|
hoveredRow int
|
|
onRowSelected func(row int)
|
|
rows [][]interface{}
|
|
}
|
|
|
|
// SetHeader sets table header.
|
|
func (t *Table) SetHeader(keys ...interface{}) {
|
|
t.AddRow(keys...)
|
|
}
|
|
|
|
// AddRow adds a new row to the table.
|
|
func (t *Table) AddRow(columns ...interface{}) {
|
|
row := t.GetRowCount()
|
|
col := backgroundColor
|
|
textColor := tview.Styles.PrimaryTextColor
|
|
|
|
if row == 0 {
|
|
col = tcell.ColorSilver
|
|
textColor = tview.Styles.InverseTextColor
|
|
} else {
|
|
t.rows = append(t.rows, columns)
|
|
}
|
|
|
|
cell := tview.NewTableCell(" ").
|
|
SetAlign(tview.AlignCenter).
|
|
SetBackgroundColor(col).
|
|
SetTextColor(textColor)
|
|
|
|
if row > 0 {
|
|
cell.SetClickedFunc(func() bool {
|
|
t.HoverRow(row)
|
|
t.SelectRow(row)
|
|
|
|
return true
|
|
})
|
|
}
|
|
|
|
t.SetCell(row, 0, cell)
|
|
|
|
for i, text := range columns {
|
|
cell = tview.NewTableCell(text.(string))
|
|
cell.SetExpansion(1)
|
|
cell.SetTextColor(textColor)
|
|
|
|
if i == len(columns)-1 {
|
|
cell.SetAlign(tview.AlignRight)
|
|
}
|
|
|
|
cell.SetBackgroundColor(col)
|
|
cell.SetSelectable(true)
|
|
t.SetCell(row, i+1, cell)
|
|
|
|
if row > 0 {
|
|
cell.SetClickedFunc(func() bool {
|
|
return t.HoverRow(row)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// SelectRow selects the row in the table.
|
|
func (t *Table) SelectRow(row int) bool {
|
|
// don't select the header
|
|
if row < 2 {
|
|
row = 1
|
|
}
|
|
|
|
if row < t.GetRowCount() {
|
|
if t.selectedRow != -1 {
|
|
t.GetCell(t.selectedRow, 0).SetText(" ")
|
|
}
|
|
|
|
t.GetCell(row, 0).SetText("►")
|
|
t.selectedRow = row
|
|
|
|
if t.onRowSelected != nil {
|
|
t.onRowSelected(row)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// HoverRow highlights the row in the table.
|
|
func (t *Table) HoverRow(row int) bool {
|
|
updateRowStyle := func(r int, foregroundColor, backgroundColor tcell.Color) {
|
|
for i := 0; i < t.GetColumnCount(); i++ {
|
|
t.GetCell(r, i).SetBackgroundColor(backgroundColor).SetTextColor(foregroundColor)
|
|
}
|
|
}
|
|
|
|
// don't select the header
|
|
if row == 0 {
|
|
row = 1
|
|
}
|
|
|
|
if row < t.GetRowCount() {
|
|
if t.hoveredRow != -1 {
|
|
updateRowStyle(t.hoveredRow, textNormalColor, backgroundColor)
|
|
}
|
|
|
|
if row != -1 {
|
|
updateRowStyle(row, selectedTextColor, selectedBackgroundColor)
|
|
}
|
|
|
|
t.hoveredRow = row
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// GetHeight implements Multiline interface.
|
|
func (t *Table) GetHeight() int {
|
|
return t.GetRowCount()
|
|
}
|
|
|
|
// SetRowSelectedFunc called when selected row is updated.
|
|
func (t *Table) SetRowSelectedFunc(callback func(row int)) {
|
|
t.onRowSelected = callback
|
|
}
|
|
|
|
// GetValue returns value in row/column.
|
|
func (t *Table) GetValue(row, column int) interface{} {
|
|
if row < len(t.rows) && column < len(t.rows[row]) {
|
|
return t.rows[row][column]
|
|
}
|
|
|
|
return ""
|
|
}
|