@@ -102,7 +102,7 @@ import Reflex.Class ()
102102
103103import Reflex.Vty.Host
104104
105−import Unsafe.NodeId
105+import Control.Monad.NodeId
106106
107107-- | The context within which a 'VtyWidget' runs
108108data VtyWidgetCtx t = VtyWidgetCtx
@@ -149,15 +149,20 @@ newtype VtyWidget t m a = VtyWidget
149149 , PostBuild t
150150 , TriggerEvent t
151151 , MonadReflexCreateTrigger t
152+ , MonadIO
152153 )
153154
154155deriving instance PerformEvent t m => PerformEvent t (VtyWidget t m)
155156instance MonadTrans (VtyWidget t) where
156157 lift f = VtyWidget $ lift $ lift f
157158
159+instance MonadNodeId m => MonadNodeId (VtyWidget t m) where
160+ getNextNodeId = VtyWidget $ do
161+ lift $ lift $ getNextNodeId
162+
158163-- | Runs a 'VtyWidget' with a given context
159164runVtyWidget
160− :: (Reflex t, Monad m)
165+ :: (Reflex t, MonadNodeId m)
161166 => VtyWidgetCtx t
162167 -> VtyWidget t m a
163168 -> m (a, Behavior t [Image])
@@ -166,7 +171,7 @@ runVtyWidget ctx w = runReaderT (runBehaviorWriterT (unVtyWidget w)) ctx
166171-- | Sets up the top-level context for a 'VtyWidget' and runs it with that context
167172mainWidgetWithHandle
168173 :: V.Vty
169− -> (forall t m. MonadVtyApp t m => VtyWidget t m (Event t ()))
174+ -> (forall t m. (MonadVtyApp t m, MonadNodeId m) => VtyWidget t m (Event t ()))
170175 -> IO ()
171176mainWidgetWithHandle vty child =
172177 runVtyAppWithHandle vty $ \dr0 inp -> do
@@ -182,7 +187,7 @@ mainWidgetWithHandle vty child =
182187 , _vtyWidgetCtx_input = inp'
183188 , _vtyWidgetCtx_focus = constDyn True
184189 }
185− (shutdown, images) <- runVtyWidget ctx $ do
190+ (shutdown, images) <- runNodeIdT $ runVtyWidget ctx $ do
186191 tellImages . ffor (current size) $ \(w, h) -> [V.charFill V.defAttr ' ' w h]
187192 child
188193 return $ VtyResult
@@ -192,7 +197,7 @@ mainWidgetWithHandle vty child =
192197
193198-- | Like 'mainWidgetWithHandle', but uses a default vty configuration
194199mainWidget
195− :: (forall t m. MonadVtyApp t m => VtyWidget t m (Event t ()))
200+ :: (forall t m. (MonadVtyApp t m, MonadNodeId m) => VtyWidget t m (Event t ()))
196201 -> IO ()
197202mainWidget child = do
198203 vty <- getDefaultVty
@@ -218,6 +223,8 @@ instance HasDisplaySize t m => HasDisplaySize t (BehaviorWriterT t x m)
218223instance HasDisplaySize t m => HasDisplaySize t (DynamicWriterT t x m)
219224instance HasDisplaySize t m => HasDisplaySize t (EventWriterT t x m)
220225
226+instance HasDisplaySize t m => HasDisplaySize t (NodeIdT m)
227+
221228-- | A class for things that can receive vty events as input
222229class HasVtyInput t m | m -> t where
223230 input :: m (Event t VtyEvent)
@@ -257,14 +264,6 @@ data DynRegion t = DynRegion
257264 , _dynRegion_height :: Dynamic t Int
258265 }
259266
260−switchDynRegion :: Reflex t => Dynamic t (DynRegion t) -> DynRegion t
261−switchDynRegion r = DynRegion
262− { _dynRegion_left = _dynRegion_left =<< r
263− , _dynRegion_top = _dynRegion_top =<< r
264− , _dynRegion_width = _dynRegion_width =<< r
265− , _dynRegion_height = _dynRegion_height =<< r
266− }
267−
268267-- | The width and height of a 'Region'
269268regionSize :: Region -> (Int, Int)
270269regionSize (Region _ _ w h) = (w, h)
@@ -296,7 +295,7 @@ withinImage (Region left top width height)
296295-- * mouse inputs inside the region have their coordinates translated such
297296-- that (0,0) is the top-left corner of the region
298297pane
299− :: (Reflex t, Monad m)
298+ :: (Reflex t, Monad m, MonadNodeId m)
300299 => DynRegion t
301300 -> Dynamic t Bool -- ^ Whether the widget should be focused when the parent is.
302301 -> VtyWidget t m a
@@ -440,7 +439,7 @@ keyCombos ks = do
440439
441440-- | A plain split of the available space into vertically stacked panes.
442441-- No visual separator is built in here.
443−splitV :: (Reflex t, Monad m)
442+splitV :: (Reflex t, Monad m, MonadNodeId m)
444443 => Dynamic t (Int -> Int)
445444 -- ^ Function used to determine size of first pane based on available size
446445 -> Dynamic t (Bool, Bool)
@@ -472,7 +471,7 @@ splitV sizeFunD focD wA wB = do
472471-- | A split of the available space into two parts with a draggable separator.
473472-- Starts with half the space allocated to each, and the first pane has focus.
474473-- Clicking in a pane switches focus.
475−splitVDrag :: (Reflex t, MonadFix m, MonadHold t m)
474+splitVDrag :: (Reflex t, MonadFix m, MonadHold t m, MonadNodeId m)
476475 => VtyWidget t m ()
477476 -> VtyWidget t m a
478477 -> VtyWidget t m b
@@ -486,7 +485,7 @@ splitVDrag wS wA wB = do
486485 rec splitterCheckpoint <- holdDyn splitter0 $ leftmost [fst <$> ffilter snd dragSplitter, resizeSplitter]
487486 splitterPos <- holdDyn splitter0 $ leftmost [fst <$> dragSplitter, resizeSplitter]
488487 splitterFrac <- holdDyn ((1::Double) / 2) $ ffor (attach (current dh) (fst <$> dragSplitter)) $ \(h, x) ->
489− fromIntegral x / fromIntegral h
488+ fromIntegral x / (max 1 (fromIntegral h))
490489 let dragSplitter = fforMaybe (attach (current splitterCheckpoint) dragE) $
491490 \(splitterY, Drag (_, fromY) (_, toY) _ _ end) ->
492491 if splitterY == fromY then Just (toY, end) else Nothing
@@ -559,7 +558,7 @@ roundedBoxStyle :: BoxStyle
559558roundedBoxStyle = BoxStyle '╭' '─' '╮' '│' '╯' '─' '╰' '│'
560559
561560-- | Draws a box in the provided style and a child widget inside of that box
562−box :: (Monad m, Reflex t)
561+box :: (Monad m, Reflex t, MonadNodeId m)
563562 => Behavior t BoxStyle
564563 -> VtyWidget t m a
565564 -> VtyWidget t m a
@@ -600,7 +599,7 @@ box boxStyle child = do
600599
601600-- | A box whose style is static
602601boxStatic
603− :: (Reflex t, Monad m)
602+ :: (Reflex t, Monad m, MonadNodeId m)
604603 => BoxStyle
605604 -> VtyWidget t m a
606605 -> VtyWidget t m a
@@ -663,7 +662,7 @@ computeSizes available constraints =
663662 (_, Constraint_Min n) -> n
664663 leftover = max 0 (available - minTotal)
665664 numStretch = Map.size $ Map.filter (isMin . snd) constraints
666− szStretch = floor $ leftover % numStretch
665+ szStretch = floor $ leftover % (max numStretch 1)
667666 adjustment = max 0 $ available - minTotal - szStretch * numStretch
668667 in snd $ Map.mapAccum (\adj (a, c) -> case c of
669668 Constraint_Fixed n -> (adj, (a, n))
@@ -684,8 +683,13 @@ data Orientation = Orientation_Column
684683 | Orientation_Row
685684 deriving (Show, Read, Eq, Ord)
686685
686+data LayoutSegment = LayoutSegment
687+ { _layoutSegment_offset :: Int
688+ , _layoutSegment_size :: Int
689+ }
690+
687691data LayoutCtx t = LayoutCtx
688− { _layoutCtx_regions :: Dynamic t (Map NodeId (DynRegion t))
692+ { _layoutCtx_regions :: Dynamic t (Map NodeId LayoutSegment)
689693 , _layoutCtx_focusDemux :: Demux t (Maybe NodeId)
690694 , _layoutCtx_orientation :: Dynamic t Orientation
691695 }
@@ -706,6 +710,8 @@ newtype Layout t m a = Layout
706710 , PerformEvent t
707711 , NotReady t
708712 , MonadReflexCreateTrigger t
713+ , HasDisplaySize t
714+ , MonadNodeId
709715 )
710716
711717instance MonadTrans (Layout t) where
@@ -718,7 +724,7 @@ instance (Adjustable t m, MonadFix m, MonadHold t m) => Adjustable t (Layout t m
718724 traverseDMapWithKeyWithAdjustWithMove f m e = Layout $ traverseDMapWithKeyWithAdjustWithMove (\k v -> unLayout $ f k v) m e
719725
720726runLayout
721− :: (MonadFix m, MonadHold t m, PostBuild t m)
727+ :: (MonadFix m, MonadHold t m, PostBuild t m, Monad m, MonadNodeId m)
722728 => Dynamic t Orientation
723729 -> Int
724730 -> Event t Int
@@ -741,19 +747,9 @@ runLayout ddir focus0 focusShift (Layout child) = do
741747 . Map.fromList
742748 . zip [0::Integer ..]
743749 $ qs
744− solutionMap = ffor solution $ \ss -> ffor ss $ \(offset, sz) -> DynRegion
745− { _dynRegion_left = ffor ddir $ \case
746− Orientation_Column -> 0
747− Orientation_Row -> offset
748− , _dynRegion_width = ffor2 dw ddir $ \w -> \case
749− Orientation_Column -> w
750− Orientation_Row -> sz
751− , _dynRegion_top = ffor ddir $ \case
752− Orientation_Column -> offset
753− Orientation_Row -> 0
754− , _dynRegion_height = ffor2 dh ddir $ \h -> \case
755− Orientation_Column -> sz
756− Orientation_Row -> h
750+ solutionMap = ffor solution $ \ss -> ffor ss $ \(offset, sz) -> LayoutSegment
751+ { _layoutSegment_offset = offset
752+ , _layoutSegment_size = sz
757753 }
758754 focusable = fmap (Bimap.fromList . zip [0..]) $
759755 ffor queries $ \qs -> fforMaybe qs $ \(nodeId, (f, _)) ->
@@ -763,7 +759,7 @@ runLayout ddir focus0 focusShift (Layout child) = do
763759 -> Either Int NodeId
764760 -> (Int, Maybe NodeId)
765761 adjustFocus (fm, (cur, _)) (Left shift) =
766− let ix = (cur + shift) `mod` Bimap.size fm
762+ let ix = (cur + shift) `mod` (max 1 $ Bimap.size fm)
767763 in (ix, Bimap.lookup ix fm)
768764 adjustFocus (fm, (cur, _)) (Right goto) =
769765 let ix = fromMaybe cur $ Bimap.lookupR goto fm
@@ -780,19 +776,39 @@ runLayout ddir focus0 focusShift (Layout child) = do
780776 return a
781777
782778tile
783− :: (Reflex t, Monad m)
779+ :: (Reflex t, Monad m, MonadNodeId m)
784780 => Dynamic t Constraint
785781 -> Dynamic t Bool
786782 -> VtyWidget t m (Event t x, a)
787783 -> Layout t m a
788784tile con focusable child = do
789− let nodeId = unsafeNodeId child
785+ nodeId <- getNextNodeId
790786 Layout $ tellDyn $ ffor2 con focusable $ \c f -> Endo ((nodeId, (f, c)):)
791− reg <- fmap switchDynRegion $ Layout $ asks $
792− fmap (Map.findWithDefault (error "tile: Could not find solution for nodeId. This should be impossible.") nodeId) . _layoutCtx_regions
787+ seg <- Layout $ asks $
788+ fmap (Map.findWithDefault (LayoutSegment 0 0) nodeId) . _layoutCtx_regions
789+ dw <- displayWidth
790+ dh <- displayHeight
791+ o <- askOrientation
792+ let cross = join $ ffor o $ \case
793+ Orientation_Column -> dw
794+ Orientation_Row -> dh
795+ let reg = DynRegion
796+ { _dynRegion_top = ffor2 seg o $ \s -> \case
797+ Orientation_Column -> _layoutSegment_offset s
798+ Orientation_Row -> 0
799+ , _dynRegion_left = ffor2 seg o $ \s -> \case
800+ Orientation_Column -> 0
801+ Orientation_Row -> _layoutSegment_offset s
802+ , _dynRegion_width = ffor3 seg cross o $ \s c -> \case
803+ Orientation_Column -> c
804+ Orientation_Row -> _layoutSegment_size s
805+ , _dynRegion_height = ffor3 seg cross o $ \s c -> \case
806+ Orientation_Column -> _layoutSegment_size s
807+ Orientation_Row -> c
808+ }
793809 focussed <- Layout $ asks _layoutCtx_focusDemux
794810 (focusReq, a) <- Layout $ lift $ lift $ lift $
795− pane reg (demuxed focussed $ Just nodeId) child
811+ pane reg (demuxed focussed $ Just nodeId) $ child
796812 Layout $ tellEvent $ First nodeId <$ focusReq
797813 return a
798814
@@ -806,20 +822,20 @@ instance Reflex t => Default (TileConfig t) where
806822 def = TileConfig (pure $ Constraint_Min 0) (pure True) (pure True)
807823
808824fixed
809− :: (Reflex t, Monad m)
825+ :: (Reflex t, Monad m, MonadNodeId m)
810826 => Dynamic t Int
811827 -> VtyWidget t m a
812828 -> Layout t m a
813829fixed sz = tile (Constraint_Fixed <$> sz) (pure True) . clickable
814830
815831stretch
816− :: (Reflex t, Monad m)
832+ :: (Reflex t, Monad m, MonadNodeId m)
817833 => VtyWidget t m a
818834 -> Layout t m a
819835stretch = tile (Constraint_Min <$> 0) (pure True) . clickable
820836
821837col
822− :: (MonadFix m, MonadHold t m, PostBuild t m)
838+ :: (MonadFix m, MonadHold t m, PostBuild t m, MonadNodeId m)
823839 => Layout t m a
824840 -> VtyWidget t m a
825841col child = do
@@ -827,7 +843,7 @@ col child = do
827843 runLayout (pure Orientation_Column) 0 nav child
828844
829845row
830− :: (MonadFix m, MonadHold t m, PostBuild t m)
846+ :: (MonadFix m, MonadHold t m, PostBuild t m, MonadNodeId m)
831847 => Layout t m a
832848 -> VtyWidget t m a
833849row child = do