@@ -37,9 +37,7 @@ module Reflex.Vty.Widget
37 , mouseDown
37 , mouseDown
41 , tellImages
40 , tellImages
44 , splitVDrag
42 , splitVDrag
@@ -62,8 +60,6 @@ import Control.Applicative (liftA2)
62import Control.Monad.Fix (MonadFix)
60import Control.Monad.Fix (MonadFix)
63import Control.Monad.Trans (lift)
61import Control.Monad.Trans (lift)
64import Control.Monad.Trans.Reader (ReaderT, runReaderT, asks, ask)
62import Control.Monad.Trans.Reader (ReaderT, runReaderT, asks, ask)
65−import Control.Monad.Trans.Writer (WriterT, runWriterT, censor, tell)
66−import Control.Monad.Writer.Adjustable ()
67import Data.Default (Default(..))
63import Data.Default (Default(..))
68import Data.Text (Text)
64import Data.Text (Text)
69import qualified Data.Text as T
65import qualified Data.Text as T
@@ -71,9 +67,10 @@ import qualified Data.Text.Zipper as TZ
71import Graphics.Vty (Image)
67import Graphics.Vty (Image)
72import qualified Graphics.Vty as V
68import qualified Graphics.Vty as V
73import Reflex
69import Reflex
74−import Reflex.Class.Switchable
75import Reflex.NotReady.Class
70import Reflex.NotReady.Class
76import Reflex.NotReady.Class.Orphans ()
71import Reflex.NotReady.Class.Orphans ()
72+import Reflex.BehaviorWriter.Class (tellBehavior)
73+import Reflex.BehaviorWriter.Base (BehaviorWriterT, runBehaviorWriterT)
78import Reflex.Vty.Host
75import Reflex.Vty.Host
@@ -93,39 +90,9 @@ data VtyWidgetCtx t = VtyWidgetCtx
94-- | The output of a 'VtyWidget'
91-- | The output of a 'VtyWidget'
95data VtyWidgetOut t = VtyWidgetOut
92data VtyWidgetOut t = VtyWidgetOut
96− { _vtyWidgetOut_images :: Behavior t [Image]
97− -- ^ The visual output of the 'VtyWidget'
98− , _vtyWidgetOut_shutdown :: Event t ()
93+ { _vtyWidgetOut_shutdown :: Event t ()
101−instance Reflex t => Semigroup (VtyWidgetOut t) where
102− wo <> wo' = VtyWidgetOut
103− { _vtyWidgetOut_images = _vtyWidgetOut_images wo <> _vtyWidgetOut_images wo'
104− , _vtyWidgetOut_shutdown = _vtyWidgetOut_shutdown wo <> _vtyWidgetOut_shutdown wo'
107−instance (Reflex t) => Monoid (VtyWidgetOut t) where
108− mempty = VtyWidgetOut mempty mempty
109− mappend wo wo' = wo <> wo'
111−instance Reflex t => Switchable t (VtyWidgetOut t) where
113− shutdown <- switching (_vtyWidgetOut_shutdown e0) $ fmap _vtyWidgetOut_shutdown e
114− images <- switching (_vtyWidgetOut_images e0) $ fmap _vtyWidgetOut_images e
115− return $ VtyWidgetOut
116− { _vtyWidgetOut_images = images
117− , _vtyWidgetOut_shutdown = shutdown
120−-- | A widget that can read its context and produce image output
121−newtype VtyWidget t m a = VtyWidget
122− { unVtyWidget :: WriterT (VtyWidgetOut t) (ReaderT (VtyWidgetCtx t) m) a
124− deriving (Functor, Applicative, Monad, MonadSample t, MonadHold t, MonadFix, NotReady t)
126−instance (PostBuild t m, Reflex t) => PostBuild t (VtyWidget t m) where
127− getPostBuild = VtyWidget $ lift getPostBuild
129instance (Adjustable t m, MonadHold t m, Reflex t) => Adjustable t (VtyWidget t m) where
96instance (Adjustable t m, MonadHold t m, Reflex t) => Adjustable t (VtyWidget t m) where
130 runWithReplace a0 a' = VtyWidget $ runWithReplace (unVtyWidget a0) $ fmap unVtyWidget a'
97 runWithReplace a0 a' = VtyWidget $ runWithReplace (unVtyWidget a0) $ fmap unVtyWidget a'
131 traverseIntMapWithKeyWithAdjust f dm0 dm' = VtyWidget $
98 traverseIntMapWithKeyWithAdjust f dm0 dm' = VtyWidget $
@@ -135,18 +102,24 @@ instance (Adjustable t m, MonadHold t m, Reflex t) => Adjustable t (VtyWidget t
135 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = VtyWidget $ do
102 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = VtyWidget $ do
136 traverseDMapWithKeyWithAdjustWithMove (\k v -> unVtyWidget (f k v)) dm0 dm'
103 traverseDMapWithKeyWithAdjustWithMove (\k v -> unVtyWidget (f k v)) dm0 dm'
105+-- | A widget that can read its context and produce image output
106+newtype VtyWidget t m a = VtyWidget
107+ { unVtyWidget :: BehaviorWriterT t [Image] (ReaderT (VtyWidgetCtx t) m) a
109+ deriving (Functor, Applicative, Monad, MonadSample t, MonadHold t, MonadFix, NotReady t, ImageWriter t)
138-- | Runs a 'VtyWidget' with a given context
111-- | Runs a 'VtyWidget' with a given context
139runVtyWidget
112runVtyWidget
140− :: Reflex t
113+ :: (Reflex t, Monad m)
141 => VtyWidgetCtx t
114 => VtyWidgetCtx t
142 -> VtyWidget t m a
115 -> VtyWidget t m a
143− -> m (a, VtyWidgetOut t)
116+ -> m (a, Behavior t [Image])
144−runVtyWidget ctx w = runReaderT (runWriterT (unVtyWidget w)) ctx
117+runVtyWidget ctx w = runReaderT (runBehaviorWriterT (unVtyWidget w)) ctx
146-- | Sets up the top-level context for a 'VtyWidget' and runs it with that context
119-- | Sets up the top-level context for a 'VtyWidget' and runs it with that context
147mainWidgetWithHandle
120mainWidgetWithHandle
149− -> (forall t m. MonadVtyApp t m => VtyWidget t m ())
122+ -> (forall t m. MonadVtyApp t m => VtyWidget t m (Event t ()))
151mainWidgetWithHandle vty child =
124mainWidgetWithHandle vty child =
152 runVtyAppWithHandle vty $ \dr0 inp -> do
125 runVtyAppWithHandle vty $ \dr0 inp -> do
@@ -161,17 +134,17 @@ mainWidgetWithHandle vty child =
161 , _vtyWidgetCtx_input = inp'
134 , _vtyWidgetCtx_input = inp'
162 , _vtyWidgetCtx_focus = constDyn True
135 , _vtyWidgetCtx_focus = constDyn True
164− ((), wo) <- runVtyWidget ctx $ do
137+ (shutdown, images) <- runVtyWidget ctx $ do
165 tellImages . ffor (current size) $ \(w, h) -> [V.charFill V.defAttr ' ' w h]
138 tellImages . ffor (current size) $ \(w, h) -> [V.charFill V.defAttr ' ' w h]
167 return $ VtyResult
140 return $ VtyResult
168− { _vtyResult_picture = fmap (V.picForLayers . reverse) (_vtyWidgetOut_images wo)
141+ { _vtyResult_picture = fmap (V.picForLayers . reverse) images
169− , _vtyResult_shutdown = _vtyWidgetOut_shutdown wo
142+ , _vtyResult_shutdown = shutdown
172-- | Like 'mainWidgetWithHandle', but uses a default vty configuration
145-- | Like 'mainWidgetWithHandle', but uses a default vty configuration
173mainWidget
146mainWidget
174− :: (forall t m. MonadVtyApp t m => VtyWidget t m ())
147+ :: (forall t m. MonadVtyApp t m => VtyWidget t m (Event t ()))
176mainWidget child = do
149mainWidget child = do
177 vty <- getDefaultVty
150 vty <- getDefaultVty
@@ -211,16 +184,8 @@ class (Reflex t, Monad m) => ImageWriter t m | m -> t where
211 -- | Send images upstream for rendering
184 -- | Send images upstream for rendering
212 tellImages :: Behavior t [Image] -> m ()
185 tellImages :: Behavior t [Image] -> m ()
214−instance (Reflex t, Monad m) => ImageWriter t (VtyWidget t m) where
187+instance (Monad m, Reflex t) => ImageWriter t (BehaviorWriterT t [Image] m) where
215− tellImages imgs = VtyWidget $ tell (mempty { _vtyWidgetOut_images = imgs })
188+ tellImages = tellBehavior
217−-- | A class for things that can shut down the vty application
218−class (Reflex t, Monad m) => Shutdown t m where
219− -- | Signals that the vty application should shut down
220− tellShutdown :: Event t () -> m ()
222−instance (Reflex t, Monad m) => Shutdown t (VtyWidget t m) where
223− tellShutdown sd = VtyWidget $ tell (mempty { _vtyWidgetOut_shutdown = sd })
225-- | A chunk of the display area
190-- | A chunk of the display area
226data Region = Region
191data Region = Region
@@ -274,11 +239,9 @@ pane reg foc child = VtyWidget $ do
275 , _vtyWidgetCtx_focus = liftA2 (&&) (_vtyWidgetCtx_focus ctx) foc
240 , _vtyWidgetCtx_focus = liftA2 (&&) (_vtyWidgetCtx_focus ctx) foc
276 , _vtyWidgetCtx_size = fmap regionSize reg }
241 , _vtyWidgetCtx_size = fmap regionSize reg }
277− (result, wo) <- lift . lift $ runVtyWidget ctx' child
242+ (result, images) <- lift . lift $ runVtyWidget ctx' child
278− let images = _vtyWidgetOut_images wo
279− images' = liftA2 (\r is -> map (withinImage r) is) (current reg) images
243+ let images' = liftA2 (\r is -> map (withinImage r) is) (current reg) images
280− wo' = wo { _vtyWidgetOut_images = images' }
244+ tellImages images'
282 return result
245 return result
284 filterInput :: Region -> Bool -> VtyEvent -> Maybe VtyEvent
247 filterInput :: Region -> Bool -> VtyEvent -> Maybe VtyEvent
@@ -445,15 +408,6 @@ fill c = do
445hRule :: (Reflex t, Monad m) => BoxStyle -> VtyWidget t m ()
408hRule :: (Reflex t, Monad m) => BoxStyle -> VtyWidget t m ()
446hRule boxStyle = fill (_boxStyle_s boxStyle)
409hRule boxStyle = fill (_boxStyle_s boxStyle)
448−-- | Transform the images produces by a widget
450− :: (Reflex t, MonadHold t m, MonadFix m)
451− => Behavior t ([Image] -> [Image])
454−modifyImages f (VtyWidget w) = VtyWidget $ flip censor w $ \wo ->
455− wo { _vtyWidgetOut_images = f <*> (_vtyWidgetOut_images wo) }
457-- | Defines a set of symbols to use to draw the outlines of boxes
411-- | Defines a set of symbols to use to draw the outlines of boxes
458-- C.f. https://en.wikipedia.org/wiki/Box-drawing_character
412-- C.f. https://en.wikipedia.org/wiki/Box-drawing_character
459data BoxStyle = BoxStyle
413data BoxStyle = BoxStyle