117 lines
2.6 KiB
Go
117 lines
2.6 KiB
Go
package table
|
|
|
|
import (
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
func (m *Model) recalculateWidth() {
|
|
if m.targetTotalWidth != 0 {
|
|
m.totalWidth = m.targetTotalWidth
|
|
} else {
|
|
total := 0
|
|
|
|
for _, column := range m.columns {
|
|
total += column.width
|
|
}
|
|
|
|
m.totalWidth = total + len(m.columns) + 1
|
|
}
|
|
|
|
updateColumnWidths(m.columns, m.targetTotalWidth)
|
|
|
|
m.recalculateLastHorizontalColumn()
|
|
}
|
|
|
|
// Updates column width in-place. This could be optimized but should be called
|
|
// very rarely so we prioritize simplicity over performance here.
|
|
func updateColumnWidths(cols []Column, totalWidth int) {
|
|
totalFlexWidth := totalWidth - len(cols) - 1
|
|
totalFlexFactor := 0
|
|
flexGCD := 0
|
|
|
|
for index, col := range cols {
|
|
if !col.isFlex() {
|
|
totalFlexWidth -= col.width
|
|
cols[index].style = col.style.Width(col.width)
|
|
} else {
|
|
totalFlexFactor += col.flexFactor
|
|
flexGCD = gcd(flexGCD, col.flexFactor)
|
|
}
|
|
}
|
|
|
|
if totalFlexFactor == 0 {
|
|
return
|
|
}
|
|
|
|
// We use the GCD here because otherwise very large values won't divide
|
|
// nicely as ints
|
|
totalFlexFactor /= flexGCD
|
|
|
|
flexUnit := totalFlexWidth / totalFlexFactor
|
|
leftoverWidth := totalFlexWidth % totalFlexFactor
|
|
|
|
for index := range cols {
|
|
if !cols[index].isFlex() {
|
|
continue
|
|
}
|
|
|
|
width := flexUnit * (cols[index].flexFactor / flexGCD)
|
|
|
|
if leftoverWidth > 0 {
|
|
width++
|
|
leftoverWidth--
|
|
}
|
|
|
|
if index == len(cols)-1 {
|
|
width += leftoverWidth
|
|
leftoverWidth = 0
|
|
}
|
|
|
|
width = max(width, 1)
|
|
|
|
cols[index].width = width
|
|
|
|
// Take borders into account for the actual style
|
|
cols[index].style = cols[index].style.Width(width)
|
|
}
|
|
}
|
|
|
|
func (m *Model) recalculateHeight() {
|
|
header := m.renderHeaders()
|
|
headerHeight := 1 // Header always has the top border
|
|
if m.headerVisible {
|
|
headerHeight = lipgloss.Height(header)
|
|
}
|
|
|
|
footer := m.renderFooter(lipgloss.Width(header), false)
|
|
var footerHeight int
|
|
if footer != "" {
|
|
footerHeight = lipgloss.Height(footer)
|
|
}
|
|
|
|
m.metaHeight = headerHeight + footerHeight
|
|
}
|
|
|
|
func (m *Model) calculatePadding(numRows int) int {
|
|
if m.minimumHeight == 0 {
|
|
return 0
|
|
}
|
|
|
|
padding := m.minimumHeight - m.metaHeight - numRows - 1 // additional 1 for bottom border
|
|
|
|
if padding == 0 && numRows == 0 {
|
|
// This is an edge case where we want to add 1 additional line of height, i.e.
|
|
// add a border without an empty row. However, this is not possible, so we need
|
|
// to add an extra row which will result in the table being 1 row taller than
|
|
// the requested minimum height.
|
|
return 1
|
|
}
|
|
|
|
if padding < 0 {
|
|
// Table is already larger than minimum height, do nothing.
|
|
return 0
|
|
}
|
|
|
|
return padding
|
|
}
|