CompiledGraphics

module CompiledGraphics where
import Geometry(Rect(..))
import Utils(number)
import DrawTypes(DrawCommand)
import ResourceIds(GCId,rootGC)
import Rects(overlaps,boundingRect)
import Maptrace(ctrace)

{-
--Version 1:
data CompiledGraphics = CGraphics Rect GCtx [DrawCommand] [CompiledGraphics]
-}

{-
--Version 2:
data CompiledGraphics = CGraphics Rect [XCommand] [CompiledGraphics]
       -- The only XCommand used is Draw MyWindow some_GC some_DrawCommand
-}

{-
--Version 3:
data CompiledGraphics = CGraphics Rect Cursor [XCommand] [CompiledGraphics]
       -- The only XCommand used is Draw MyWindow some_GC some_DrawCommand
-}

{-
--Version 4:
data CompiledGraphics
  = CGraphics Rect Cursor [XCommand] [CompiledGraphics]
       -- The only XCommand used is Draw MyWindow some_GC some_DrawCommand
  | CGMark CompiledGraphics -- path preserving dummy nodes
-}

--Version 5:
data CompiledGraphics
  = CGraphics Rect Cursor [(GCId,[DrawCommand])] [CompiledGraphics]
  | CGMark CompiledGraphics -- path preserving dummy nodes
  deriving (Show)

type Cursor = Bool

cgLeaf r rcmds =
    --ctrace "gctrace" cmds $
    cg
  where
    cg = CGraphics r False  cmds []
    --cmds = (map (Draw MyWindow gc) (f r))
    cmds = rcmds r

cgMark = CGMark

cgCompose r cgs = CGraphics r False cmds cgs
  where
    cmds = if anyOverlap cgs
	   then ctrace "cgoverlap" (map cgrect cgs) $
		[(rootGC,[])] --trick coding to force all subtrees to be redrawn
	   else []

    -- This is O(n^2) in general, but the bounding rect makes it O(n) for
    -- linear placers. It may also help somewhat for tables...
    -- Sorting the rectangles can cut down the complexity too...
    -- Better to let the placers tell if they produce overlapping parts...
    anyOverlap [] = False
    anyOverlap (cg:cgs) = anyOverlaps' [r] r cgs
      where r = cgrect cg

    anyOverlaps' rs bounding [] = False
    anyOverlaps' rs bounding (cg:cgs) =
        r `overlaps` bounding && any (overlaps r) rs ||
	anyOverlaps' (r:rs) (boundingRect bounding r) cgs
      where r = cgrect cg

cgrect (CGMark cg) = cgrect cg
cgrect (CGraphics r _ _ _) = r
cgsize = rectsize.cgrect

addcursor (CGMark cg) = CGMark (addcursor cg) -- hmm!!
addcursor (CGraphics r _ cmds cgs) = CGraphics r True cmds cgs
removecursor (CGMark cg) = CGMark (removecursor cg) -- hmm!!
removecursor (CGraphics r _ cmds cgs) = CGraphics r False cmds cgs
hascursor (CGMark cg) = hascursor cg -- hmm!!
hascursor (CGraphics _ cur _ _) = cur

cgpart cg [] = cg
cgpart (CGMark cg) (0:ps) = cgpart cg ps
cgpart (CGraphics _ _ _ parts) (p:ps) =
  if p<1||p>length parts then error "bad path in CompiledGraphics.cgpart " else
  cgpart (parts !! ((p::Int)-1)) ps

cgreplace cg path new = cgupdate cg path (const new)

{-
cgupdate cg ps f =
  (if any (<1) ps
  then ctrace "cgupdate" ps
  else id) $ cgupdate' cg ps f
-}

cgupdate cg                            []     f = f cg
cgupdate (CGMark cg)                   (0:ps) f = CGMark (cgupdate cg ps f)
cgupdate (CGMark cg)                   ps     f =
   ctrace "badpath" ("(CGMark _) "++show ps) $
   CGMark (cgupdate cg ps f)
cgupdate cg                            (0:ps) f =
   ctrace "badpath" (cg,0:ps) $
   CGMark (cgupdate cg ps f)
cgupdate (CGraphics r cur dcmds parts) (p:ps) f =
    CGraphics r cur dcmds (pre++cgupdate cg' ps f:post)
  where pre = take (p-1) parts
        cg':post = drop ((p-1)::Int) parts

cgcursors :: CompiledGraphics -> [[Int]]
cgcursors (CGMark cg) = map (0:) (cgcursors cg)
cgcursors (CGraphics _ cur _ parts) =
    if cur
    then []:partcursors
    else partcursors
  where
    partcursors =
      concatMap (\(n,ps) -> map (n:) (cgcursors ps)) (number 1 parts)

cgGroup pos len (CGMark cg) = CGMark (cgGroup pos len cg) -- hmm!!
cgGroup pos len (CGraphics r cur dcmds parts) =
    CGraphics r cur dcmds (ds1++cgCompose r2 ds2:ds3)
  where
    (ds1,ds2a) = splitAt (pos-1) parts
    (ds2,ds3) = splitAt len ds2a
    r2 = foldr (boundingRect.cgrect) (Rect 0 0) ds2

cgUngroup pos (CGMark cg) = CGMark (cgUngroup pos cg) -- hmm!!
cgUngroup pos cg@(CGraphics r cur dcmds parts) =
    case splitAt (pos-1) parts of
      (ds1,d2:ds3) ->
        case unmark 0 d2 of
          (m,CGraphics r2 cur2 dcmds2 ds2) ->
            CGraphics r cur (dcmds++dcmds2) (ds1++map (mark m) ds2++ds3)
          _ -> cg -- hmm!!

      _ -> cg -- hmm!!
  where
    unmark n (CGMark cg) = unmark (n+1) cg
    unmark n cg = (n,cg)

    mark 0 cg = cg
    mark n cg = mark (n-1) (CGMark cg)