on develop help sign in
Remove DynRegion in favor of Dynamic t Region
9f79773Ali Abrar
src/Reflex/Vty/Widget.hs+15−75
@@ -28,12 +28,6 @@ module Reflex.Vty.Widget
28 , HasDisplaySize(..)
28 , HasDisplaySize(..)
29 , HasFocus(..)
29 , HasFocus(..)
30 , HasVtyInput(..)
30 , HasVtyInput(..)
31− , DynRegion(..)
32− -- TODO get rid of DynRegion?
33− , joinDynRegion
34− , dynRegion
35− , dynamicRegion
36− , currentRegion
37 , Region(..)
31 , Region(..)
38 , regionSize
32 , regionSize
39 , regionBlankImage
33 , regionBlankImage
@@ -247,14 +241,6 @@ data Region = Region
247 }
241 }
248 deriving (Show, Read, Eq, Ord)
242 deriving (Show, Read, Eq, Ord)
249
243
250−-- | A dynamic chunk of the display area
251−data DynRegion t = DynRegion
252− { _dynRegion_left :: Dynamic t Int
253− , _dynRegion_top :: Dynamic t Int
254− , _dynRegion_width :: Dynamic t Int
255− , _dynRegion_height :: Dynamic t Int
256− }
257−
258-- | The width and height of a 'Region'
244-- | The width and height of a 'Region'
259regionSize :: Region -> (Int, Int)
245regionSize :: Region -> (Int, Int)
260regionSize (Region _ _ w h) = (w, h)
246regionSize (Region _ _ w h) = (w, h)
@@ -264,32 +250,6 @@ regionBlankImage :: Region -> Image
264regionBlankImage r@(Region _ _ width height) =
250regionBlankImage r@(Region _ _ width height) =
265 withinImage r $ V.charFill V.defAttr ' ' width height
251 withinImage r $ V.charFill V.defAttr ' ' width height
266
252
267−-- | A behavior of the current display area represented by a 'DynRegion'
268−currentRegion :: Reflex t => DynRegion t -> Behavior t Region
269−currentRegion (DynRegion l t w h) = Region <$> current l <*> current t <*> current w <*> current h
270−
271−joinDynRegion :: Reflex t => Dynamic t (DynRegion t) -> DynRegion t
272−joinDynRegion d = DynRegion
273− (_dynRegion_left =<< d)
274− (_dynRegion_top =<< d)
275− (_dynRegion_width =<< d)
276− (_dynRegion_height =<< d)
277−
278−dynRegion :: Reflex t => Dynamic t Region -> DynRegion t
279−dynRegion r = DynRegion
280− { _dynRegion_left = _region_left <$> r
281− , _dynRegion_top = _region_top <$> r
282− , _dynRegion_width = _region_width <$> r
283− , _dynRegion_height = _region_height <$> r
284− }
285−
286−dynamicRegion :: Reflex t => DynRegion t -> Dynamic t Region
287−dynamicRegion d = Region
288− <$> _dynRegion_left d
289− <*> _dynRegion_top d
290− <*> _dynRegion_width d
291− <*> _dynRegion_height d
292−
293-- | Translates and crops an 'Image' so that it is contained by
253-- | Translates and crops an 'Image' so that it is contained by
294-- the given 'Region'.
254-- the given 'Region'.
295withinImage
255withinImage
@@ -309,13 +269,13 @@ withinImage (Region left top width height)
309-- that (0,0) is the top-left corner of the region
269-- that (0,0) is the top-left corner of the region
310pane
270pane
311 :: (Reflex t, Monad m, MonadNodeId m)
271 :: (Reflex t, Monad m, MonadNodeId m)
312− => DynRegion t
272+ => Dynamic t Region
313 -> Dynamic t Bool -- ^ Whether the widget should be focused when the parent is.
273 -> Dynamic t Bool -- ^ Whether the widget should be focused when the parent is.
314 -> VtyWidget t m a
274 -> VtyWidget t m a
315 -> VtyWidget t m a
275 -> VtyWidget t m a
316pane dr foc child = VtyWidget $ do
276pane dr foc child = VtyWidget $ do
317 ctx <- lift ask
277 ctx <- lift ask
318− let reg = currentRegion dr
278+ let reg = current dr
319 let ctx' = VtyWidgetCtx
279 let ctx' = VtyWidgetCtx
320 { _vtyWidgetCtx_input = leftmost -- TODO: think about this leftmost more.
280 { _vtyWidgetCtx_input = leftmost -- TODO: think about this leftmost more.
321 [ fmapMaybe id $
281 [ fmapMaybe id $
@@ -324,8 +284,8 @@ pane dr foc child = VtyWidget $ do
324 (_vtyWidgetCtx_input ctx)
284 (_vtyWidgetCtx_input ctx)
325 ]
285 ]
326 , _vtyWidgetCtx_focus = liftA2 (&&) (_vtyWidgetCtx_focus ctx) foc
286 , _vtyWidgetCtx_focus = liftA2 (&&) (_vtyWidgetCtx_focus ctx) foc
327− , _vtyWidgetCtx_width = _dynRegion_width dr
287+ , _vtyWidgetCtx_width = _region_width <$> dr
328− , _vtyWidgetCtx_height = _dynRegion_height dr
288+ , _vtyWidgetCtx_height = _region_height <$> dr
329 }
289 }
330 (result, images) <- lift . lift $ runVtyWidget ctx' child
290 (result, images) <- lift . lift $ runVtyWidget ctx' child
331 let images' = liftA2 (\r is -> map (withinImage r) is) reg images
291 let images' = liftA2 (\r is -> map (withinImage r) is) reg images
@@ -488,18 +448,8 @@ splitV :: (Reflex t, Monad m, MonadNodeId m)
488splitV sizeFunD focD wA wB = do
448splitV sizeFunD focD wA wB = do
489 dw <- displayWidth
449 dw <- displayWidth
490 dh <- displayHeight
450 dh <- displayHeight
491− let regA = DynRegion
451+ let regA = Region 0 0 <$> dw <*> (sizeFunD <*> dh)
492− { _dynRegion_left = pure 0
452+ regB = Region 0 <$> (_region_height <$> regA) <*> dw <*> liftA2 (-) dh (_region_height <$> regA)
493− , _dynRegion_top = pure 0
494− , _dynRegion_width = dw
495− , _dynRegion_height = sizeFunD <*> dh
496− }
497− regB = DynRegion
498− { _dynRegion_left = pure 0
499− , _dynRegion_top = _dynRegion_height regA
500− , _dynRegion_width = dw
501− , _dynRegion_height = liftA2 (-) dh (_dynRegion_height regA)
502− }
503 ra <- pane regA (fst <$> focD) wA
453 ra <- pane regA (fst <$> focD) wA
504 rb <- pane regB (snd <$> focD) wB
454 rb <- pane regB (snd <$> focD) wB
505 return (ra,rb)
455 return (ra,rb)
@@ -519,18 +469,8 @@ splitH :: (Reflex t, Monad m, MonadNodeId m)
519splitH sizeFunD focD wA wB = do
469splitH sizeFunD focD wA wB = do
520 dw <- displayWidth
470 dw <- displayWidth
521 dh <- displayHeight
471 dh <- displayHeight
522− let regA = DynRegion
472+ let regA = Region 0 0 <$> (sizeFunD <*> dw) <*> dh
523− { _dynRegion_left = pure 0
473+ regB = Region <$> (_region_width <$> regA) <*> 0 <*> liftA2 (-) dw (_region_width <$> regA) <*> dh
524− , _dynRegion_top = pure 0
525− , _dynRegion_width = sizeFunD <*> dw
526− , _dynRegion_height = dh
527− }
528− regB = DynRegion
529− { _dynRegion_left = _dynRegion_width regA
530− , _dynRegion_top = pure 0
531− , _dynRegion_width = liftA2 (-) dw (_dynRegion_width regA)
532− , _dynRegion_height = dh
533− }
534 liftA2 (,) (pane regA (fmap fst focD) wA) (pane regB (fmap snd focD) wB)
474 liftA2 (,) (pane regA (fmap fst focD) wA) (pane regB (fmap snd focD) wB)
535
475
536-- | A split of the available space into two parts with a draggable separator.
476-- | A split of the available space into two parts with a draggable separator.
@@ -554,9 +494,9 @@ splitVDrag wS wA wB = do
554 let dragSplitter = fforMaybe (attach (current splitterCheckpoint) dragE) $
494 let dragSplitter = fforMaybe (attach (current splitterCheckpoint) dragE) $
555 \(splitterY, Drag (_, fromY) (_, toY) _ _ end) ->
495 \(splitterY, Drag (_, fromY) (_, toY) _ _ end) ->
556 if splitterY == fromY then Just (toY, end) else Nothing
496 if splitterY == fromY then Just (toY, end) else Nothing
557− regA = DynRegion 0 0 dw splitterPos
497+ regA = Region 0 0 <$> dw <*> splitterPos
558− regS = DynRegion 0 splitterPos dw 1
498+ regS = Region 0 <$> splitterPos <*> dw <*> 1
559− regB = DynRegion 0 (splitterPos + 1) dw (dh - splitterPos - 1)
499+ regB = Region 0 <$> (splitterPos + 1) <*> dw <*> (dh - splitterPos - 1)
560 resizeSplitter = ffor (attach (current splitterFrac) (updated dh)) $
500 resizeSplitter = ffor (attach (current splitterFrac) (updated dh)) $
561 \(frac, h) -> round (frac * fromIntegral h)
501 \(frac, h) -> round (frac * fromIntegral h)
562 focA <- holdDyn True $ leftmost
502 focA <- holdDyn True $ leftmost
@@ -631,10 +571,10 @@ boxTitle :: (Monad m, Reflex t, MonadNodeId m)
631boxTitle boxStyle title child = do
571boxTitle boxStyle title child = do
632 dh <- displayHeight
572 dh <- displayHeight
633 dw <- displayWidth
573 dw <- displayWidth
634− let boxReg = DynRegion (pure 0) (pure 0) dw dh
574+ let boxReg = Region 0 0 <$> dw <*> dh
635− innerReg = DynRegion (pure 1) (pure 1) (subtract 2 <$> dw) (subtract 2 <$> dh)
575+ innerReg = Region 1 1 <$> (subtract 2 <$> dw) <*> (subtract 2 <$> dh)
636− tellImages (boxImages <$> boxStyle <*> currentRegion boxReg)
576+ tellImages (boxImages <$> boxStyle <*> current boxReg)
637− tellImages (fmap (\r -> [regionBlankImage r]) (currentRegion innerReg))
577+ tellImages (fmap (\r -> [regionBlankImage r]) (current innerReg))
638 pane innerReg (pure True) child
578 pane innerReg (pure True) child
639 where
579 where
640 boxImages :: BoxStyle -> Region -> [Image]
580 boxImages :: BoxStyle -> Region -> [Image]
src/Reflex/Vty/Widget/Layout.hs+35−235
@@ -9,40 +9,38 @@ Description: Monad transformer and tools for arranging widgets and building scre
9{-# LANGUAGE RecursiveDo #-}
9{-# LANGUAGE RecursiveDo #-}
10{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE OverloadedStrings #-}
11{-# LANGUAGE OverloadedStrings #-}
12−{-# LANGUAGE TupleSections #-}
13{-# LANGUAGE UndecidableInstances #-}
12{-# LANGUAGE UndecidableInstances #-}
14
13
15−module Reflex.Vty.Widget.Layout where
14+module Reflex.Vty.Widget.Layout
16− -- ( Orientation(..)
15+ ( Orientation(..)
17− -- , Constraint(..)
16+ , Constraint(..)
18− -- , Layout
17+ , Layout(..)
19− -- , runLayout
18+ , runLayout
20− -- , TileConfig(..)
19+ , TileConfig(..)
21− -- , tile
20+ , tile
22− -- , fixed
21+ , fixed
23− -- , stretch
22+ , stretch
24− -- , col
23+ , col
25− -- , row
24+ , row
26− -- , tabNavigation
25+ , tabNavigation
27− -- , askOrientation
26+ , askOrientation
27+ , Focus(..)
28+ , runFocus
29+ , focusId
30+ , LForest(..)
31+
32+ , test
28− -- ) where
33+ ) where
29−
34+
30−import Control.Monad.NodeId (MonadNodeId(..), NodeId, NodeIdT)
35+import Control.Monad.NodeId (MonadNodeId(..), NodeId)
31import Control.Monad.Reader
36import Control.Monad.Reader
32−import Data.Bimap (Bimap)
33−import qualified Data.Bimap as Bimap
34import Data.Default (Default(..))
37import Data.Default (Default(..))
35import Data.List
38import Data.List
36−import Data.Map (Map)
37−import qualified Data.Map as Map
38−import Data.Maybe (fromMaybe)
39−import Data.Monoid hiding (First(..))
40import Data.Ratio ((%))
39import Data.Ratio ((%))
41−import Data.Semigroup (First(..))
42import Data.Sequence (Seq)
40import Data.Sequence (Seq)
43import qualified Data.Sequence as Seq
41import qualified Data.Sequence as Seq
44import qualified Graphics.Vty as V
42import qualified Graphics.Vty as V
45−import Data.Map.Ordered (OMap, Bias(..), L)
43+import Data.Map.Ordered (OMap)
46import qualified Data.Map.Ordered as OMap
44import qualified Data.Map.Ordered as OMap
47import qualified Graphics.Vty.Attributes as V
45import qualified Graphics.Vty.Attributes as V
48
46
@@ -93,18 +91,13 @@ runFocus e (Focus x) = do
93 sel <- holdDyn Nothing e
91 sel <- holdDyn Nothing e
94 pure (a, focusIds)
92 pure (a, focusIds)
95
93
96−withFocus
94+isFocused
97 :: (Reflex t, Monad m)
95 :: (Reflex t, Monad m)
98 => FocusId
96 => FocusId
99− -> (Dynamic t Bool -> Focus t m a) -- TODO unnecessary: just return the dynamic bool
97+ -> Focus t m (Dynamic t Bool)
100− -> Focus t m a
98+isFocused fid = do
101−withFocus focusId builder = do
102 sel <- Focus ask
99 sel <- Focus ask
103− builder $ demuxed sel $ Just focusId
100+ pure $ demuxed sel $ Just fid
104−
105−-- focus builder = do
106−-- fid <- focusId
107−-- withFocus fid builder
108
101
109-- | Configuration options for and constraints on 'tile'
102-- | Configuration options for and constraints on 'tile'
110data TileConfig t = TileConfig
103data TileConfig t = TileConfig
@@ -123,7 +116,7 @@ tile
123 -> Layout t (Focus t (VtyWidget t m)) a
116 -> Layout t (Focus t (VtyWidget t m)) a
124tile w = do
117tile w = do
125 fid <- lift focusId
118 fid <- lift focusId
126− focused <- lift $ withFocus fid return
119+ focused <- lift $ isFocused fid
127 stretch $ \r -> lift $ pane r focused w
120 stretch $ \r -> lift $ pane r focused w
128
121
129-- * Layout
122-- * Layout
@@ -194,7 +187,7 @@ axis
194 -> Layout t m a
187 -> Layout t m a
195axis o c (Layout x) = Layout $ do
188axis o c (Layout x) = Layout $ do
196 nodeId <- getNextNodeId
189 nodeId <- getNextNodeId
197− (result, forest) <- lift $ local (\t -> (\(Just x) -> x) . lookupLF nodeId . ltreeForest <$> t) $ runDynamicWriterT x -- TODO?
190+ (result, forest) <- lift $ local (\t -> (\(Just x) -> x) . lookupLF nodeId . ltreeForest <$> t) $ runDynamicWriterT x
198 tellDyn $ fmap (singletonLF nodeId . LTree (c, o)) forest
191 tellDyn $ fmap (singletonLF nodeId . LTree (c, o)) forest
199 pure result
192 pure result
200
193
@@ -209,28 +202,29 @@ col = axis Orientation_Column
209leaf
202leaf
210 :: (Monad m, MonadNodeId m, Reflex t, MonadFix m)
203 :: (Monad m, MonadNodeId m, Reflex t, MonadFix m)
211 => Dynamic t Constraint
204 => Dynamic t Constraint
212− -> (DynRegion t -> m a)
205+ -> (Dynamic t Region -> m a)
213 -> Layout t m a
206 -> Layout t m a
214leaf c f = do
207leaf c f = do
215 nodeId <- lift getNextNodeId
208 nodeId <- lift getNextNodeId
216 Layout $ tellDyn $ ffor c $ \c' -> singletonLF nodeId $ LTree (c', Orientation_Row) mempty
209 Layout $ tellDyn $ ffor c $ \c' -> singletonLF nodeId $ LTree (c', Orientation_Row) mempty
217 solutions <- Layout ask
210 solutions <- Layout ask
218 let r = maybe (Region 0 0 0 0) (fst . ltreeRoot) . lookupLF nodeId . ltreeForest <$> solutions -- TODO revisit this fromMaybe
211 let r = maybe (Region 0 0 0 0) (fst . ltreeRoot) . lookupLF nodeId . ltreeForest <$> solutions -- TODO revisit this fromMaybe
219− lift $ f $ dynRegion r
212+ lift $ f r
220
213
221fixed
214fixed
222 :: (Monad m, MonadNodeId m, Reflex t, MonadFix m)
215 :: (Monad m, MonadNodeId m, Reflex t, MonadFix m)
223 => Dynamic t Int
216 => Dynamic t Int
224− -> (DynRegion t -> m a)
217+ -> (Dynamic t Region -> m a)
225 -> Layout t m a
218 -> Layout t m a
226fixed = leaf . fmap Constraint_Fixed
219fixed = leaf . fmap Constraint_Fixed
227
220
228stretch
221stretch
229 :: (Monad m, MonadNodeId m, Reflex t, MonadFix m)
222 :: (Monad m, MonadNodeId m, Reflex t, MonadFix m)
230− => (DynRegion t -> m a)
223+ => (Dynamic t Region -> m a)
231 -> Layout t m a
224 -> Layout t m a
232stretch = leaf (pure $ Constraint_Min 0)
225stretch = leaf (pure $ Constraint_Min 0)
233
226
227+-- | Retrieve the current orientation of a 'Layout'
234askOrientation :: (Monad m, Reflex t) => Layout t m (Dynamic t Orientation)
228askOrientation :: (Monad m, Reflex t) => Layout t m (Dynamic t Orientation)
235askOrientation = Layout $ asks $ fmap (snd . ltreeRoot)
229askOrientation = Layout $ asks $ fmap (snd . ltreeRoot)
236
230
@@ -301,197 +295,6 @@ runLayout o r (Layout x) = do
301 return result
295 return result
302
296
303{-
297{-
304−data LayoutSegment = LayoutSegment
305− { _layoutSegment_offset :: Int
306− , _layoutSegment_size :: Int
307− }
308−
309−data LayoutCtx t = LayoutCtx
310− { _layoutCtx_regions :: Dynamic t (Map NodeId LayoutSegment)
311− , _layoutCtx_focusDemux :: Demux t (Maybe NodeId)
312− , _layoutCtx_orientation :: Dynamic t Orientation
313− }
314−
315−-- | The Layout monad transformer keeps track of the configuration (e.g., 'Orientation') and
316−-- 'Constraint's of its child widgets, apportions vty real estate to each, and acts as a
317−-- switchboard for focus requests. See 'tile' and 'runLayout'.
318−newtype Layout t m a = Layout
319− { unLayout :: EventWriterT t (First NodeId)
320− (DynamicWriterT t (Endo [(NodeId, (Bool, Constraint))])
321− (ReaderT (LayoutCtx t)
322− (VtyWidget t m))) a
323− } deriving
324− ( Functor
325− , Applicative
326− , Monad
327− , MonadHold t
328− , MonadSample t
329− , MonadFix
330− , TriggerEvent t
331− , PerformEvent t
332− , NotReady t
333− , MonadReflexCreateTrigger t
334− , HasDisplaySize t
335− , MonadNodeId
336− , PostBuild t
337− )
338−
339−instance MonadTrans (Layout t) where
340− lift x = Layout $ lift $ lift $ lift $ lift x
341−
342−instance (Adjustable t m, MonadFix m, MonadHold t m) => Adjustable t (Layout t m) where
343− runWithReplace (Layout a) e = Layout $ runWithReplace a $ fmap unLayout e
344− traverseIntMapWithKeyWithAdjust f m e = Layout $ traverseIntMapWithKeyWithAdjust (\k v -> unLayout $ f k v) m e
345− traverseDMapWithKeyWithAdjust f m e = Layout $ traverseDMapWithKeyWithAdjust (\k v -> unLayout $ f k v) m e
346− traverseDMapWithKeyWithAdjustWithMove f m e = Layout $ traverseDMapWithKeyWithAdjustWithMove (\k v -> unLayout $ f k v) m e
347−
348−-- | Run a 'Layout' action
349−runLayout
350− :: (MonadFix m, MonadHold t m, PostBuild t m, Monad m, MonadNodeId m)
351− => Dynamic t Orientation -- ^ The main-axis 'Orientation' of this 'Layout'
352− -> Int -- ^ The positional index of the initially focused tile
353− -> Event t Int -- ^ An event that shifts focus by a given number of tiles
354− -> Layout t m a -- ^ The 'Layout' widget
355− -> VtyWidget t m a
356−runLayout ddir focus0 focusShift (Layout child) = do
357− dw <- displayWidth
358− dh <- displayHeight
359− let main = ffor3 ddir dw dh $ \d w h -> case d of
360− Orientation_Column -> h
361− Orientation_Row -> w
362− pb <- getPostBuild
363− rec ((a, focusReq), queriesEndo) <- runReaderT (runDynamicWriterT $ runEventWriterT child) $ LayoutCtx solutionMap focusDemux ddir
364− let queries = flip appEndo [] <$> queriesEndo
365− solution = ffor2 main queries $ \sz qs -> Map.fromList
366− . Map.elems
367− . computeEdges
368− . computeSizes sz
369− . fmap (fmap snd)
370− . Map.fromList
371− . zip [0::Integer ..]
372− $ qs
373− solutionMap = ffor solution $ \ss -> ffor ss $ \(offset, sz) -> LayoutSegment
374− { _layoutSegment_offset = offset
375− , _layoutSegment_size = sz
376− }
377− -- focusable = fmap (Bimap.fromList . zip [0..]) $
378− -- ffor queries $ \qs -> fforMaybe qs $ \(nodeId, (f, _)) ->
379− -- if f then Just nodeId else Nothing
380− -- adjustFocus
381− -- :: (Bimap Int NodeId, (Int, Maybe NodeId))
382− -- -> Either Int NodeId
383− -- -> (Int, Maybe NodeId)
384− -- adjustFocus (fm, (cur, _)) (Left shift) =
385− -- let ix = (cur + shift) `mod` (max 1 $ Bimap.size fm)
386− -- in (ix, Bimap.lookup ix fm)
387− -- adjustFocus (fm, (cur, _)) (Right goto) =
388− -- let ix = fromMaybe cur $ Bimap.lookupR goto fm
389− -- in (ix, Just goto)
390− -- focusChange = attachWith
391− -- adjustFocus
392− -- (current $ (,) <$> focusable <*> focussed)
393− -- $ leftmost [Left <$> focusShift, Left 0 <$ pb, Right . getFirst <$> focusReq]
394− -- A pair (Int, Maybe NodeId) which represents the index
395− -- that we're trying to focus, and the node that actually gets
396− -- focused (at that index) if it exists
397− focussed <- holdDyn (focus0, Nothing) focusChange
398− let focusDemux = demux $ snd <$> focussed
399− return a
400−
401−-- | Tiles are the basic building blocks of 'Layout' widgets. Each tile has a constraint
402−-- on its size and ability to grow and on whether it can be focused. It also allows its child
403−-- widget to request focus.
404−tile
405− :: (Reflex t, Monad m, MonadNodeId m)
406− => TileConfig t -- ^ The tile's configuration
407− -> VtyWidget t m (Event t x, a) -- ^ A child widget. The 'Event' that it returns is used to request that it be focused.
408− -> Layout t m a
409−tile (TileConfig con focusable) child = do
410− nodeId <- getNextNodeId
411− Layout $ tellDyn $ ffor2 con focusable $ \c f -> Endo ((nodeId, (f, c)):)
412− seg <- Layout $ asks $
413− fmap (Map.findWithDefault (LayoutSegment 0 0) nodeId) . _layoutCtx_regions
414− dw <- displayWidth
415− dh <- displayHeight
416− o <- askOrientation
417− let cross = join $ ffor o $ \case
418− Orientation_Column -> dw
419− Orientation_Row -> dh
420− let reg = DynRegion
421− { _dynRegion_top = ffor2 seg o $ \s -> \case
422− Orientation_Column -> _layoutSegment_offset s
423− Orientation_Row -> 0
424− , _dynRegion_left = ffor2 seg o $ \s -> \case
425− Orientation_Column -> 0
426− Orientation_Row -> _layoutSegment_offset s
427− , _dynRegion_width = ffor3 seg cross o $ \s c -> \case
428− Orientation_Column -> c
429− Orientation_Row -> _layoutSegment_size s
430− , _dynRegion_height = ffor3 seg cross o $ \s c -> \case
431− Orientation_Column -> _layoutSegment_size s
432− Orientation_Row -> c
433− }
434− focussed <- Layout $ asks _layoutCtx_focusDemux
435− (focusReq, a) <- Layout $ lift $ lift $ lift $
436− pane reg (demuxed focussed $ Just nodeId) $ child
437− Layout $ tellEvent $ First nodeId <$ focusReq
438− return a
439−
440−-- | Configuration options for and constraints on 'tile'
441−data TileConfig t = TileConfig
442− { _tileConfig_constraint :: Dynamic t Constraint
443− -- ^ 'Constraint' on the tile's size
444− , _tileConfig_focusable :: Dynamic t Bool
445− -- ^ Whether the tile is focusable
446− }
447−
448−instance Reflex t => Default (TileConfig t) where
449− def = TileConfig (pure $ Constraint_Min 0) (pure True)
450−
451−-- | A 'tile' of a fixed size that is focusable and gains focus on click
452−fixed
453− :: (Reflex t, Monad m, MonadNodeId m)
454− => Dynamic t Int
455− -> VtyWidget t m a
456− -> Layout t m a
457−fixed sz = tile (def { _tileConfig_constraint = Constraint_Fixed <$> sz }) . clickable
458−
459−-- | A 'tile' that can stretch (i.e., has no fixed size) and has a minimum size of 0.
460−-- This tile is focusable and gains focus on click.
461−stretch
462− :: (Reflex t, Monad m, MonadNodeId m)
463− => VtyWidget t m a
464− -> Layout t m a
465−stretch = tile def . clickable
466−
467−-- | A version of 'runLayout' that arranges tiles in a column and uses 'tabNavigation' to
468−-- change tile focus.
469−col
470− :: (MonadFix m, MonadHold t m, PostBuild t m, MonadNodeId m)
471− => Layout t m a
472− -> VtyWidget t m a
473−col child = do
474− nav <- tabNavigation
475− runLayout (pure Orientation_Column) 0 nav child
476−
477−-- | A version of 'runLayout' that arranges tiles in a row and uses 'tabNavigation' to
478−-- change tile focus.
479−row
480− :: (MonadFix m, MonadHold t m, PostBuild t m, MonadNodeId m)
481− => Layout t m a
482− -> VtyWidget t m a
483−row child = do
484− nav <- tabNavigation
485− runLayout (pure Orientation_Row) 0 nav child
486−
487−-- | Produces an 'Event' that navigates forward one tile when the Tab key is pressed
488−-- and backward one tile when Shift+Tab is pressed.
489−tabNavigation :: (Reflex t, Monad m) => VtyWidget t m (Event t Int)
490−tabNavigation = do
491− fwd <- fmap (const 1) <$> key (V.KChar '\t')
492− back <- fmap (const (-1)) <$> key V.KBackTab
493− return $ leftmost [fwd, back]
494−
495-- | Captures the click event in a 'VtyWidget' context and returns it. Useful for
298-- | Captures the click event in a 'VtyWidget' context and returns it. Useful for
496-- requesting focus when using 'tile'.
299-- requesting focus when using 'tile'.
497clickable
300clickable
@@ -503,10 +306,6 @@ clickable child = do
503 a <- child
306 a <- child
504 return (() <$ click, a)
307 return (() <$ click, a)
505
308
506−-- | Retrieve the current orientation of a 'Layout'
507−askOrientation :: Monad m => Layout t m (Dynamic t Orientation)
508−askOrientation = Layout $ asks _layoutCtx_orientation
509−
510-}
309-}
511
310
512-- | Produces an 'Event' that navigates forward one tile when the Tab key is pressed
311-- | Produces an 'Event' that navigates forward one tile when the Tab key is pressed
@@ -545,3 +344,4 @@ test = mainWidget $ do
545 _ -> Nothing
344 _ -> Nothing
546
345
547 -- TODO These functions shouldn't be so higher order
346 -- TODO These functions shouldn't be so higher order
347+ -- TODO request focus