@@ -35,6 +35,13 @@ module Reflex.Vty.Widget
3535 , fractionSz
3636 , box
3737 , string
38+ , hyphenBoxStyle
39+ , singleBoxStyle
40+ , roundedBoxStyle
41+ , thickBoxStyle
42+ , doubleBoxStyle
43+ , fill
44+ , hRule
3845 ) where
3946
4047import Control.Applicative (liftA2)
@@ -96,9 +103,12 @@ mainWidgetWithHandle vty child =
96103 size <- holdDyn dr0 $ fforMaybe inp $ \case
97104 V.EvResize w h -> Just (w, h)
98105 _ -> Nothing
106+ let inp' = fforMaybe inp $ \case
107+ V.EvResize {} -> Nothing
108+ x -> Just x
99109 let ctx = VtyWidgetCtx
100110 { _vtyWidgetCtx_size = size
101− , _vtyWidgetCtx_input = inp
111+ , _vtyWidgetCtx_input = inp'
102112 , _vtyWidgetCtx_focus = constDyn True
103113 }
104114 ((), wo) <- runVtyWidget ctx child
@@ -170,8 +180,7 @@ pane reg foc child = VtyWidget $ do
170180 ctx <- lift ask
171181 let ctx' = VtyWidgetCtx
172182 { _vtyWidgetCtx_input = leftmost -- TODO: think about this leftmost more.
173− [ ffor (updated reg) $ \(Region _ _ w h) -> V.EvResize w h
174− , fmapMaybe id $
183+ [ fmapMaybe id $
175184 attachWith (\(r,f) e -> filterInput r f e)
176185 (liftA2 (,) (current reg) (current foc))
177186 (_vtyWidgetCtx_input ctx)
@@ -236,7 +245,7 @@ drag btn = do
236245 | otherwise -> Just $ Drag from (x,y) btn mods True
237246 _ -> Nothing
238247 rec let newDrag = attachWithMaybe f (current dragD) inp
239− dragD <- holdDyn (Drag (0,0) (0,0) V.BLeft [] True) -- gross, but ok.
248+ dragD <- holdDyn (Drag (0,0) (0,0) btn [] True) -- gross, but ok because it'll never be produced.
240249 newDrag
241250 return (updated dragD)
242251
@@ -274,27 +283,33 @@ splitV sizeFunD focD wA wB = do
274283-- Starts with half the space allocated to each, and the first pane has focus.
275284-- Clicking in a pane switches focus.
276285splitVDrag :: (Reflex t, MonadFix m, MonadHold t m)
277− => VtyWidget t m a
286+ => VtyWidget t m ()
287+ -> VtyWidget t m a
278288 -> VtyWidget t m b
279289 -> VtyWidget t m (a,b)
280−splitVDrag wA wB = do
290+splitVDrag wS wA wB = do
281291 sz <- displaySize
282292 (_, h0) <- sample $ current sz
283293 dragE <- drag V.BLeft
284294 let splitter0 = h0 `div` 2
285− rec splitterCheckpoint <- holdDyn splitter0 $ fst <$> ffilter snd dragSplitter
286− splitterPos <- holdDyn splitter0 $ fst <$> dragSplitter
287− let dragSplitter = fforMaybe (attach (current splitterCheckpoint) dragE) $ \(splitterY, Drag (_, fromY) (_, toY) _ _ end) ->
288− if splitterY == fromY then Just (toY, end) else Nothing
295+ rec splitterCheckpoint <- holdDyn splitter0 $ leftmost [fst <$> ffilter snd dragSplitter, resizeSplitter]
296+ splitterPos <- holdDyn splitter0 $ leftmost [fst <$> dragSplitter, resizeSplitter]
297+ splitterFrac <- holdDyn (1/2) $ ffor (attach (current sz) (fst <$> dragSplitter)) $ \((_,h),x) ->
298+ fromIntegral x / fromIntegral h
299+ let dragSplitter = fforMaybe (attach (current splitterCheckpoint) dragE) $
300+ \(splitterY, Drag (_, fromY) (_, toY) _ _ end) ->
301+ if splitterY == fromY then Just (toY, end) else Nothing
289302 regA = (\(w,_) sp -> Region 0 0 w sp) <$> sz <*> splitterPos
290303 regS = (\(w,_) sp -> Region 0 sp w 1) <$> sz <*> splitterPos
291304 regB = (\(w,h) sp -> Region 0 (sp + 1) w (h - sp - 1)) <$> sz <*> splitterPos
305+ resizeSplitter = ffor (attach (current splitterFrac) (updated sz)) $
306+ \(frac, (_,h)) -> round (frac * fromIntegral h)
292307 focA <- holdDyn True $ leftmost
293308 [ True <$ mA
294309 , False <$ mB
295310 ]
296311 (mA, rA) <- pane regA focA $ withMouseDown wA
297− tellImages $ ffor (current regS) $ \r -> [withinImage r (V.string mempty (replicate (_region_width r) '='))]
312+ pane regS (pure False) wS
298313 (mB, rB) <- pane regB (not <$> focA) $ withMouseDown wB
299314 return (rA, rB)
300315 where
@@ -303,6 +318,17 @@ splitVDrag wA wB = do
303318 x' <- x
304319 return (m, x')
305320
321+-- | Fill the background with a particular character.
322+fill :: (Reflex t, Monad m) => Char -> VtyWidget t m ()
323+fill c = do
324+ sz <- displaySize
325+ let fillImg = ffor (current sz) $ \(w,h) -> [V.charFill mempty c w h]
326+ tellImages fillImg
327+
328+-- | Fill the background with the bottom
329+hRule :: (Reflex t, Monad m) => BoxStyle -> VtyWidget t m ()
330+hRule boxStyle = fill (_boxStyle_s boxStyle)
331+
306332fractionSz :: Double -> Int -> Int
307333fractionSz x h = round (fromIntegral h * x)
308334
@@ -314,10 +340,37 @@ modifyImages
314340modifyImages f (VtyWidget w) = VtyWidget $ flip censor w $ \wo ->
315341 wo { _vtyWidgetOut_images = f <*> (_vtyWidgetOut_images wo) }
316342
343+data BoxStyle = BoxStyle
344+ { _boxStyle_nw :: Char
345+ , _boxStyle_n :: Char
346+ , _boxStyle_ne :: Char
347+ , _boxStyle_e :: Char
348+ , _boxStyle_se :: Char
349+ , _boxStyle_s :: Char
350+ , _boxStyle_sw :: Char
351+ , _boxStyle_w :: Char
352+ }
353+
354+hyphenBoxStyle :: BoxStyle
355+hyphenBoxStyle = BoxStyle '-' '-' '-' '|' '-' '-' '-' '|'
356+
357+singleBoxStyle :: BoxStyle
358+singleBoxStyle = BoxStyle '┌' '─' '┐' '│' '┘' '─' '└' '│'
359+
360+thickBoxStyle :: BoxStyle
361+thickBoxStyle = BoxStyle '┏' '━' '┓' '┃' '┛' '━' '┗' '┃'
362+
363+doubleBoxStyle :: BoxStyle
364+doubleBoxStyle = BoxStyle '╔' '═' '╗' '║' '╝' '═' '╚' '║'
365+
366+roundedBoxStyle :: BoxStyle
367+roundedBoxStyle = BoxStyle '╭' '─' '╮' '│' '╯' '─' '╰' '│'
368+
317369box :: (Monad m, Reflex t)
318− => VtyWidget t m a
370+ => BoxStyle
319371 -> VtyWidget t m a
320−box child = do
372+ -> VtyWidget t m a
373+box style child = do
321374 sz <- displaySize
322375 let boxReg = ffor (current sz) $ \(w,h) -> Region 0 0 w h
323376 innerReg = ffor sz $ \(w,h) -> Region 1 1 (w - 2) (h - 2)
@@ -327,13 +380,29 @@ box child = do
327380 where
328381 boxImages :: Region -> [Image]
329382 boxImages r@(Region left top width height) =
330− let hBorder = V.string mempty $ replicate width '-'
331− vBorder = wrapString 1 mempty $ replicate (height - 2) '|'
332− in [ withinImage (r { _region_height = 1 }) hBorder
333− , withinImage (Region left (top + 1) 1 (height - 2)) vBorder
334− , withinImage (Region (left + width - 1) (top + 1) 1 (height - 2)) vBorder
335− , withinImage (r { _region_top = top + height - 1 }) hBorder
336− ]
383+ let right = left + width - 1
384+ bottom = top + height - 1
385+ sides =
386+ [ withinImage (Region (left + 1) top (width - 2) 1) $
387+ V.charFill mempty (_boxStyle_n style) (width - 2) 1
388+ , withinImage (Region right (top + 1) 1 (height - 2)) $
389+ V.charFill mempty (_boxStyle_e style) 1 (height - 2)
390+ , withinImage (Region (left + 1) bottom (width - 2) 1) $
391+ V.charFill mempty (_boxStyle_s style) (width - 2) 1
392+ , withinImage (Region left (top + 1) 1 (height - 2)) $
393+ V.charFill mempty (_boxStyle_w style) 1 (height - 2)
394+ ]
395+ corners =
396+ [ withinImage (Region left top 1 1) $
397+ V.char mempty (_boxStyle_nw style)
398+ , withinImage (Region right top 1 1) $
399+ V.char mempty (_boxStyle_ne style)
400+ , withinImage (Region right bottom 1 1) $
401+ V.char mempty (_boxStyle_se style)
402+ , withinImage (Region left bottom 1 1) $
403+ V.char mempty (_boxStyle_sw style)
404+ ]
405+ in sides ++ if width > 1 && height > 1 then corners else []
337406
338407string :: (Reflex t, Monad m) => Behavior t String -> VtyWidget t m ()
339408string msg = do