Posters: always a 2:3 box
The poster box followed the image's shape, so images Radarr/Sonarr hand out in another shape came out smaller than the others in a list. The box is now always 2:3: an image within 12% of that fills it, trimmed at the long sides (block characters too, which were stretched before); one further off is shown whole, centred in the box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+34
-11
@@ -311,13 +311,26 @@ func (c *coverView) aspectOfCells() float64 {
|
||||
func (c *coverView) setImage(img *image.RGBA) { c.img, c.note, c.cells = img, "", nil }
|
||||
func (c *coverView) setNote(note string) { c.img, c.note, c.cells = nil, note, nil }
|
||||
|
||||
// aspect returns the width and height of the poster (2:3 until one is loaded).
|
||||
func (c *coverView) aspect() (w, h int) {
|
||||
if c.img == nil {
|
||||
return 2, 3
|
||||
// Every poster gets a box of the usual poster shape, 2:3, so all posters of a
|
||||
// list have the same size whatever image Radarr/Sonarr hand out.
|
||||
const (
|
||||
posterW, posterH = 2, 3
|
||||
// posterShapeTolerance is how far an image's shape may differ from 2:3 and
|
||||
// still fill the box (trimmed at the long sides); one further off is shown
|
||||
// whole inside it.
|
||||
posterShapeTolerance = 0.12
|
||||
)
|
||||
|
||||
// aspect returns the shape of the box the poster is shown in.
|
||||
func (c *coverView) aspect() (w, h int) { return posterW, posterH }
|
||||
|
||||
// nearPosterShape reports whether an image is close enough to 2:3 to fill the box.
|
||||
func nearPosterShape(b image.Rectangle) bool {
|
||||
if b.Dx() <= 0 || b.Dy() <= 0 {
|
||||
return false
|
||||
}
|
||||
b := c.img.Bounds()
|
||||
return b.Dx(), b.Dy()
|
||||
d := float64(b.Dx())*posterH/(float64(b.Dy())*posterW) - 1
|
||||
return d >= -posterShapeTolerance && d <= posterShapeTolerance
|
||||
}
|
||||
|
||||
// coverFitTolerance is how far the shape of the cell box may differ from the
|
||||
@@ -376,19 +389,26 @@ func (c *coverView) Draw(screen tcell.Screen) {
|
||||
return
|
||||
}
|
||||
|
||||
// The 2:3 box, right-aligned in the area. An image close to that shape
|
||||
// fills it (trimmed); one far from it (square, landscape) is shown whole,
|
||||
// centred in the box.
|
||||
b := c.img.Bounds()
|
||||
cols, rows := coverCells(b.Dx(), b.Dy(), w, h, c.aspectOfCells())
|
||||
boxW, boxH := coverCells(posterW, posterH, w, h, c.aspectOfCells())
|
||||
cols, rows := boxW, boxH
|
||||
if !nearPosterShape(b) {
|
||||
cols, rows = coverCells(b.Dx(), b.Dy(), boxW, boxH, c.aspectOfCells())
|
||||
}
|
||||
if cols < 1 || rows < 1 {
|
||||
return
|
||||
}
|
||||
if c.drawGraphics(screen, x+w-cols, y, cols, rows) {
|
||||
x += w - boxW + (boxW-cols)/2
|
||||
y += (boxH - rows) / 2
|
||||
if c.drawGraphics(screen, x, y, cols, rows) {
|
||||
return
|
||||
}
|
||||
if c.cells == nil || c.cols != cols || c.rows != rows {
|
||||
c.cols, c.rows, c.cells = cols, rows, c.build(cols, rows)
|
||||
}
|
||||
// Right-align the poster inside its area, so a narrower poster sits against the edge.
|
||||
x += w - cols
|
||||
for row := 0; row < rows; row++ {
|
||||
for col := 0; col < cols; col++ {
|
||||
cell := c.cells[row*cols+col]
|
||||
@@ -445,7 +465,10 @@ func (c *coverView) drawGraphics(screen tcell.Screen, x, y, cols, rows int) bool
|
||||
// build renders the poster into cols×rows cells.
|
||||
func (c *coverView) build(cols, rows int) []styledCell {
|
||||
st := c.style
|
||||
scaled := boxScale(c.img, cols*st.sw, rows*st.sh)
|
||||
// Trim the image to the shape of the cells first, as for real images, so
|
||||
// it is not stretched.
|
||||
crop := cropToBox(c.img.Bounds(), cols, rows, c.aspectOfCells())
|
||||
scaled := boxScale(c.img.SubImage(crop), cols*st.sw, rows*st.sh)
|
||||
cells := make([]styledCell, 0, cols*rows)
|
||||
px := make([]color.RGBA, st.sw*st.sh)
|
||||
for row := 0; row < rows; row++ {
|
||||
|
||||
Reference in New Issue
Block a user