-------------------------------------------------------------------------------- -- | -- module: Dialog.Internal -- copyright: (c) 2015 Nikita Churaev -- license: BSD3 -------------------------------------------------------------------------------- {-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-} {-# OPTIONS_HADDOCK not-home #-} -------------------------------------------------------------------------------- module Dialog.Internal where -------------------------------------------------------------------------------- import Control.Monad (ap) import Control.Monad.Trans.Class (MonadTrans (..)) import Control.Monad.IO.Class (MonadIO (..)) import Data.String (IsString (..)) import Data.Word (Word8) -------------------------------------------------------------------------------- -- Dialog monad transformer -------------------------------------------------------------------------------- -- | Dialog monad transformer. data DialogT m a where Pure :: a -> DialogT m a Bind :: (forall r. (forall b . DialogT m b -> (b -> DialogT m a) -> r) -> r) -> DialogT m a Lift :: m a -> DialogT m a ChangeTitle :: String -> DialogT m () ChangeEndMessage :: String -> DialogT m () Display :: [Paragraph] -> DialogT m () AskLine :: String -> DialogT m String instance Functor (DialogT m) where fmap func (Pure val) = Pure (func val) fmap func action = action >>= (\val -> pure (func val)) instance Applicative (DialogT m) where pure = Pure (<*>) = ap instance Monad (DialogT m) where actionA >>= makeActionB = Bind (\func -> func actionA makeActionB) instance MonadTrans DialogT where lift = Lift instance MonadIO m => MonadIO (DialogT m) where liftIO action = Lift (liftIO action) -- | Dialog with 'IO' as the base monad. type DialogIO = DialogT IO -------------------------------------------------------------------------------- -- Changing dialog title -------------------------------------------------------------------------------- -- | Changes the title of the dialog window. Default: @\"Dialog\"@ changeTitle :: String -> DialogT m () changeTitle = ChangeTitle -- | Changes the end message of the dialog. Default: @\"End of program.\"@ changeEndMessage :: String -> DialogT m () changeEndMessage = ChangeEndMessage -------------------------------------------------------------------------------- -- Displaying simple messages -------------------------------------------------------------------------------- -- | Displays a plain-text single-line message. displayLine :: String -> DialogT m () displayLine string = display [TextParagraph (Plain string)] -------------------------------------------------------------------------------- -- Asking for input -------------------------------------------------------------------------------- -- | Asks the user for a line of text. askLine :: String -> DialogT m String askLine = AskLine -------------------------------------------------------------------------------- -- Displaying formatted messages -------------------------------------------------------------------------------- -- | Displays a message. display :: [Paragraph] -> DialogT m () display = Display -------------------------------------------------------------------------------- -- Formatted text -------------------------------------------------------------------------------- data Paragraph = TextParagraph FormattedText | Picture PictureSource | List ListStyle [ListItem] | Table [TableRow] deriving (Eq, Ord, Show) -------------------------------------------------------------------------------- data FormattedText = Plain String | Colored Color FormattedText | Bold FormattedText | Italic FormattedText | Underline FormattedText | Size FontSize FormattedText | Link String FormattedText | CompositeText [FormattedText] deriving (Eq, Ord, Show) instance IsString FormattedText where fromString string = Plain string instance Monoid FormattedText where mempty = CompositeText [] mappend (CompositeText []) text = text mappend text (CompositeText []) = text mappend (CompositeText a) (CompositeText b) = CompositeText (a ++ b) mappend a (CompositeText b) = CompositeText (a:b) mappend (CompositeText a) b = CompositeText (a ++ [b]) mappend a b = CompositeText [a, b] -------------------------------------------------------------------------------- data PictureSource = PictureFromURL String deriving (Eq, Ord, Show) -------------------------------------------------------------------------------- data ListStyle = NumberedList | BulletList deriving (Eq, Ord, Show) newtype ListItem = ListItem [Paragraph] deriving (Eq, Ord, Show) -------------------------------------------------------------------------------- newtype TableRow = TableRow [TableCell] deriving (Eq, Ord, Show) data TableCell = TableCell CellStyle [Paragraph] deriving (Eq, Ord, Show) data CellStyle = NormalCell | HeaderCell deriving (Eq, Ord, Show) -------------------------------------------------------------------------------- -- | Font size (in percent of the base font size). data FontSize = FontSize Int deriving (Eq, Ord) instance Num FontSize where (FontSize a) + (FontSize b) = mkFontSize (a + b) (FontSize a) - (FontSize b) = mkFontSize (a - b) (FontSize a) * (FontSize b) = mkFontSize (a * b) negate = undefined "Can not negate a FontSize" signum _ = FontSize 1 abs size = size fromInteger integer = mkFontSize (fromInteger integer) instance Show FontSize where showsPrec prec (FontSize int) = showsPrec prec int mkFontSize :: Int -> FontSize mkFontSize int | int < 0 = error ("FontSize " ++ show int ++ " is negative") | int == 0 = error ("FontSize can not be zero") | int < 25 = error ("FontSize " ++ show int ++ " is too small (maximum is 25)") | int > 1000 = error ("FontSize " ++ show int ++ " is too large (maximum is 1000)") | otherwise = FontSize int -------------------------------------------------------------------------------- -- | Color. data Color = Color Word8 Word8 Word8 deriving (Eq, Ord, Show) -- | Pure white (red: 255, green: 255, blue: 255). white :: Color white = Color 255 255 255 -- | Pure black (red: 0, green: 0, blue: 0). black :: Color black = Color 0 0 0 -- | Pure red (red: 255, green: 0, blue: 0). red :: Color red = Color 255 0 0 -- | Pure green (red: 0, green: 255, blue: 0). green :: Color green = Color 0 255 0 -- | Pure blue (red: 0, green: 0, blue: 255). blue :: Color blue = Color 0 0 255 -- | Makes a color from red, green and blue components. rgb :: Word8 -> Word8 -> Word8 -> Color rgb = Color -- | Unpacks a color into red, green and blue components. toRGB :: Color -> (Word8, Word8, Word8) toRGB (Color r g b) = (r, g, b) --------------------------------------------------------------------------------