packages feed

monomer-1.4.0.0: src/Monomer/Widgets/Singles/SeparatorLine.hs

{-|
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 viceversa.

@
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 Data.Tuple

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 spaced 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