on develop help sign in
Click with mouse to move text input cursor
commitc5331bfac8a1914dd2876b2b50cf134530079f0b authorAli Abrar <aliabrar@gmail.com> dateSun 4 Nov 2018, 16:05 (8 years ago) parent1dfbb64
2 files changed+38−18
src/Data/Text/Zipper.hs+17−2 src/Reflex/Vty/Widget/Input/Text.hs+21−16
src/Data/Text/Zipper.hs+17−2
@@ -228,8 +228,6 @@ displayLines width tag cursorTag (TextZipper lb b a la) =
228228 ]
229229 }
230230 where
231− spansLength :: [Span tag] -> Int
232− spansLength = sum . map (\(Span _ t) -> T.length t)
233231 initLast :: [a] -> Maybe ([a], a)
234232 initLast = \case
235233 [] -> Nothing
@@ -281,3 +279,20 @@ offsetMap ts = evalState (offsetMap' ts) (0, 0)
281279 (dl, o) <- get
282280 put (dl, o + 1)
283281 return $ Map.insert dl (o + 1) $ Map.unions maps
282+
283+-- | Move the cursor of the given 'TextZipper' to the logical position indicated by
284+-- the given display line coordinates, using the provided 'DisplayLines' information.
285+goToDisplayLinePosition :: Int -> Int -> DisplayLines tag -> TextZipper -> TextZipper
286+goToDisplayLinePosition x y dl tz =
287+ let offset = Map.lookup y $ _displayLines_offsetMap dl
288+ in case offset of
289+ Nothing -> tz
290+ Just o ->
291+ let displayLineLength = case drop y $ _displayLines_spans dl of
292+ [] -> x
293+ (s:_) -> spansLength s
294+ in rightN (o + (min displayLineLength x)) $ top tz
295+
296+-- | Get the length of the text in a set of 'Span's
297+spansLength :: [Span tag] -> Int
298+spansLength = sum . map (\(Span _ t) -> T.length t)
src/Reflex/Vty/Widget/Input/Text.hs+21−16
@@ -37,22 +37,27 @@ textInput
3737 -> VtyWidget t m (Dynamic t Text)
3838textInput cfg = do
3939 i <- input
40− v <- foldDyn ($) (_textInputConfig_initialValue cfg) $ mergeWith (.)
41− [ updateTextZipper <$> i
42− , _textInputConfig_modify cfg
43− ]
44− dw <- displayWidth
45− dh <- displayHeight
46− let rows = (\w s -> displayLines w V.defAttr cursorAttributes s) <$> dw <*> v
47− img = images . _displayLines_spans <$> rows
48− y <- holdUniqDyn $ _displayLines_cursorY <$> rows
49− let newScrollTop st (h, cursorY)
50− | cursorY < st = cursorY
51− | cursorY >= st + h = cursorY - h + 1
52− | otherwise = st
53− rec let hy = attachWith newScrollTop (current scrollTop) $ updated $ zipDyn dh y
54− scrollTop <- holdDyn 0 hy
55− tellImages $ (\imgs st -> (:[]) . V.vertCat $ drop st imgs) <$> current img <*> current scrollTop
40+ rec v <- foldDyn ($) (_textInputConfig_initialValue cfg) $ mergeWith (.)
41+ [ updateTextZipper <$> i
42+ , _textInputConfig_modify cfg
43+ , let displayInfo = (,) <$> rows <*> scrollTop
44+ in ffor (attach (current displayInfo) click) $ \((dl, st), MouseDown _ (mx, my) _) ->
45+ goToDisplayLinePosition mx (st + my) dl
46+ ]
47+ dw <- displayWidth
48+ dh <- displayHeight
49+ click <- mouseDown V.BLeft
50+ let rows = (\w s -> displayLines w V.defAttr cursorAttributes s) <$> dw <*> v
51+ img = images . _displayLines_spans <$> rows
52+ y <- holdUniqDyn $ _displayLines_cursorY <$> rows
53+ let newScrollTop :: Int -> (Int, Int) -> Int
54+ newScrollTop st (h, cursorY)
55+ | cursorY < st = cursorY
56+ | cursorY >= st + h = cursorY - h + 1
57+ | otherwise = st
58+ rec let hy = attachWith newScrollTop (current scrollTop) $ updated $ zipDyn dh y
59+ scrollTop <- holdDyn 0 hy
60+ tellImages $ (\imgs st -> (:[]) . V.vertCat $ drop st imgs) <$> current img <*> current scrollTop
5661 return $ value <$> v
5762
5863-- | A widget that allows multiline text input