    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    -- | Slideshows.
    module Game.LambdaHack.Client.UI.Slideshow
      ( FontOverlayMap, maxYofFontOverlayMap
      , KeyOrSlot, MenuSlot, natSlots
      , ButtonWidth(..)
      , KYX, xytranslateKXY, xtranslateKXY, ytranslateKXY, yrenumberKXY
      , OKX, emptyOKX, xytranslateOKX, sideBySideOKX, labDescOKX
      , Slideshow(slideshow), emptySlideshow, unsnocSlideshow, toSlideshow
      , attrLinesToFontMap, menuToSlideshow, wrapOKX, splitOverlay, splitOKX
      , highSlideshow
    #ifdef EXPOSE_INTERNAL
        -- * Internal operations
      , keysOKX, showTable, showNearbyScores
    #endif
      ) where

    import Prelude ()

    import Game.LambdaHack.Core.Prelude

    import           Data.Binary
    import qualified Data.EnumMap.Strict as EM
    import           Data.Time.LocalTime

    import qualified Game.LambdaHack.Client.UI.Key as K
    import           Game.LambdaHack.Client.UI.Msg
    import           Game.LambdaHack.Client.UI.Overlay
    import           Game.LambdaHack.Client.UI.PointUI
    import qualified Game.LambdaHack.Common.HighScore as HighScore
    import qualified Game.LambdaHack.Definition.Color as Color

    type FontOverlayMap = EM.EnumMap DisplayFont Overlay

    maxYofFontOverlayMap :: FontOverlayMap -> Int
    maxYofFontOverlayMap :: EnumMap DisplayFont Overlay -> Int
    maxYofFontOverlayMap EnumMap DisplayFont Overlay
    ovs = [Int] -> Int
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    maximum (Int
    0 Int -> [Int] -> [Int]
    forall a. a -> [a] -> [a]
    : (Overlay -> Int) -> [Overlay] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map Overlay -> Int
    maxYofOverlay (EnumMap DisplayFont Overlay -> [Overlay]
    forall k a. EnumMap k a -> [a]
    EM.elems EnumMap DisplayFont Overlay
    ovs))

    type KeyOrSlot = Either K.KM MenuSlot

    newtype MenuSlot = MenuSlot Int
      deriving (Int -> MenuSlot -> ShowS
    [MenuSlot] -> ShowS
    MenuSlot -> [Char]
    (Int -> MenuSlot -> ShowS)
    -> (MenuSlot -> [Char]) -> ([MenuSlot] -> ShowS) -> Show MenuSlot
    forall a.
    (Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> MenuSlot -> ShowS
    showsPrec :: Int -> MenuSlot -> ShowS
    $cshow :: MenuSlot -> [Char]
    show :: MenuSlot -> [Char]
    $cshowList :: [MenuSlot] -> ShowS
    showList :: [MenuSlot] -> ShowS
    Show, MenuSlot -> MenuSlot -> Bool
    (MenuSlot -> MenuSlot -> Bool)
    -> (MenuSlot -> MenuSlot -> Bool) -> Eq MenuSlot
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: MenuSlot -> MenuSlot -> Bool
    == :: MenuSlot -> MenuSlot -> Bool
    $c/= :: MenuSlot -> MenuSlot -> Bool
    /= :: MenuSlot -> MenuSlot -> Bool
    Eq, Eq MenuSlot
    Eq MenuSlot =>
    (MenuSlot -> MenuSlot -> Ordering)
    -> (MenuSlot -> MenuSlot -> Bool)
    -> (MenuSlot -> MenuSlot -> Bool)
    -> (MenuSlot -> MenuSlot -> Bool)
    -> (MenuSlot -> MenuSlot -> Bool)
    -> (MenuSlot -> MenuSlot -> MenuSlot)
    -> (MenuSlot -> MenuSlot -> MenuSlot)
    -> Ord MenuSlot
    MenuSlot -> MenuSlot -> Bool
    MenuSlot -> MenuSlot -> Ordering
    MenuSlot -> MenuSlot -> MenuSlot
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: MenuSlot -> MenuSlot -> Ordering
    compare :: MenuSlot -> MenuSlot -> Ordering
    $c< :: MenuSlot -> MenuSlot -> Bool
    < :: MenuSlot -> MenuSlot -> Bool
    $c<= :: MenuSlot -> MenuSlot -> Bool
    <= :: MenuSlot -> MenuSlot -> Bool
    $c> :: MenuSlot -> MenuSlot -> Bool
    > :: MenuSlot -> MenuSlot -> Bool
    $c>= :: MenuSlot -> MenuSlot -> Bool
    >= :: MenuSlot -> MenuSlot -> Bool
    $cmax :: MenuSlot -> MenuSlot -> MenuSlot
    max :: MenuSlot -> MenuSlot -> MenuSlot
    $cmin :: MenuSlot -> MenuSlot -> MenuSlot
    min :: MenuSlot -> MenuSlot -> MenuSlot
    Ord, Get MenuSlot
    [MenuSlot] -> Put
    MenuSlot -> Put
    (MenuSlot -> Put)
    -> Get MenuSlot -> ([MenuSlot] -> Put) -> Binary MenuSlot
    forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
    $cput :: MenuSlot -> Put
    put :: MenuSlot -> Put
    $cget :: Get MenuSlot
    get :: Get MenuSlot
    $cputList :: [MenuSlot] -> Put
    putList :: [MenuSlot] -> Put
    Binary, Int -> MenuSlot
    MenuSlot -> Int
    MenuSlot -> [MenuSlot]
    MenuSlot -> MenuSlot
    MenuSlot -> MenuSlot -> [MenuSlot]
    MenuSlot -> MenuSlot -> MenuSlot -> [MenuSlot]
    (MenuSlot -> MenuSlot)
    -> (MenuSlot -> MenuSlot)
    -> (Int -> MenuSlot)
    -> (MenuSlot -> Int)
    -> (MenuSlot -> [MenuSlot])
    -> (MenuSlot -> MenuSlot -> [MenuSlot])
    -> (MenuSlot -> MenuSlot -> [MenuSlot])
    -> (MenuSlot -> MenuSlot -> MenuSlot -> [MenuSlot])
    -> Enum MenuSlot
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: MenuSlot -> MenuSlot
    succ :: MenuSlot -> MenuSlot
    $cpred :: MenuSlot -> MenuSlot
    pred :: MenuSlot -> MenuSlot
    $ctoEnum :: Int -> MenuSlot
    toEnum :: Int -> MenuSlot
    $cfromEnum :: MenuSlot -> Int
    fromEnum :: MenuSlot -> Int
    $cenumFrom :: MenuSlot -> [MenuSlot]
    enumFrom :: MenuSlot -> [MenuSlot]
    $cenumFromThen :: MenuSlot -> MenuSlot -> [MenuSlot]
    enumFromThen :: MenuSlot -> MenuSlot -> [MenuSlot]
    $cenumFromTo :: MenuSlot -> MenuSlot -> [MenuSlot]
    enumFromTo :: MenuSlot -> MenuSlot -> [MenuSlot]
    $cenumFromThenTo :: MenuSlot -> MenuSlot -> MenuSlot -> [MenuSlot]
    enumFromThenTo :: MenuSlot -> MenuSlot -> MenuSlot -> [MenuSlot]
    Enum)

    natSlots :: [MenuSlot]
    {-# INLINE natSlots #-}
    natSlots :: [MenuSlot]
    natSlots = [Int -> MenuSlot
    MenuSlot Int
    0 ..]

    -- TODO: probably best merge the PointUI into that and represent
    -- the position as characters, too, translating to UI positions as needed.
    -- The problem is that then I need to do a lot of reverse translation
    -- when creating buttons.
    -- | Width of on-screen button text, expressed in characters,
    -- and so UI (mono font) width is deduced from the used font.
    data ButtonWidth = ButtonWidth
      { ButtonWidth -> DisplayFont
    buttonFont  :: DisplayFont
      , ButtonWidth -> Int
    buttonWidth :: Int }
      deriving (Int -> ButtonWidth -> ShowS
    [ButtonWidth] -> ShowS
    ButtonWidth -> [Char]
    (Int -> ButtonWidth -> ShowS)
    -> (ButtonWidth -> [Char])
    -> ([ButtonWidth] -> ShowS)
    -> Show ButtonWidth
    forall a.
    (Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> ButtonWidth -> ShowS
    showsPrec :: Int -> ButtonWidth -> ShowS
    $cshow :: ButtonWidth -> [Char]
    show :: ButtonWidth -> [Char]
    $cshowList :: [ButtonWidth] -> ShowS
    showList :: [ButtonWidth] -> ShowS
    Show, ButtonWidth -> ButtonWidth -> Bool
    (ButtonWidth -> ButtonWidth -> Bool)
    -> (ButtonWidth -> ButtonWidth -> Bool) -> Eq ButtonWidth
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: ButtonWidth -> ButtonWidth -> Bool
    == :: ButtonWidth -> ButtonWidth -> Bool
    $c/= :: ButtonWidth -> ButtonWidth -> Bool
    /= :: ButtonWidth -> ButtonWidth -> Bool
    Eq)

    -- | A key or a menu slot at a given position on the screen.
    type KYX = (KeyOrSlot, (PointUI, ButtonWidth))

    xytranslateKXY :: Int -> Int -> KYX -> KYX
    xytranslateKXY :: Int -> Int -> KYX -> KYX
    xytranslateKXY Int
    dx Int
    dy (Either KM MenuSlot
    km, (PointUI Int
    x Int
    y, ButtonWidth
    len)) =
      (Either KM MenuSlot
    km, (Int -> Int -> PointUI
    PointUI (Int
    x Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    dx) (Int
    y Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    dy), ButtonWidth
    len))

    xtranslateKXY :: Int -> KYX -> KYX
    xtranslateKXY :: Int -> KYX -> KYX
    xtranslateKXY Int
    dx = Int -> Int -> KYX -> KYX
    xytranslateKXY Int
    dx Int
    0

    ytranslateKXY :: Int -> KYX -> KYX
    ytranslateKXY :: Int -> KYX -> KYX
    ytranslateKXY = Int -> Int -> KYX -> KYX
    xytranslateKXY Int
    0

    yrenumberKXY :: Int -> KYX -> KYX
    yrenumberKXY :: Int -> KYX -> KYX
    yrenumberKXY Int
    ynew (Either KM MenuSlot
    km, (PointUI Int
    x Int
    _, ButtonWidth
    len)) = (Either KM MenuSlot
    km, (Int -> Int -> PointUI
    PointUI Int
    x Int
    ynew, ButtonWidth
    len))

    -- | An Overlay of text with an associated list of keys or slots
    -- that activate when the specified screen position is pointed at.
    -- The list should be sorted wrt rows and then columns.
    type OKX = (FontOverlayMap, [KYX])

    emptyOKX :: OKX
    emptyOKX :: OKX
    emptyOKX = (EnumMap DisplayFont Overlay
    forall k a. EnumMap k a
    EM.empty, [])

    xytranslateOKX ::Int -> Int -> OKX -> OKX
    xytranslateOKX :: Int -> Int -> OKX -> OKX
    xytranslateOKX Int
    dx Int
    dy (EnumMap DisplayFont Overlay
    ovs, [KYX]
    kyxs) =
      ( (Overlay -> Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
    EM.map (Int -> Int -> Overlay -> Overlay
    xytranslateOverlay Int
    dx Int
    dy) EnumMap DisplayFont Overlay
    ovs
      , (KYX -> KYX) -> [KYX] -> [KYX]
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> Int -> KYX -> KYX
    xytranslateKXY Int
    dx Int
    dy) [KYX]
    kyxs )

    sideBySideOKX :: Int -> Int -> OKX -> OKX -> OKX
    sideBySideOKX :: Int -> Int -> OKX -> OKX -> OKX
    sideBySideOKX Int
    dx Int
    dy (EnumMap DisplayFont Overlay
    ovs1, [KYX]
    kyxs1) (EnumMap DisplayFont Overlay
    ovs2, [KYX]
    kyxs2) =
      let (EnumMap DisplayFont Overlay
    ovs3, [KYX]
    kyxs3) = Int -> Int -> OKX -> OKX
    xytranslateOKX Int
    dx Int
    dy (EnumMap DisplayFont Overlay
    ovs2, [KYX]
    kyxs2)
      in ( (Overlay -> Overlay -> Overlay)
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall a k.
    (a -> a -> a) -> EnumMap k a -> EnumMap k a -> EnumMap k a
    EM.unionWith Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    (++) EnumMap DisplayFont Overlay
    ovs1 EnumMap DisplayFont Overlay
    ovs3
         , (KYX -> (Int, Int)) -> [KYX] -> [KYX]
    forall b a. Ord b => (a -> b) -> [a] -> [a]
    sortOn (\(Either KM MenuSlot
    _, (PointUI Int
    x Int
    y, ButtonWidth
    _)) -> (Int
    y, Int
    x)) ([KYX] -> [KYX]) -> [KYX] -> [KYX]
    forall a b. (a -> b) -> a -> b
    $ [KYX]
    kyxs1 [KYX] -> [KYX] -> [KYX]
    forall a. [a] -> [a] -> [a]
    ++ [KYX]
    kyxs3 )

    -- The bangs are to free the possibly very long input list ASAP.
    labDescOKX :: DisplayFont -> DisplayFont
               -> [(AttrString, AttrString, KeyOrSlot)]
               -> OKX
    labDescOKX :: DisplayFont
    -> DisplayFont
    -> [(AttrString, AttrString, Either KM MenuSlot)]
    -> OKX
    labDescOKX DisplayFont
    labFont DisplayFont
    descFont [(AttrString, AttrString, Either KM MenuSlot)]
    l =
      let descFontSize :: AttrString -> Int
    descFontSize | DisplayFont -> Bool
    isPropFont DisplayFont
    descFont = AttrString -> Int
    forall a. [a] -> Int
    length  -- may be less or a bit more
                       | Bool
    otherwise = DisplayFont -> AttrString -> Int
    forall a. DisplayFont -> [a] -> Int
    textSize DisplayFont
    descFont
          processRow :: (AttrString, AttrString, KeyOrSlot)
                     -> (AttrLine, (Int, AttrLine), KYX)
          processRow :: (AttrString, AttrString, Either KM MenuSlot)
    -> (AttrLine, (Int, AttrLine), KYX)
    processRow (!AttrString
    tLab, !AttrString
    tDesc, !Either KM MenuSlot
    ekm) =
            let labLen :: Int
    labLen = DisplayFont -> AttrString -> Int
    forall a. DisplayFont -> [a] -> Int
    textSize DisplayFont
    labFont AttrString
    tLab
                lenButton :: Int
    lenButton = Int
    labLen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + AttrString -> Int
    descFontSize AttrString
    tDesc
            in ( AttrString -> AttrLine
    attrStringToAL AttrString
    tLab
               , (Int
    labLen, AttrString -> AttrLine
    attrStringToAL AttrString
    tDesc)
               , (Either KM MenuSlot
    ekm, (Int -> Int -> PointUI
    PointUI Int
    0 Int
    0, DisplayFont -> Int -> ButtonWidth
    ButtonWidth DisplayFont
    descFont Int
    lenButton)) )
          ([AttrLine]
    tsLab, [(Int, AttrLine)]
    tsDesc, [KYX]
    kxs) = [(AttrLine, (Int, AttrLine), KYX)]
    -> ([AttrLine], [(Int, AttrLine)], [KYX])
    forall a b c. [(a, b, c)] -> ([a], [b], [c])
    unzip3 ([(AttrLine, (Int, AttrLine), KYX)]
     -> ([AttrLine], [(Int, AttrLine)], [KYX]))
    -> [(AttrLine, (Int, AttrLine), KYX)]
    -> ([AttrLine], [(Int, AttrLine)], [KYX])
    forall a b. (a -> b) -> a -> b
    $ ((AttrString, AttrString, Either KM MenuSlot)
     -> (AttrLine, (Int, AttrLine), KYX))
    -> [(AttrString, AttrString, Either KM MenuSlot)]
    -> [(AttrLine, (Int, AttrLine), KYX)]
    forall a b. (a -> b) -> [a] -> [b]
    map (AttrString, AttrString, Either KM MenuSlot)
    -> (AttrLine, (Int, AttrLine), KYX)
    processRow [(AttrString, AttrString, Either KM MenuSlot)]
    l
          ovs :: EnumMap DisplayFont Overlay
    ovs = (Overlay -> Overlay -> Overlay)
    -> DisplayFont
    -> Overlay
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall k a.
    Enum k =>
    (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
    EM.insertWith Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    (++) DisplayFont
    labFont ([AttrLine] -> Overlay
    offsetOverlay [AttrLine]
    tsLab)
                (EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall a b. (a -> b) -> a -> b
    $ DisplayFont -> Overlay -> EnumMap DisplayFont Overlay
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton DisplayFont
    descFont (Overlay -> EnumMap DisplayFont Overlay)
    -> Overlay -> EnumMap DisplayFont Overlay
    forall a b. (a -> b) -> a -> b
    $ [(Int, AttrLine)] -> Overlay
    offsetOverlayX [(Int, AttrLine)]
    tsDesc
      in (EnumMap DisplayFont Overlay
    ovs, (Int -> KYX -> KYX) -> [Int] -> [KYX] -> [KYX]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Int -> KYX -> KYX
    yrenumberKXY [Int
    0..] [KYX]
    kxs)

    -- | A list of active screenfulls to be shown one after another.
    -- Each screenful has an independent numbering of rows and columns.
    newtype Slideshow = Slideshow {Slideshow -> [OKX]
    slideshow :: [OKX]}
      deriving (Int -> Slideshow -> ShowS
    [Slideshow] -> ShowS
    Slideshow -> [Char]
    (Int -> Slideshow -> ShowS)
    -> (Slideshow -> [Char])
    -> ([Slideshow] -> ShowS)
    -> Show Slideshow
    forall a.
    (Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Slideshow -> ShowS
    showsPrec :: Int -> Slideshow -> ShowS
    $cshow :: Slideshow -> [Char]
    show :: Slideshow -> [Char]
    $cshowList :: [Slideshow] -> ShowS
    showList :: [Slideshow] -> ShowS
    Show, Slideshow -> Slideshow -> Bool
    (Slideshow -> Slideshow -> Bool)
    -> (Slideshow -> Slideshow -> Bool) -> Eq Slideshow
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Slideshow -> Slideshow -> Bool
    == :: Slideshow -> Slideshow -> Bool
    $c/= :: Slideshow -> Slideshow -> Bool
    /= :: Slideshow -> Slideshow -> Bool
    Eq)

    emptySlideshow :: Slideshow
    emptySlideshow :: Slideshow
    emptySlideshow = [OKX] -> Slideshow
    Slideshow []

    unsnocSlideshow :: Slideshow -> Maybe (Slideshow, OKX)
    unsnocSlideshow :: Slideshow -> Maybe (Slideshow, OKX)
    unsnocSlideshow Slideshow{[OKX]
    slideshow :: Slideshow -> [OKX]
    slideshow :: [OKX]
    slideshow} =
      case [OKX] -> [OKX]
    forall a. [a] -> [a]
    reverse [OKX]
    slideshow of
        [] -> Maybe (Slideshow, OKX)
    forall a. Maybe a
    Nothing
        OKX
    okx : [OKX]
    rest -> (Slideshow, OKX) -> Maybe (Slideshow, OKX)
    forall a. a -> Maybe a
    Just ([OKX] -> Slideshow
    Slideshow ([OKX] -> Slideshow) -> [OKX] -> Slideshow
    forall a b. (a -> b) -> a -> b
    $ [OKX] -> [OKX]
    forall a. [a] -> [a]
    reverse [OKX]
    rest, OKX
    okx)

    toSlideshow :: FontSetup -> Bool -> [OKX] -> Slideshow
    toSlideshow :: FontSetup -> Bool -> [OKX] -> Slideshow
    toSlideshow FontSetup{DisplayFont
    squareFont :: DisplayFont
    monoFont :: DisplayFont
    propFont :: DisplayFont
    propFont :: FontSetup -> DisplayFont
    monoFont :: FontSetup -> DisplayFont
    squareFont :: FontSetup -> DisplayFont
    ..}Bool
    displayTutorialHints [OKX]
    okxs =
      [OKX] -> Slideshow
    Slideshow ([OKX] -> Slideshow) -> [OKX] -> Slideshow
    forall a b. (a -> b) -> a -> b
    $ Bool -> [OKX] -> [OKX]
    addFooters Bool
    False [OKX]
    okxs
     where
      atEnd :: [a] -> [a] -> [a]
    atEnd = ([a] -> [a] -> [a]) -> [a] -> [a] -> [a]
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip [a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    (++)
      appendToFontOverlayMap :: FontOverlayMap -> String
                             -> (FontOverlayMap, PointUI, DisplayFont, Int)
      appendToFontOverlayMap :: EnumMap DisplayFont Overlay
    -> [Char]
    -> (EnumMap DisplayFont Overlay, PointUI, DisplayFont, Int)
    appendToFontOverlayMap EnumMap DisplayFont Overlay
    ovs [Char]
    msgPrefix =
        let msg :: [Char]
    msg | Bool
    displayTutorialHints =
                  [Char]
    msgPrefix
                  [Char] -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    "  (ESC to exit, PGUP, HOME, mouse, wheel, arrows, etc.)"
                | Bool
    otherwise = [Char]
    msgPrefix
            maxYminXofOverlay :: [(PointUI, b)] -> (Int, Int)
    maxYminXofOverlay [(PointUI, b)]
    ov =
              let ymxOfOverlay :: (PointUI, b) -> (Int, Int)
    ymxOfOverlay (PointUI Int
    x Int
    y, b
    _) = (- Int
    y, Int
    x)
              in [(Int, Int)] -> (Int, Int)
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    minimum ([(Int, Int)] -> (Int, Int)) -> [(Int, Int)] -> (Int, Int)
    forall a b. (a -> b) -> a -> b
    $ (Int, Int)
    forall a. Bounded a => a
    maxBound (Int, Int) -> [(Int, Int)] -> [(Int, Int)]
    forall a. a -> [a] -> [a]
    : ((PointUI, b) -> (Int, Int)) -> [(PointUI, b)] -> [(Int, Int)]
    forall a b. (a -> b) -> [a] -> [b]
    map (PointUI, b) -> (Int, Int)
    forall {b}. (PointUI, b) -> (Int, Int)
    ymxOfOverlay [(PointUI, b)]
    ov
            -- @sortOn@ less efficient here, because function cheap.
            assocsYX :: [(DisplayFont, (Int, Int))]
    assocsYX = ((DisplayFont, (Int, Int))
     -> (DisplayFont, (Int, Int)) -> Ordering)
    -> [(DisplayFont, (Int, Int))] -> [(DisplayFont, (Int, Int))]
    forall a. (a -> a -> Ordering) -> [a] -> [a]
    sortBy (((DisplayFont, (Int, Int)) -> (Int, Int))
    -> (DisplayFont, (Int, Int))
    -> (DisplayFont, (Int, Int))
    -> Ordering
    forall a b. Ord a => (b -> a) -> b -> b -> Ordering
    comparing (DisplayFont, (Int, Int)) -> (Int, Int)
    forall a b. (a, b) -> b
    snd)
                       ([(DisplayFont, (Int, Int))] -> [(DisplayFont, (Int, Int))])
    -> [(DisplayFont, (Int, Int))] -> [(DisplayFont, (Int, Int))]
    forall a b. (a -> b) -> a -> b
    $ EnumMap DisplayFont (Int, Int) -> [(DisplayFont, (Int, Int))]
    forall k a. Enum k => EnumMap k a -> [(k, a)]
    EM.assocs (EnumMap DisplayFont (Int, Int) -> [(DisplayFont, (Int, Int))])
    -> EnumMap DisplayFont (Int, Int) -> [(DisplayFont, (Int, Int))]
    forall a b. (a -> b) -> a -> b
    $ (Overlay -> (Int, Int))
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont (Int, Int)
    forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
    EM.map Overlay -> (Int, Int)
    forall {b}. [(PointUI, b)] -> (Int, Int)
    maxYminXofOverlay EnumMap DisplayFont Overlay
    ovs
            (DisplayFont
    fontMax, Int
    yMax) = case [(DisplayFont, (Int, Int))]
    assocsYX of
              [] -> (DisplayFont
    monoFont, Int
    0)
              (DisplayFont
    font, (Int
    yNeg, Int
    _x)) : [(DisplayFont, (Int, Int))]
    rest ->
                let unique :: Bool
    unique = ((DisplayFont, (Int, Int)) -> Bool)
    -> [(DisplayFont, (Int, Int))] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (\(DisplayFont
    _, (Int
    yNeg2, Int
    _)) -> Int
    yNeg Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    yNeg2) [(DisplayFont, (Int, Int))]
    rest
                in ( if DisplayFont -> Bool
    isSquareFont DisplayFont
    font Bool -> Bool -> Bool
    && Bool
    unique
                     then DisplayFont
    font
                     else DisplayFont
    monoFont
                   , - Int
    yNeg )
            pMax :: PointUI
    pMax = Int -> Int -> PointUI
    PointUI Int
    0 (Int
    yMax Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1)  -- append after last line
        in ( (Overlay -> Overlay -> Overlay)
    -> DisplayFont
    -> Overlay
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall k a.
    Enum k =>
    (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
    EM.insertWith Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    atEnd DisplayFont
    fontMax [(PointUI
    pMax, [Char] -> AttrLine
    stringToAL [Char]
    msg)] EnumMap DisplayFont Overlay
    ovs
           , PointUI
    pMax
           , DisplayFont
    fontMax
           , [Char] -> Int
    forall a. [a] -> Int
    length [Char]
    msg )
      addFooters :: Bool -> [OKX] -> [OKX]
      addFooters :: Bool -> [OKX] -> [OKX]
    addFooters Bool
    _ [] = [Char] -> [OKX]
    forall a. (?callStack::CallStack) => [Char] -> a
    error ([Char] -> [OKX]) -> [Char] -> [OKX]
    forall a b. (a -> b) -> a -> b
    $ [Char]
    "" [Char] -> [OKX] -> [Char]
    forall v. Show v => [Char] -> v -> [Char]
    `showFailure` [OKX]
    okxs
      addFooters Bool
    _ [(EnumMap DisplayFont Overlay
    als, [])] =
        -- TODO: make sure this case never coincides with the space button
        -- actually returning to top, as opposed to finishing preview.
        let (EnumMap DisplayFont Overlay
    ovs, PointUI
    p, DisplayFont
    font, Int
    width) = EnumMap DisplayFont Overlay
    -> [Char]
    -> (EnumMap DisplayFont Overlay, PointUI, DisplayFont, Int)
    appendToFontOverlayMap EnumMap DisplayFont Overlay
    als [Char]
    "--end--"
        in [(EnumMap DisplayFont Overlay
    ovs, [(KM -> Either KM MenuSlot
    forall a b. a -> Either a b
    Left KM
    K.safeSpaceKM, (PointUI
    p, DisplayFont -> Int -> ButtonWidth
    ButtonWidth DisplayFont
    font Int
    width))])]
      addFooters Bool
    False [(EnumMap DisplayFont Overlay
    als, [KYX]
    kxs)] = [(EnumMap DisplayFont Overlay
    als, [KYX]
    kxs)]
      addFooters Bool
    True [(EnumMap DisplayFont Overlay
    als, [KYX]
    kxs)] =
        let (EnumMap DisplayFont Overlay
    ovs, PointUI
    p, DisplayFont
    font, Int
    width) = EnumMap DisplayFont Overlay
    -> [Char]
    -> (EnumMap DisplayFont Overlay, PointUI, DisplayFont, Int)
    appendToFontOverlayMap EnumMap DisplayFont Overlay
    als [Char]
    "--back to top--"
        in [(EnumMap DisplayFont Overlay
    ovs, [KYX]
    kxs [KYX] -> [KYX] -> [KYX]
    forall a. [a] -> [a] -> [a]
    ++ [(KM -> Either KM MenuSlot
    forall a b. a -> Either a b
    Left KM
    K.safeSpaceKM, (PointUI
    p, DisplayFont -> Int -> ButtonWidth
    ButtonWidth DisplayFont
    font Int
    width))])]
      addFooters Bool
    _ ((EnumMap DisplayFont Overlay
    als, [KYX]
    kxs) : [OKX]
    rest) =
        let (EnumMap DisplayFont Overlay
    ovs, PointUI
    p, DisplayFont
    font, Int
    width) = EnumMap DisplayFont Overlay
    -> [Char]
    -> (EnumMap DisplayFont Overlay, PointUI, DisplayFont, Int)
    appendToFontOverlayMap EnumMap DisplayFont Overlay
    als [Char]
    "--more--"
        in (EnumMap DisplayFont Overlay
    ovs, [KYX]
    kxs [KYX] -> [KYX] -> [KYX]
    forall a. [a] -> [a] -> [a]
    ++ [(KM -> Either KM MenuSlot
    forall a b. a -> Either a b
    Left KM
    K.safeSpaceKM, (PointUI
    p, DisplayFont -> Int -> ButtonWidth
    ButtonWidth DisplayFont
    font Int
    width))])
           OKX -> [OKX] -> [OKX]
    forall a. a -> [a] -> [a]
    : Bool -> [OKX] -> [OKX]
    addFooters Bool
    True [OKX]
    rest

    -- | This appends vertically a list of blurbs into a single font overlay map.
    -- Not to be used if some blurbs need to be places overlapping vertically,
    -- e.g., when the square font symbol needs to be in the same line
    -- as the start of the descritpion of the denoted item
    -- or when mono font buttons need to be after a prompt.
    attrLinesToFontMap :: [(DisplayFont, [AttrLine])] -> FontOverlayMap
    attrLinesToFontMap :: [(DisplayFont, [AttrLine])] -> EnumMap DisplayFont Overlay
    attrLinesToFontMap [(DisplayFont, [AttrLine])]
    blurb =
      let zipAttrLines :: Int -> [AttrLine] -> (Overlay, Int)
          zipAttrLines :: Int -> [AttrLine] -> (Overlay, Int)
    zipAttrLines Int
    start [AttrLine]
    als =
            ( (Int -> AttrLine -> (PointUI, AttrLine))
    -> [Int] -> [AttrLine] -> Overlay
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith (((Int, AttrLine) -> (PointUI, AttrLine))
    -> Int -> AttrLine -> (PointUI, AttrLine)
    forall a b c. ((a, b) -> c) -> a -> b -> c
    curry ((Int -> PointUI) -> (Int, AttrLine) -> (PointUI, AttrLine)
    forall b c d. (b -> c) -> (b, d) -> (c, d)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (b, d) (c, d)
    first ((Int -> PointUI) -> (Int, AttrLine) -> (PointUI, AttrLine))
    -> (Int -> PointUI) -> (Int, AttrLine) -> (PointUI, AttrLine)
    forall a b. (a -> b) -> a -> b
    $ Int -> Int -> PointUI
    PointUI Int
    0)) [Int
    start ..] [AttrLine]
    als
            , Int
    start Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + [AttrLine] -> Int
    forall a. [a] -> Int
    length [AttrLine]
    als )
          addOverlay :: (FontOverlayMap, Int) -> (DisplayFont, [AttrLine])
                     -> (FontOverlayMap, Int)
          addOverlay :: (EnumMap DisplayFont Overlay, Int)
    -> (DisplayFont, [AttrLine]) -> (EnumMap DisplayFont Overlay, Int)
    addOverlay (!EnumMap DisplayFont Overlay
    em, !Int
    start) (DisplayFont
    font, [AttrLine]
    als) =
            let (Overlay
    als2, Int
    start2) = Int -> [AttrLine] -> (Overlay, Int)
    zipAttrLines Int
    start [AttrLine]
    als
            in ( (Overlay -> Overlay -> Overlay)
    -> DisplayFont
    -> Overlay
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall k a.
    Enum k =>
    (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
    EM.insertWith Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    (++) DisplayFont
    font Overlay
    als2 EnumMap DisplayFont Overlay
    em
               , Int
    start2 )
          (EnumMap DisplayFont Overlay
    ov, Int
    _) = ((EnumMap DisplayFont Overlay, Int)
     -> (DisplayFont, [AttrLine]) -> (EnumMap DisplayFont Overlay, Int))
    -> (EnumMap DisplayFont Overlay, Int)
    -> [(DisplayFont, [AttrLine])]
    -> (EnumMap DisplayFont Overlay, Int)
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (EnumMap DisplayFont Overlay, Int)
    -> (DisplayFont, [AttrLine]) -> (EnumMap DisplayFont Overlay, Int)
    addOverlay (EnumMap DisplayFont Overlay
    forall k a. EnumMap k a
    EM.empty, Int
    0) [(DisplayFont, [AttrLine])]
    blurb
      in EnumMap DisplayFont Overlay
    ov

    menuToSlideshow :: OKX -> Slideshow
    menuToSlideshow :: OKX -> Slideshow
    menuToSlideshow (EnumMap DisplayFont Overlay
    als, [KYX]
    kxs) =
      Bool -> Slideshow -> Slideshow
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert (Bool -> Bool
    not (EnumMap DisplayFont Overlay -> Bool
    forall k a. EnumMap k a -> Bool
    EM.null EnumMap DisplayFont Overlay
    als Bool -> Bool -> Bool
    || [KYX] -> Bool
    forall a. [a] -> Bool
    null [KYX]
    kxs)) (Slideshow -> Slideshow) -> Slideshow -> Slideshow
    forall a b. (a -> b) -> a -> b
    $ [OKX] -> Slideshow
    Slideshow [(EnumMap DisplayFont Overlay
    als, [KYX]
    kxs)]

    wrapOKX :: DisplayFont -> Int -> Int -> Int -> [(K.KM, String)]
            -> (Overlay, [KYX])
    wrapOKX :: DisplayFont
    -> Int -> Int -> Int -> [(KM, [Char])] -> (Overlay, [KYX])
    wrapOKX DisplayFont
    _ Int
    _ Int
    _ Int
    _ [] = ([], [])
    wrapOKX DisplayFont
    displayFont Int
    ystart Int
    xstart Int
    width [(KM, [Char])]
    ks =
      let overlayLineFromStrings :: Int -> Int -> [String] -> (PointUI, AttrLine)
          overlayLineFromStrings :: Int -> Int -> [[Char]] -> (PointUI, AttrLine)
    overlayLineFromStrings Int
    xlineStart Int
    y [[Char]]
    strings =
            let p :: PointUI
    p = Int -> Int -> PointUI
    PointUI Int
    xlineStart Int
    y
            in (PointUI
    p, [Char] -> AttrLine
    stringToAL ([Char] -> AttrLine) -> [Char] -> AttrLine
    forall a b. (a -> b) -> a -> b
    $ [[Char]] -> [Char]
    unwords ([[Char]] -> [[Char]]
    forall a. [a] -> [a]
    reverse [[Char]]
    strings))
          f :: ((Int, Int), (Int, [String], Overlay, [KYX])) -> (K.KM, String)
            -> ((Int, Int), (Int, [String], Overlay, [KYX]))
          f :: ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    -> (KM, [Char]) -> ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    f ((Int
    y, Int
    x), (Int
    xlineStart, [[Char]]
    kL, Overlay
    kV, [KYX]
    kX)) (KM
    key, [Char]
    s) =
            let len :: Int
    len = DisplayFont -> [Char] -> Int
    forall a. DisplayFont -> [a] -> Int
    textSize DisplayFont
    displayFont [Char]
    s
                len1 :: Int
    len1 = Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + DisplayFont -> [Char] -> Int
    forall a. DisplayFont -> [a] -> Int
    textSize DisplayFont
    displayFont [Char]
    " "
            in if Int
    x Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    len Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    width
               then let iov :: (PointUI, AttrLine)
    iov = Int -> Int -> [[Char]] -> (PointUI, AttrLine)
    overlayLineFromStrings Int
    xlineStart Int
    y [[Char]]
    kL
                    in ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    -> (KM, [Char]) -> ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    f ((Int
    y Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1, Int
    0), (Int
    0, [], (PointUI, AttrLine)
    iov (PointUI, AttrLine) -> Overlay -> Overlay
    forall a. a -> [a] -> [a]
    : Overlay
    kV, [KYX]
    kX)) (KM
    key, [Char]
    s)
               else ( (Int
    y, Int
    x Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    len1)
                    , ( Int
    xlineStart
                      , [Char]
    s [Char] -> [[Char]] -> [[Char]]
    forall a. a -> [a] -> [a]
    : [[Char]]
    kL
                      , Overlay
    kV
                      , (KM -> Either KM MenuSlot
    forall a b. a -> Either a b
    Left KM
    key, ( Int -> Int -> PointUI
    PointUI Int
    x Int
    y
                                   , DisplayFont -> Int -> ButtonWidth
    ButtonWidth DisplayFont
    displayFont ([Char] -> Int
    forall a. [a] -> Int
    length [Char]
    s) ))
                        KYX -> [KYX] -> [KYX]
    forall a. a -> [a] -> [a]
    : [KYX]
    kX ) )
          ((Int
    ystop, Int
    _), (Int
    xlineStop, [[Char]]
    kL1, Overlay
    kV1, [KYX]
    kX1)) =
            (((Int, Int), (Int, [[Char]], Overlay, [KYX]))
     -> (KM, [Char]) -> ((Int, Int), (Int, [[Char]], Overlay, [KYX])))
    -> ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    -> [(KM, [Char])]
    -> ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    -> (KM, [Char]) -> ((Int, Int), (Int, [[Char]], Overlay, [KYX]))
    f ((Int
    ystart, Int
    xstart), (Int
    xstart, [], [], [])) [(KM, [Char])]
    ks
          iov1 :: (PointUI, AttrLine)
    iov1 = Int -> Int -> [[Char]] -> (PointUI, AttrLine)
    overlayLineFromStrings Int
    xlineStop Int
    ystop [[Char]]
    kL1
      in (Overlay -> Overlay
    forall a. [a] -> [a]
    reverse (Overlay -> Overlay) -> Overlay -> Overlay
    forall a b. (a -> b) -> a -> b
    $ (PointUI, AttrLine)
    iov1 (PointUI, AttrLine) -> Overlay -> Overlay
    forall a. a -> [a] -> [a]
    : Overlay
    kV1, [KYX] -> [KYX]
    forall a. [a] -> [a]
    reverse [KYX]
    kX1)

    keysOKX :: DisplayFont -> Int -> Int -> Int -> [K.KM] -> (Overlay, [KYX])
    keysOKX :: DisplayFont -> Int -> Int -> Int -> [KM] -> (Overlay, [KYX])
    keysOKX DisplayFont
    displayFont Int
    ystart Int
    xstart Int
    width [KM]
    keys =
      let wrapB :: String -> String
          wrapB :: ShowS
    wrapB [Char]
    s = [Char]
    "[" [Char] -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    s [Char] -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    "]"
          ks :: [(KM, [Char])]
    ks = (KM -> (KM, [Char])) -> [KM] -> [(KM, [Char])]
    forall a b. (a -> b) -> [a] -> [b]
    map (\KM
    key -> (KM
    key, ShowS
    wrapB ShowS -> ShowS
    forall a b. (a -> b) -> a -> b
    $ KM -> [Char]
    K.showKM KM
    key)) [KM]
    keys
      in DisplayFont
    -> Int -> Int -> Int -> [(KM, [Char])] -> (Overlay, [KYX])
    wrapOKX DisplayFont
    displayFont Int
    ystart Int
    xstart Int
    width [(KM, [Char])]
    ks

    -- The font argument is for the report and keys overlay. Others already have
    -- assigned fonts.
    splitOverlay :: FontSetup -> Bool -> Int -> Int -> Int -> Report -> [K.KM]
                 -> OKX
                 -> Slideshow
    splitOverlay :: FontSetup
    -> Bool -> Int -> Int -> Int -> Report -> [KM] -> OKX -> Slideshow
    splitOverlay FontSetup
    fontSetup Bool
    displayTutorialHints
                 Int
    width Int
    height Int
    wrap Report
    report [KM]
    keys (EnumMap DisplayFont Overlay
    ls0, [KYX]
    kxs0) =
      let renderedReport :: [AttrString]
    renderedReport = Bool -> Report -> [AttrString]
    renderReport Bool
    True Report
    report
          reportAS :: AttrString
    reportAS = (AttrString -> AttrString -> AttrString)
    -> AttrString -> [AttrString] -> AttrString
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr AttrString -> AttrString -> AttrString
    (<\:>) [] [AttrString]
    renderedReport
      in FontSetup -> Bool -> [OKX] -> Slideshow
    toSlideshow FontSetup
    fontSetup Bool
    displayTutorialHints ([OKX] -> Slideshow) -> [OKX] -> Slideshow
    forall a b. (a -> b) -> a -> b
    $
           FontSetup
    -> Bool -> Int -> Int -> Int -> AttrString -> [KM] -> OKX -> [OKX]
    splitOKX FontSetup
    fontSetup Bool
    False Int
    width Int
    height Int
    wrap AttrString
    reportAS [KM]
    keys (EnumMap DisplayFont Overlay
    ls0, [KYX]
    kxs0)

    -- Note that we only split wrt @White@ space, nothing else.
    splitOKX :: FontSetup -> Bool -> Int -> Int -> Int -> AttrString -> [K.KM]
             -> OKX
             -> [OKX]
    splitOKX :: FontSetup
    -> Bool -> Int -> Int -> Int -> AttrString -> [KM] -> OKX -> [OKX]
    splitOKX FontSetup{DisplayFont
    propFont :: FontSetup -> DisplayFont
    monoFont :: FontSetup -> DisplayFont
    squareFont :: FontSetup -> DisplayFont
    squareFont :: DisplayFont
    monoFont :: DisplayFont
    propFont :: DisplayFont
    ..} Bool
    msgLong Int
    width Int
    height Int
    wrap AttrString
    reportAS [KM]
    keys (EnumMap DisplayFont Overlay
    ls0, [KYX]
    kxs0) =
      Bool -> [OKX] -> [OKX]
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert (Int
    width Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    2 Bool -> Bool -> Bool
    && Int
    height Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    2) ([OKX] -> [OKX]) -> [OKX] -> [OKX]
    forall a b. (a -> b) -> a -> b
    $
        -- if the strings to split are long these minimums won't be enough,
        -- but content validation ensures larger values (perhaps large enough?)
      let reportParagraphs :: [AttrLine]
    reportParagraphs = AttrString -> [AttrLine]
    linesAttr AttrString
    reportAS
          -- TODO: until SDL support for measuring prop font text is released,
          -- we have to use MonoFont for the paragraph that ends with buttons.
          ([AttrLine]
    repProp, AttrLine
    repMono) =
            if [KM] -> Bool
    forall a. [a] -> Bool
    null [KM]
    keys
            then ([AttrLine]
    reportParagraphs, AttrLine
    emptyAttrLine)
            else case [AttrLine] -> [AttrLine]
    forall a. [a] -> [a]
    reverse [AttrLine]
    reportParagraphs of
              [] -> ([], AttrLine
    emptyAttrLine)
              AttrLine
    l : [AttrLine]
    rest ->
                ([AttrLine] -> [AttrLine]
    forall a. [a] -> [a]
    reverse [AttrLine]
    rest, AttrString -> AttrLine
    attrStringToAL (AttrString -> AttrLine) -> AttrString -> AttrLine
    forall a b. (a -> b) -> a -> b
    $ AttrLine -> AttrString
    attrLine AttrLine
    l AttrString -> AttrString -> AttrString
    forall a. [a] -> [a] -> [a]
    ++ [AttrCharW32
    Color.nbspAttrW32])
          msgWrap :: Int
    msgWrap = if Bool
    msgLong Bool -> Bool -> Bool
    && Bool -> Bool
    not (DisplayFont -> Bool
    isSquareFont DisplayFont
    propFont)
                    then Int
    2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    width
                    else Int
    wrap  -- TODO if with width fits on one screen, use it
          msgWidth :: Int
    msgWidth = if Bool
    msgLong Bool -> Bool -> Bool
    && Bool -> Bool
    not (DisplayFont -> Bool
    isSquareFont DisplayFont
    propFont)
                     then Int
    2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    width
                     else Int
    width
          repProp0 :: Overlay
    repProp0 = [AttrLine] -> Overlay
    offsetOverlay ([AttrLine] -> Overlay) -> [AttrLine] -> Overlay
    forall a b. (a -> b) -> a -> b
    $ case [AttrLine]
    repProp of
            [] -> []
            AttrLine
    r : [AttrLine]
    rs ->
              -- Make lines of first paragraph long if it has 2 lines at most.
              -- The first line does not obscure anything and the second line
              -- is often short anyway.
              let firstWidth :: Int
    firstWidth = if AttrString -> Int
    forall a. [a] -> Int
    length (AttrLine -> AttrString
    attrLine AttrLine
    r) Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    msgWidth
                               then Int
    msgWidth
                               else Int
    msgWrap
              in (DisplayFont -> Int -> AttrString -> [AttrLine]
    indentSplitAttrString DisplayFont
    propFont Int
    firstWidth (AttrString -> [AttrLine])
    -> (AttrLine -> AttrString) -> AttrLine -> [AttrLine]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . AttrLine -> AttrString
    attrLine) AttrLine
    r
                   -- first possibly long
                 [AttrLine] -> [AttrLine] -> [AttrLine]
    forall a. [a] -> [a] -> [a]
    ++ (AttrLine -> [AttrLine]) -> [AttrLine] -> [AttrLine]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (DisplayFont -> Int -> AttrString -> [AttrLine]
    indentSplitAttrString DisplayFont
    propFont Int
    msgWrap (AttrString -> [AttrLine])
    -> (AttrLine -> AttrString) -> AttrLine -> [AttrLine]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . AttrLine -> AttrString
    attrLine) [AttrLine]
    rs
          -- TODO: refactor this ugly pile of copy-paste
          repPropW :: Overlay
    repPropW = [AttrLine] -> Overlay
    offsetOverlay
                     ([AttrLine] -> Overlay) -> [AttrLine] -> Overlay
    forall a b. (a -> b) -> a -> b
    $ (AttrLine -> [AttrLine]) -> [AttrLine] -> [AttrLine]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (DisplayFont -> Int -> AttrString -> [AttrLine]
    indentSplitAttrString DisplayFont
    propFont Int
    width (AttrString -> [AttrLine])
    -> (AttrLine -> AttrString) -> AttrLine -> [AttrLine]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . AttrLine -> AttrString
    attrLine)
                                 [AttrLine]
    repProp
          -- If the mono portion first on the line, let it take half width,
          -- but if previous lines shorter, match them and only buttons
          -- are permitted to stick out.
          monoWidth :: Int
    monoWidth = if [AttrLine] -> Bool
    forall a. [a] -> Bool
    null [AttrLine]
    repProp then Int
    msgWidth else Int
    msgWrap
          repMono0 :: Overlay
    repMono0 = Int -> Overlay -> Overlay
    ytranslateOverlay (Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    repProp0)
                     (Overlay -> Overlay) -> Overlay -> Overlay
    forall a b. (a -> b) -> a -> b
    $ [AttrLine] -> Overlay
    offsetOverlay
                     ([AttrLine] -> Overlay) -> [AttrLine] -> Overlay
    forall a b. (a -> b) -> a -> b
    $ DisplayFont -> Int -> AttrString -> [AttrLine]
    indentSplitAttrString DisplayFont
    monoFont Int
    monoWidth (AttrString -> [AttrLine]) -> AttrString -> [AttrLine]
    forall a b. (a -> b) -> a -> b
    $ AttrLine -> AttrString
    attrLine AttrLine
    repMono
          repMonoW :: Overlay
    repMonoW = Int -> Overlay -> Overlay
    ytranslateOverlay (Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    repPropW)
                     (Overlay -> Overlay) -> Overlay -> Overlay
    forall a b. (a -> b) -> a -> b
    $ [AttrLine] -> Overlay
    offsetOverlay
                     ([AttrLine] -> Overlay) -> [AttrLine] -> Overlay
    forall a b. (a -> b) -> a -> b
    $ DisplayFont -> Int -> AttrString -> [AttrLine]
    indentSplitAttrString DisplayFont
    monoFont Int
    width (AttrString -> [AttrLine]) -> AttrString -> [AttrLine]
    forall a b. (a -> b) -> a -> b
    $ AttrLine -> AttrString
    attrLine AttrLine
    repMono
          repWhole0 :: Overlay
    repWhole0 = [AttrLine] -> Overlay
    offsetOverlay
                      ([AttrLine] -> Overlay) -> [AttrLine] -> Overlay
    forall a b. (a -> b) -> a -> b
    $ (AttrLine -> [AttrLine]) -> [AttrLine] -> [AttrLine]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (DisplayFont -> Int -> AttrString -> [AttrLine]
    indentSplitAttrString DisplayFont
    propFont Int
    msgWidth
                                   (AttrString -> [AttrLine])
    -> (AttrLine -> AttrString) -> AttrLine -> [AttrLine]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . AttrLine -> AttrString
    attrLine)
                                  [AttrLine]
    reportParagraphs
          repWhole1 :: Overlay
    repWhole1 = Int -> Overlay -> Overlay
    ytranslateOverlay Int
    1 Overlay
    repWhole0
          lenOfRep0 :: Int
    lenOfRep0 = Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    repProp0 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    repMono0
          lenOfRepW :: Int
    lenOfRepW = Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    repPropW Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    repMonoW
          startOfKeys :: Int
    startOfKeys = if Overlay -> Bool
    forall a. [a] -> Bool
    null Overlay
    repMono0
                        then Int
    0
                        else DisplayFont -> AttrString -> Int
    forall a. DisplayFont -> [a] -> Int
    textSize DisplayFont
    monoFont (AttrLine -> AttrString
    attrLine (AttrLine -> AttrString) -> AttrLine -> AttrString
    forall a b. (a -> b) -> a -> b
    $ (PointUI, AttrLine) -> AttrLine
    forall a b. (a, b) -> b
    snd ((PointUI, AttrLine) -> AttrLine)
    -> (PointUI, AttrLine) -> AttrLine
    forall a b. (a -> b) -> a -> b
    $ Overlay -> (PointUI, AttrLine)
    forall a. (?callStack::CallStack) => [a] -> a
    last Overlay
    repMono0)
          startOfKeysW :: Int
    startOfKeysW = if Overlay -> Bool
    forall a. [a] -> Bool
    null Overlay
    repMonoW
                         then Int
    0
                         else DisplayFont -> AttrString -> Int
    forall a. DisplayFont -> [a] -> Int
    textSize DisplayFont
    monoFont (AttrLine -> AttrString
    attrLine (AttrLine -> AttrString) -> AttrLine -> AttrString
    forall a b. (a -> b) -> a -> b
    $ (PointUI, AttrLine) -> AttrLine
    forall a b. (a, b) -> b
    snd ((PointUI, AttrLine) -> AttrLine)
    -> (PointUI, AttrLine) -> AttrLine
    forall a b. (a -> b) -> a -> b
    $ Overlay -> (PointUI, AttrLine)
    forall a. (?callStack::CallStack) => [a] -> a
    last Overlay
    repMonoW)
          pressAKey :: AttrString
    pressAKey = [Char] -> AttrString
    stringToAS [Char]
    "A long report is shown. Press a key:"
                      AttrString -> AttrString -> AttrString
    forall a. [a] -> [a] -> [a]
    ++ [AttrCharW32
    Color.nbspAttrW32]
          (Overlay
    lX0, [KYX]
    keysX0) = DisplayFont -> Int -> Int -> Int -> [KM] -> (Overlay, [KYX])
    keysOKX DisplayFont
    monoFont Int
    0 (AttrString -> Int
    forall a. [a] -> Int
    length AttrString
    pressAKey) Int
    width [KM]
    keys
          (Overlay
    lX1, [KYX]
    keysX1) = DisplayFont -> Int -> Int -> Int -> [KM] -> (Overlay, [KYX])
    keysOKX DisplayFont
    monoFont Int
    1 Int
    0 Int
    width [KM]
    keys
          (Overlay
    lX, [KYX]
    keysX) = DisplayFont -> Int -> Int -> Int -> [KM] -> (Overlay, [KYX])
    keysOKX DisplayFont
    monoFont (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    0 (Int -> Int) -> Int -> Int
    forall a b. (a -> b) -> a -> b
    $ Int
    lenOfRep0 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) Int
    startOfKeys
                                (Int
    2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    width) [KM]
    keys
          (Overlay
    lXW, [KYX]
    keysXW) = DisplayFont -> Int -> Int -> Int -> [KM] -> (Overlay, [KYX])
    keysOKX DisplayFont
    monoFont (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    0 (Int -> Int) -> Int -> Int
    forall a b. (a -> b) -> a -> b
    $ Int
    lenOfRepW Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) Int
    startOfKeysW
                                  (Int
    2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    width) [KM]
    keys
          splitO :: Int -> (Overlay, Overlay, [KYX]) -> OKX -> [OKX]
          splitO :: Int -> (Overlay, Overlay, [KYX]) -> OKX -> [OKX]
    splitO Int
    yoffset (Overlay
    hdrProp, Overlay
    hdrMono, [KYX]
    rk) (EnumMap DisplayFont Overlay
    ls, [KYX]
    kxs) =
            let hdrOff :: Int
    hdrOff | Overlay -> Bool
    forall a. [a] -> Bool
    null Overlay
    hdrProp Bool -> Bool -> Bool
    && Overlay -> Bool
    forall a. [a] -> Bool
    null Overlay
    hdrMono = Int
    0
                       | Bool
    otherwise = Int
    1 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Overlay -> Int
    maxYofOverlay Overlay
    hdrMono
                keyTranslate :: [KYX] -> [KYX]
    keyTranslate = (KYX -> KYX) -> [KYX] -> [KYX]
    forall a b. (a -> b) -> [a] -> [b]
    map ((KYX -> KYX) -> [KYX] -> [KYX]) -> (KYX -> KYX) -> [KYX] -> [KYX]
    forall a b. (a -> b) -> a -> b
    $ Int -> KYX -> KYX
    ytranslateKXY (Int
    hdrOff Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    yoffset)
                lineTranslate :: EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    lineTranslate = (Overlay -> Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
    EM.map ((Overlay -> Overlay)
     -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay)
    -> (Overlay -> Overlay)
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall a b. (a -> b) -> a -> b
    $ Int -> Overlay -> Overlay
    ytranslateOverlay (Int
    hdrOff Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    yoffset)
                yoffsetNew :: Int
    yoffsetNew = Int
    yoffset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    height Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    hdrOff Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1
                ltOffset :: (PointUI, a) -> Bool
                ltOffset :: forall a. (PointUI, a) -> Bool
    ltOffset (PointUI Int
    _ Int
    y, a
    _) = Int
    y Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    yoffsetNew
                (EnumMap DisplayFont Overlay
    pre, EnumMap DisplayFont Overlay
    post) = ( ((PointUI, AttrLine) -> Bool) -> Overlay -> Overlay
    forall a. (a -> Bool) -> [a] -> [a]
    filter (PointUI, AttrLine) -> Bool
    forall a. (PointUI, a) -> Bool
    ltOffset (Overlay -> Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> EnumMap DisplayFont Overlay
    ls
                              , ((PointUI, AttrLine) -> Bool) -> Overlay -> Overlay
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not (Bool -> Bool)
    -> ((PointUI, AttrLine) -> Bool) -> (PointUI, AttrLine) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (PointUI, AttrLine) -> Bool
    forall a. (PointUI, a) -> Bool
    ltOffset) (Overlay -> Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> EnumMap DisplayFont Overlay
    ls )
                prependHdr :: EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    prependHdr = (Overlay -> Overlay -> Overlay)
    -> DisplayFont
    -> Overlay
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall k a.
    Enum k =>
    (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
    EM.insertWith Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    (++) DisplayFont
    propFont Overlay
    hdrProp
                             (EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay)
    -> (EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay)
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Overlay -> Overlay -> Overlay)
    -> DisplayFont
    -> Overlay
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall k a.
    Enum k =>
    (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
    EM.insertWith Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    (++) DisplayFont
    monoFont Overlay
    hdrMono
            in if (Overlay -> Bool) -> [Overlay] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Overlay -> Bool
    forall a. [a] -> Bool
    null ([Overlay] -> Bool) -> [Overlay] -> Bool
    forall a b. (a -> b) -> a -> b
    $ EnumMap DisplayFont Overlay -> [Overlay]
    forall k a. EnumMap k a -> [a]
    EM.elems EnumMap DisplayFont Overlay
    post  -- all fits on one screen
               then [(EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    prependHdr (EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall a b. (a -> b) -> a -> b
    $ EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    lineTranslate EnumMap DisplayFont Overlay
    pre, [KYX]
    rk [KYX] -> [KYX] -> [KYX]
    forall a. [a] -> [a] -> [a]
    ++ [KYX] -> [KYX]
    keyTranslate [KYX]
    kxs)]
               else let ([KYX]
    preX, [KYX]
    postX) = (KYX -> Bool) -> [KYX] -> ([KYX], [KYX])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    span (\(Either KM MenuSlot
    _, (PointUI, ButtonWidth)
    pa) -> (PointUI, ButtonWidth) -> Bool
    forall a. (PointUI, a) -> Bool
    ltOffset (PointUI, ButtonWidth)
    pa) [KYX]
    kxs
                    in (EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    prependHdr (EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall a b. (a -> b) -> a -> b
    $ EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    lineTranslate EnumMap DisplayFont Overlay
    pre, [KYX]
    rk [KYX] -> [KYX] -> [KYX]
    forall a. [a] -> [a] -> [a]
    ++ [KYX] -> [KYX]
    keyTranslate [KYX]
    preX)
                       OKX -> [OKX] -> [OKX]
    forall a. a -> [a] -> [a]
    : Int -> (Overlay, Overlay, [KYX]) -> OKX -> [OKX]
    splitO Int
    yoffsetNew (Overlay
    hdrProp, Overlay
    hdrMono, [KYX]
    rk) (EnumMap DisplayFont Overlay
    post, [KYX]
    postX)
          firstParaReport :: AttrLine
    firstParaReport = AttrString -> AttrLine
    firstParagraph AttrString
    reportAS
          hdrShortened :: (Overlay, Overlay, [KYX])
    hdrShortened = ( [(Int -> Int -> PointUI
    PointUI Int
    0 Int
    0, AttrLine
    firstParaReport)]
                             -- shortened for the main slides; in full beforehand
                         , Int -> Overlay -> Overlay
    forall a. Int -> [a] -> [a]
    take Int
    3 Overlay
    lX1  -- 3 lines ought to be enough for everyone
                         , [KYX]
    keysX1 )
          ((EnumMap DisplayFont Overlay
    lsInit, [KYX]
    kxsInit), (Overlay
    headerProp, Overlay
    headerMono, [KYX]
    rkxs)) =
            -- Check whether all space taken by report and keys.
            if | (Int
    lenOfRep0 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    lX) Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    height ->  -- display normally
                 (OKX
    emptyOKX, (Overlay
    repProp0, Overlay
    lX Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    ++ Overlay
    repMono0, [KYX]
    keysX))
               | (Int
    lenOfRepW Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Overlay -> Int
    forall a. [a] -> Int
    length Overlay
    lXW) Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    height ->  -- display widely
                 (OKX
    emptyOKX, (Overlay
    repPropW, Overlay
    lXW Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    ++ Overlay
    repMonoW, [KYX]
    keysXW))
               | [AttrLine] -> Int
    forall a. [a] -> Int
    length [AttrLine]
    reportParagraphs Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    1
                 Bool -> Bool -> Bool
    && AttrString -> Int
    forall a. [a] -> Int
    length (AttrLine -> AttrString
    attrLine AttrLine
    firstParaReport) Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    width ->
                 ( OKX
    emptyOKX  -- already shown in full in @hdrShortened@
                 , (Overlay, Overlay, [KYX])
    hdrShortened )
               | Bool
    otherwise -> case Overlay
    lX0 of
                   [] ->
                     ( (DisplayFont -> Overlay -> EnumMap DisplayFont Overlay
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton DisplayFont
    propFont Overlay
    repWhole0, [])
                         -- showing in full in the init slide
                     , (Overlay, Overlay, [KYX])
    hdrShortened )
                   (PointUI, AttrLine)
    lX0first : Overlay
    _ ->
                     ( ( (Overlay -> Overlay -> Overlay)
    -> DisplayFont
    -> Overlay
    -> EnumMap DisplayFont Overlay
    -> EnumMap DisplayFont Overlay
    forall k a.
    Enum k =>
    (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
    EM.insertWith Overlay -> Overlay -> Overlay
    forall a. [a] -> [a] -> [a]
    (++) DisplayFont
    propFont Overlay
    repWhole1
                         (EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay)
    -> EnumMap DisplayFont Overlay -> EnumMap DisplayFont Overlay
    forall a b. (a -> b) -> a -> b
    $ DisplayFont -> Overlay -> EnumMap DisplayFont Overlay
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton DisplayFont
    monoFont
                             [(Int -> Int -> PointUI
    PointUI Int
    0 Int
    0, AttrString -> AttrLine
    firstParagraph AttrString
    pressAKey), (PointUI, AttrLine)
    lX0first]
                       , (KYX -> Bool) -> [KYX] -> [KYX]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (\(Either KM MenuSlot
    _, (PointUI Int
    _ Int
    y, ButtonWidth
    _)) -> Int
    y Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0) [KYX]
    keysX0 )
                     , (Overlay, Overlay, [KYX])
    hdrShortened )
          initSlides :: [OKX]
    initSlides = if EnumMap DisplayFont Overlay -> Bool
    forall k a. EnumMap k a -> Bool
    EM.null EnumMap DisplayFont Overlay
    lsInit
                       then Bool -> [OKX] -> [OKX]
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert ([KYX] -> Bool
    forall a. [a] -> Bool
    null [KYX]
    kxsInit) []
                       else Int -> (Overlay, Overlay, [KYX]) -> OKX -> [OKX]
    splitO Int
    0 ([], [], []) (EnumMap DisplayFont Overlay
    lsInit, [KYX]
    kxsInit)
          -- If @ls0@ is not empty, we still want to display the report,
          -- one way or another.
          mainSlides :: [OKX]
    mainSlides = if EnumMap DisplayFont Overlay -> Bool
    forall k a. EnumMap k a -> Bool
    EM.null EnumMap DisplayFont Overlay
    ls0 Bool -> Bool -> Bool
    && Bool -> Bool
    not (EnumMap DisplayFont Overlay -> Bool
    forall k a. EnumMap k a -> Bool
    EM.null EnumMap DisplayFont Overlay
    lsInit)
                       then Bool -> [OKX] -> [OKX]
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert ([KYX] -> Bool
    forall a. [a] -> Bool
    null [KYX]
    kxs0) []
                       else Int -> (Overlay, Overlay, [KYX]) -> OKX -> [OKX]
    splitO Int
    0 (Overlay
    headerProp, Overlay
    headerMono, [KYX]
    rkxs) (EnumMap DisplayFont Overlay
    ls0, [KYX]
    kxs0)
      in [OKX]
    initSlides [OKX] -> [OKX] -> [OKX]
    forall a. [a] -> [a] -> [a]
    ++ [OKX]
    mainSlides

    -- | Generate a slideshow with the current and previous scores.
    highSlideshow :: FontSetup
                  -> Bool
                  -> Int        -- ^ width of the display area
                  -> Int        -- ^ height of the display area
                  -> HighScore.ScoreTable -- ^ current score table
                  -> Int        -- ^ position of the current score in the table
                  -> Text       -- ^ the name of the game mode
                  -> TimeZone   -- ^ the timezone where the game is run
                  -> Slideshow
    highSlideshow :: FontSetup
    -> Bool
    -> Int
    -> Int
    -> ScoreTable
    -> Int
    -> Text
    -> TimeZone
    -> Slideshow
    highSlideshow fontSetup :: FontSetup
    fontSetup@FontSetup{DisplayFont
    monoFont :: FontSetup -> DisplayFont
    monoFont :: DisplayFont
    monoFont} Bool
    displayTutorialHints
                  Int
    width Int
    height ScoreTable
    table Int
    pos Text
    gameModeName TimeZone
    tz =
      let entries :: Int
    entries = (Int
    height Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    3) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    3
          msg :: Text
    msg = Int -> ScoreTable -> Int -> Text -> Text
    HighScore.showAward Int
    entries ScoreTable
    table Int
    pos Text
    gameModeName
          tts :: [Overlay]
    tts = ([AttrLine] -> Overlay) -> [[AttrLine]] -> [Overlay]
    forall a b. (a -> b) -> [a] -> [b]
    map [AttrLine] -> Overlay
    offsetOverlay ([[AttrLine]] -> [Overlay]) -> [[AttrLine]] -> [Overlay]
    forall a b. (a -> b) -> a -> b
    $ TimeZone -> Int -> ScoreTable -> Int -> [[AttrLine]]
    showNearbyScores TimeZone
    tz Int
    pos ScoreTable
    table Int
    entries
          al :: AttrString
    al = Text -> AttrString
    textToAS Text
    msg
          splitScreen :: Overlay -> [OKX]
    splitScreen Overlay
    ts =
            FontSetup
    -> Bool -> Int -> Int -> Int -> AttrString -> [KM] -> OKX -> [OKX]
    splitOKX FontSetup
    fontSetup Bool
    False Int
    width Int
    height Int
    width AttrString
    al [KM
    K.spaceKM, KM
    K.escKM]
                     (DisplayFont -> Overlay -> EnumMap DisplayFont Overlay
    forall k a. Enum k => k -> a -> EnumMap k a
    EM.singleton DisplayFont
    monoFont Overlay
    ts, [])
      in FontSetup -> Bool -> [OKX] -> Slideshow
    toSlideshow FontSetup
    fontSetup Bool
    displayTutorialHints ([OKX] -> Slideshow) -> [OKX] -> Slideshow
    forall a b. (a -> b) -> a -> b
    $ (Overlay -> [OKX]) -> [Overlay] -> [OKX]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Overlay -> [OKX]
    splitScreen [Overlay]
    tts

    -- | Show a screenful of the high scores table.
    -- Parameter @entries@ is the number of (3-line) scores to be shown.
    showTable :: TimeZone -> Int -> HighScore.ScoreTable -> Int -> Int
              -> [AttrLine]
    showTable :: TimeZone -> Int -> ScoreTable -> Int -> Int -> [AttrLine]
    showTable TimeZone
    tz Int
    pos ScoreTable
    table Int
    start Int
    entries =
      let zipped :: [(Int, ScoreRecord)]
    zipped    = [Int] -> [ScoreRecord] -> [(Int, ScoreRecord)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Int
    1..] ([ScoreRecord] -> [(Int, ScoreRecord)])
    -> [ScoreRecord] -> [(Int, ScoreRecord)]
    forall a b. (a -> b) -> a -> b
    $ ScoreTable -> [ScoreRecord]
    HighScore.unTable ScoreTable
    table
          screenful :: [(Int, ScoreRecord)]
    screenful = Int -> [(Int, ScoreRecord)] -> [(Int, ScoreRecord)]
    forall a. Int -> [a] -> [a]
    take Int
    entries ([(Int, ScoreRecord)] -> [(Int, ScoreRecord)])
    -> ([(Int, ScoreRecord)] -> [(Int, ScoreRecord)])
    -> [(Int, ScoreRecord)]
    -> [(Int, ScoreRecord)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [(Int, ScoreRecord)] -> [(Int, ScoreRecord)]
    forall a. Int -> [a] -> [a]
    drop (Int
    start Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) ([(Int, ScoreRecord)] -> [(Int, ScoreRecord)])
    -> [(Int, ScoreRecord)] -> [(Int, ScoreRecord)]
    forall a b. (a -> b) -> a -> b
    $ [(Int, ScoreRecord)]
    zipped
          renderScore :: (Int, ScoreRecord) -> [AttrLine]
    renderScore (Int
    pos1, ScoreRecord
    score1) =
            (Text -> AttrLine) -> [Text] -> [AttrLine]
    forall a b. (a -> b) -> [a] -> [b]
    map (if Int
    pos1 Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    pos then Color -> Text -> AttrLine
    textFgToAL Color
    Color.BrWhite else Text -> AttrLine
    textToAL)
            ([Text] -> [AttrLine]) -> [Text] -> [AttrLine]
    forall a b. (a -> b) -> a -> b
    $ TimeZone -> Int -> ScoreRecord -> [Text]
    HighScore.showScore TimeZone
    tz Int
    pos1 ScoreRecord
    score1
      in AttrLine
    emptyAttrLine AttrLine -> [AttrLine] -> [AttrLine]
    forall a. a -> [a] -> [a]
    : [AttrLine] -> [[AttrLine]] -> [AttrLine]
    forall a. [a] -> [[a]] -> [a]
    intercalate [AttrLine
    emptyAttrLine] (((Int, ScoreRecord) -> [AttrLine])
    -> [(Int, ScoreRecord)] -> [[AttrLine]]
    forall a b. (a -> b) -> [a] -> [b]
    map (Int, ScoreRecord) -> [AttrLine]
    renderScore [(Int, ScoreRecord)]
    screenful)

    -- | Produce a couple of renderings of the high scores table.
    showNearbyScores :: TimeZone -> Int -> HighScore.ScoreTable -> Int
                     -> [[AttrLine]]
    showNearbyScores :: TimeZone -> Int -> ScoreTable -> Int -> [[AttrLine]]
    showNearbyScores TimeZone
    tz Int
    pos ScoreTable
    h Int
    entries =
      if Int
    pos Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    entries
      then [TimeZone -> Int -> ScoreTable -> Int -> Int -> [AttrLine]
    showTable TimeZone
    tz Int
    pos ScoreTable
    h Int
    1 Int
    entries]
      else [ TimeZone -> Int -> ScoreTable -> Int -> Int -> [AttrLine]
    showTable TimeZone
    tz Int
    pos ScoreTable
    h Int
    1 Int
    entries
           , TimeZone -> Int -> ScoreTable -> Int -> Int -> [AttrLine]
    showTable TimeZone
    tz Int
    pos ScoreTable
    h (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max (Int
    entries Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) (Int
    pos Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    entries Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    2))
                       Int
    entries ]