{- | The per-track panel stacked into "Termtab.UI"'s main layout: a header
naming the track (highlighted when it's the focused\/current track) plus
its content, laid out according to the track's 'DisplayMode'. Chooses
between the rasterized Bravura notation image
("Termtab.UI.NotationGraphics") and the plain-text Unicode staff
("Termtab.UI.Widgets.Notation") depending on whether graphics blitting
is actually available in the current terminal.
-}
module Termtab.UI.Widgets.TrackPanel (renderTrackPanel, focusedTrackAttr) where

import Brick
import Data.Map.Strict qualified as Map
import Data.Text qualified as T

import Termtab.Types
import Termtab.UI.NotationGraphics (graphicsNotationActive, notationRegionWidget)
import Termtab.UI.Types
import Termtab.UI.Widgets.Notation (renderNotation)
import Termtab.UI.Widgets.Tablature (renderTablature)

-- | Attribute name for a track header when it's the focused track.
focusedTrackAttr :: AttrName
focusedTrackAttr :: AttrName
focusedTrackAttr = String -> AttrName
attrName String
"focusedTrack"

{- | Render one track's panel. A 'Standard' (non-fretted) instrument is
always forced to 'NotationOnly' regardless of its stored 'DisplayMode'
(there's no tab to show for it); every other track respects
'asDisplayModes', falling back to 'defaultModeFor' if the track has no
entry there yet.
-}
renderTrackPanel :: AppState -> TrackIndex -> Track -> Widget ResourceName
renderTrackPanel :: AppState -> TrackIndex -> Track -> Widget ResourceName
renderTrackPanel AppState
st TrackIndex
tIdx Track
track =
    let TrackIndex Int
i = TrackIndex
tIdx
        label :: String
label = String
"Track " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack (Track -> Text
trackName Track
track)
        isFocused :: Bool
isFocused = TrackIndex
tIdx TrackIndex -> TrackIndex -> Bool
forall a. Eq a => a -> a -> Bool
== AppState -> TrackIndex
asCurrentTrack AppState
st
        header :: Widget n
header =
            if Bool
isFocused
                then AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
withAttr AttrName
focusedTrackAttr (String -> Widget n
forall n. String -> Widget n
str String
label)
                else String -> Widget n
forall n. String -> Widget n
str String
label
        mode :: DisplayMode
mode = DisplayMode
-> TrackIndex -> Map TrackIndex DisplayMode -> DisplayMode
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault (Track -> DisplayMode
defaultModeFor Track
track) TrackIndex
tIdx (AppState -> Map TrackIndex DisplayMode
asDisplayModes AppState
st)
        effectiveMode :: DisplayMode
effectiveMode = case Track -> Instrument
trackInstrument Track
track of
            Standard MidiProgram
_ -> DisplayMode
NotationOnly
            Instrument
_ -> DisplayMode
mode
        -- Prefer the rasterized Bravura image (Kitty): reserve a blank region the
        -- image is blitted over; otherwise fall back to the Unicode text staff.
        notation :: Widget ResourceName
notation
            | AppState -> Bool
graphicsNotationActive AppState
st = TrackIndex -> Widget ResourceName
notationRegionWidget TrackIndex
tIdx
            | Bool
otherwise = AppState -> TrackIndex -> Widget ResourceName
renderNotation AppState
st TrackIndex
tIdx
        content :: Widget ResourceName
content = case DisplayMode
effectiveMode of
            DisplayMode
TabOnly -> AppState -> TrackIndex -> Widget ResourceName
renderTablature AppState
st TrackIndex
tIdx
            DisplayMode
NotationOnly -> Widget ResourceName
notation
            DisplayMode
TabAndNotation ->
                [Widget ResourceName] -> Widget ResourceName
forall n. [Widget n] -> Widget n
vBox
                    [ Widget ResourceName
notation
                    , AppState -> TrackIndex -> Widget ResourceName
renderTablature AppState
st TrackIndex
tIdx
                    ]
     in [Widget ResourceName] -> Widget ResourceName
forall n. [Widget n] -> Widget n
vBox [Widget ResourceName
forall {n}. Widget n
header, Widget ResourceName
content]

{- | Fallback 'DisplayMode' for a track absent from 'asDisplayModes'.
Differs from 'Termtab.UI.Types.initAppState''s own default
(@TabAndNotation@ for fretted tracks) — this one is only reached if a
track was added after initial state construction and never got an
explicit entry.
-}
defaultModeFor :: Track -> DisplayMode
defaultModeFor :: Track -> DisplayMode
defaultModeFor Track
track = case Track -> Instrument
trackInstrument Track
track of
    Guitar [Pitch]
_ Int
_ -> DisplayMode
TabOnly
    Bass [Pitch]
_ Int
_ -> DisplayMode
TabOnly
    Standard MidiProgram
_ -> DisplayMode
NotationOnly