m-chart.tex / last modification: 2008-03-25 14:22
%D \module
%D   [       file=m-chart,
%D        version=1998.10.10,
%D          title=\CONTEXT\ Modules,
%D       subtitle=Flow Charts,
%D         author={Hans Hagen \& Ton Otten},
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

% to do: \localpushmacro/\localpopmacro (dohandleflowchart etc)

% will be redone with layers and dimexpr ro even better, by just using
% textext

%D This is an experimental module. Pieces of code will be moved
%D to other modules. More features are possible but will be
%D interfaces later.
%D
%D When finished this module will be documented. The main macro
%D is still a rather big one and there is some redundant and
%D slow code that needs a clean up.

% arrow, dash
% crossing
% \goto -> \normalgoto
% class -> class:name (ref prefix)
% c, automatisch geen overlap zoeken
% eind eerder chart connecties
% relateren aan korps
% check op bestaan naam, bestaan shape
% auto als extern figuur
% subchart
% pijlen
% focus
% ook nog \MPmessage
% areapath -> krappe vlak
% clippath -> gehele vlak
%
% offset  : clip offset
% breedte : breedte cel
% hoogte  : hoogte cel
% dx      : halve afstand in breedte (grid breedte = breedte + 2dx)
% dy      : halve afstand in hoogte (grid hoogte = hoogte + 2dy)
% x       : x offset (clipping)
% y       : y offset (clipping)
% nx      : minimaal aantal cellen horizontaal
% ny      : minimaal aantal cellen vertikaal
%
% shape none en geen equivalent maken
%
% kaderkleur achtergrondkleur
% lijnkleur lijndikte
% focus focuskaderkleur focusachtergrondkleur
% richting
%
% focus koppelen aan kleur

\unprotect

\definesorting [flowchart] [flowcharts] [\v!none] % no access
\setupsorting  [flowchart] [\c!state=\v!stop]     % off by default

\def\@FLOW@{@FLOW@}
\def\@FLOC@{@FLOC@}
\def\@FLOX@{@FLOX@}

\def\@@FLOW{@@FLOW}
\def\@@FLOL{@@FLOL}
\def\@@FLOS{@@FLOS}
\def\@@FLOF{@@FLOF}
\def\@@FLOT{@@FLOT}
\def\@@FLOX{@@FLOX}

\def\@@MPx {@@MPx}
\def\@@MPy {@@MPy}

\def\FLOWbufferprefix{flw-}

\def\processFLOWbuffer#1{\getbuffer[\FLOWbufferprefix#1]}
\def\typeFLOWbuffer   #1{\typebuffer[\FLOWbufferprefix#1]}

\def\setFLOWname#1#2% funny hack that makes sure that we get
  {\bgroup          % names that are acceptable for METAPOST
   \lccode`0=`a\lccode`1=`b\lccode`2=`c\lccode`3=`d\lccode`4=`e%
   \lccode`5=`f\lccode`6=`g\lccode`7=`h\lccode`8=`i\lccode`9=`j%
   \lccode` =`\_\lccode`-=`\_\lccode`_=`\_%
   \lowercase{\gdef#1{#2}}%
   \egroup}

% een gobble als default is sneller, en dan alleen setten als
% nodig

\def\resetFLOWcell
  {% variables
   \global\let\FLOWname       \empty
   \global\let\FLOWalign      \empty
   \global\let\FLOWshape      \empty
   \global\let\FLOWlocation   \empty
   \global\let\FLOWtext       \empty
   \global\let\FLOWhelp       \empty
   \global\let\FLOWdestination\empty
   \global\let\FLOWoverlay    \empty
   \global\let\FLOWfocus      \empty
   \global\let\tFLOWlabel     \empty
   \global\let\bFLOWlabel     \empty
   \global\let\lFLOWlabel     \empty
   \global\let\rFLOWlabel     \empty
   \global\let\bcFLOWlabel    \empty
   \global\let\tcFLOWlabel    \empty
   \global\let\lcFLOWlabel    \empty
   \global\let\rcFLOWlabel    \empty
   \global\let\tFLOWexit      \empty
   \global\let\bFLOWexit      \empty
   \global\let\lFLOWexit      \empty
   \global\let\rFLOWexit      \empty
   % commands
   \let\name       \doFLOWname
   \let\shape      \doFLOWshape
   \let\destination\doFLOWdestination
   \let\location   \doFLOWlocation
   \let\focus      \doFLOWfocus
   \let\overlay    \doFLOWoverlay
   \let\figure     \doFLOWfigure
   \let\text       \doFLOWtext
   \let\comment    \doFLOWcomment
   \let\label      \doFLOWlabel
   \let\help       \doFLOWhelp
   \let\connection \doFLOWconnection
   \let\exit       \doFLOWexit
   % convenience commands
   \let\locate     \doFLOWlocate
   \let\connect    \doFLOWconnect}

\let\FLOWcell       \s!unknown
\let\FLOWshape      \s!unknown
\let\FLOWdestination\s!unknown
\let\FLOWfocus      \s!unknown
\let\FLOWoverlay    \empty
\let\FLOWtext       \empty

\def\doFLOWname#1%
  {\def\FLOWcell{#1}\setFLOWname\FLOWname{name_#1}\ignorespaces}

\def\doFLOWshape#1%
  {\gdef\FLOWshape{#1}\ignorespaces}

\def\doFLOWdestination#1%
  {\gdef\FLOWdestination{#1}\ignorespaces}

\def\doFLOWlocation#1%
  {\setFLOWlocation#1\end\ignorespaces}

\def\doFLOWfocus#1%
  {\gdef\FLOWfocus{#1}\ignorespaces}

\def\doFLOWoverlay#1%
  {\gdef\FLOWoverlay{#1}\ignorespaces}

\def\doFLOWfigure#1%
  {\defineoverlay[\s!dummy][\overlayfigure{#1}]%
   \overlay\s!dummy}

\def\doFLOWtext
  {\dosingleempty\dodoFLOWtext}

\def\dodoFLOWtext[#1]%               %  #2%
  {\gdef\FLOWalign{#1}\gdef\FLOWtext}% {#2}}

\def\doFLOWcomment[#1]#2%
  {\ignorespaces\dogobblesingleempty}

\def\doFLOWlabel[#1]#2% wordt dit gebruikt ?
  {\setgvalue{#1FLOWlabel}{#2}\ignorespaces}

\def\doFLOWhelp#1%
  {\gdef\FLOWhelp{#1}\ignorespaces}

\def\doFLOWconnection
  {\dodoubleempty\dodoFLOWconnection}

\def\dodoFLOWconnection[#1][#2]#3%
  {\ignorespaces}

\def\doFLOWconnect%
  {\connection}

\def\doFLOWlocate%
  {\location}

\def\doFLOWexit[#1]#2%
  {\setgvalue{#1FLOWexit}{#2}\ignorespaces}

\def\startFLOWchart
  {\bgroup
   \let\stopFLOWchart\egroup
   \obeylines % lelijk, buffers nog eens fatsoeneren
   \dodoubleempty\dostartFLOWchart}

\def\dostartFLOWchart[#1][#2]%
  {\preparenextFLOWchart{#1}{#2}%
   \dostartbuffer[\FLOWbufferprefix\nofFLOWcharts][startFLOWchart][stopFLOWchart]}

\def\defineFLOWchart%
  {\dodoubleempty\dodefineFLOWchart}

\long\def\dodefineFLOWchart[#1][#2]#3%
  {\preparenextFLOWchart{#1}{#2}%
   \setbuffer[\FLOWbufferprefix\nofFLOWcharts]#3\endbuffer}

\def\preparenextFLOWchart#1#2%
  {\doglobal\increment\nofFLOWcharts
   \flowchart{#1}%
   \setxvalue{\@FLOW@-#1}{\noexpand\dohandleflowchart[\nofFLOWcharts][#2]}}

\def\setupFLOWcharts{\dodoubleargument\getparameters[\@@FLOW]}
\def\setupFLOWlines {\dodoubleargument\getparameters[\@@FLOL]}
\def\setupFLOWshapes{\dodoubleargument\getparameters[\@@FLOS]}
\def\setupFLOWfocus {\dodoubleargument\getparameters[\@@FLOF]}
\def\setupFLOWsets  {\dodoubleargument\getparameters[\@@FLOX]}

\setupFLOWcharts
  [\c!option=,
   \c!bodyfont=,
   \c!dot=,  % private option
   \c!width=12\bodyfontsize,
   \c!height=7\bodyfontsize,
   \c!maxwidth=,
   \c!maxheight=,
   \c!offset=\v!standard, % == auto offset
   \c!dx=2\bodyfontsize,
   \c!dy=2\bodyfontsize,
   \c!nx=0, % 1,
   \c!ny=0, % 1,
   \c!x=1,
   \c!y=1,
   \c!autofocus=,
   \c!focus=,
   \c!background=,      % \v!color,
   \c!backgroundcolor=\s!white,
   \c!rulethickness=\linewidth,
   \c!frame=\v!off,
   \c!framecolor=]

\setupFLOWlines
  [\c!corner=\v!round,
   \c!arrow=\v!yes,
   \c!dash=\v!no,
   \c!radius=.375\bodyfontsize,      % 2.5\c!rulethickness
   \c!color=FLOWlinecolor,
   \c!rulethickness=.15\bodyfontsize,  % 2pt,
   \c!offset=\v!none]

\setupFLOWshapes
  [\c!default=action,
   \c!framecolor=FLOWframecolor,
   \c!background=\v!color,
   \c!backgroundcolor=FLOWbackgroundcolor,
   \c!backgroundscreen=\@@rsscreen,
   \c!rulethickness=.15\bodyfontsize,  % 2pt,
   \c!offset=.5\bodyfontsize]

\setupFLOWfocus
  [\c!framecolor=FLOWfocuscolor,
   \c!background=\@@FLOSbackground,
   \c!backgroundcolor=\@@FLOSbackgroundcolor,
   \c!backgroundscreen=\@@FLOSbackgroundscreen,
   \c!rulethickness=\@@FLOSrulethickness,
   \c!offset=\@@FLOSoffset]

\definecolor [FLOWfocuscolor]      [s=.2]
\definecolor [FLOWlinecolor]       [s=.5]
\definecolor [FLOWframecolor]      [s=.7]
\definecolor [FLOWbackgroundcolor] [s=.9]

\newcounter\includeFLOWx
\newcounter\includeFLOWy

\def\includeFLOWchart
  {\dodoubleempty\doincludeFLOWchart}

\def\doincludeFLOWchart[#1][#2]%
  {\pushmacro\includeFLOWx
   \pushmacro\includeFLOWy
   \getparameters[FLOWi][x=1,y=1,#2]%
   \increment(\includeFLOWx,0\FLOWix)\decrement\includeFLOWx
   \increment(\includeFLOWy,0\FLOWiy)\decrement\includeFLOWy
   \def\dodoincludeFLOWchart##1%
     {\doifdefined{\@FLOW@-##1}
        {\globalpushmacro\dohandleflowchart % was local
         \gdef\dohandleflowchart[####1][####2]%
           {\globalpopmacro\dohandleflowchart % was local
            \resetFLOWlocation
            \processFLOWbuffer{####1}}%
         \getvalue{\@FLOW@-##1}}}%
   \processcommalist[#1]\dodoincludeFLOWchart
   \popmacro\includeFLOWx
   \popmacro\includeFLOWy}

%\def\setFLOWlocation#1,#2\end%
% {\scratchcounter=0#1\advance\scratchcounter\includeFLOWx
%  \xdef\FLOWlocation{\the\scratchcounter}%
%  \scratchcounter=0#2\advance\scratchcounter\includeFLOWy
%  \xdef\FLOWlocation{\FLOWlocation,\the\scratchcounter}}

\def\resetFLOWlocation
  {\gdef\lastFLOWx{0}%
   \gdef\lastFLOWy{0}}

\def\dosetFLOWlocation[#1#2]#3#4%
  {\processaction
     [#1#2]
     [         +=>\scratchcounter=#4\advance\scratchcounter+1,
               -=>\scratchcounter=#4\advance\scratchcounter-1,
             +#2=>\scratchcounter=#4\advance\scratchcounter+#2,
             -#2=>\scratchcounter=#4\advance\scratchcounter-#2,
      \s!default=>\scratchcounter=#4,
      \s!unknown=>\scratchcounter=0#1#2]%
   \advance\scratchcounter#3%
   \xdef#4{\the\scratchcounter}}

\def\setFLOWlocation#1,#2\end
  {\dosetFLOWlocation[#1\empty]\includeFLOWx\lastFLOWx
   \dosetFLOWlocation[#2\empty]\includeFLOWy\lastFLOWy
   \xdef\FLOWlocation{\lastFLOWx,\lastFLOWy}}

\def\FLOWshapes
  {node, action, procedure, product, decision, archive,
   loop, wait, subprocedure, singledocument, multidocument,
   sub procedure, single document, multi document, up, down,
   left, right}

\def\FLOWlines
  {up, down, left, right}

\def\FLOWsetconnect#1%
  {\donefalse
   \let\cFLOWfrom\empty
   \let\cFLOWto\empty
   \def\zFLOWfrom{0}%
   \def\zFLOWto{0}%
   \handletokens#1\with\doFLOWsetconnect
   \ifx\cFLOWto\empty\let\cFLOWfrom\empty\fi}

\def\doFLOWsetconnect#1%
  {\ifx     #1p%
     \ifdone\def\zFLOWto{+1}\else\def\zFLOWfrom{+1}\fi
   \else\ifx#1+%
     \ifdone\def\zFLOWto{+1}\else\def\zFLOWfrom{+1}\fi
   \else\ifx#1n%
     \ifdone\def\zFLOWto{-1}\else\def\zFLOWfrom{-1}\fi
   \else\ifx#1-%
     \ifdone\def\zFLOWto{-1}\else\def\zFLOWfrom{-1}\fi
   \else\ifdone
     \edef\cFLOWto{\FLOWconnector#1}%
   \else
     \edef\cFLOWfrom{\FLOWconnector#1}%
     \donetrue
   \fi\fi\fi\fi\fi}

\def\FLOWconnector#1%
  {\if#1bbottom\else\if#1ttop\else\if#1lleft\else\if#1rright\fi\fi\fi\fi}

\newif\ifFLOWscaling \FLOWscalingtrue

\def\@@FLOW@@offset{\@@FLOWoffset}

\def\getFLOWchart
  {\dodoubleempty\dogetFLOWchart}

\def\dogetFLOWchart[#1][#2]%
  {\doifundefinedelse{\@FLOW@-#1}
     {\writestatus{FLOW}{unknown chart #1}%
      \framed
        [\c!width=12\bodyfontsize,\c!height=8\bodyfontsize]
        {\tttf [chart #1]}}
     {\dodogetFLOWchart[#1][#2]}}

\def\dodogetFLOWchart[#1][#2]% to be split a bit more
  {\vbox\bgroup
   \insidefloattrue
   \forgetall
   \dontcomplain
   % \offinterlineskip % we now explicitly use \nointerlineskip later on
   \def\dohandleflowchart[##1][##2]%
     {\def\currentFLOWnumber{##1}%
      \getparameters[\@@FLOW][##2]}%
   \getvalue{\@FLOW@-#1}%
   \getparameters[\@@FLOW][#2]% dubbelop ?
   \doifsomething{\@@FLOWautofocus}
     {\checkFLOWautofocus}%
  %\message{AUTOSHAPE 3: (\@@FLOWx,\@@FLOWy)->(\@@FLOWnx,\@@FLOWny)}\wait
   \global\let\FLOWwidth \@@FLOWnx
   \global\let\FLOWheight\@@FLOWny
   \let\startFLOWcell\startFLOWcellA
   \resetFLOWlocation
   \processFLOWbuffer\currentFLOWnumber
   \ifcase\@@FLOWnx\relax \let\@@FLOWnx\FLOWwidth  \fi
   \ifcase\@@FLOWny\relax \let\@@FLOWny\FLOWheight \fi
   \doifnothing{\@@FLOWmaxwidth\@@FLOWmaxheight}{\FLOWscalingfalse}%
   \ifFLOWscaling
     \doifnothing{\@@FLOWmaxwidth }{\let\@@FLOWmaxwidth \maxdimen}%
     \doifnothing{\@@FLOWmaxheight}{\let\@@FLOWmaxheight\maxdimen}%
     \scratchcounter=\bodyfontpoints
     \doloop  % NOG FONTSWITCH OM EX EN EM TE LATEN WERKEN
       {\ifnum\scratchcounter>1 % NU DIMENSIONS IN TERMS OF BODYFONTSIZE
          \bodyfontsize=\the\scratchcounter pt
          \dimen0=\@@FLOWmaxwidth
          \dimen2=\@@FLOWwidth
          \dimen4=\@@FLOWdx
          \advance\dimen2 2\dimen4
          \dimen2=\@@FLOWnx\dimen2
          \advance\dimen2 2\dimen4
          \ifdim\dimen2>\dimen0
            \advance\scratchcounter \minusone
          \else
            \dimen0=\@@FLOWmaxheight
            \dimen2=\@@FLOWheight
            \dimen4=\@@FLOWdy
            \advance\dimen2 2\dimen4
            \dimen2=\@@FLOWny\dimen2
            \advance\dimen2 2\dimen4
            \ifdim\dimen2>\dimen0
              \advance\scratchcounter \minusone
            \else
              \exitloop
            \fi
          \fi
        \else
          \exitloop
        \fi}%
     \expanded{\switchtobodyfont[\the\scratchcounter pt]}%
     \forgetall
     % \offinterlineskip % needed ?
   \else\ifx\@@FLOWbodyfont\empty\else
     \expanded{\switchtobodyfont[\@@FLOWbodyfont]}% \expanded ?
   \fi\fi
   \global\let\FLOWcells\empty
   \dimen0=\@@FLOWwidth
   \edef\FLOWshapewidth{\the\dimen0}%
   \dimen2=\@@FLOWdx
   \advance\dimen0 2\dimen2
   \edef\FLOWgridwidth{\the\dimen0}%
   \dimen0=\@@FLOWheight
   \edef\FLOWshapeheight{\the\dimen0}%
   \dimen2=\@@FLOWdy
   \advance\dimen0 2\dimen2
   \edef\FLOWgridheight{\the\dimen0}%
   \scratchdimen=\@@FLOSrulethickness
   \edef\@@FLOSrulethickness{\the\scratchdimen}%
   \scratchdimen=\@@FLOFrulethickness
   \edef\@@FLOFrulethickness{\the\scratchdimen}%
   \scratchdimen=\@@FLOLrulethickness
   \edef\@@FLOLrulethickness{\the\scratchdimen}%
   \ifdim\@@FLOLradius<2.5\scratchdimen
     \scratchdimen=2.5\scratchdimen
     \edef\@@FLOLradius{\the\scratchdimen}%
     \ifdim\@@FLOLradius>\@@FLOWdx
       \scratchdimen=\@@FLOWdx
       \edef\@@FLOLradius{\the\scratchdimen}%
     \fi
     \ifdim\@@FLOLradius>\@@FLOWdy
       \scratchdimen=\@@FLOWdy
       \edef\@@FLOLradius{\the\scratchdimen}%
     \fi
   \else
     \scratchdimen=\@@FLOLradius
     \edef\@@FLOLradius{\the\scratchdimen}%
   \fi
   \processaction % magic 2.5
     [\@@FLOWoffset]
     [      \v!none=>\scratchdimen=-2.5\scratchdimen,
         \v!overlay=>\scratchdimen=-2.5\scratchdimen,
        \v!standard=>\scratchdimen=\scratchdimen,
         \s!unknown=>\scratchdimen=\@@FLOWoffset,
         \s!default=>\scratchdimen=-2.5\scratchdimen]%
   \edef\@@FLOW@@offset{\the\scratchdimen}%
   \forgetall
   \offinterlineskip
   \resetMPdrawing
   \doglobal\newcounter\FLOWcomment
   \startMPdrawing
     if unknown context_char : input mp-char.mp ; fi ;
     grid_width             := \FLOWgridwidth ;
     grid_height            := \FLOWgridheight ;
     shape_width            := \FLOWshapewidth ;
     shape_height           := \FLOWshapeheight ;
     connection_line_width  := \@@FLOLrulethickness ;
     connection_smooth_size := \@@FLOLradius ;
     connection_arrow_size  := \@@FLOLradius ;
     connection_dash_size   := \@@FLOLradius ;
%  \stopMPdrawing
%  \def\getFLOWlocationX##1,##2\end%
%    {\ifnum0##1>\FLOWwidth \xdef\FLOWwidth {##1}\fi
%     \ifnum0##2>\FLOWheight\xdef\FLOWheight{##2}\fi}%
%  \long\def\startFLOWcellX##1\stopFLOWcell%
%    {\resetFLOWcell
%     \ignorespaces##1\unskip
%     \expandafter\getFLOWlocationX\FLOWlocation\end
%     \ignorespaces}%
%  \let\startFLOWcell\startFLOWcellX
%  \resetFLOWlocation
%  \processFLOWbuffer\currentFLOWnumber
%  \ifnum\@@FLOWnx\@@FLOWny=11 % listig
%    \let\@@FLOWnx\FLOWwidth
%    \let\@@FLOWny\FLOWheight
%  \fi
%  \startMPdrawing
     begin_chart(0,\FLOWwidth,\FLOWheight);
     reverse_y := true ;
     chart_offset := \@@FLOW@@offset ;
   \stopMPdrawing
   \doifelsenothing\@@FLOWbackgroundcolor
     {\startMPdrawing
      chart_background_color := white ;
      \stopMPdrawing}
     {\startMPdrawing
      chart_background_color := \MPcolor{\@@FLOWbackgroundcolor} ;
      \stopMPdrawing}%
   \doif\@@FLOWoption\v!test
     {\startMPdrawing
        show_con_points := true ;
        show_mid_points := true ;
        show_all_points := true ;
      \stopMPdrawing}%
   \processaction % private
     [\@@FLOWdot]
     [     \v!yes=>\startMPdrawing
                    show_con_points := true ;
                    show_mid_points := true ;
                    show_all_points := true ;
                  \stopMPdrawing,
      \s!unknown=>\startMPdrawing
                    show_\@@FLOWdot_points := true ;
                  \stopMPdrawing]%
\doglobal\newcounter\FLOWcomment
   \let\startFLOWcell\startFLOWcellB
   \resetFLOWlocation
   \processFLOWbuffer\currentFLOWnumber
\doglobal\newcounter\FLOWcomment
   \let\startFLOWcell\startFLOWcellC
   \resetFLOWlocation
   \processFLOWbuffer\currentFLOWnumber
   \startMPdrawing
     clip_chart(\@@FLOWx,\@@FLOWy,\@@FLOWnx,\@@FLOWny) ;
     end_chart ;
   \stopMPdrawing
   \MPdrawingdonetrue
   \setbox0\hbox
     {\MPstaticgraphictrue
      \MPshiftdrawingfalse
      \getMPdrawing}%
   \def\MPmessage##1%
     {\writestatus{MP charts}{##1}}%
   \def\MPposition##1##2##3%
     {\setvalue{\@@MPx##1}{##2}\setvalue{\@@MPy##1}{##3}}%
   \def\MPclippath##1##2##3##4%
     {\def\clipMPllx{##1bp}\def\clipMPlly{##2bp}%
      \def\clipMPurx{##3bp}\def\clipMPury{##4bp}}%
   \def\MPareapath##1##2##3##4%
     {\def\areaMPllx{##1bp}\def\areaMPlly{##2bp}%
      \def\areaMPurx{##3bp}\def\areaMPury{##4bp}}%
   \getMPdata
   \doglobal\newcounter\FLOWcomment
   \let\startFLOWcell\startFLOWcellD
   \setbox2\vbox to \ht0
     {\forgetall % \offinterlineskip
      \resetFLOWlocation
      \processFLOWbuffer\currentFLOWnumber\vss}%
   \setbox2\hbox
     {\hskip\@@FLOW@@offset\lower\@@FLOW@@offset\box2}%
   \wd2\wd0\ht2\ht0\dp2\dp0
   \let\startFLOWcell\startFLOWcellE
   \setbox4\vbox to \ht0
     {\forgetall % \offinterlineskip
      \resetFLOWlocation
      \processFLOWbuffer\currentFLOWnumber\vss}%
   \setbox4\hbox
     {\hskip\@@FLOW@@offset\lower\@@FLOW@@offset\box4}%
   \wd4\wd0\ht4\ht0\dp4\dp0
   \doifelse\@@FLOWoption\v!test
     {\setbox6\vbox
        {\forgetall
         \vskip\@@FLOW@@offset
         \hskip\@@FLOW@@offset
         \basegrid
           [\c!x=\@@FLOWx,\c!nx=\@@FLOWnx,\c!dx=\withoutpt\FLOWgridwidth,
            \c!y=\@@FLOWy,\c!ny=\@@FLOWny,\c!dy=\withoutpt\FLOWgridheight,
            \c!xstep=1,\c!ystep=1,
            \c!unit=pt,\c!location=\v!middle]}%
      \wd6\wd0\ht6\ht0\dp6\dp0
      \setbox8\vbox
        {\forgetall
         \offinterlineskip
         \vskip\@@FLOW@@offset
         \dostepwiserecurse\@@FLOWy\@@FLOWny\plusone
           {\vbox to \FLOWgridheight
              {\vfill
               \hskip\@@FLOW@@offset
               \hbox
                 {\dostepwiserecurse\@@FLOWx\@@FLOWnx\plusone
                    {\hbox to \FLOWgridwidth
                       {\hfill
                        \framed
                          [\c!framecolor=red,
                           \c!width=\FLOWshapewidth,
                           \c!height=\FLOWshapeheight]
                          {}%
                        \hfill}}}
               \vfill}}}%
      \wd8\wd0\ht8\ht0\dp8\dp0
      \framed
        [\c!offset=\v!overlay,\c!framecolor=green]
        {\hbox{\box4\hskip-\wd0\box0\hskip-\wd2\box2\hskip-\wd6\box6\hskip-\wd8\box8}}}
     {\framed
        [\c!offset=\v!overlay,
         \c!frame=\@@FLOWframe,
         \c!rulethickness=\@@FLOWrulethickness,
         \c!framecolor=\@@FLOWframecolor,
         \c!background=\@@FLOWbackground,
         \c!backgroundcolor=\@@FLOWbackgroundcolor]
        {\hbox{\box4\hskip-\wd0\box0\hskip-\wd2\box2}}}%
  %\message{[\FLOWcells]}\wait
   \egroup}

% Pass A

\long\def\startFLOWcellA#1\stopFLOWcell%
  {\resetFLOWcell
   \ignorespaces#1\unskip
   \expandafter\getFLOWlocationA\FLOWlocation\end
   \ignorespaces}

\def\getFLOWlocationA#1,#2\end
  {\ifnum0#1>\FLOWwidth \xdef\FLOWwidth {#1}\fi
   \ifnum0#2>\FLOWheight\xdef\FLOWheight{#2}\fi}

% Pass B
%
% beware: the - after \@FLOC@ is needed since name can be
% empty and we don't want to redefine \@FLOC@ itself by
% mistake

\long\def\startFLOWcellB#1\stopFLOWcell
  {\resetFLOWcell\ignorespaces#1\unskip
   \setxvalue{\@FLOC@-\FLOWname}{\FLOWlocation}% kost veel cs's
   \ifx\FLOWshape\empty
     \global\let\FLOWshape\@@FLOSdefault
   \fi
   \doifnot\FLOWshape{none} % {\v!none}
     {\ExpandBothAfter\doifinsetelse{\FLOWshape}{\FLOWshapes}
        {\edef\FLOWshapetag{shape_\FLOWshape}% beter \expanded
         \@EA\setFLOWname\@EA\FLOWshapetag\@EA{\FLOWshapetag}}
        {\doifnumberelse\FLOWshape
           {\let\FLOWshapetag\FLOWshape}
           {\let\FLOWshapetag\empty}}%
      \ifx\FLOWshapetag\empty \else
        \ExpandBothAfter\doifinsetelse{\FLOWshape}{\FLOWlines}
          {\chardef\FLOWstate0 }
          {\ExpandBothAfter\doifcommonelse{\FLOWcell,\FLOWfocus}{\@@FLOWfocus}
             {\chardef\FLOWstate1 }
             {\chardef\FLOWstate2 }}%
        \startMPdrawing
          begin_sub_chart ;
          \ifcase\FLOWstate
            shape_line_color := \MPcolor{\@@FLOLcolor} ;
            shape_fill_color := \MPcolor{\@@FLOLcolor} ;
            shape_line_width := \@@FLOLrulethickness ;
          \or
            shape_line_color := \MPcolor{\@@FLOFframecolor} ;
            shape_fill_color := \MPcolor{\@@FLOFbackgroundcolor} ;
            shape_line_width := \@@FLOFrulethickness ;
          \or
            shape_line_color := \MPcolor{\@@FLOSframecolor} ;
            shape_fill_color := \MPcolor{\@@FLOSbackgroundcolor} ;
            shape_line_width := \@@FLOSrulethickness ;
          \fi
         %\ifx\FLOWoverlay\empty
         %  peepshape := false ;
         %\else
         %  peepshape := true ;
         %\fi
          peepshape := \ifx\FLOWoverlay\empty false \else true \fi ;
          new_shape(\FLOWlocation,\FLOWshapetag) ;
          end_sub_chart ;
        \stopMPdrawing
      \fi