From bfcf5236b8c5f107233b6e61ac535fb9ef53a831 Mon Sep 17 00:00:00 2001 From: Ali Abrar Date: Thu, 6 Jul 2023 16:56:45 -0400 Subject: [PATCH 1/3] Revert inputInFocusedRegion; Add mkTile so that custom pane functions can be used to build layouts --- src/Reflex/Vty/Widget.hs | 21 +++++++++++++++++---- src/Reflex/Vty/Widget/Layout.hs | 23 ++++++++++++++++------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/Reflex/Vty/Widget.hs b/src/Reflex/Vty/Widget.hs index 81d4eb6..02ccf01 100644 --- a/src/Reflex/Vty/Widget.hs +++ b/src/Reflex/Vty/Widget.hs @@ -202,6 +202,21 @@ mouseInRegion (Region l t w h) e = case e of | otherwise = Just (con (x - l) (y - t)) +-- | Filter mouse input outside the current display region and +-- all input if the region is not focused +inputInFocusedRegion + :: (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 + -- | -- * 'Tracking' state means actively tracking the current stream of mouse events -- * 'NotTracking' state means not tracking the current stream of mouse events @@ -212,10 +227,10 @@ data MouseTrackingState = Tracking V.Button | NotTracking | WaitingForInput deri -- 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 +inputStartedInFocusedRegion :: forall t m. (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasFocusReader t m, HasInput t m) => m (Event t VtyEvent) -inputInFocusedRegion = do +inputStartedInFocusedRegion = do inp <- input reg <- current <$> askRegion foc <- current <$> focus @@ -589,8 +604,6 @@ imagesInRegion reg = liftA2 (\r is -> map (withinImage r) is) reg -- * unfocused widgets receive no key events -- * mouse inputs inside the region have their coordinates translated such -- that (0,0) is the top-left corner of the region --- * mouse drag sequences that start OFF the region are ignored --- * mouse drag sequences that start ON the region and drag off are NOT ignored pane :: (MonadFix m, MonadHold t m, HasInput t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m) => Dynamic t Region diff --git a/src/Reflex/Vty/Widget/Layout.hs b/src/Reflex/Vty/Widget/Layout.hs index 683cfd6..8d08f9d 100644 --- a/src/Reflex/Vty/Widget/Layout.hs +++ b/src/Reflex/Vty/Widget/Layout.hs @@ -507,19 +507,18 @@ initManager_ = fmap fst . initManager -- *** Focusable --- | A widget that is focusable and occupies a layout region based on the --- provided constraint. Returns the 'FocusId' allowing for manual focus --- management. -tile' +-- | +mkTile :: (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 + => (forall a. Dynamic t Region -> Dynamic t Bool -> m a -> m a) + -> Dynamic t Constraint -> m a -> m (FocusId, a) -tile' c w = do +mkTile customPane c w = do fid <- makeFocus r <- region c parentFocused <- isFocused fid - rec (click, result, childFocused) <- pane r focused $ anyChildFocused $ \childFoc -> do + rec (click, result, childFocused) <- customPane r focused $ anyChildFocused $ \childFoc -> do m <- mouseDown V.BLeft x <- w pure (m, x, childFoc) @@ -527,6 +526,16 @@ tile' c w = do requestFocus $ Refocus_Id fid <$ click pure (fid, result) +-- | A widget that is focusable and occupies a layout region based on the +-- provided constraint. Returns the 'FocusId' allowing for manual focus +-- management. +tile' + :: (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) +tile' = mkTile pane + -- | A widget that is focusable and occupies a layout region based on the -- provided constraint. tile From b56b0e3ea78220d8db3488699ae0dff028ce36de Mon Sep 17 00:00:00 2001 From: Ali Abrar Date: Thu, 6 Jul 2023 17:04:27 -0400 Subject: [PATCH 2/3] Add mkPane --- ChangeLog.md | 7 +++++++ reflex-vty.cabal | 2 +- src/Reflex/Vty/Widget.hs | 13 +++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 7351e4b..bf9c116 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,12 @@ # Revision history for reflex-vty +## 0.6.0.0 + +* *Breaking change:* + * Reverted the behavior of `inputInFocusedRegion` to simply filter mouse events to those that occur within the display region of a widget. It no longer attempts to track mouse drag events that occur outside the region that are part of a drag that started inside the region. + * To recover the previous behavior, you can use the new `mkPane` function with `inputStartedInFocusedRegion` to construct a pane that does the drag-tracking described above. To use that pane in a tile, use `mkTile (mkPane inputStartedInFocusedRegion)` +* Added `mkTile` and `mkPane` + ## 0.5.0.0 * *Breaking change*: diff --git a/reflex-vty.cabal b/reflex-vty.cabal index 459c154..85d5076 100644 --- a/reflex-vty.cabal +++ b/reflex-vty.cabal @@ -1,5 +1,5 @@ name: reflex-vty -version: 0.5.0.0 +version: 0.6.0.0 synopsis: Reflex FRP host and widgets for VTY applications description: Build terminal applications using functional reactive programming (FRP) with Reflex FRP (). diff --git a/src/Reflex/Vty/Widget.hs b/src/Reflex/Vty/Widget.hs index 02ccf01..90e664c 100644 --- a/src/Reflex/Vty/Widget.hs +++ b/src/Reflex/Vty/Widget.hs @@ -615,6 +615,19 @@ pane dr foc child = localRegion (const dr) $ localFocus (const foc) $ inputInFocusedRegion >>= \e -> localInput (const e) child +-- | Build a pane with a custom event source +mkPane + :: (MonadFix m, MonadHold t m, HasInput t m, HasImageWriter t m, HasDisplayRegion t m, HasFocusReader t m) + => m (Event t VtyEvent) + -> Dynamic t Region + -> Dynamic t Bool -- ^ Whether the widget should be focused when the parent is. + -> m a + -> m a +mkPane f dr foc child = localRegion (const dr) $ + mapImages (imagesInRegion $ current dr) $ + localFocus (const foc) $ + f >>= \e -> localInput (const e) child + -- * Misc -- | A widget that draws nothing From e365940980846b581d7b5509495c1018ed4dcf77 Mon Sep 17 00:00:00 2001 From: Ali Abrar Date: Thu, 6 Jul 2023 23:54:40 -0400 Subject: [PATCH 3/3] inputStartedInFocusedRegion: Scroll events should register whenever they are over a region --- src/Reflex/Vty/Widget.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Reflex/Vty/Widget.hs b/src/Reflex/Vty/Widget.hs index 26a2fc6..3247204 100644 --- a/src/Reflex/Vty/Widget.hs +++ b/src/Reflex/Vty/Widget.hs @@ -252,9 +252,9 @@ inputStartedInFocusedRegion = do V.EvKey _ _ | not focused -> Nothing -- filter scroll wheel input based on mouse position - x@(V.EvMouseDown _ _ btn _) | btn == V.BScrollUp || btn == V.BScrollDown -> case tracking of + e@(V.EvMouseDown x y btn _) | btn == V.BScrollUp || btn == V.BScrollDown -> case tracking of trck@(Tracking _) -> Just (trck, Nothing) - _ -> Just (WaitingForInput, if focused then Just x else Nothing) + _ -> Just (WaitingForInput, if withinRegion reg x y then Just e else Nothing) -- only do tracking for l/m/r mouse buttons V.EvMouseDown x y btn m ->