{-# Language OverloadedStrings #-}
{-|
Module      : Client.View.WindowSwitch
Description : Line renderers for window switcher
Copyright   : (c) TheDaemoness, 2024
License     : ISC
Maintainer  : emertens@gmail.com

This module renders lines used in the preview for /c
-}
module Client.View.WindowSwitch ( windowSwitchImages ) where

import           Client.Image.Focus (windowLabel)
import           Client.Image.PackedImage
import           Client.State
import           Client.State.Focus
import           Client.State.Window (winMention)
import           Control.Lens
import qualified Data.Map.Strict as Map
import           Data.List
import           Data.List.Split
import           Graphics.Vty (defAttr)

-- | Render the lines used by the @/c@ command.
windowSwitchImages ::
  String      {- ^ filter       -} ->
  Int         {- ^ window width -} ->
  ClientState {- ^ client state -} ->
  [Image']
windowSwitchImages :: String -> Int -> ClientState -> [Image']
windowSwitchImages String
arg Int
w ClientState
st = [Image'] -> [Image']
forall a. [a] -> [a]
reverse [[Image'] -> Image'
forall a. Monoid a => [a] -> a
mconcat (Image' -> [Image'] -> [Image']
forall a. a -> [a] -> [a]
intersperse Image'
gap [Image']
row) | [Image']
row <- Int -> [Image'] -> [[Image']]
forall e. Int -> [e] -> [[e]]
chunksOf Int
columns [Image']
paddedNames]
  where
    paddedNames :: [Image']
paddedNames = (Image' -> Image') -> [Image'] -> [Image']
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Image' -> Image'
resizeImage Int
maxWidth) [Image']
nameImages
    nameImages :: [Image']
nameImages = ((Focus, Window) -> Image') -> [(Focus, Window)] -> [Image']
forall a b. (a -> b) -> [a] -> [b]
map (ClientState -> (Focus, Window) -> Image'
windowLabel ClientState
st) [(Focus, Window)]
windowList
    maxWidth :: Int
maxWidth   = [Int] -> Int
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ((Image' -> Int) -> [Image'] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map Image' -> Int
imageWidth [Image']
nameImages)
    columns :: Int
columns    = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 ((Int
wInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` (Int
maxWidthInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
2))
    gap :: Image'
gap = Attr -> String -> Image'
string Attr
defAttr String
"  "
    windowList :: [(Focus, Window)]
windowList = ((Focus, Window) -> (Focus, Window) -> Ordering)
-> [(Focus, Window)] -> [(Focus, Window)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Focus, Window) -> (Focus, Window) -> Ordering
forall {a} {a}. (a, Window) -> (a, Window) -> Ordering
activity ([(Focus, Window)] -> [(Focus, Window)])
-> (Map Focus Window -> [(Focus, Window)])
-> Map Focus Window
-> [(Focus, Window)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Focus, Window) -> Bool) -> [(Focus, Window)] -> [(Focus, Window)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Focus, Window) -> Bool
forall {b}. (Focus, b) -> Bool
filterByFocus ([(Focus, Window)] -> [(Focus, Window)])
-> (Map Focus Window -> [(Focus, Window)])
-> Map Focus Window
-> [(Focus, Window)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Focus Window -> [(Focus, Window)]
forall k a. Map k a -> [(k, a)]
Map.toAscList (Map Focus Window -> [(Focus, Window)])
-> Map Focus Window -> [(Focus, Window)]
forall a b. (a -> b) -> a -> b
$ Getting (Map Focus Window) ClientState (Map Focus Window)
-> ClientState -> Map Focus Window
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Map Focus Window) ClientState (Map Focus Window)
Lens' ClientState (Map Focus Window)
clientWindows ClientState
st
      where
        filterByFocus :: (Focus, b) -> Bool
filterByFocus (Focus
focus,b
_) = String -> Focus -> Bool
isPrefixOfFocus String
arg Focus
focus
        activity :: (a, Window) -> (a, Window) -> Ordering
activity (a
_,Window
wa) (a
_,Window
wb) = WindowLineImportance -> WindowLineImportance -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Getting WindowLineImportance Window WindowLineImportance
-> Window -> WindowLineImportance
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting WindowLineImportance Window WindowLineImportance
Lens' Window WindowLineImportance
winMention Window
wa) (Getting WindowLineImportance Window WindowLineImportance
-> Window -> WindowLineImportance
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting WindowLineImportance Window WindowLineImportance
Lens' Window WindowLineImportance
winMention Window
wb)