vgrep-0.2.0.0: src/Vgrep/Widget/HorizontalSplit.hs
-- | A split-view widget that displays two widgets side-by-side.
module Vgrep.Widget.HorizontalSplit (
-- * Horizontal split view widget
hSplitWidget
, HSplitWidget
-- ** Widget state
, HSplit ()
, Focus (..)
-- ** Widget actions
, leftOnly
, rightOnly
, splitView
, switchFocus
-- ** Lenses
, leftWidget
, rightWidget
, currentWidget
, leftWidgetFocused
, rightWidgetFocused
) where
import Control.Applicative (liftA2)
import Control.Lens.Compat
import Graphics.Vty.Image hiding (resize)
import Vgrep.Environment
import Vgrep.Event
import Vgrep.Type
import Vgrep.Widget.HorizontalSplit.Internal
import Vgrep.Widget.Type
type HSplitWidget s t = Widget (HSplit s t)
-- | Compose two 'Widget's side-by-side
--
-- * __Initial state__
--
-- Initially, the left widget is rendered full-screen.
--
-- * __Drawing the Widgets__
--
-- Drawing is delegated to the child widgets in a local environment
-- reduced to thir respective 'Viewport'.
hSplitWidget
:: Widget s
-> Widget t
-> HSplitWidget s t
hSplitWidget left right = Widget
{ initialize = initHSplit left right
, draw = drawWidgets left right }
initHSplit :: Widget s -> Widget t -> HSplit s t
initHSplit left right = HSplit
{ _leftWidget = initialize left
, _rightWidget = initialize right
, _layout = LeftOnly }
-- | Display the left widget full-screen
leftOnly :: Monad m => VgrepT (HSplit s t) m Redraw
leftOnly = use layout >>= \case
LeftOnly -> pure Unchanged
_other -> assign layout LeftOnly >> pure Redraw
-- | Display the right widget full-screen
rightOnly :: Monad m => VgrepT (HSplit s t) m Redraw
rightOnly = use layout >>= \case
RightOnly -> pure Unchanged
_other -> assign layout RightOnly >> pure Redraw
-- | Display both widgets in a split view.
splitView
:: Monad m
=> Focus -- ^ Focus left or right area
-> Rational -- ^ Left area width as fraction of overall width
-> VgrepT (HSplit s t) m Redraw
splitView focus ratio = assign layout (Split focus ratio) >> pure Redraw
-- | Switch focus from left to right child widget and vice versa (only if
-- the '_layout' is 'Split')
switchFocus :: Monad m => VgrepT (HSplit s t) m Redraw
switchFocus = use layout >>= \case
Split focus ratio -> assign layout (switch focus ratio) >> pure Redraw
_otherwise -> pure Unchanged
where
switch FocusLeft ratio = Split FocusRight (1 - ratio)
switch FocusRight ratio = Split FocusLeft (1 - ratio)
drawWidgets
:: Monad m
=> Widget s
-> Widget t
-> VgrepT (HSplit s t) m Image
drawWidgets left right = use layout >>= \case
LeftOnly -> zoom leftWidget (draw left)
RightOnly -> zoom rightWidget (draw right)
Split _ ratio -> liftA2 (<|>)
(runInLeftWidget ratio (draw left))
(runInRightWidget ratio (draw right))
runInLeftWidget
:: Monad m
=> Rational
-> VgrepT s m Image
-> VgrepT (HSplit s t) m Image
runInLeftWidget ratio action =
let leftRegion = over viewportWidth $ \w ->
ceiling (ratio * fromIntegral w)
in zoom leftWidget (local leftRegion action)
runInRightWidget
:: Monad m
=> Rational
-> VgrepT t m Image
-> VgrepT (HSplit s t) m Image
runInRightWidget ratio action =
let rightRegion = over viewportWidth $ \w ->
floor ((1-ratio) * fromIntegral w)
in zoom rightWidget (local rightRegion action)