module Data.Comic (
Hint(..), Position(..), Font(..), FontName, FontSize, RGBA, Comic(..), Panel(..)
, HintSize, ImageName
, ComicDelta(..)
, blackRGBA
) where
import Control.Monad
import Control.Applicative
import Data.Text (Text)
import qualified Data.Aeson as JS
import qualified Data.Aeson.Types as JS
import Data.Aeson (ToJSON(..), FromJSON(..), (.:))
type ImageName = Text
type FontName = Text
type FontSize = Int
type HintSize = Int
type RGBA = (Float, Float, Float, Float)
blackRGBA :: RGBA
blackRGBA = (0, 0, 0, 1)
data Font =
Font FontName FontSize RGBA
deriving (Show, Eq, Ord)
data Position =
Pos Int Int
deriving (Show, Eq, Ord)
instance ToJSON Position where
toJSON (Pos x y) = JS.object [("x", toJSON x), ("y", toJSON y)]
instance FromJSON Position where
parseJSON (JS.Object v) = Pos <$> v .: "x" <*> v .: "y"
parseJSON _ = mzero
data Hint =
ZoneHint {
_hintTxt :: Text
}
| ClickZoneHint {
_hintLocal :: Maybe (Position, HintSize)
, _hintLink :: Text
}
| HoverHint {
_hintPos :: Position
, _hintSize :: HintSize
, _hintTxt :: Text
}
deriving (Show, Eq, Ord)
instance ToJSON Hint where
toJSON (ZoneHint t) = JS.object [("txt", toJSON t)]
toJSON (ClickZoneHint ml l) = JS.object $ [ ("href", toJSON l) ] ++
maybe [] (\(p, s) -> [("size", toJSON s), ("pos", toJSON p)]) ml
toJSON (HoverHint p s t) =
JS.object
[ ("pos", toJSON p)
, ("size", toJSON s)
, ("txt", toJSON t) ]
instance FromJSON Hint where
parseJSON (JS.Object v) =
(ClickZoneHint <$> (((\s p -> Just (p, s)) <$> v .: "size" <*> v .: "pos") <|> pure Nothing) <*> v .: "href") <|>
(HoverHint <$> v .: "pos" <*> v .: "size" <*> v .: "txt") <|>
(ZoneHint <$> v .: "txt")
parseJSON _ = mzero
data Panel =
Panel {
_panelBackground :: ImageName
, _panelHints :: [Hint]
, _panelTexts :: [((Position, Position), Font, Text)]
, _panelOverlays :: [(Position, ImageName)]
}
deriving (Show, Eq, Ord)
text2json :: ((Position, Position), Font, Text) -> JS.Value
text2json ((tl, br), Font fn fs c, t) =
JS.object [ ("tl", toJSON tl), ("br", toJSON br)
, ("font", toJSON fn), ("size", toJSON fs), ("color", toJSON c)
, ("txt", toJSON t) ]
json2text :: JS.Value -> JS.Parser ((Position, Position), Font, Text)
json2text (JS.Object v1) =
(\tl br fn fs c t -> ((tl, br), Font fn fs c, t)) <$>
v1 .: "tl" <*> v1 .: "br" <*>
v1 .: "font" <*> v1 .: "size" <*> v1 .: "color" <*>
v1 .: "txt"
json2text _ = mzero
instance ToJSON Panel where
toJSON (Panel ss hs txts overs) =
JS.object $ [
("background", toJSON ss)
, ("hints", toJSON hs)
, ("texts", toJSON $ map text2json txts)
, ("overlays", toJSON $ map (\(p, i) ->
JS.object [ ("tl", toJSON p)
, ("img", toJSON i) ]) overs)
]
instance FromJSON Panel where
parseJSON (JS.Object v) =
Panel <$>
v .: "background" <*>
v .: "hints" <*>
(v .: "texts" >>= mapM json2text) <*>
(v .: "overlays" >>= mapM parseOver)
where
parseOver (JS.Object v1) = (,) <$> v1 .: "tl" <*> v1 .: "img"
parseOver _ = mzero
parseJSON _ = mzero
data Comic =
Comic {
_comicPanels :: [Panel]
, _comicAlt :: Text
, _comicPad :: Int
}
deriving (Show, Eq, Ord)
instance ToJSON Comic where
toJSON (Comic ps alt pad) = JS.object [("panels", toJSON ps), ("pad", toJSON pad), ("alt", toJSON alt)]
instance FromJSON Comic where
parseJSON (JS.Object v) =
Comic <$> v .: "panels" <*> v .: "alt" <*> v .: "pad"
parseJSON _ = mzero
data ComicDelta =
CompleteComic Comic
| AppendPanels [Panel]
| AddTexts [((Position, Position), Font, Text)]
deriving (Show, Eq)
instance ToJSON ComicDelta where
toJSON (CompleteComic c) = JS.object [("complete", toJSON c)]
toJSON (AppendPanels ps) = JS.object [("append_panels", toJSON ps)]
toJSON (AddTexts txts) = JS.object [("add_texts", toJSON $ map text2json txts)]
instance FromJSON ComicDelta where
parseJSON (JS.Object v) =
(CompleteComic <$> v .: "complete") <|>
(AppendPanels <$> v .: "append_panels") <|>
(AddTexts <$> (v .: "add_texts" >>= mapM json2text))
parseJSON _ = mzero