Posters: re-place after a resize, measure cell size without padding, log failed posters
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
+36
-2
@@ -66,6 +66,7 @@ type App struct {
|
||||
covers bool // poster thumbnails enabled
|
||||
coverStyle coverStyle
|
||||
gfx *kittyGraphics // real-image posters, nil when not used
|
||||
lastWindow [3]int // columns, rows and cell shape at the last draw
|
||||
cellAspect float64 // height of a terminal cell divided by its width
|
||||
coverCache *coverCache
|
||||
}
|
||||
@@ -181,6 +182,7 @@ func New(cfg *config.Config) *App {
|
||||
s.HideCursor()
|
||||
a.screen = s
|
||||
a.cellAspect = cellAspectOf(s)
|
||||
a.noteWindow(s)
|
||||
return false
|
||||
})
|
||||
a.app.SetRoot(&toastRoot{Flex: layout, app: a}, true).EnableMouse(false)
|
||||
@@ -190,6 +192,22 @@ func New(cfg *config.Config) *App {
|
||||
return a
|
||||
}
|
||||
|
||||
// noteWindow notices when the terminal's size or cell size changed. The
|
||||
// placements of real-image posters are then made again: the picture would
|
||||
// otherwise rely on the terminal rescaling an existing placement correctly.
|
||||
func (a *App) noteWindow(s tcell.Screen) {
|
||||
w, h := s.Size()
|
||||
win := [3]int{w, h, int(a.cellAspect * 1000)}
|
||||
if win == a.lastWindow {
|
||||
return
|
||||
}
|
||||
first := a.lastWindow == [3]int{}
|
||||
a.lastWindow = win
|
||||
if !first && a.gfx != nil {
|
||||
a.gfx.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
// writeTerminal sends raw bytes (graphics commands) to the terminal through the
|
||||
// screen's own connection. UI goroutine only, so it stays in step with drawing.
|
||||
func (a *App) writeTerminal(b []byte) error {
|
||||
@@ -208,13 +226,29 @@ func (a *App) writeTerminal(b []byte) error {
|
||||
// pixels; 2 when the terminal does not report pixel sizes.
|
||||
func cellAspectOf(s tcell.Screen) float64 {
|
||||
if tty, ok := s.Tty(); ok {
|
||||
if ws, err := tty.WindowSize(); err == nil && ws.Width > 0 && ws.Height > 0 && ws.PixelWidth > 0 && ws.PixelHeight > 0 {
|
||||
return (float64(ws.PixelHeight) / float64(ws.Height)) / (float64(ws.PixelWidth) / float64(ws.Width))
|
||||
if ws, err := tty.WindowSize(); err == nil {
|
||||
return cellAspectFromWindow(ws.Width, ws.Height, ws.PixelWidth, ws.PixelHeight)
|
||||
}
|
||||
}
|
||||
return 2
|
||||
}
|
||||
|
||||
// cellAspectFromWindow derives the cell shape from the window size in cells
|
||||
// and pixels. The pixel size usually includes some padding around the cell
|
||||
// grid, which would skew a plain division (more with a small grid, and it
|
||||
// changes while the window is resized); cell sizes are whole pixels, so the
|
||||
// division is rounded down, which drops that padding.
|
||||
func cellAspectFromWindow(cols, rows, pixelW, pixelH int) float64 {
|
||||
if cols <= 0 || rows <= 0 || pixelW <= 0 || pixelH <= 0 {
|
||||
return 2
|
||||
}
|
||||
cw, ch := pixelW/cols, pixelH/rows
|
||||
if cw <= 0 || ch <= 0 {
|
||||
return 2
|
||||
}
|
||||
return float64(ch) / float64(cw)
|
||||
}
|
||||
|
||||
// coverMaxHeight is how tall the stored poster copies are: real images keep
|
||||
// more detail than block characters need.
|
||||
func (a *App) coverMaxHeight() int {
|
||||
|
||||
Reference in New Issue
Block a user