{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_HADDOCK hide #-}
module Data.GraphViz.Attributes.Values where
import qualified Data.GraphViz.Attributes.HTML as Html
import Data.GraphViz.Attributes.Internal
import Data.GraphViz.Internal.State (getLayerListSep,
getLayerSep,
setLayerListSep,
setLayerSep)
import Data.GraphViz.Internal.Util (bool, stringToInt)
import Data.GraphViz.Parsing
import Data.GraphViz.Printing
import Data.List (intercalate)
import Data.Maybe (isJust)
import Data.Monoid ((<>))
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as T
import Data.Word (Word16)
import System.FilePath (searchPathSeparator, splitSearchPath)
type EscString = Text
data Rect = Rect Point Point
deriving (Eq, Ord, Show, Read)
instance PrintDot Rect where
unqtDot (Rect p1 p2) = printPoint2DUnqt p1 <> comma <> printPoint2DUnqt p2
toDot = dquotes . unqtDot
unqtListToDot = hsep . mapM unqtDot
instance ParseDot Rect where
parseUnqt = uncurry Rect <$> commaSep' parsePoint2D parsePoint2D
parse = quotedParse parseUnqt
parseUnqtList = sepBy1 parseUnqt whitespace1
data ClusterMode = Local
| Global
| NoCluster
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot ClusterMode where
unqtDot Local = text "local"
unqtDot Global = text "global"
unqtDot NoCluster = text "none"
instance ParseDot ClusterMode where
parseUnqt = oneOf [ stringRep Local "local"
, stringRep Global "global"
, stringRep NoCluster "none"
]
data DirType = Forward
| Back
| Both
| NoDir
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot DirType where
unqtDot Forward = text "forward"
unqtDot Back = text "back"
unqtDot Both = text "both"
unqtDot NoDir = text "none"
instance ParseDot DirType where
parseUnqt = oneOf [ stringRep Forward "forward"
, stringRep Back "back"
, stringRep Both "both"
, stringRep NoDir "none"
]
data DEConstraints = EdgeConstraints
| NoConstraints
| HierConstraints
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot DEConstraints where
unqtDot EdgeConstraints = unqtDot True
unqtDot NoConstraints = unqtDot False
unqtDot HierConstraints = text "hier"
instance ParseDot DEConstraints where
parseUnqt = fmap (bool NoConstraints EdgeConstraints) parse
`onFail`
stringRep HierConstraints "hier"
data DPoint = DVal Double
| PVal Point
deriving (Eq, Ord, Show, Read)
instance PrintDot DPoint where
unqtDot (DVal d) = unqtDot d
unqtDot (PVal p) = printPoint2DUnqt p
toDot (DVal d) = toDot d
toDot (PVal p) = printPoint2D p
instance ParseDot DPoint where
parseUnqt = optional (character '+')
*> oneOf [ PVal <$> parsePoint2D
, DVal <$> parseUnqt
]
parse = quotedParse parseUnqt
`onFail`
fmap DVal (parseSignedFloat False)
data SVGFontNames = SvgNames
| PostScriptNames
| FontConfigNames
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot SVGFontNames where
unqtDot SvgNames = text "svg"
unqtDot PostScriptNames = text "ps"
unqtDot FontConfigNames = text "gd"
instance ParseDot SVGFontNames where
parseUnqt = oneOf [ stringRep SvgNames "svg"
, stringRep PostScriptNames "ps"
, stringRep FontConfigNames "gd"
]
parse = stringRep SvgNames "\"\""
`onFail`
optionalQuoted parseUnqt
data GraphSize = GSize { width :: Double
, height :: Maybe Double
, desiredSize :: Bool
}
deriving (Eq, Ord, Show, Read)
instance PrintDot GraphSize where
unqtDot (GSize w mh ds) = bool id (<> char '!') ds
. maybe id (\h -> (<> unqtDot h) . (<> comma)) mh
$ unqtDot w
toDot (GSize w Nothing False) = toDot w
toDot gs = dquotes $ unqtDot gs
instance ParseDot GraphSize where
parseUnqt = GSize <$> parseUnqt
<*> optional (parseComma *> whitespace *> parseUnqt)
<*> (isJust <$> optional (character '!'))
parse = quotedParse parseUnqt
`onFail`
fmap (\ w -> GSize w Nothing False) (parseSignedFloat False)
data ModeType = Major
| KK
| Hier
| IpSep
| SpringMode
| MaxEnt
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot ModeType where
unqtDot Major = text "major"
unqtDot KK = text "KK"
unqtDot Hier = text "hier"
unqtDot IpSep = text "ipsep"
unqtDot SpringMode = text "spring"
unqtDot MaxEnt = text "maxent"
instance ParseDot ModeType where
parseUnqt = oneOf [ stringRep Major "major"
, stringRep KK "KK"
, stringRep Hier "hier"
, stringRep IpSep "ipsep"
, stringRep SpringMode "spring"
, stringRep MaxEnt "maxent"
]
data Model = ShortPath
| SubSet
| Circuit
| MDS
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot Model where
unqtDot ShortPath = text "shortpath"
unqtDot SubSet = text "subset"
unqtDot Circuit = text "circuit"
unqtDot MDS = text "mds"
instance ParseDot Model where
parseUnqt = oneOf [ stringRep ShortPath "shortpath"
, stringRep SubSet "subset"
, stringRep Circuit "circuit"
, stringRep MDS "mds"
]
data Label = StrLabel EscString
| HtmlLabel Html.Label
| RecordLabel RecordFields
deriving (Eq, Ord, Show, Read)
instance PrintDot Label where
unqtDot (StrLabel s) = unqtDot s
unqtDot (HtmlLabel h) = angled $ unqtDot h
unqtDot (RecordLabel fs) = unqtDot fs
toDot (StrLabel s) = toDot s
toDot h@HtmlLabel{} = unqtDot h
toDot (RecordLabel fs) = toDot fs
instance ParseDot Label where
parseUnqt = oneOf [ HtmlLabel <$> parseAngled parseUnqt
, RecordLabel <$> parseUnqt
, StrLabel <$> parseUnqt
]
parse = oneOf [ HtmlLabel <$> parseAngled parse
, RecordLabel <$> parse
, StrLabel <$> parse
]
type RecordFields = [RecordField]
data RecordField = LabelledTarget PortName EscString
| PortName PortName
| FieldLabel EscString
| FlipFields RecordFields
deriving (Eq, Ord, Show, Read)
instance PrintDot RecordField where
unqtDot (LabelledTarget t s) = printPortName t <+> unqtRecordString s
unqtDot (PortName t) = printPortName t
unqtDot (FieldLabel s) = unqtRecordString s
unqtDot (FlipFields rs) = braces $ unqtDot rs
toDot (FieldLabel s) = printEscaped recordEscChars s
toDot rf = dquotes $ unqtDot rf
unqtListToDot [f] = unqtDot f
unqtListToDot fs = hcat . punctuate (char '|') $ mapM unqtDot fs
listToDot [f] = toDot f
listToDot fs = dquotes $ unqtListToDot fs
instance ParseDot RecordField where
parseUnqt = (liftA2 maybe PortName LabelledTarget
<$> (PN <$> parseAngled parseRecord)
<*> optional (whitespace1 *> parseRecord)
)
`onFail`
fmap FieldLabel parseRecord
`onFail`
fmap FlipFields (parseBraced parseUnqt)
`onFail`
fail "Unable to parse RecordField"
parse = quotedParse parseUnqt
parseUnqtList = wrapWhitespace $ sepBy1 parseUnqt (wrapWhitespace $ character '|')
parseList = do rfs <- quotedParse parseUnqtList
if validRFs rfs
then return rfs
else fail "This is a StrLabel, not a RecordLabel"
where
validRFs [FieldLabel str] = T.any (`elem` recordEscChars) str
validRFs _ = True
printPortName :: PortName -> DotCode
printPortName = angled . unqtRecordString . portName
parseRecord :: Parse Text
parseRecord = parseEscaped False recordEscChars []
unqtRecordString :: Text -> DotCode
unqtRecordString = unqtEscaped recordEscChars
recordEscChars :: [Char]
recordEscChars = ['{', '}', '|', ' ', '<', '>']
data LabelScheme = NotEdgeLabel
| CloseToCenter
| CloseToOldCenter
| RemoveAndStraighten
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot LabelScheme where
unqtDot NotEdgeLabel = int 0
unqtDot CloseToCenter = int 1
unqtDot CloseToOldCenter = int 2
unqtDot RemoveAndStraighten = int 3
instance ParseDot LabelScheme where
parseUnqt = stringValue [ ("0", NotEdgeLabel)
, ("1", CloseToCenter)
, ("2", CloseToOldCenter)
, ("3", RemoveAndStraighten)
]
data Point = Point { xCoord :: Double
, yCoord :: Double
, zCoord :: Maybe Double
, forcePos :: Bool
}
deriving (Eq, Ord, Show, Read)
createPoint :: Double -> Double -> Point
createPoint x y = Point x y Nothing False
printPoint2DUnqt :: Point -> DotCode
printPoint2DUnqt p = commaDel (xCoord p) (yCoord p)
printPoint2D :: Point -> DotCode
printPoint2D = dquotes . printPoint2DUnqt
parsePoint2D :: Parse Point
parsePoint2D = uncurry createPoint <$> commaSepUnqt
instance PrintDot Point where
unqtDot (Point x y mz frs) = bool id (<> char '!') frs
. maybe id (\ z -> (<> unqtDot z) . (<> comma)) mz
$ commaDel x y
toDot = dquotes . unqtDot
unqtListToDot = hsep . mapM unqtDot
listToDot = dquotes . unqtListToDot
instance ParseDot Point where
parseUnqt = uncurry Point
<$> commaSepUnqt
<*> optional (parseComma *> parseUnqt)
<*> (isJust <$> optional (character '!'))
parse = quotedParse parseUnqt
parseUnqtList = sepBy1 parseUnqt whitespace1
data Overlap = KeepOverlaps
| ScaleOverlaps
| ScaleXYOverlaps
| PrismOverlap (Maybe Word16)
| VoronoiOverlap
| CompressOverlap
| VpscOverlap
| IpsepOverlap
deriving (Eq, Ord, Show, Read)
instance PrintDot Overlap where
unqtDot KeepOverlaps = unqtDot True
unqtDot ScaleOverlaps = text "scale"
unqtDot ScaleXYOverlaps = text "scalexy"
unqtDot (PrismOverlap i) = maybe id (flip (<>) . unqtDot) i $ text "prism"
unqtDot VoronoiOverlap = text "voronoi"
unqtDot CompressOverlap = text "compress"
unqtDot VpscOverlap = text "vpsc"
unqtDot IpsepOverlap = text "ipsep"
instance ParseDot Overlap where
parseUnqt = oneOf [ stringRep KeepOverlaps "true"
, stringRep ScaleXYOverlaps "scalexy"
, stringRep ScaleOverlaps "scale"
, string "prism" *> fmap PrismOverlap (optional parse)
, stringRep (PrismOverlap Nothing) "false"
, stringRep VoronoiOverlap "voronoi"
, stringRep CompressOverlap "compress"
, stringRep VpscOverlap "vpsc"
, stringRep IpsepOverlap "ipsep"
]
newtype LayerSep = LSep Text
deriving (Eq, Ord, Show, Read)
instance PrintDot LayerSep where
unqtDot (LSep ls) = setLayerSep (T.unpack ls) *> unqtDot ls
toDot (LSep ls) = setLayerSep (T.unpack ls) *> toDot ls
instance ParseDot LayerSep where
parseUnqt = do ls <- parseUnqt
setLayerSep $ T.unpack ls
return $ LSep ls
parse = do ls <- parse
setLayerSep $ T.unpack ls
return $ LSep ls
newtype LayerListSep = LLSep Text
deriving (Eq, Ord, Show, Read)
instance PrintDot LayerListSep where
unqtDot (LLSep ls) = setLayerListSep (T.unpack ls) *> unqtDot ls
toDot (LLSep ls) = setLayerListSep (T.unpack ls) *> toDot ls
instance ParseDot LayerListSep where
parseUnqt = do ls <- parseUnqt
setLayerListSep $ T.unpack ls
return $ LLSep ls
parse = do ls <- parse
setLayerListSep $ T.unpack ls
return $ LLSep ls
type LayerRange = [LayerRangeElem]
data LayerRangeElem = LRID LayerID
| LRS LayerID LayerID
deriving (Eq, Ord, Show, Read)
instance PrintDot LayerRangeElem where
unqtDot (LRID lid) = unqtDot lid
unqtDot (LRS id1 id2) = do ls <- getLayerSep
let s = unqtDot $ head ls
unqtDot id1 <> s <> unqtDot id2
toDot (LRID lid) = toDot lid
toDot lrs = dquotes $ unqtDot lrs
unqtListToDot lr = do lls <- getLayerListSep
let s = unqtDot $ head lls
hcat . punctuate s $ mapM unqtDot lr
listToDot [lre] = toDot lre
listToDot lrs = dquotes $ unqtListToDot lrs
instance ParseDot LayerRangeElem where
parseUnqt = ignoreSep LRS parseUnqt parseLayerSep parseUnqt
`onFail`
fmap LRID parseUnqt
parse = quotedParse (ignoreSep LRS parseUnqt parseLayerSep parseUnqt)
`onFail`
fmap LRID parse
parseUnqtList = sepBy parseUnqt parseLayerListSep
parseList = quotedParse parseUnqtList
`onFail`
fmap ((:[]) . LRID) parse
parseLayerSep :: Parse ()
parseLayerSep = do ls <- getLayerSep
many1Satisfy (`elem` ls) *> return ()
parseLayerName :: Parse Text
parseLayerName = parseEscaped False [] =<< liftA2 (++) getLayerSep getLayerListSep
parseLayerName' :: Parse Text
parseLayerName' = stringBlock
`onFail`
quotedParse parseLayerName
parseLayerListSep :: Parse ()
parseLayerListSep = do lls <- getLayerListSep
many1Satisfy (`elem` lls) *> return ()
data LayerID = AllLayers
| LRInt Int
| LRName Text
deriving (Eq, Ord, Show, Read)
instance PrintDot LayerID where
unqtDot AllLayers = text "all"
unqtDot (LRInt n) = unqtDot n
unqtDot (LRName nm) = unqtDot nm
toDot (LRName nm) = toDot nm
toDot li = unqtDot li
unqtListToDot ll = do ls <- getLayerSep
let s = unqtDot $ head ls
hcat . punctuate s $ mapM unqtDot ll
listToDot [l] = toDot l
listToDot ll = dquotes $ unqtDot ll
instance ParseDot LayerID where
parseUnqt = checkLayerName <$> parseLayerName
parse = oneOf [ checkLayerName <$> parseLayerName'
, LRInt <$> parse
]
checkLayerName :: Text -> LayerID
checkLayerName str = maybe checkAll LRInt $ stringToInt str
where
checkAll = if T.toLower str == "all"
then AllLayers
else LRName str
newtype LayerList = LL [LayerID]
deriving (Eq, Ord, Show, Read)
instance PrintDot LayerList where
unqtDot (LL ll) = unqtDot ll
toDot (LL ll) = toDot ll
instance ParseDot LayerList where
parseUnqt = LL <$> sepBy1 parseUnqt parseLayerSep
parse = quotedParse parseUnqt
`onFail`
fmap (LL . (:[]) . LRName) stringBlock
`onFail`
quotedParse (stringRep (LL []) "")
data Order = OutEdges
| InEdges
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot Order where
unqtDot OutEdges = text "out"
unqtDot InEdges = text "in"
instance ParseDot Order where
parseUnqt = oneOf [ stringRep OutEdges "out"
, stringRep InEdges "in"
]
data OutputMode = BreadthFirst | NodesFirst | EdgesFirst
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot OutputMode where
unqtDot BreadthFirst = text "breadthfirst"
unqtDot NodesFirst = text "nodesfirst"
unqtDot EdgesFirst = text "edgesfirst"
instance ParseDot OutputMode where
parseUnqt = oneOf [ stringRep BreadthFirst "breadthfirst"
, stringRep NodesFirst "nodesfirst"
, stringRep EdgesFirst "edgesfirst"
]
data Pack = DoPack
| DontPack
| PackMargin Int
deriving (Eq, Ord, Show, Read)
instance PrintDot Pack where
unqtDot DoPack = unqtDot True
unqtDot DontPack = unqtDot False
unqtDot (PackMargin m) = unqtDot m
instance ParseDot Pack where
parseUnqt = oneOf [ PackMargin <$> parseUnqt
, bool DontPack DoPack <$> onlyBool
]
data PackMode = PackNode
| PackClust
| PackGraph
| PackArray Bool Bool (Maybe Int)
deriving (Eq, Ord, Show, Read)
instance PrintDot PackMode where
unqtDot PackNode = text "node"
unqtDot PackClust = text "clust"
unqtDot PackGraph = text "graph"
unqtDot (PackArray c u mi) = addNum . isU . isC . isUnder
$ text "array"
where
addNum = maybe id (flip (<>) . unqtDot) mi
isUnder = if c || u
then (<> char '_')
else id
isC = if c
then (<> char 'c')
else id
isU = if u
then (<> char 'u')
else id
instance ParseDot PackMode where
parseUnqt = oneOf [ stringRep PackNode "node"
, stringRep PackClust "clust"
, stringRep PackGraph "graph"
, do string "array"
mcu <- optional $ character '_' *> many1 (satisfy isCU)
let c = hasCharacter mcu 'c'
u = hasCharacter mcu 'u'
mi <- optional parseUnqt
return $ PackArray c u mi
]
where
hasCharacter ms c = maybe False (elem c) ms
isCU = (`elem` ['c', 'u'])
data Pos = PointPos Point
| SplinePos [Spline]
deriving (Eq, Ord, Show, Read)
instance PrintDot Pos where
unqtDot (PointPos p) = unqtDot p
unqtDot (SplinePos ss) = unqtDot ss
toDot (PointPos p) = toDot p
toDot (SplinePos ss) = toDot ss
instance ParseDot Pos where
parseUnqt = do splns <- parseUnqt
case splns of
[Spline Nothing Nothing [p]] -> return $ PointPos p
_ -> return $ SplinePos splns
parse = quotedParse parseUnqt
data EdgeType = SplineEdges
| LineEdges
| NoEdges
| PolyLine
| Ortho
| Curved
| CompoundEdge
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot EdgeType where
unqtDot SplineEdges = text "spline"
unqtDot LineEdges = text "line"
unqtDot NoEdges = empty
unqtDot PolyLine = text "polyline"
unqtDot Ortho = text "ortho"
unqtDot Curved = text "curved"
unqtDot CompoundEdge = text "compound"
toDot NoEdges = dquotes empty
toDot et = unqtDot et
instance ParseDot EdgeType where
parseUnqt = oneOf [ bool LineEdges SplineEdges <$> parse
, stringRep SplineEdges "spline"
, stringRep LineEdges "line"
, stringRep NoEdges "none"
, stringRep PolyLine "polyline"
, stringRep Ortho "ortho"
, stringRep Curved "curved"
, stringRep CompoundEdge "compound"
]
parse = stringRep NoEdges "\"\""
`onFail`
optionalQuoted parseUnqt
data PageDir = Bl | Br | Tl | Tr | Rb | Rt | Lb | Lt
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot PageDir where
unqtDot Bl = text "BL"
unqtDot Br = text "BR"
unqtDot Tl = text "TL"
unqtDot Tr = text "TR"
unqtDot Rb = text "RB"
unqtDot Rt = text "RT"
unqtDot Lb = text "LB"
unqtDot Lt = text "LT"
instance ParseDot PageDir where
parseUnqt = stringValue [ ("BL", Bl)
, ("BR", Br)
, ("TL", Tl)
, ("TR", Tr)
, ("RB", Rb)
, ("RT", Rt)
, ("LB", Lb)
, ("LT", Lt)
]
data Spline = Spline { endPoint :: Maybe Point
, startPoint :: Maybe Point
, splinePoints :: [Point]
}
deriving (Eq, Ord, Show, Read)
instance PrintDot Spline where
unqtDot (Spline me ms ps) = addE . addS
. hsep
$ mapM unqtDot ps
where
addP t = maybe id ((<+>) . commaDel t)
addS = addP 's' ms
addE = addP 'e' me
toDot = dquotes . unqtDot
unqtListToDot = hcat . punctuate semi . mapM unqtDot
listToDot = dquotes . unqtListToDot
instance ParseDot Spline where
parseUnqt = Spline <$> parseP 'e' <*> parseP 's'
<*> sepBy1 parseUnqt whitespace1
where
parseP t = optional (character t *> parseComma *> parseUnqt <* whitespace1)
parse = quotedParse parseUnqt
parseUnqtList = sepBy1 parseUnqt (character ';')
data QuadType = NormalQT
| FastQT
| NoQT
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot QuadType where
unqtDot NormalQT = text "normal"
unqtDot FastQT = text "fast"
unqtDot NoQT = text "none"
instance ParseDot QuadType where
parseUnqt = oneOf [ stringRep NormalQT "normal"
, stringRep FastQT "fast"
, stringRep NoQT "none"
, character '2' *> return FastQT
, bool NoQT NormalQT <$> parse
]
data Root = IsCentral
| NotCentral
| NodeName Text
deriving (Eq, Ord, Show, Read)
instance PrintDot Root where
unqtDot IsCentral = unqtDot True
unqtDot NotCentral = unqtDot False
unqtDot (NodeName n) = unqtDot n
toDot (NodeName n) = toDot n
toDot r = unqtDot r
instance ParseDot Root where
parseUnqt = fmap (bool NotCentral IsCentral) onlyBool
`onFail`
fmap NodeName parseUnqt
parse = optionalQuoted (bool NotCentral IsCentral <$> onlyBool)
`onFail`
fmap NodeName parse
data RankType = SameRank
| MinRank
| SourceRank
| MaxRank
| SinkRank
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot RankType where
unqtDot SameRank = text "same"
unqtDot MinRank = text "min"
unqtDot SourceRank = text "source"
unqtDot MaxRank = text "max"
unqtDot SinkRank = text "sink"
instance ParseDot RankType where
parseUnqt = stringValue [ ("same", SameRank)
, ("min", MinRank)
, ("source", SourceRank)
, ("max", MaxRank)
, ("sink", SinkRank)
]
data RankDir = FromTop
| FromLeft
| FromBottom
| FromRight
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot RankDir where
unqtDot FromTop = text "TB"
unqtDot FromLeft = text "LR"
unqtDot FromBottom = text "BT"
unqtDot FromRight = text "RL"
instance ParseDot RankDir where
parseUnqt = oneOf [ stringRep FromTop "TB"
, stringRep FromLeft "LR"
, stringRep FromBottom "BT"
, stringRep FromRight "RL"
]
data Shape
= BoxShape
| Polygon
| Ellipse
| Circle
| PointShape
| Egg
| Triangle
| PlainText
| DiamondShape
| Trapezium
| Parallelogram
| House
| Pentagon
| Hexagon
| Septagon
| Octagon
| DoubleCircle
| DoubleOctagon
| TripleOctagon
| InvTriangle
| InvTrapezium
| InvHouse
| MDiamond
| MSquare
| MCircle
| Square
| Star
| Underline
| Note
| Tab
| Folder
| Box3D
| Component
| Promoter
| CDS
| Terminator
| UTR
| PrimerSite
| RestrictionSite
| FivePovOverhang
| ThreePovOverhang
| NoOverhang
| Assembly
| Signature
| Insulator
| Ribosite
| RNAStab
| ProteaseSite
| ProteinStab
| RPromoter
| RArrow
| LArrow
| LPromoter
| Record
| MRecord
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot Shape where
unqtDot BoxShape = text "box"
unqtDot Polygon = text "polygon"
unqtDot Ellipse = text "ellipse"
unqtDot Circle = text "circle"
unqtDot PointShape = text "point"
unqtDot Egg = te