-------------------------------------------------- -- Copyright 1994 by Peter Thiemann -- $Log: PsOutput.hs,v $ -- Revision 1.1 2004/08/05 11:11:58 malcolm -- Add a regression testsuite for the nhc98 compiler. It isn't very good, -- but it is better than nothing. I've been using it for about four years -- on nightly builds, so it's about time it entered the repository! It -- includes a slightly altered version of the nofib suite. -- Instructions are in the README. -- -- Revision 1.2 1999/01/18 19:38:47 sof -- Misc (backward compatible) changes to make srcs acceptable -- to a Haskell 98 compiler. -- -- Revision 1.1 1996/01/08 20:02:34 partain -- Initial revision -- -- Revision 1.4 1994/03/15 15:34:53 thiemann -- added full color support, XColorDB based -- --Revision 1.3 1993/08/31 12:31:32 thiemann --Reflect changes in type FONT -- --Revision 1.2 1993/08/25 15:11:11 thiemann --added PostScript prolog to use shorter command names --fixed backslash bug in psString -- --Revision 1.1 1993/08/17 12:34:29 thiemann --Initial revision -- -- $Locker: $ -------------------------------------------------- module PsOutput (psShowsWrapper) where -- import EbnfLayout import Fonts (FONT, fontName, fontScale, noFont) import Color (Color (..), showsPsColor, noColor) import Info (Container (..), GObject (..), TDirection (..), WrapperType (..), INFO(..), ColorInfo(..)) -- psState = (currentColor, currentFont, currentLinewidth) type PsState = (Color, FONT, Int, ShowS) type PsTrafo = PsState -> PsState initialState :: PsState initialState = (noColor, noFont, -1, id) setColor :: Color -> PsTrafo setColor clr st@(clr0, fnt0, lw0, shower) | clr == clr0 = st | otherwise = (clr, fnt0, lw0, shower . showsPsColor clr) setFont :: FONT -> PsTrafo setFont font st@(clr0, fnt0, lw0, shower) | font == fnt0 = st | otherwise = (clr0, font, lw0, shower . showString ('/':fontName font) . showString " findfont " . shows (fontScale font) . showString " scalefont" . showString " setfont\n") setLineWidth :: Int -> PsTrafo setLineWidth lw st@(clr0, fnt0, lw0, shower) | lw == lw0 = st | otherwise = (clr0, fnt0, lw, shower . showsPsNum lw . showString " slw\n") drawBox :: Bool -> Int -> Int -> Int -> Int -> Int -> PsTrafo drawBox rounded ax ay width height lw (clr0, fnt0, lw0, shower) = (clr0, fnt0, lw, shower . showsPsNum ax . showsPsNum ay . showsPsNum width . showsPsNum height . showsPsNum lw . showString (if rounded then " RBox\n" else " Box\n")) drawString :: Int -> Int -> String -> PsTrafo drawString ax ay str (clr0, fnt0, lw0, shower) = (clr0, fnt0, lw0, shower . showsMoveto ax ay . showChar '(' . showString (psString str) . showChar ')' . showString " show\n") drawRLine :: Int -> Int -> [(Int, Int)] -> PsTrafo drawRLine ax ay rels (clr0, fnt0, lw0, shower) = (clr0, fnt0, lw0, shower . showString "n" . showsMoveto ax ay . foldr (.) (showString " s\n") [ showsRLineto rx ry | (rx, ry) <- rels ]) insertShowS :: ShowS -> PsTrafo insertShowS shower1 (clr0, fnt0, lw0, shower) = (clr0, fnt0, lw0, shower . shower1) runTrafo :: PsTrafo -> ShowS runTrafo f = shower where (_, _, _, shower) = f initialState psShowsWrapper :: WrapperType psShowsWrapper title (borderDistX, borderDistY, lineWidth, fatLineWidth, arrowSize, ntFont, tFont, (ntColor, tColor, lineColor, fatLineColor)) container@(rx, ry, width, height, inOutY, gobj) = showString "%!PS-Adobe-1.0\n" . showString "%%DocumentFonts: " . showString ntFontName . (if ntFontName == tFontName then id else (showChar ' ' . showString tFontName)) . showString "\n%%Title: " . showString title . showString "\n%%Creator: ebnf2ps (Copyright 1994 by Peter Thiemann)\n" . showString "%%Pages: 0\n" . showString "%%BoundingBox:" . showsPsNum (psFloor rx) . showsPsNum (psFloor ry) . showsPsNum (psCeil (rx+width)) . showsPsNum (psCeil (ry+height)) . showString "\n%%EndComments\n" . showString psProlog . showString "%%EndProlog\n" . showString "\n$Ebnf2psBegin\n" . runTrafo (psShowsContainer rx ry container) . showString "\n$Ebnf2psEnd\n" where ntFontName = fontName ntFont tFontName = fontName tFont psShowsContainer :: Int -> Int -> Container -> PsTrafo psShowsContainer ax ay (rx, ry, width, height, inOutY, gobj) = case gobj of AString color font theString -> drawString ax1 ay1 theString . setColor color . setFont font ABox color rounded content -> psShowsContainer ax1 ay1 content . drawBox rounded ax1 ay1 width height fatLineWidth . setColor color Arrow color size -> drawRLine (ax1-size) (ay1+abs size) [(size, -abs size), (-size, -abs size)] . setLineWidth lineWidth . setColor color Aline color -> drawRLine ax1 ay1 [(width, height)] . setLineWidth lineWidth . setColor color ATurn color dir -> insertShowS( showString "n" . showsIt dir . showString " s\n") . setLineWidth lineWidth . setColor color where showsIt SE = showsMoveto ax1 ay1 . showsArcto ax1 (ay1+height) (ax1+width) (ay1+height) radius . showsLineto (ax1+width) (ay1+height) showsIt WN = showsMoveto ax1 ay1 . showsArcto (ax1+width) ay1 (ax1+width) (ay1+height) radius . showsLineto (ax1+width) (ay1+height) showsIt SW = showsMoveto (ax1+width) ay1 . showsArcto (ax1+width) (ay1+height) ax1 (ay1+height) radius . showsLineto ax1 (ay1+height) showsIt NE = showsMoveto (ax1+width) ay1 . showsArcto ax1 ay1 ax1 (ay1+height) radius . showsLineto ax1 (ay1+height) radius = min height width AComposite contents -> foldr (.) id (map (psShowsContainer ax1 ay1) contents) where ax1 = ax + rx ay1 = ay + ry -- showsPsColor color = showString " col" . showsColor color showsSetlinewidth lineWidth = showsPsNum lineWidth . showString " slw" showsMoveto x y = showsPsXY x y . showString " m" showsLineto x y = showsPsXY x y . showString " l" showsArcto x1 y1 x2 y2 r = showsPsXY x1 y1 . showsPsXY x2 y2 . showsPsNum r . showString " apr\n" showsRMoveto x y = showsPsXY x y . showString " rm" showsRLineto x y = showsPsXY x y . showString " rl" showsPsXY x y = showsPsNum x . showsPsNum y showsPsNum :: Int -> ShowS showsPsNum x = showChar ' ' . shows x100 . if x99 == 0 then id else showChar '.' . shows x1 . shows x2 where (x100,x99) = x `divMod` 100 (x1,x2) = x99 `divMod` 10 psFloor, psCeil :: Int -> Int psFloor x = 100 * (x `div` 100) psCeil x = 100 * ((x + 99) `div` 100) -- showsPsInt :: Int -> showS -- showsPsInt x = showChar ' ' . showInt (x `div` 100) psString "" = "" psString ('(':cs) = "\\(" ++ psString cs psString (')':cs) = "\\)" ++ psString cs psString ('\\':cs)= "\\\\" ++ psString cs psString ('-':cs) = "\\261" ++ psString cs -- endash looks much nicer psString (c:cs) = c:psString cs -- Box: width height linewidth Box -> - -- draw box at current point psProlog :: String psProlog = "\ \/$Ebnf2psDict 100 dict def\n\ \$Ebnf2psDict begin\n\ \/l {lineto} bind def\n\ \/m {moveto} bind def\n\ \/rl {rlineto} bind def\n\ \/rm {rmoveto} bind def\n\ \/s {stroke} bind def\n\ \/n {newpath} bind def\n\ \/gs {gsave} bind def\n\ \/gr {grestore} bind def\n\ \/clp {closepath} bind def\n\ \/slw {setlinewidth} bind def\n\ \/graycol {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul\n\ \4 -2 roll mul setrgbcolor} bind def\n\ \/scol {3 {255 div 3 1 roll} repeat setrgbcolor} bind def\n\ \ \ \/apr {arcto 4 {pop} repeat} def\n\ \/Box {\n\ \ /linewidth exch def\n\ \ linewidth sub /height exch def\n\ \ linewidth sub /width exch def\n\ \ \ \ n m\n\ \ width 0 rl\n\ \ 0 height rl\n\ \ width neg 0 rl\n\ \ 0 height neg rl\n\ \ clp linewidth slw s\n\ \} def\n\ \ \ \/RBox {\n\ \ /linewidth exch def\n\ \ /height exch def\n\ \ /width exch def\n\ \ /lly exch def\n\ \ /llx exch def\n\ \ linewidth 2 div dup llx add /llx exch def lly add /lly exch def\n\ \ /height height linewidth sub def\n\ \ /width width linewidth sub def\n\ \ /height2 height 2 div def\n\ \ /width2 width 2 div def\n\ \ /urx llx width add def\n\ \ /ury lly height add def\n\ \ /mmx llx width2 add def\n\ \ /mmy lly height2 add def\n\ \ /radius width2 height2 ge {height2} {width2} ifelse def\n\ \ \ \ n mmx lly m\n\ \ urx lly urx mmy radius apr\n\ \ urx ury mmx ury radius apr\n\ \ llx ury llx mmy radius apr\n\ \ llx lly mmx lly radius apr\n\ \ mmx lly l\n\ \ clp linewidth slw s\n\ \} def\n\ \end\n\ \/$Ebnf2psBegin {$Ebnf2psDict begin /$Ebnf2psEnteredState save def} def\n\ \/$Ebnf2psEnd {$Ebnf2psEnteredState restore end} def\n\ \\n"