content: {-|
  Module      : Monomer.Widgets.Singles.SeparatorLine
  Copyright   : (c) 2018 Francisco Vallarino
  License     : BSD-3-Clause (see the LICENSE file)
  Maintainer  : fjvallarino@gmail.com
  Stability   : experimental
  Portability : non-portable
  
  SeparatorLine is used for adding a separator line between two widgets. It adapts
  to the active layout direction, creating a vertical line on a horizontal layout
  and vice versa.
  
  @
  hstack [
    label "Left half",
    separatorLine,
    label "Right half"
  ]
  @
  
  The separator line has the provided width in the direction orthogonal to the
  parent layout, and takes all the available space in the other axis. In case of
  wanting a shorter line, padding should be used.
  -}
  {-# LANGUAGE BangPatterns #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE StrictData #-}
  
  module Monomer.Widgets.Singles.SeparatorLine (
    -- * Configuration
    SeparatorLineCfg,
    -- * Constructors
    separatorLine,
    separatorLine_
  ) where
  
  import Control.Applicative ((<|>))
  import Control.Lens ((^.))
  import Data.Default
  import Data.Maybe
  
  import Monomer.Widgets.Single
  
  import qualified Monomer.Core.Lens as L
  
  {-|
  Configuration options for separatorLine:
  
  - 'width': the max width of the line.
  - 'resizeFactor': flexibility to have more or less space assigned.
  -}
  data SeparatorLineCfg = SeparatorLineCfg {
    _slcWidth :: Maybe Double,
    _slcFactor :: Maybe Double
  }
  
  instance Default SeparatorLineCfg where
    def = SeparatorLineCfg {
      _slcWidth = Nothing,
      _slcFactor = Nothing
    }
  
  instance Semigroup SeparatorLineCfg where
    (<>) s1 s2 = SeparatorLineCfg {
      _slcWidth = _slcWidth s2 <|> _slcWidth s1,
      _slcFactor = _slcFactor s2 <|> _slcFactor s1
    }
  
  instance Monoid SeparatorLineCfg where
    mempty = def
  
  instance CmbWidth SeparatorLineCfg where
    width w = def {
      _slcWidth = Just w
    }
  
  instance CmbResizeFactor SeparatorLineCfg where
    resizeFactor f = def {
      _slcFactor = Just f
    }
  
  -- | Creates a separatorLine widget.
  separatorLine :: WidgetNode s e
  separatorLine = separatorLine_ def
  
  -- | Creates a separatorLine widget. Accepts config.
  separatorLine_ :: [SeparatorLineCfg] -> WidgetNode s e
  separatorLine_ configs = defaultWidgetNode "separatorLine" widget where
    config = mconcat (resizeFactor 0 : configs)
    widget = makeSeparatorLine config
  
  makeSeparatorLine :: SeparatorLineCfg -> Widget s e
  makeSeparatorLine !config = widget where
    widget = createSingle () def {
      singleGetBaseStyle = getBaseStyle,
      singleGetSizeReq = getSizeReq,
      singleRender = render
    }
  
    getBaseStyle wenv node = Just style where
      style = collectTheme wenv L.separatorLineStyle
  
    getSizeReq wenv node = sizeReq where
      theme = currentTheme wenv node
      direction = wenv ^. L.layoutDirection
      width = fromMaybe (theme ^. L.separatorLineWidth) (_slcWidth config)
      factor = fromMaybe 0 (_slcFactor config)
  
      isFixed = factor < 0.01
      flexSide = flexSize 10 0.5
      fixedW = fixedSize width
      flexW = flexSize width factor
      expandW = expandSize width factor
  
      sizeReq
        | isFixed && direction == LayoutNone = (fixedW, fixedW)
        | isFixed && direction == LayoutHorizontal = (fixedW, flexSide)
        | isFixed = (flexSide, fixedW)
        | direction == LayoutNone = (expandW, expandW)
        | direction == LayoutHorizontal = (expandW, flexW)
        | otherwise = (flexW, expandW)
  
    render wenv node renderer = do
      beginPath renderer
      setFillColor renderer fgColor
      renderRect renderer lineRect
      fill renderer
      where
        theme = currentTheme wenv node
        style = currentStyle wenv node
        direction = wenv ^. L.layoutDirection
        fgColor = styleFgColor style
        width = fromMaybe (theme ^. L.separatorLineWidth) (_slcWidth config)
  
        Rect cx cy cw ch = getContentArea node style
        lineW = cx + (cw - width) / 2
        lineH = cy + (ch - width) / 2
        lineRect
          | direction == LayoutNone = Rect cx cy cw ch
          | direction == LayoutHorizontal = Rect lineW cy width ch
          | otherwise = Rect cx lineH cw width
  