on develop help sign in
Add StackWidget
commitefe7df854a3c4e2feaa65f86614b755cce1b0afa authorAli Abrar <aliabrar@gmail.com> dateSun 17 Feb 2019, 16:20 (8 years ago) parent784a0a0
4 files changed+94−17
reflex-vty.cabal+1 src-bin/example.hs+17−10 src/Reflex/Class/Orphans.hs+1 src/Reflex/Vty/Widget.hs+75−7
reflex-vty.cabal+1
@@ -45,6 +45,7 @@ library
4545 vty
4646 hs-source-dirs: src
4747 default-language: Haskell2010
48+ ghc-options: -Wall
4849
4950executable example
5051 hs-source-dirs: src-bin
src-bin/example.hs+17−10
@@ -27,19 +27,12 @@ import Reflex.Class.Switchable
2727import Reflex.NotReady.Class
2828import Reflex.Vty
2929
30−import Data.Tree
31−
32−-- Unlimited Stack
33− -- Parent provides orientation and maximum cross-dimension size
34− -- Each child takes as much main-dimension space as it wants and reports what it took
35− -- Parent offsets each child so that it does not overlap with other children
36− -- If parent runs of out space, parent provides a scroll bar
37−
3830data Example = Example_TextEditor
3931 | Example_Todo
32+ | Example_Stack
4033 deriving (Show, Read, Eq, Ord, Enum, Bounded)
4134
42−div' :: (Integral a, Applicative f) => f a ->f a -> f a
35+div' :: (Integral a, Applicative f) => f a -> f a -> f a
4336div' = liftA2 div
4437
4538main :: IO ()
@@ -48,6 +41,20 @@ main = mainWidget $ do
4841
4942 w <- displayWidth
5043 h <- displayHeight
44+
45+ row $ sized (div' w 2) $ col $ do
46+ sized 5 $ display (current w)
47+ sized 5 $ textButtonStatic def "A"
48+ sized 5 $ textButtonStatic def "B"
49+ -- (th, label) <- StackWidget $ \_ -> do
50+ -- (TextInput value lines) <- multilineTextInput def
51+ -- return (lines, (lines, value))
52+ -- sized (th+4) $ textButton def ("\n" <> current label)
53+ sized 5 $ textButtonStatic def "E"
54+ sized 1 $ text "asdf"
55+ sized 1 $ text "zxcv"
56+
57+ {-
5158 let buttons = do
5259 text $ pure "Select an example. Esc will bring you back here. Ctrl+c to quit."
5360 let w' = fmap (`div`6) w
@@ -70,7 +77,7 @@ main = mainWidget $ do
7077 Left Example_TextEditor -> escapable testBoxes
7178 Left Example_Todo -> escapable taskList
7279 Right () -> buttons
73−
80+ -}
7481 return $ fforMaybe inp $ \case
7582 V.EvKey (V.KChar 'c') [V.MCtrl] -> Just ()
7683 _ -> Nothing
src/Reflex/Class/Orphans.hs+1
@@ -2,6 +2,7 @@
22Module: Reflex.Class.Orphans
33Description: Orphan instances for Dynamic. These should be upstreamed.
44-}
5+{-# OPTIONS_GHC -fno-warn-orphans #-}
56module Reflex.Class.Orphans where
67
78import Control.Applicative
src/Reflex/Vty/Widget.hs+75−7
@@ -2,6 +2,7 @@
22Module: Reflex.Vty.Widget
33Description: Basic set of widgets and building blocks for reflex-vty applications
44-}
5+{-# LANGUAGE DeriveFunctor #-}
56{-# LANGUAGE FlexibleContexts #-}
67{-# LANGUAGE FlexibleInstances #-}
78{-# LANGUAGE FunctionalDependencies #-}
@@ -13,6 +14,7 @@ Description: Basic set of widgets and building blocks for reflex-vty application
1314{-# LANGUAGE RecursiveDo #-}
1415{-# LANGUAGE ScopedTypeVariables #-}
1516{-# LANGUAGE StandaloneDeriving #-}
17+{-# LANGUAGE TupleSections #-}
1618{-# LANGUAGE TypeFamilies #-}
1719{-# LANGUAGE UndecidableInstances #-}
1820module Reflex.Vty.Widget
@@ -23,6 +25,14 @@ module Reflex.Vty.Widget
2325 , runVtyWidget
2426 , mainWidget
2527 , mainWidgetWithHandle
28+
29+ , StackWidget(..)
30+ , stack
31+ , Direction(..)
32+ , col
33+ , row
34+ , sized
35+
2636 , HasDisplaySize(..)
2737 , HasFocus(..)
2838 , HasVtyInput(..)
@@ -57,6 +67,7 @@ module Reflex.Vty.Widget
5767 ) where
5868
5969import Control.Applicative (liftA2)
70+import Control.Monad (ap)
6071import Control.Monad.Fix (MonadFix)
6172import Control.Monad.Trans (lift)
6273import Control.Monad.Trans.Reader (ReaderT, runReaderT, asks, ask)
@@ -67,7 +78,7 @@ import qualified Data.Text.Zipper as TZ
6778import Graphics.Vty (Image)
6879import qualified Graphics.Vty as V
6980import Reflex
70−import Reflex.Class.Orphans
81+import Reflex.Class.Orphans ()
7182import Reflex.NotReady.Class
7283import Reflex.NotReady.Class.Orphans ()
7384
@@ -238,22 +249,22 @@ pane
238249 -> Dynamic t Bool -- ^ Whether the widget should be focused when the parent is.
239250 -> VtyWidget t m a
240251 -> VtyWidget t m a
241−pane (DynRegion l t w h) foc child = VtyWidget $ do
252+pane dr foc child = VtyWidget $ do
242253 ctx <- lift ask
243− let reg = Region <$> l <*> t <*> w <*> h
254+ let reg = currentRegion dr
244255 let ctx' = VtyWidgetCtx
245256 { _vtyWidgetCtx_input = leftmost -- TODO: think about this leftmost more.
246257 [ fmapMaybe id $
247258 attachWith (\(r,f) e -> filterInput r f e)
248− (liftA2 (,) (current reg) (current foc))
259+ (liftA2 (,) reg (current foc))
249260 (_vtyWidgetCtx_input ctx)
250261 ]
251262 , _vtyWidgetCtx_focus = liftA2 (&&) (_vtyWidgetCtx_focus ctx) foc
252− , _vtyWidgetCtx_width = w
253− , _vtyWidgetCtx_height = h
263+ , _vtyWidgetCtx_width = _dynRegion_width dr
264+ , _vtyWidgetCtx_height = _dynRegion_height dr
254265 }
255266 (result, images) <- lift . lift $ runVtyWidget ctx' child
256− let images' = liftA2 (\r is -> map (withinImage r) is) (current reg) images
267+ let images' = liftA2 (\r is -> map (withinImage r) is) reg images
257268 tellImages images'
258269 return result
259270 where
@@ -561,3 +572,60 @@ display
561572 => Behavior t a
562573 -> VtyWidget t m ()
563574display a = text $ T.pack . show <$> a
575+
576+data Direction = Direction_Column
577+ | Direction_Row
578+ deriving (Show, Read, Eq, Ord)
579+
580+newtype StackWidget t m a = StackWidget { unStackWidget :: Direction -> VtyWidget t m (Dynamic t Int, a) }
581+ deriving (Functor)
582+
583+instance (Reflex t, MonadFix m) => Applicative (StackWidget t m) where
584+ pure = return
585+ (<*>) = ap
586+
587+instance (MonadFix m, Reflex t) => Monad (StackWidget t m) where
588+ w >>= g = StackWidget $ \dir -> do
589+ (sz, r) <- runStackWidget dir 0 w
590+ (sz', r') <- runStackWidget dir sz (g r)
591+ return (sz + sz', r')
592+ return x = StackWidget $ \_ -> return (0, x)
593+
594+runStackWidget
595+ :: (Reflex t, MonadFix m)
596+ => Direction
597+ -> Dynamic t Int
598+ -> StackWidget t m a
599+ -> VtyWidget t m (Dynamic t Int, a)
600+runStackWidget dir offset x = do
601+ mkRegion <- case dir of
602+ Direction_Column -> (\w sz -> DynRegion 0 offset w sz) <$> displayWidth
603+ Direction_Row -> (\h sz -> DynRegion offset 0 sz h) <$> displayHeight
604+ rec (h, a) <- pane (mkRegion h) (pure True) $ unStackWidget x dir
605+ return (h, a)
606+
607+stack
608+ :: (Reflex t, MonadFix m)
609+ => Direction
610+ -> StackWidget t m a
611+ -> VtyWidget t m a
612+stack dir w = fmap snd $ runStackWidget dir 0 w
613+
614+col
615+ :: (Reflex t, MonadFix m)
616+ => StackWidget t m a
617+ -> VtyWidget t m a
618+col = stack Direction_Column
619+
620+row
621+ :: (Reflex t, MonadFix m)
622+ => StackWidget t m a
623+ -> VtyWidget t m a
624+row = stack Direction_Row
625+
626+sized
627+ :: (Reflex t, MonadFix m)
628+ => Dynamic t Int
629+ -> VtyWidget t m a
630+ -> StackWidget t m a
631+sized sz w = StackWidget $ \_ -> (sz,) <$> w