{-# Language OverloadedStrings #-}
module Client.Image.PackedImage
( Image'
, unpackImage
, char
, text'
, string
, imageWidth
, splitImage
, imageText
, resizeImage
) where
import Data.List (findIndex)
import qualified Data.Text as S
import qualified Data.Text.Lazy as L
import Data.String
import Graphics.Vty.Attributes
import Graphics.Vty.Image ((<|>), wcswidth, wcwidth)
import Graphics.Vty.Image.Internal (Image(..))
unpackImage :: Image' -> Image
unpackImage :: Image' -> Image
unpackImage Image'
i =
case Image'
i of
Image'
EmptyImage' -> Image
EmptyImage
HorizText' Attr
a Text
b Int
c Int
d Image'
e -> Attr -> DisplayText -> Int -> Int -> Image
HorizText Attr
a (Text -> DisplayText
L.fromStrict Text
b) Int
c Int
d Image -> Image -> Image
<|> Image' -> Image
unpackImage Image'
e
data Image'
= HorizText'
!Attr
{-# UNPACK #-} !S.Text
{-# UNPACK #-} !Int
{-# UNPACK #-} !Int
!Image'
| EmptyImage'
deriving (Int -> Image' -> ShowS
[Image'] -> ShowS
Image' -> String
(Int -> Image' -> ShowS)
-> (Image' -> String) -> ([Image'] -> ShowS) -> Show Image'
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Image'] -> ShowS
$cshowList :: [Image'] -> ShowS
show :: Image' -> String
$cshow :: Image' -> String
showsPrec :: Int -> Image' -> ShowS
$cshowsPrec :: Int -> Image' -> ShowS
Show)
instance Monoid Image' where
mempty :: Image'
mempty = Image'
EmptyImage'
mappend :: Image' -> Image' -> Image'
mappend = Image' -> Image' -> Image'
forall a. Semigroup a => a -> a -> a
(<>)
instance Semigroup Image' where
HorizText' Attr
a Text
b Int
c Int
d Image'
EmptyImage' <> :: Image' -> Image' -> Image'
<> HorizText' Attr
a' Text
b' Int
c' Int
d' Image'
rest
| Attr
a Attr -> Attr -> Bool
forall a. Eq a => a -> a -> Bool
== Attr
a' = Attr -> Text -> Int -> Int -> Image' -> Image'
HorizText' Attr
a (Text
b Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
b') (Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
c') (Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d') Image'
rest
Image'
EmptyImage' <> Image'
y = Image'
y
HorizText' Attr
a Text
b Int
c Int
d Image'
e <> Image'
y = Attr -> Text -> Int -> Int -> Image' -> Image'
HorizText' Attr
a Text
b Int
c Int
d (Image'
e Image' -> Image' -> Image'
forall a. Semigroup a => a -> a -> a
<> Image'
y)
instance IsString Image' where fromString :: String -> Image'
fromString = Attr -> String -> Image'
string Attr
defAttr
text' :: Attr -> S.Text -> Image'
text' :: Attr -> Text -> Image'
text' Attr
a Text
s
| Text -> Bool
S.null Text
s = Image'
EmptyImage'
| Bool
otherwise = Attr -> Text -> Int -> Int -> Image' -> Image'
HorizText' Attr
a Text
s (String -> Int
wcswidth (Text -> String
S.unpack Text
s)) (Text -> Int
S.length Text
s) Image'
EmptyImage'
char :: Attr -> Char -> Image'
char :: Attr -> Char -> Image'
char Attr
a Char
c = Attr -> Text -> Int -> Int -> Image' -> Image'
HorizText' Attr
a (Char -> Text
S.singleton Char
c) (Char -> Int
wcwidth Char
c) Int
1 Image'
EmptyImage'
string :: Attr -> String -> Image'
string :: Attr -> String -> Image'
string Attr
a String
s
| String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
s = Image'
EmptyImage'
| Bool
otherwise = Attr -> Text -> Int -> Int -> Image' -> Image'
HorizText' Attr
a Text
t (String -> Int
wcswidth String
s) (Text -> Int
S.length Text
t) Image'
EmptyImage'
where t :: Text
t = String -> Text
S.pack String
s
splitImage :: Int -> Image' -> (Image',Image')
splitImage :: Int -> Image' -> (Image', Image')
splitImage Int
_ Image'
EmptyImage' = (Image'
EmptyImage', Image'
EmptyImage')
splitImage Int
w (HorizText' Attr
a Text
t Int
w' Int
l Image'
rest)
| Int
w Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
w' = case Int -> Image' -> (Image', Image')
splitImage (Int
wInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
w') Image'
rest of
(Image'
x,Image'
y) -> (Attr -> Text -> Int -> Int -> Image' -> Image'
HorizText' Attr
a Text
t Int
w' Int
l Image'
x, Image'
y)
| Bool
otherwise = (Attr -> Text -> Image'
text' Attr
a (Int -> Text -> Text
S.take Int
i Text
t), Attr -> Text -> Image'
text' Attr
a (Int -> Text -> Text
S.drop Int
i Text
t) Image' -> Image' -> Image'
forall a. Semigroup a => a -> a -> a
<> Image'
rest)
where
ws :: [Int]
ws = (Int -> Int -> Int) -> [Int] -> [Int]
forall a. (a -> a -> a) -> [a] -> [a]
scanl1 Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) ((Char -> Int) -> String -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Int
wcwidth (Text -> String
S.unpack Text
t))
i :: Int
i = case (Int -> Bool) -> [Int] -> Maybe Int
forall a. (a -> Bool) -> [a] -> Maybe Int
findIndex (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
w) [Int]
ws of
Maybe Int
Nothing -> Int
0
Just Int
ix -> Int
ix
imageWidth :: Image' -> Int
imageWidth :: Image' -> Int
imageWidth = Int -> Image' -> Int
go Int
0
where
go :: Int -> Image' -> Int
go Int
acc Image'
EmptyImage' = Int
acc
go Int
acc (HorizText' Attr
_ Text
_ Int
w Int
_ Image'
x) = Int -> Image' -> Int
go (Int
acc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
w) Image'
x
imageText :: Image' -> L.Text
imageText :: Image' -> DisplayText
imageText = [Text] -> DisplayText
L.fromChunks ([Text] -> DisplayText)
-> (Image' -> [Text]) -> Image' -> DisplayText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Image' -> [Text]
go
where
go :: Image' -> [Text]
go Image'
EmptyImage' = []
go (HorizText' Attr
_ Text
t Int
_ Int
_ Image'
xs) = Text
t Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: Image' -> [Text]
go Image'
xs
resizeImage :: Int -> Image' -> Image'
resizeImage :: Int -> Image' -> Image'
resizeImage Int
w Image'
img =
let iw :: Int
iw = Image' -> Int
imageWidth Image'
img in
case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
w Int
iw of
Ordering
LT -> (Image', Image') -> Image'
forall a b. (a, b) -> a
fst (Int -> Image' -> (Image', Image')
splitImage Int
w Image'
img)
Ordering
EQ -> Image'
img
Ordering
GT -> Image'
img Image' -> Image' -> Image'
forall a. Semigroup a => a -> a -> a
<> Attr -> String -> Image'
string Attr
defAttr (Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
wInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
iw) Char
' ')