on develop help sign in
WIP: HasDisplayRegion
fa4990fAli Abrar
reflex-vty.cabal+2
@@ -21,6 +21,7 @@ library
21 ref-tf,
21 ref-tf,
22 reflex,
22 reflex,
23 stm,
23 stm,
24+ transformers,
24 time,
25 time,
25 vty
26 vty
26 hs-source-dirs: src
27 hs-source-dirs: src
@@ -34,5 +35,6 @@ executable example
34 reflex,
35 reflex,
35 reflex-vty,
36 reflex-vty,
36 time,
37 time,
38+ transformers,
37 vty
39 vty
38 default-language: Haskell2010
40 default-language: Haskell2010
src-bin/example.hs+62−6
@@ -1,25 +1,81 @@
1{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE GADTs #-}
2{-# LANGUAGE GADTs #-}
3{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE LambdaCase #-}
4+{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE RankNTypes #-}
5{-# LANGUAGE RankNTypes #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
5
7
6import Control.Monad.IO.Class
8import Control.Monad.IO.Class
9+import Control.Monad.Trans.Reader
7import Data.Time
10import Data.Time
8−import qualified Graphics.Vty as V
11+import Graphics.Vty as V
9import Reflex
12import Reflex
10import Reflex.Vty
13import Reflex.Vty
11
14
15+data Region = Region
16+ { _region_left :: Int
17+ , _region_top :: Int
18+ , _region_width :: Int
19+ , _region_height :: Int
20+ }
21+ deriving (Show, Read, Eq, Ord)
22+
23+regionToDisplayRegion :: Region -> DisplayRegion
24+regionToDisplayRegion (Region _ _ w h) = (w, h)
25+
26+region :: Region -> (DisplayRegion -> Image) -> [Image]
27+region r@(Region left top width height) i =
28+ [ within r $ resize width height $ i (width, height)
29+ , within r $ wrapString width defAttr $ replicate (width * height) ' '
30+ ]
31+
32+within :: Region -> Image -> Image
33+within (Region left top width height) =
34+ translate left top . V.crop width height
35+
36+wrapString :: Int -> Attr -> String -> Image
37+wrapString maxWidth attrs = vertCat . concatMap (fmap (string attrs) . fmap (take maxWidth) . takeWhile (not . null) . iterate (drop maxWidth)) . lines
38+
39+box :: Region -> (DisplayRegion -> Image) -> [Image]
40+box r@(Region left top width height) i =
41+ let hBorder = string mempty $ replicate width '-'
42+ vBorder = wrapString 1 mempty $ replicate (height - 2) '|'
43+ internal = Region
44+ { _region_left = left + 1
45+ , _region_top = top + 1
46+ , _region_width = width - 2
47+ , _region_height = height - 2
48+ }
49+ in [ within (r { _region_height = 1 }) hBorder
50+ , within (Region left (top + 1) 1 (height - 2)) vBorder
51+ , within (Region (left + width - 1) (top + 1) 1 (height - 2)) vBorder
52+ , within (r { _region_top = top + height - 1 }) hBorder
53+ ] ++ region internal i
54+
12guest :: forall t m. VtyApp t m
55guest :: forall t m. VtyApp t m
13guest e = do
56guest e = do
14− now <- liftIO getCurrentTime
57+ dr0@(w, h) <- displayRegion
15− ticks <- fmap show <$> tickLossy 1 now
58+ dr <- holdDyn dr0 $ fforMaybe e $ \case
59+ V.EvResize w h -> Just (w, h)
60+ _ -> Nothing
61+ let region = fmap (\(w,h) -> Region 0 0 w h) dr
62+ region1 = fmap (\(w,h) -> Region (w `div` 5) (h `div` 5) (w `div` 2) (h `div` 2)) dr
63+ region2 = fmap (\(w,h) -> Region (w `div` 4) (h `div` 4) (2 * (w `div` 3)) (2*(h `div` 3))) dr
64+ debugRegion = fmap (\(w, _) -> Region 0 0 w 3) dr
65+ events <- holdDyn "" $ show <$> e
66+ let debugOut = ffor (zipDyn events debugRegion) $ \(ev, r) ->
67+ box r $ \(w, _) -> wrapString w mempty ev
68+
16 let shutdown = fforMaybe e $ \case
69 let shutdown = fforMaybe e $ \case
17 V.EvKey V.KEsc _ -> Just ()
70 V.EvKey V.KEsc _ -> Just ()
18 _ -> Nothing
71 _ -> Nothing
19− picture <- hold (V.picForImage $ V.string mempty "Initial") $ V.picForImage . V.string mempty <$>
72+ output = fmap V.picForLayers $
20− leftmost [show <$> e, show <$> ticks]
73+ current $ ffor ((,,) <$> region1 <*> region2 <*> debugOut) $ \(r1, r2, d) ->
74+ let b1 = box r1 (\(w, _) -> wrapString w mempty $ take 500 $ cycle ('\n' : ['a'..'z']))
75+ b2 = box r2 (\(w, _) -> wrapString w mempty $ take 500 $ cycle ('\n' : ['a'..'z']))
76+ in d ++ b2 ++ b1
21 return $ VtyResult
77 return $ VtyResult
22− { _vtyResult_picture = picture
78+ { _vtyResult_picture = output
23 , _vtyResult_shutdown = shutdown
79 , _vtyResult_shutdown = shutdown
24 }
80 }
25
81
src/Reflex/Vty.hs+15−2
@@ -11,6 +11,7 @@ module Reflex.Vty
11 , VtyResult(..)
11 , VtyResult(..)
12 , runVtyApp
12 , runVtyApp
13 , runVtyAppWith
13 , runVtyAppWith
14+ , HasDisplayRegion(..)
14 ) where
15 ) where
15
16
16import Control.Concurrent (forkIO, killThread)
17import Control.Concurrent (forkIO, killThread)
@@ -21,6 +22,7 @@ import Control.Monad.IO.Class (liftIO, MonadIO)
21import Control.Monad.Identity (Identity(..))
22import Control.Monad.Identity (Identity(..))
22import Control.Monad.Primitive (PrimMonad)
23import Control.Monad.Primitive (PrimMonad)
23import Control.Monad.Ref (MonadRef, Ref, readRef)
24import Control.Monad.Ref (MonadRef, Ref, readRef)
25+import Control.Monad.Trans.Reader
24import Data.Dependent.Sum (DSum ((:=>)))
26import Data.Dependent.Sum (DSum ((:=>)))
25import Data.IORef (IORef)
27import Data.IORef (IORef)
26import Data.IORef (readIORef)
28import Data.IORef (readIORef)
@@ -41,6 +43,12 @@ data VtyResult t = VtyResult
41 -- ^ An event that requests application termination.
43 -- ^ An event that requests application termination.
42 }
44 }
43
45
46+class HasDisplayRegion m where
47+ displayRegion :: m V.DisplayRegion
48+
49+instance Monad m => HasDisplayRegion (ReaderT V.DisplayRegion m) where
50+ displayRegion = ask
51+
44-- | A functional reactive vty application.
52-- | A functional reactive vty application.
45type VtyApp t m =
53type VtyApp t m =
46 ( Reflex t
54 ( Reflex t
@@ -58,6 +66,8 @@ type VtyApp t m =
58 , PerformEvent t m
66 , PerformEvent t m
59 , MonadIO m
67 , MonadIO m
60 , MonadIO (Performable m)
68 , MonadIO (Performable m)
69+
70+ , HasDisplayRegion m
61 )
71 )
62 => Event t (V.Event)
72 => Event t (V.Event)
63 -- ^ Vty input events.
73 -- ^ Vty input events.
@@ -97,6 +107,8 @@ runVtyAppWith vty vtyGuest =
97 -- processed.
107 -- processed.
98 events <- liftIO newChan
108 events <- liftIO newChan
99
109
110+ displayRegion0 <- V.displayBounds $ V.outputIface vty
111+
100 -- Run the vty "guest" application, providing the appropriate context. The
112 -- Run the vty "guest" application, providing the appropriate context. The
101 -- result is a 'VtyResult', and a 'FireCommand' that will be used to
113 -- result is a 'VtyResult', and a 'FireCommand' that will be used to
102 -- trigger events.
114 -- trigger events.
@@ -115,7 +127,8 @@ runVtyAppWith vty vtyGuest =
115 -- which they will be read and
127 -- which they will be read and
116 -- processed.
128 -- processed.
117
129
130+ flip runReaderT displayRegion0 $
118− vtyGuest vtyEvent -- The guest app is provided an
131+ vtyGuest vtyEvent -- The guest app is provided an
119 -- 'Event' of vty inputs.
132 -- 'Event' of vty inputs.
120
133
121 -- Reads the current value of the 'Picture' behavior and updates the
134 -- Reads the current value of the 'Picture' behavior and updates the
@@ -205,5 +218,5 @@ runVtyApp
205 -> IO ()
218 -> IO ()
206runVtyApp app = do
219runVtyApp app = do
207 cfg <- liftIO V.standardIOConfig
220 cfg <- liftIO V.standardIOConfig
208− vty <- liftIO $ V.mkVty cfg
221+ vty <- liftIO $ V.mkVty $ cfg { V.mouseMode = Just True }
209 runVtyAppWith vty app
222 runVtyAppWith vty app