fudgets-0.18.3: hsrc/layout/NameLayout.hs
module NameLayout(LName(..),placeNL,spaceNL,modNL,marginNL,sepNL,hvAlignNL,marginHVAlignNL,nullNL,hBoxNL,hBoxNL',vBoxNL, vBoxNL',leafNL, NameLayout, nameF,
listNF, nameLayoutF) where
--import NonStdTrace(trace)
import LayoutRequest
import NullF
import Spops
--import Command
--import Event
import FRequest
--import Xtypes
import EitherUtils(plookup)
import Data.Maybe(fromJust)
import Fudget
import Path
import Geometry
import Placers
import Spacers
--import Message
import ListF
import Loopthrough
import Cont
--import LayoutDir
import AlignP
--import Alignment
import Utils
import Maptrace
import AutoLayout
import ParF
type LName = String
newtype NameLayout = NL (MLNode LName) -- abstract
-- The layout structure datatype
type MLNode a = (Maybe LayoutRequest, LNode a)
data LNode a =
LNode Int Placer (Maybe (Rect -> [Rect])) [MLNode a]
| LLeaf (LLeaf a) deriving Show
data LLeaf a = Name a | Req LayoutRequest deriving Show
type NPath = [Int]
-----------------------------------------------------------------------------------
-- Exported functions
placeNL :: Placer -> [NameLayout] -> NameLayout
placeNL lter ns = let dns = map deNL ns in
buildnl $ LNode (length (filter (nothing.fst) dns)) lter Nothing dns
spaceNL :: Spacer -> NameLayout -> NameLayout
spaceNL = modNL . spacerP
modNL :: (Placer -> Placer) -> NameLayout -> NameLayout
modNL ltermod (NL (req,n)) = NL $ case n of
LNode i lter f ls -> (req,LNode i (ltermod lter) f ls)
LLeaf l ->
let lter = ltermod idP
P lter' = lter in
case l of
Req r -> leafReq $ fst $ lter' $ [r]
_ -> (Nothing,LNode 1 lter Nothing [(req,n)])
marginNL = spaceNL . marginS
sepNL = spaceNL . sepS
hvAlignNL = spaceNL `oo` hvAlignS
marginHVAlignNL sep ha va = spaceNL (marginHVAlignS sep ha va)
hBoxNL = placeNL $ horizontalP
hBoxNL' d = placeNL $ horizontalP' d
vBoxNL = placeNL $ verticalP
vBoxNL' d = placeNL $ verticalP' d
leafNL name = buildnl $ LLeaf $ Name name
nullNL = NL $ leafReq $ plainLayout (Point 1 1) False False
nameF :: LName -> F a b -> F a b
nameF n = putMessageFu (Low (LCmd (LayoutName n))) . autoLayoutF
-- local
nothing Nothing = True
nothing _ = False
buildnl :: LNode LName -> NameLayout
buildnl x = NL (Nothing,x)
deNL (NL x) = x
leafReq :: LayoutRequest -> MLNode a
leafReq req = (Just req,LLeaf $ Req $ req)
listNF :: (Eq a, Show a) => [(a, F b c)] -> F (a, b) (a, c)
listNF fs = listF [(t, nameF (show t) f) | (t, f) <- fs]
-- The main layout function
nameLayoutF :: NameLayout -> F a b -> F a b
nameLayoutF (NL ltree) (F fsp) =
let layoutSP =
getAllPNames (countLNames ltree) [] $ \pnames ->
let (pathTable, ltree') = rebuildTree pnames [] ltree
in lSP pathTable ltree'
lSP pt ltree =
let same = lSP pt ltree in
getSP $ \msg ->
case msg of
-- A message from the fudget
Left (Low (path, LCmd (LayoutRequest lr))) ->
ctrace "nameLayoutF" lr $
let ltree' = updateTree path (pathlookup pt path) ltree lr
in case ltree' of
(Just lreq, _) -> --trace (show ltree') $
putSP (Right (Low ([], layoutRequestCmd lreq))) $
lSP pt ltree'
_ -> lSP pt ltree'
Left x -> putSP (Right x) $ same
-- A message to the fudget
Right (Low (path, LEvt (LayoutPlace r))) ->
putsSP (map (Left. Low) $ traverseTree r ltree) $ same
Right x -> putSP (Left x) $ same
in parF nullF $ F{-ff-} $ loopThroughRightSP layoutSP fsp
-- fix for autolayout
-----------------------------------------------------------------------------------
-- Local functions
-- Counts the number of named leafs in a layout structure
countLNames :: MLNode a -> Int
countLNames (_, LLeaf (Name _)) = 1
countLNames (_, LLeaf _) = 0
countLNames (_, LNode _ _ _ ns) = sum (map countLNames ns)
-- Traverses the layout structure, returning a mapping from leaf names to paths
getAllPNames :: Int -> [(LName, Path)] ->
Cont (SP (Either (FCommand a) b) c) [(LName,Path)]
getAllPNames 0 pnames c = c pnames
getAllPNames n pnames c =
waitForSP layoutName $ \pname ->
getAllPNames (n-1) (pname:pnames) c
where layoutName (Left (Low (path, LCmd (LayoutName name)))) =
Just(name, path)
layoutName _ = Nothing
-- Rebuilds the layout structure.
-- Returns also a mapping from ordinary paths to number paths.
rebuildTree :: [(LName, Path)] -> NPath -> MLNode LName ->
([(Path, NPath)], MLNode Path)
rebuildTree pnames np (_, LLeaf (Name name)) =
case lookup name pnames of
Nothing -> error ("Couldn't find name "++ show name ++
" in (name, path) table.")
Just path -> ([(path, np)], (Nothing, LLeaf $ Name path))
rebuildTree pnames np (_, (LLeaf (Req r))) = ([],(Just r, (LLeaf (Req r))))
rebuildTree pnames np (_, LNode c lter Nothing ns) =
(concat ts, (Nothing, LNode c lter Nothing ns'))
where (ts, ns') = unzip (zipWith (rebuildTree pnames)
(map ((np++) . (:[])) [1..]) ns)
-- Inserts layout requests in the layout structure.
-- Trigged by some fudget emitting a layout request
updateTree :: Path ->
Maybe NPath ->
MLNode Path ->
LayoutRequest ->
MLNode Path
updateTree path Nothing _ lr =
error ("Hmmm. Couldn't find path " ++ show path ++
"in updateTree\nSomeone has probably forgotten to name a fudget.")
updateTree path (Just npath) lo lr = snd $ upd npath lo lr
where upd _ (mlr, LLeaf (Name p)) lr =
(nothing mlr, (Just lr, LLeaf (Name path)))
upd (n:np) (mlr, LNode c lter@(P lter') mr ns) lr =
let (before, this:after) = splitAt (n-1) ns
(ready, child) = upd np this lr
c' = if ready then max (c-1) 0 else c
ns' = before ++ [child] ++ after
in if c' == 0 then
let (lreq, rectf) = lter' (map (fromJust . fst) ns')
in (nothing mlr,
(Just lreq, LNode c' lter (Just rectf) ns'))
else
(False, (Nothing, LNode c' lter mr ns'))
upd _ othernode _ = (False,othernode)
-- We have got a rectangle. Emit commands to all subfudgets saying how large
-- they should be.
traverseTree :: Rect -> MLNode Path -> [TEvent]
traverseTree r (_, LLeaf (Name path)) = [(path, LEvt $ LayoutPlace r)]
traverseTree r (_, LLeaf _) = []
traverseTree r (_, LNode _ _ (Just rectf) ns) =
concat (zipWith traverseTree (rectf r) ns)
pathlookup table p = plookup (flip subPath p) table