packages feed

nano-ui-0.1.0.0: lib/NanoUI/Frame/TextEdit.hs

-- | Text-field editing facade: single-line fields ("NanoUI.Frame.TextInput"),
-- text areas ("NanoUI.Frame.TextArea") and their context menu
-- ("NanoUI.Frame.TextEdit.Menu"), plus the dispatchers that pick between the
-- two field kinds.
module NanoUI.Frame.TextEdit
  ( -- * Dispatch between field kinds
    finalizeTextFieldMouse
  , collapseTextFieldSelection
    -- * Context menu
  , applyTextFieldMenuAction
  , textEditMenuRectAt
  , textEditMenuWidth
    -- * Shared field helpers
  , normalizeTextFieldClicks
  , textWordBounds
    -- * Text areas
  , TextAreaHit (..)
  , TextAreaScrollBarLayouts (..)
  , resolveTextAreaFont
  , textAreaContentMetrics
  , textAreaBarLane
  , textAreaLineHeight
  , textAreaHitForWidget
  , textAreaScrollBarLayout
  , textAreaHScrollBarLayout
  , textAreaScrollBarLayouts
  ) where

import Control.Monad (unless, when)
import Data.IORef (readIORef)
import NanoUI.Context (Context (..), setTextInputDrag)
import NanoUI.Frame.Hit (findNodeByWidgetId)
import NanoUI.Frame.TextArea
import NanoUI.Frame.TextArea.Content (resolveTextAreaFont, textAreaContentMetrics)
import NanoUI.Frame.TextArea.Geometry
import NanoUI.Frame.TextEdit.Menu (applyTextFieldMenuAction, textEditMenuRectAt, textEditMenuWidth)
import NanoUI.Frame.TextInput
import NanoUI.Id (WidgetId, hashWidgetId)
import NanoUI.Input (Input, inputMouseReleased)
import NanoUI.Layout.Arena (NodeType (NodeTextArea, NodeTextInput), getNodeType)
import NanoUI.Widgets.TextCommon (textWordBounds)

-- | Mouse selection in the focused field, whichever kind it is. A release
-- ends any drag.
finalizeTextFieldMouse :: Context -> Input -> IO ()
finalizeTextFieldMouse ctx inp = do
  focus <- readIORef (ctxFocusId ctx)
  when (hashWidgetId focus /= 0) $ do
    handled <- finalizeTextInputMouse ctx inp focus
    unless handled $ finalizeTextAreaMouse ctx inp focus
  when (inputMouseReleased inp) $
    setTextInputDrag ctx Nothing

collapseTextFieldSelection :: Context -> WidgetId -> IO ()
collapseTextFieldSelection ctx wid =
  when (hashWidgetId wid /= 0) $ do
    mIdx <- findNodeByWidgetId ctx wid
    case mIdx of
      Nothing -> pure ()
      Just idx ->
        getNodeType (ctxNodeArena ctx) idx >>= \case
          NodeTextInput -> collapseTextInputSelection ctx wid
          NodeTextArea -> collapseTextAreaSelection ctx wid
          _ -> pure ()