packages feed

reflex-vty 0.3.1.1 → 0.4.0.0

raw patch · 11 files changed

+77/−25 lines, 11 files

Files

ChangeLog.md view
@@ -1,5 +1,15 @@ # Revision history for reflex-vty +## 0.4.0.0++* _Breaking Changes_:+  * Added mouse tracking to the behavior of `pane` such that+    * Mouse actions that start outside of the region are not tracked+    * Mouse drag sequences that start OFF the region are NOT reported+    * Mouse drag sequences that start ON the region and drag off ARE reported+    * Introduce `MonadHold` constraint to `pane`+  * Added `MonadHold` constraint to several methods that use `pane`+   ## 0.3.1.1  * Loosen version bounds and support GHC 9.4
README.md view
@@ -1,6 +1,6 @@ # reflex-vty -[![Haskell](https://img.shields.io/badge/language-Haskell-orange.svg)](https://haskell.org) [![Hackage](https://img.shields.io/hackage/v/reflex-vty.svg)](https://hackage.haskell.org/package/reflex-vty) [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/reflex-vty/badge)](https://matrix.hackage.haskell.org/#/package/reflex-vty) [![Travis CI](https://api.travis-ci.org/reflex-frp/reflex-vty.svg?branch=develop)](https://travis-ci.org/reflex-frp/reflex-vty) [![BSD3 License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://github.com/reflex-frp/reflex-vty/blob/master/LICENSE)+[![Haskell](https://img.shields.io/badge/language-Haskell-orange.svg)](https://haskell.org) [![Hackage](https://img.shields.io/hackage/v/reflex-vty.svg)](https://hackage.haskell.org/package/reflex-vty) [![Travis CI](https://api.travis-ci.org/reflex-frp/reflex-vty.svg?branch=develop)](https://travis-ci.org/reflex-frp/reflex-vty) [![BSD3 License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://github.com/reflex-frp/reflex-vty/blob/master/LICENSE)  Build terminal applications using functional reactive programming (FRP) with [Reflex FRP](https://reflex-frp.org). 
reflex-vty.cabal view
@@ -1,5 +1,5 @@ name: reflex-vty-version: 0.3.1.1+version: 0.4.0.0 synopsis: Reflex FRP host and widgets for VTY applications description:   Build terminal applications using functional reactive programming (FRP) with Reflex FRP (<https://reflex-frp.org>).
src-bin/Example/CPU.hs view
@@ -117,6 +117,7 @@  chart   :: ( MonadFix m+     , MonadHold t m      , HasFocus t m      , HasLayout t m      , HasImageWriter t m
src-bin/example.hs view
@@ -18,12 +18,14 @@  type VtyExample t m =   ( MonadFix m+  , MonadHold t m   , Reflex t   , HasInput t m   , HasImageWriter t m   , HasDisplayRegion t m   , HasFocus t m-  , HasFocusReader t m, HasTheme t m+  , HasFocusReader t m+  , HasTheme t m   )  type Manager t m =
src/Reflex/Vty/Widget.hs view
@@ -202,20 +202,52 @@       | otherwise =         Just (con (x - l) (y - t)) +-- |+-- * 'Tracking' state means actively tracking the current stream of mouse events+-- * 'NotTracking' state means not tracking the current stream of mouse events+-- * 'WaitingForInput' means state will be set on next 'EvMouseDown' event+data MouseTrackingState = Tracking V.Button | NotTracking | WaitingForInput deriving (Show, Eq)+ -- | Filter mouse input outside the current display region and -- all input if the region is not focused+-- mouse drag sequences that start OFF the region are NOT reported+-- mouse drag sequences that start ON the region and drag off ARE reported inputInFocusedRegion-  :: (HasDisplayRegion t m, HasFocusReader t m, HasInput t m)+  :: forall t m. (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasFocusReader t m, HasInput t m)   => m (Event t VtyEvent) inputInFocusedRegion = do   inp <- input   reg <- current <$> askRegion   foc <- current <$> focus-  pure $ fmapMaybe id $ attachWith filterInput ((,) <$> reg <*> foc) inp-  where-    filterInput (r, f) = \case-      V.EvKey {} | not f -> Nothing-      x -> mouseInRegion r x+  let+    trackMouse ::+      VtyEvent+      -> (MouseTrackingState, Maybe VtyEvent)+      -> PushM t (Maybe (MouseTrackingState, Maybe VtyEvent))+    trackMouse e (tracking, _) = do+      -- sampling (as oppose to using attachPromptlyDyn) is necessary here as the focus may change from the event produced here+      focused <- sample foc+      -- strictly speaking the same could also happen here too+      reg'@(Region l t _ _) <- sample reg+      return $ case e of+        V.EvKey _ _ | not focused -> Nothing+        V.EvMouseDown x y btn m ->+          if tracking == Tracking btn || (tracking == WaitingForInput && isWithin reg' x y)+            then Just (Tracking btn, Just $ V.EvMouseDown (x - l) (y - t) btn m)+            else Just (NotTracking, Nothing)+        V.EvMouseUp x y mbtn -> case mbtn of+          Nothing -> case tracking of+            Tracking _ -> Just (WaitingForInput, Just $ V.EvMouseUp (x - l) (y - t) mbtn)+            _ -> Just (WaitingForInput, Nothing)+          Just btn -> if tracking == Tracking btn+            -- NOTE we only report EvMouseUp for the button we are tracking+            -- vty has mouse buttons override others (seems to be based on ordering of Button) when multiple are pressed.+            -- so it IS possible for child widget to miss out on a 'EvMouseUp' event with this current implementation+            then Just (WaitingForInput, Just $ V.EvMouseUp (x - l) (y - t) mbtn)+            else Just (WaitingForInput, Nothing)+        _ -> Just (tracking, Just e)+  dynInputEvTracking <- foldDynMaybeM trackMouse (WaitingForInput, Nothing) $ inp+  return (fmapMaybe snd $ updated dynInputEvTracking)  -- * Getting and setting the display region @@ -236,6 +268,12 @@ regionSize :: Region -> (Int, Int) regionSize (Region _ _ w h) = (w, h) +isWithin :: Region -> Int -> Int -> Bool+isWithin (Region l t w h) x y = not . or $ [ x < l+                                           , y < t+                                           , x >= l + w+                                           , y >= t + h ]+ -- | Produces an 'Image' that fills a region with space characters regionBlankImage :: V.Attr -> Region -> Image regionBlankImage attr r@(Region _ _ width height) =@@ -540,11 +578,12 @@ -- a given region and context. This widget filters and modifies the input -- that the child widget receives such that: -- * unfocused widgets receive no key events--- * mouse inputs outside the region are ignored -- * mouse inputs inside the region have their coordinates translated such+-- * mouse drag sequences that start OFF the region are ignored+-- * mouse drag sequences that start ON the region and drag off are NOT ignored --   that (0,0) is the top-left corner of the region pane-  :: (Reflex t, Monad m, HasInput t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)+  :: (MonadFix m, MonadHold t m, HasInput t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)   => Dynamic t Region   -> Dynamic t Bool -- ^ Whether the widget should be focused when the parent is.   -> m a
src/Reflex/Vty/Widget/Box.hs view
@@ -3,6 +3,7 @@ -} module Reflex.Vty.Widget.Box where +import Control.Monad.Fix (MonadFix) import Data.Default import Data.Text (Text) import qualified Data.Text as T@@ -54,7 +55,7 @@ roundedBoxStyle = BoxStyle '╭' '─' '╮' '│' '╯' '─' '╰' '│'  -- | Draws a titled box in the provided style and a child widget inside of that box-boxTitle :: (Monad m, Reflex t ,HasDisplayRegion t m, HasImageWriter t m, HasInput t m, HasFocusReader t m, HasTheme t m)+boxTitle :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasImageWriter t m, HasInput t m, HasFocusReader t m, HasTheme t m)     => Behavior t BoxStyle     -> Behavior t Text     -> m a@@ -109,7 +110,7 @@         right = mkHalf delta  -- | A box without a title-box :: (Monad m, Reflex t, HasDisplayRegion t m, HasImageWriter t m, HasInput t m, HasFocusReader t m, HasTheme t m)+box :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasImageWriter t m, HasInput t m, HasFocusReader t m, HasTheme t m)     => Behavior t BoxStyle     -> m a     -> m a@@ -117,7 +118,7 @@  -- | A box whose style is static boxStatic-  :: (Monad m, Reflex t, HasDisplayRegion t m, HasImageWriter t m, HasInput t m, HasFocusReader t m, HasTheme t m)+  :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasImageWriter t m, HasInput t m, HasFocusReader t m, HasTheme t m)   => BoxStyle   -> m a   -> m a
src/Reflex/Vty/Widget/Input.hs view
@@ -35,7 +35,7 @@  -- | A button widget that contains a sub-widget button-  :: (Reflex t, Monad m, HasFocusReader t m, HasTheme t m, HasDisplayRegion t m, HasImageWriter t m, HasInput t m)+  :: (MonadFix m, MonadHold t m, HasFocusReader t m, HasTheme t m, HasDisplayRegion t m, HasImageWriter t m, HasInput t m)   => ButtonConfig t   -> m ()   -> m (Event t ())@@ -53,7 +53,7 @@  -- | A button widget that displays text that can change textButton-  :: (Reflex t, Monad m, HasDisplayRegion t m, HasFocusReader t m, HasTheme t m, HasImageWriter t m, HasInput t m)+  :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasFocusReader t m, HasTheme t m, HasImageWriter t m, HasInput t m)   => ButtonConfig t   -> Behavior t Text   -> m (Event t ())@@ -61,7 +61,7 @@  -- | A button widget that displays a static bit of text textButtonStatic-  :: (Reflex t, Monad m, HasDisplayRegion t m, HasFocusReader t m, HasTheme t m, HasImageWriter t m, HasInput t m)+  :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasFocusReader t m, HasTheme t m, HasImageWriter t m, HasInput t m)   => ButtonConfig t   -> Text   -> m (Event t ())
src/Reflex/Vty/Widget/Input/Text.hs view
@@ -144,7 +144,7 @@ -- the computed line count to greedily size the tile when vertically -- oriented, and uses the fallback width when horizontally oriented. textInputTile-  :: (Monad m, Reflex t, MonadFix m, HasLayout t m, HasInput t m, HasFocus t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m, HasTheme t m)+  :: (MonadFix m, MonadHold t m, HasLayout t m, HasInput t m, HasFocus t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m, HasTheme t m)   => m (TextInput t)   -> Dynamic t Int   -> m (TextInput t)
src/Reflex/Vty/Widget/Layout.hs view
@@ -510,7 +510,7 @@ -- provided constraint. Returns the 'FocusId' allowing for manual focus -- management. tile'-  :: (MonadFix m, Reflex t, HasInput t m, HasFocus t m, HasLayout t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)+  :: (MonadFix m, MonadHold t m, HasInput t m, HasFocus t m, HasLayout t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)   => Dynamic t Constraint   -> m a   -> m (FocusId, a)@@ -529,7 +529,7 @@ -- | A widget that is focusable and occupies a layout region based on the -- provided constraint. tile-  :: (MonadFix m, Reflex t, HasInput t m, HasFocus t m, HasLayout t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)+  :: (MonadFix m, MonadHold t m, HasInput t m, HasFocus t m, HasLayout t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)   => Dynamic t Constraint   -> m a   -> m a@@ -540,7 +540,7 @@ -- | A widget that is not focusable and occupies a layout region based on the -- provided constraint. grout-  :: (Reflex t, HasLayout t m, HasInput t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)+  :: (MonadFix m, MonadHold t m, HasLayout t m, HasInput t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m)   => Dynamic t Constraint   -> m a   -> m a
src/Reflex/Vty/Widget/Split.hs view
@@ -13,7 +13,7 @@ -- | A split of the available space into two parts with a draggable separator. -- Starts with half the space allocated to each, and the first pane has focus. -- Clicking in a pane switches focus.-splitVDrag :: (Reflex t, MonadFix m, MonadHold t m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)+splitVDrag :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)   => m ()   -> m a   -> m b@@ -52,7 +52,7 @@  -- | A plain split of the available space into vertically stacked panes. -- No visual separator is built in here.-splitV :: (Reflex t, Monad m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)+splitV :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)        => Dynamic t (Int -> Int)        -- ^ Function used to determine size of first pane based on available size        -> Dynamic t (Bool, Bool)@@ -73,7 +73,7 @@  -- | A plain split of the available space into horizontally stacked panes. -- No visual separator is built in here.-splitH :: (Reflex t, Monad m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)+splitH :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)        => Dynamic t (Int -> Int)        -- ^ Function used to determine size of first pane based on available size        -> Dynamic t (Bool, Bool)@@ -89,4 +89,3 @@   let regA = Region 0 0 <$> (sizeFunD <*> dw) <*> dh       regB = Region <$> (_region_width <$> regA) <*> 0 <*> liftA2 (-) dw (_region_width <$> regA) <*> dh   liftA2 (,) (pane regA (fmap fst focD) wA) (pane regB (fmap snd focD) wB)-