package ui import ( "image" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) const ( minCoverRows = 6 // a smaller poster is not worth showing minCoverCols = 8 // minTextRows = 10 // the poster never takes these rows from the text ) // detailPane shows the details of one title: the head (title and facts) with // the poster to its right on top, and the plot below both. On panes too small // for the poster everything is one text. type detailPane struct { *tview.Flex // column: top row, plot app *App top *tview.Flex // row: head, cover head *tview.TextView cover *coverView plot *tview.TextView text detailText want string // key of the poster that should be shown hasCover bool // a poster (or its loading note) is part of the content combined bool // head and plot are shown together in the plot view } func newDetailPane(app *App) *detailPane { d := &detailPane{ Flex: tview.NewFlex().SetDirection(tview.FlexRow), app: app, top: tview.NewFlex(), head: tview.NewTextView().SetDynamicColors(true).SetWordWrap(true), cover: newCoverView(app.coverStyle), plot: tview.NewTextView().SetDynamicColors(true).SetWordWrap(true), } d.cover.SetBorderPadding(0, 0, 1, 0) d.top.AddItem(d.head, 0, 1, false).AddItem(d.cover, 0, 0, false) d.AddItem(d.top, 0, 0, false).AddItem(d.plot, 0, 1, false) d.SetBorder(true).SetTitle(" Details ") d.combined = true return d } // Show displays the text and, if there is one, the poster. func (d *detailPane) Show(text detailText, ref coverRef) { d.text = text d.applyText() if !d.app.covers || ref.fetch == nil { d.want, d.hasCover = "", false d.cover.setImage(nil) return } d.want, d.hasCover = ref.key, true d.cover.setNote("loading cover…") want := ref.key d.app.loadCover(ref, func(img *image.RGBA, err error) { if d.want != want { return // the selection moved on } if err != nil { d.hasCover = false // nothing to show: give the room back to the text d.cover.setImage(nil) return } d.cover.setImage(img) }) } // Clear empties the pane. func (d *detailPane) Clear() { d.Show(detailText{}, coverRef{}) } // applyText puts the texts into their views for the current layout. func (d *detailPane) applyText() { if d.combined { d.head.SetText("") d.plot.SetText(d.text.String()).ScrollToBeginning() return } d.head.SetText(d.text.head).ScrollToBeginning() d.plot.SetText(d.text.plot).ScrollToBeginning() } func (d *detailPane) Draw(screen tcell.Screen) { _, _, w, h := d.GetInnerRect() coverW, coverH := 0, 0 if d.hasCover { aw, ah := d.cover.aspect() // At most 40% of the width, and the plot keeps its rows. coverW, coverH = coverCells(aw, ah, w*2/5, h-minTextRows) if coverH < minCoverRows || coverW < minCoverCols { coverW, coverH = 0, 0 } } if combined := coverW == 0; combined != d.combined { d.combined = combined d.applyText() } d.ResizeItem(d.top, coverH, 0) d.top.ResizeItem(d.cover, coverW+1, 0) // +1: the padding left of the poster d.Flex.Draw(screen) }