packages feed

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

-- | Floating panel overlays: windows, popups and modals (with the modal
-- backdrop), each a menu-style panel with its subtree painted inside.
module NanoUI.Frame.Overlay
  ( drawWindowOverlays
  , drawModalOverlays
  , drawPopupOverlays
  ) where

import Control.Monad (when)
import Data.IORef (readIORef)
import NanoUI.Context (Context (..), nodeTheme)
import NanoUI.Draw (pushRect, withClip)
import NanoUI.Frame.Chrome (overlayMenuStyle, overlayModalStyle, overlayWindowStyle, paintMenuPanel)
import NanoUI.Frame.Hit (modalTreeOpen)
import NanoUI.Frame.Paint (walkChildren)
import NanoUI.Layout.Arena (NodeIdx, NodeType (..), forNodes_, getNodeType, getPadding, getRect)
import NanoUI.Style (Padding (..), Style, Theme, themeOverlayDim, themeSeparator)
import NanoUI.Types (Rect (..), Size (..))
import NanoUI.Widgets.Chrome (titleBarChromeHFor, windowChromeSepH)

drawWindowOverlays :: Context -> IO ()
drawWindowOverlays ctx =
  forFloatingNode ctx NodeWindow $ \idx rect@(Rect x y w _) -> do
    theme <- nodeTheme ctx idx
    drawFloatingPanel ctx theme idx (overlayWindowStyle theme) rect
    pad <- getPadding (ctxNodeArena ctx) idx
    let sepY = y + padT pad + titleBarChromeHFor - windowChromeSepH
    pushRect
      (ctxDrawArena ctx)
      (Rect (x + padL pad) sepY (max 0 (w - padL pad - padR pad)) windowChromeSepH)
      (themeSeparator theme)

drawPopupOverlays :: Context -> IO ()
drawPopupOverlays ctx =
  forFloatingNode ctx NodePopup $ \idx rect -> do
    theme <- nodeTheme ctx idx
    drawFloatingPanel ctx theme idx (overlayMenuStyle theme) rect

drawModalOverlays :: Context -> Size -> IO ()
drawModalOverlays ctx (Size ww wh) = do
  found <- modalTreeOpen ctx
  when found $ do
    theme <- readIORef (ctxTheme ctx)
    pushRect (ctxDrawArena ctx) (Rect 0 0 ww wh) (themeOverlayDim theme)
    forFloatingNode ctx NodeModal $ \idx rect -> do
      modalTheme <- nodeTheme ctx idx
      drawFloatingPanel ctx modalTheme idx (overlayModalStyle modalTheme) rect

forFloatingNode :: Context -> NodeType -> (NodeIdx -> Rect -> IO ()) -> IO ()
forFloatingNode ctx nodeType draw =
  forNodes_ (ctxNodeArena ctx) $ \idx -> do
    nt <- getNodeType (ctxNodeArena ctx) idx
    when (nt == nodeType) $ do
      (x, y, w, h) <- getRect (ctxNodeArena ctx) idx
      draw idx (Rect x y w h)

drawFloatingPanel :: Context -> Theme -> NodeIdx -> Style -> Rect -> IO ()
drawFloatingPanel ctx theme idx style rect = do
  paintMenuPanel (ctxDrawArena ctx) theme style rect
  withClip (ctxDrawArena ctx) rect (walkChildren ctx idx)