GoSetup-bubble/setup/final.go

192 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package setup
import (
"bubble/setup/ui"
"bubble/types"
"fmt"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
)
// FinalModel структур описывающая модель отрисовки таблицы переменных
type FinalModel struct {
variables []types.Variable //Список переменных
table *table.Table //Таблица для вывода
viewport viewport.Model //Объект куда помещена таблица для возможности прокручивать её
width int //Ширина окна
height int //Высота окна
}
// NewFinalModel создается новую модель таблицы переменных
func NewFinalModel(variables []types.Variable, width, height int) *FinalModel {
m := &FinalModel{
variables: variables,
width: width,
height: height,
}
if width > 0 && height > 0 {
m.initViewport(width, height)
}
return m
}
func (m *FinalModel) Init() tea.Cmd {
return nil
}
// Update отслеживает действия со таблицей
func (m *FinalModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
//Отслеживаем нажатие клавиш
switch msg.String() {
case "up":
//Обработчик up для прокручивания вверх на 1 позицию
m.viewport.ScrollUp(1)
case "down":
//Обработчик down для прокручивания вниз на 1 позицию
m.viewport.ScrollDown(1)
case "left":
//Обработчик left для прокручивания влево на 1 позицию
m.viewport.ScrollLeft(1)
case "right":
//Обработчик right для прокручивания вправо на 1 позицию
m.viewport.ScrollRight(1)
case "pageup":
//Обработчик pageup для прокручивания вверх на половину допустимой высоты viewport
m.viewport.HalfPageUp()
case "pagedown":
//Обработчик pagedown для прокручивания вниз на половину допустимой высоты viewport
m.viewport.HalfPageDown()
case "home":
//Обработчик home для перехода в самый вверх
m.viewport.GotoTop()
case "end":
//Обработчик end для перехода в самый низ
m.viewport.GotoBottom()
}
case tea.WindowSizeMsg:
//Отслеживаем и записываем новые размер окна, вносим изменения в размеры viewport
m.height = msg.Height
m.width = msg.Width
m.initViewport(msg.Width, msg.Height)
}
//Если сообщение было иным, передаем его напрямую в viewport
//todo проверить есть ли эти функции уже у viewport.Update, возможно мой код дублирует
m.viewport, cmd = m.viewport.Update(msg)
return m, cmd
}
// View формирует строку для вывода таблицы переменных
func (m *FinalModel) View() string {
//Получаем размеры контейнера и ширину контента
containerWidth, containerHeight, contentWidth, _ := ui.ContentSizes(m.width, m.height)
//Формируем шапку с заголовком
header := ui.FinalHeader.
Width(contentWidth).
Render("Итоговые значения переменных")
//Формируем "подвал"
footer := ui.FinalFooter.
Width(contentWidth).
Render(fmt.Sprintf("Количество переменных: %d", len(m.variables)))
//Обновляем отображение таблицы
m.rebuildTable(contentWidth)
//Формируем единый контент из шапки, видимой области и подвала
fullContent := lipgloss.JoinVertical(lipgloss.Top, header, m.viewport.View(), footer)
//Формируем главный контейнер
container := ui.AppContainer.
Width(containerWidth).
Height(containerHeight).
Render(fullContent)
return lipgloss.Place(
m.width, m.height,
lipgloss.Center, lipgloss.Center,
container,
lipgloss.WithWhitespaceChars("+"),
lipgloss.WithWhitespaceForeground(ui.ColorError),
)
}
// initViewport создание видимой области таблицы
func (m *FinalModel) initViewport(width, height int) {
_, _, contentWidth, contentHeight := ui.ContentSizes(width, height)
tableWidth := contentWidth - 2*1
tableHeight := int(float64(contentHeight)*ui.TableWithRatio) - 2*1
//Создание видимой области, куда будет помещена таблица
m.viewport = viewport.New(contentWidth, tableHeight)
//Обновление таблицы
m.rebuildTable(tableWidth)
}
func (m *FinalModel) rebuildTable(width int) {
//Если переменных нет, то делаем спец таблицу
if len(m.variables) == 0 {
m.table = table.New().
Border(lipgloss.RoundedBorder()).
BorderStyle(ui.FinalTableBorder).
StyleFunc(func(row, col int) lipgloss.Style {
return ui.FinalTableHeader
}).Headers("Нет переменных")
m.viewport.SetContent(m.table.Render())
return
}
//Вычисляем размеры колонок
variableNameColWidth := 20
defaultValueColWidth := 25
usedValueColWidth := width - variableNameColWidth - defaultValueColWidth - 4*1
//ширина таблицы - ширина первой колонки - ширина второй колонки - 4 границы (2 крайние, 2 между колонками)
if usedValueColWidth < 30 { //если значение сильно меньше
usedValueColWidth = 30
}
//Создаем модель таблицы
t := table.New().
Width(variableNameColWidth+defaultValueColWidth+usedValueColWidth+4).
Border(lipgloss.RoundedBorder()).
BorderStyle(ui.FinalTableBorder).
StyleFunc(func(row, col int) lipgloss.Style {
var style lipgloss.Style
if row == table.HeaderRow {
return ui.FinalTableHeader
}
if row%2 == 0 {
style = ui.FinalTableEvenRow
} else {
style = ui.FinalTableOddRow
}
switch col {
case 0:
return style.Width(variableNameColWidth).Align(lipgloss.Left)
case 1:
return style.Width(defaultValueColWidth).Align(lipgloss.Left)
case 2:
return style.Width(usedValueColWidth).Align(lipgloss.Left)
}
return style
}).
Headers("Variable name", "Default value", "Used value")
//Заполняем таблицу данными
for _, v := range m.variables {
used := fmt.Sprintf("%v", v.Value)
if used == "" {
used = "<Пусто>"
}
t.Row(v.Name, v.Default, used)
}
//записываем таблицу в модель
m.table = t
//Помещение в видимую область таблицы
m.viewport.SetContent(m.table.Render())
}