%D \module %D [ file=meta-ini, %D version=2008.03.25, %D title=\METAPOST\ Graphics, %D subtitle=Initialization, %D author=Hans Hagen, %D date=\currentdate, %D copyright=PRAGMA] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \writestatus{loading}{MetaPost Graphics / Initializations} \unprotect %D Instead of sharing code with \MKII, I decided to copy %D the code. Otherwise maintainance becomes a pain and after all, %D the \MKII\ code will not change. \let \useMETAFUNformattrue\relax \let \useMETAFUNformatfalse\relax \let \longMPlinestrue\relax \let \longMPlinesfalse\relax \let \runMPgraphicstrue\relax \let \runMPgraphicsfalse\relax \let \runMPTEXgraphicstrue\relax \let \runMPTEXgraphicsfalse\relax \let \MPstaticgraphictrue\relax \let \MPstaticgraphicfalse\relax \let\forceMPTEXgraphictrue\relax \let\forceMPTEXgraphicfalse\relax \let \obeyMPlines\relax \let \forceMPTEXcheck\gobbleoneargument \let\maxnofMPgraphics\scratchcounter \newtoks \MPextensions % mp, once \newtoks \MPinitializations % tex, each \newtoks \MPuserinclusions % mp, user \newtoks \MPfinalizations % mp, user \newtoks \everyMPgraphic % mp \newtoks \everyMPTEXgraphic % tex \newif\ifMPrun \def\MPruntimefile{mprun} % The next command is, of course, dedicated to Mojca, who % needs it for gnuplot. Anyway, the whole multiple engine % mechanism is to keep her gnuplot from interfering. \def\startMPdefinitions {\dosinglegroupempty\dostartMPdefinitions} \long\def\dostartMPdefinitions#1#2\stopMPdefinitions {\edef\currentMPgraphicinstance{#1}% \ifx\currentMPgraphicinstance\empty \let\currentMPgraphicinstance\defaultMPgraphicinstance \fi \global\MPinstancetoks\expandafter{\the\MPinstancetoks#2}} \long\def\startMPextensions#1\stopMPextensions {\global\MPextensions\expandafter{\the\MPextensions#1}} \long\def\startMPinitializations#1\stopMPinitializations {\global\MPinitializations\expandafter{\the\MPinitializations#1}} \long\def\startMPinclusions {\dosingleempty\dostartMPinclusions} \long\def\dostartMPinclusions[#1]#2\stopMPinclusions {\doifnot{#1}{+}{\global\MPuserinclusions\emptytoks}% \global\MPuserinclusions\expandafter{\the\MPuserinclusions#2}} \def\MPinclusions {\dosingleempty\doMPinclusions} \long\def\doMPinclusions[#1]#2% {\doifnot{#1}{+}{\global\MPuserinclusions\emptytoks}% \global\MPuserinclusions\expandafter{\the\MPuserinclusions#2}} \def\presetMPdefinitions {\edef\overlaywidth {\overlaywidth \space}% \edef\overlayheight {\overlayheight \space}% \edef\overlaylinewidth{\overlaylinewidth\space}% \edef\currentwidth {\the\hsize \space}% \edef\currentheight {\the\vsize \space}} \def\currentMPformat{metafun} \def\@@MPF{@MPF@} \def\MPinstancetoks{\csname\@@MPF::\currentMPgraphicinstance\endcsname} \unexpanded\def\defineMPinstance {\dodoubleargument\dodefineMPinstance} \def\dodefineMPinstance[#1][#2]% {\ifcsname\@@MPF::#1\endcsname\else\expandafter\newtoks\csname\@@MPF::#1\endcsname\fi \MPinstancetoks\emptytoks % in case we redefine \getparameters[\@@MPF#1][\s!format=mpost,\s!extensions=\v!no,\s!initializations=\v!no,#2]} \def\resetMPinstance[#1]% {\writestatus\m!metapost{reset will be implemented when needed}} \def\defaultMPgraphicinstance{metafun} \def\splitMPgraphicname[#1]% {\dosplitMPgraphicname[#1::::]} \def\dosplitMPgraphicname[#1::#2::#3]% instance :: {\edef\currentMPgraphicname{#2}% \ifx\currentMPgraphicname\empty \edef\currentMPgraphicname{#1}% \let\currentMPgraphicinstance\defaultMPgraphicinstance \else \edef\currentMPgraphicinstance{#1}% \fi \edef\currentMPgraphicformat {\ifcsname\@@MPF\currentMPgraphicinstance\s!format\endcsname \csname\@@MPF\currentMPgraphicinstance\s!format\endcsname \else \defaultMPgraphicinstance \fi}} \def\currentMPgraphicinstance{\defaultMPgraphicinstance} \def\currentMPgraphicformat {\currentMPgraphicinstance} \defineMPinstance[metafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes] \defineMPinstance[extrafun][\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes] \defineMPinstance[mprun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes] \defineMPinstance[metapost][\s!format=mpost] \defineMPinstance[nofun] [\s!format=mpost] \def\beginMPgraphicgroup#1% {\begingroup \splitMPgraphicname[#1]} \def\endMPgraphicgroup {\endgroup} \newconditional \METAFUNinitialized \def\MPaskedfigure{false} \def\currentMPinitializations {\ifconditional\includeMPinitializations\the\MPinitializations;\fi\theMPrandomseed;} \def\currentMPpreamble {\ifconditional\includeMPextensions\the\MPextensions;\the\MPuserinclusions;\fi\the\MPinstancetoks;} \def\dostartcurrentMPgraphic {\begingroup \enableincludeMPgraphics \the\everyMPgraphic \presetMPdefinitions \setMPrandomseed % this has to change % we need to preexpand the token lists \doifelsevalue{\@@MPF\currentMPgraphicinstance\s!extensions}\v!yes {\settrue \includeMPextensions\letgvalue{\@@MPF\currentMPgraphicinstance\s!extensions}\v!no} {\setfalse\includeMPextensions}% \doifelsevalue{\@@MPF\currentMPgraphicinstance\s!initializations}\v!yes {\settrue \includeMPinitializations}% {\setfalse\includeMPinitializations}} \def\dostopcurrentMPgraphic {\global\MPinstancetoks\emptytoks \global\settrue\METAFUNinitialized % becomes obsolete \endgroup} \unexpanded\long\def\processMPgraphic#1% todo: extensions and inclusions outside beginfig {\dostartcurrentMPgraphic \forgetall \setbox\MPgraphicbox\hbox\bgroup \normalexpanded{\noexpand\ctxlua{metapost.graphic( "\currentMPgraphicinstance", "\currentMPgraphicformat", \!!bs#1\!!es, \!!bs\currentMPinitializations\!!es, \!!bs\currentMPpreamble\!!es, \MPaskedfigure )}}% \egroup \placeMPgraphic \dostopcurrentMPgraphic} \newif\ifsetMPrandomseed \setMPrandomseedtrue % false by default \def\setMPrandomseed {\let\theMPrandomseed\empty \ifsetMPrandomseed \ifx\getrandomnumber\undefined \else \getrandomnumber\localMPseed\zerocount{4095}% \def\theMPrandomseed{randomseed:=\localMPseed}% \fi\fi} %D To be integrated \def\@@MPG{@MPG@} \def\doifMPgraphicelse#1% {\ifcsname\@@MPG#1\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi} \def\includeMPgraphic#1% {\executeifdefined{\@@MPG#1};} % ; if not found \def\enableincludeMPgraphics {\let\handleuseMPgraphic \thirdofthreearguments \let\handlereusableMPgraphic\thirdofthreearguments} \let\MPdrawingdata\empty \newif\ifMPdrawingdone \MPdrawingdonefalse \def\resetMPdrawing {\globallet\MPdrawingdata\empty \global\MPdrawingdonefalse} \def\pushMPdrawing {\globalpushmacro\MPdrawingdata \globallet\MPdrawingdata\empty} \def\popMPdrawing {\globalpopmacro\MPdrawingdata} \def\getMPdrawing{\dosinglegroupempty\dogetMPdrawing} \def\startMPdrawing {\dosingleempty\dostartMPdrawing} \long\def\dostartMPdrawing[#1]#2\stopMPdrawing {\relax \bgroup \enableincludeMPgraphics \presetMPdefinitions % in case #2 has measures \doifelse{#1}{-}{\convertargument#2\to\asciia}{\long\def\asciia{#2}}% \long\xdef\MPdrawingdata{\MPdrawingdata\asciia}% \egroup} \let\stopMPdrawing\relax \let\MPdrawingdata\empty \newif\ifMPshiftdrawing \MPshiftdrawingfalse \def\resetMPdrawing {\globallet\MPdrawingdata\empty \global\MPdrawingdonefalse} \def\pushMPdrawing {\globalpushmacro\MPdrawingdata \globallet\MPdrawingdata\empty} \def\popMPdrawing {\globalpopmacro\MPdrawingdata} \def\getMPdrawing {\ifMPdrawingdone \expandafter\processMPgraphic\expandafter{\MPdrawingdata}% is this expansion still needed? \fi} \def\startMPdrawing {\dosingleempty\dostartMPdrawing} \long\def\dostartMPdrawing[#1]#2\stopMPdrawing {\relax \bgroup \enableincludeMPgraphics \presetMPdefinitions % in case #2 has measures \doifelse{#1}{-}{\convertargument#2\to\asciia}{\long\def\asciia{#2}}% \long\xdef\MPdrawingdata{\MPdrawingdata\asciia}% \egroup} \let\stopMPdrawing\relax \let\stopMPclip\relax \long\def\startMPclip#1#2\stopMPclip % todo: store at the lua end or just store less {\long\setgvalue{MPC:#1}{#2}} \def\grabMPclippath#1#2#3#4#5% #5 is alternative {\begingroup \edef\width {#3\space}\let\overlaywidth \width \edef\height{#4\space}\let\overlayheight\height \ifcsname MPC:#1\endcsname \dostartcurrentMPgraphic \xdef\MPclippath{\normalexpanded{\noexpand\ctxlua{metapost.theclippath( "\currentMPgraphicinstance", "\currentMPgraphicformat", \!!bs\getvalue{MPC:#1}\!!es, \!!bs\currentMPinitializations\!!es, \!!bs\currentMPpreamble\!!es )}}}% \dostopcurrentMPgraphic \ifx\MPclippath\empty\xdef\MPclippath{#5}\fi \else \xdef\MPclippath{#5}% \fi % #2 : method is obsolete, only pdf now, we can always % gsub the result to ps \endgroup} %D Next we will use these support macros. \startMPextensions if unknown context_tool: input mp-tool; fi; if unknown context_spec: input mp-spec; fi; if unknown context_grph: input mp-grph; fi; \stopMPextensions %D Since we want lables to follow the document settings, we %D also set the font related variables. \startMPinitializations % scale is not yet ok defaultfont:="\truefontname{Regular}"; defaultscale:=\the\bodyfontsize/10pt; \stopMPinitializations % watch out, this is a type1 font because mp can only handle 8 bit fonts \startMPinitializations % scale is not yet ok defaultfont:="rm-lmtt10"; \stopMPinitializations %D A signal that we're in combines \CONTEXT||\METAFUN mode: \startMPextensions string contextversion; contextversion:="\contextversion"; \stopMPextensions %D Some safeguards: %D %D \starttyping %D \appendtoks \cleanupfeatures \to \everyMPgraphic %D \stoptyping %D %D No, we don't want that (else we loose UTF etc). %D Another one: \prependtoks \MPstaticgraphictrue \to \everyoverlay \prependtoks \MPstaticgraphictrue \to \everypagebody %D \macros %D {setupMPvariables} %D %D When we build collections of \METAPOST\ graphics, like %D background and buttons, the need for passing settings %D arises. By (mis|)|using the local prefix that belongs to %D \type {\framed}, we get a rather natural interface to %D backgrounds. To prevent conflicts, we will use the \type %D {-} in \METAPOST\ specific variables, like: %D %D \starttyping %D \setupMPvariables[meta:button][size=20pt] %D \stoptyping \def\@@meta{meta:} \unexpanded\def\setupMPvariables {\dodoubleempty\dosetupMPvariables} \def\dosetupMPvariables[#1][#2]% {\ifsecondargument \getrawparameters[#1:][#2]% brr, todo: [\@@meta#1:] \else \getrawparameters[\@@meta][#1]% \fi} \let\@@framed\s!unknown \def\MPvariable#1% {\csname \ifcsname\@@framed\@@meta#1\endcsname\@@framed\fi\@@meta#1% \endcsname} \let\MPvar\MPvariable \let\setMPvariables\setupMPvariables \def\MPrawvar#1#2{\csname#1:#2\endcsname} \def\presetMPvariable {\dodoubleargument\dopresetMPvariable} \def\dopresetMPvariable[#1][#2=#3]% {\ifcsname#1:#2\endcsname\else\setvalue{#1:#2}{#3}\fi} \def\useMPvariables {\dodoubleargument\douseMPvariables} \def\douseMPvariables[#1][#2]% {\def\@@meta{#1:}% \prepareMPvariables{#2}} %D \macros %D {startuniqueMPgraphic, uniqueMPgraphic} %D %D This macros is probably of most use to myself, since I like %D to use graphics that adapt themselves. The next \METAPOST\ %D kind of graphic is both unique and reused when possible. %D %D \starttyping %D \defineoverlay[example][\uniqueMPgraphic{test}] %D %D \startuniqueMPgraphic {test} %D draw unitsquare xscaled \overlaywidth yscaled \overlayheight ; %D \stopuniqueMPgraphic %D \stoptyping \def\overlaystamp % watch the \MPcolor, since colors can be redefined {\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor} %D A better approach is to let additional variables play a role %D in determining the uniqueness. In the next macro, the %D second, optional, argument is used to guarantee the %D uniqueness, as well as prepare variables for passing them to %D \METAPOST. %D %D \starttyping %D \startuniqueMPgraphic{meta:hash}{gap,angle,...} %D \stoptyping %D %D The calling macro also accepts a second argument. For %D convenient use in overlay definitions, we use \type {{}} %D instead of \type {[]}. %D %D \starttyping %D \uniqueMPgraphic{meta:hash}{gap=10pt,angle=30} %D \stoptyping \newcount\MPobjectcounter \newbox \MPgraphicbox \chardef\MPboxmode\zerocount \def\doobeyMPboxdepth % mode = 1 {\setbox\MPgraphicbox\hbox{\hskip\MPllx\onebasepoint\raise\MPlly\onebasepoint\box\MPgraphicbox}} \def\doignoreMPboxdepth % mode = 2 {\normalexpanded {\noexpand\doobeyMPboxdepth \wd\MPgraphicbox\the\wd\MPgraphicbox \ht\MPgraphicbox\the\ht\MPgraphicbox \dp\MPgraphicbox\the\dp\MPgraphicbox}} \def\obeyMPboxdepth {\chardef\MPboxmode\plusone} \def\ignoreMPboxdepth{\chardef\MPboxmode\plustwo} \def\normalMPboxdepth{\chardef\MPboxmode\zerocount} % compatibility hack: \let\MPshiftdrawingtrue \ignoreMPboxdepth \let\MPshiftdrawingfalse\normalMPboxdepth \unexpanded\def\placeMPgraphic {\ifcase\MPboxmode \or % 1 \doobeyMPboxdepth \or % 2 \doignoreMPboxdepth \fi \box\MPgraphicbox} \def\reuseMPbox#1#2#3#4#5% space delimiting would save some tokens {\xdef\MPllx{#2}% but it's not worth the effort and looks \xdef\MPlly{#3}% ugly as well \xdef\MPurx{#4}% \xdef\MPury{#5}% \hbox{\forcecolorhack\getobject{MP}{#1}}} % else no proper color intent \long\def\handleuniqueMPgraphic#1#2#3% {\begingroup \def\@@meta{#1:}% \extendMPoverlaystamp{#2}% incl prepare \ifcsname\@@MPG\overlaystamp:#1\endcsname\else \enableincludeMPgraphics % redundant \global\advance\MPobjectcounter\plusone \setobject{MP}{\number\MPobjectcounter}\hbox{\processMPgraphic{#3}}% was vbox, graphic must end up as hbox \setxvalue{\@@MPG\overlaystamp:#1}{\noexpand\reuseMPbox{\number\MPobjectcounter}{\MPllx}{\MPlly}{\MPurx}{\MPury}}% \fi \getvalue{\@@MPG\overlaystamp:#1}% \endgroup} \long\unexpanded\def\startuniqueMPgraphic {\dodoublegroupempty\dostartuniqueMPgraphic} \long\def\dostartuniqueMPgraphic#1#2#3\stopuniqueMPgraphic% {\long\setgvalue{\@@MPG#1}{\handleuniqueMPgraphic{#1}{#2}{#3}}} \unexpanded\def\uniqueMPgraphic {\dodoublegroupempty\douniqueMPgraphic} \def\douniqueMPgraphic#1#2% {\beginMPgraphicgroup{#1}% \setupMPvariables[\currentMPgraphicname][#2]% \getvalue{\@@MPG\currentMPgraphicname}\empty \endMPgraphicgroup} \let\stopuniqueMPcode \relax % so that we can use it in \expanded \long\def\handleuseMPgraphic#1#2#3% {\begingroup \def\@@meta{#1:}% \prepareMPvariables{#2}% \enableincludeMPgraphics % redundant \processMPgraphic{#3}% \endgroup} \long\unexpanded\def\startuseMPgraphic {\dodoublegroupempty\dostartuseMPgraphic} \long\def\dostartuseMPgraphic#1#2#3\stopuseMPgraphic {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}} \long\unexpanded\def\startusableMPgraphic % redundant but handy {\dodoublegroupempty\dostartusableMPgraphic} \long\def\dostartusableMPgraphic#1#2#3\stopusableMPgraphic {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}} \let\stopuseMPgraphic \relax % so that we can use it in \expanded \let\stopusableMPgraphic \relax % so that we can use it in \expanded \long\def\handlereusableMPgraphic#1#2#3% {\begingroup \def\@@meta{#1:}% \prepareMPvariables{#2}% \enableincludeMPgraphics % redundant \global\advance\MPobjectcounter\plusone \setobject{MP}{\number\MPobjectcounter}\hbox{\processMPgraphic{#3}}% was vbox, graphic must end up as hbox \setxvalue{\@@MPG#1}{\noexpand\reuseMPbox{\number\MPobjectcounter}{\MPllx}{\MPlly}{\MPurx}{\MPury}}% \getvalue{\@@MPG#1}% \endgroup} \long\unexpanded\def\startreusableMPgraphic {\dodoublegroupempty\dostartreusableMPgraphic} \long\def\dostartreusableMPgraphic#1#2#3\stopreusableMPgraphic {\long\setgvalue{\@@MPG#1}{\handlereusableMPgraphic{#1}{#2}{#3}}} \let\stopreusableMPgraphic \relax % so that we can use it in \expanded \unexpanded\def\useMPgraphic {\dodoublegroupempty\douseMPgraphic} \def\douseMPgraphic#1#2% {\beginMPgraphicgroup{#1}% \doifsomething{#2}{\setupMPvariables[\currentMPgraphicname][#2]}% \getvalue{\@@MPG\currentMPgraphicname}\empty \endMPgraphicgroup} \let\reuseMPgraphic \useMPgraphic % we can save a setup here if needed \let\reusableMPgraphic\reuseMPgraphic % we can save a setup here if needed \let\stopuseMPcode \relax % so that we can use it in \expanded \let\stopusableMPcode \relax % so that we can use it in \expanded \let\stopreusableMPcode \relax % so that we can use it in \expanded \let\stopuniqueMPcode \relax % so that we can use it in \expanded \def\enableincludeMPgraphics {\let\handleuseMPgraphic \thirdofthreearguments \let\handlereusableMPgraphic\thirdofthreearguments} %D \macros %D {startuniqueMPpagegraphic,uniqueMPpagegraphic} %D %D Experimental. \def\MPpageprefix{\doifoddpageelse oe:} \def\overlaypagestamp {\MPpageprefix\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor} \long\unexpanded\def\startuniqueMPpagegraphic {\dodoublegroupempty\dostartuniqueMPpagegraphic} \long\def\dostartuniqueMPpagegraphic#1#2#3\stopuniqueMPpagegraphic {\long\setgvalue{\@@MPG o:#1}{\handleuniqueMPgraphic{o:#1}{#2}{#3}}% \long\setgvalue{\@@MPG e:#1}{\handleuniqueMPgraphic{e:#1}{#2}{#3}}} \unexpanded\def\uniqueMPpagegraphic {\dodoublegroupempty\douniqueMPpagegraphic} \def\douniqueMPpagegraphic#1#2% {\beginMPgraphicgroup{#1}% \let\overlaystamp\overlaypagestamp \setupMPvariables[\MPpageprefix\currentMPgraphicname][#2]% prefix is new here \getvalue{\@@MPG\MPpageprefix\currentMPgraphicname}{}% \endMPgraphicgroup} %D One way of defining a stamp is: %D %D \starttyping %D \def\extendMPoverlaystamp#1% %D {\def\docommand##1% %D {\edef\overlaystamp{\overlaystamp:\MPvariable{##1}}}% %D \processcommalist[#1]\docommand} %D \stoptyping %D Since we need to feed \METAPOST\ with expanded dimensions, %D we introduce a dedicated expansion engine. \def\prepareMPvariable#1% {\ifcsname\@@framed\@@meta#1\endcsname \doprepareMPvariable{\@@framed\@@meta#1}% \else \doprepareMPvariable{\@@meta#1}% \fi} % \startlines % \def\xxx{\lineheight} \doprepareMPvariable{xxx} \xxx % \def\xxx{2pt} \doprepareMPvariable{xxx} \xxx % \def\xxx{2} \doprepareMPvariable{xxx} \xxx % \def\xxx{\scratchcounter} \doprepareMPvariable{xxx} \xxx % \def\xxx{red} \doprepareMPvariable{xxx} \xxx % \def\xxx{0.4} \doprepareMPvariable{xxx} \xxx % \stoplines \def\doprepareMPvariable#1% {\edef\theMPvariable{\getvalue{#1}}% \doifelsenothing\theMPvariable {\setevalue{#1}{\MPcolor{black}}} {\defconvertedcommand\ascii\theMPvariable % otherwise problems \doifcolorelse \ascii % with 2\bodyfontsize {\setevalue{#1}{\MPcolor\theMPvariable}} {% can be aux macro \setbox\scratchbox\hbox{\scratchdimen\theMPvariable sp}% \ifdim\wd\scratchbox=\zeropoint % \scratchcounter\theMPvariable % \setevalue{#1}{\the\scratchcounter}% % also accepts 0.number : \setevalue{#1}{\number\theMPvariable}% \else \scratchdimen\theMPvariable \setevalue{#1}{\the\scratchdimen}% \fi}}} %D We redefine \type {\extendMPoverlaystamp} to preprocess %D variables using \type {\prepareMPvariable}. \def\doextendMPoverlaystamp#1% {\prepareMPvariable{#1}% \edef\overlaystamp{\overlaystamp:\MPvariable{#1}}} \def\extendMPoverlaystamp#1% {\processcommalist[#1]\doextendMPoverlaystamp} \def\prepareMPvariables#1% {\processcommalist[#1]\prepareMPvariable} %D \macros %D {MPdatafile} %D %D We redefine a macro from \type {supp-mps.tex}: \def\MPdataMPDfile{\jobname-mpgraph.mpd} \def\MPdataMPOfile{\jobname-mpgraph.mpo} \def\MPdataMPYfile{\jobname-mpgraph.mpy} \startMPextensions boolean collapse_data; collapse_data:=true; def data_mpd_file = "\MPdataMPDfile" enddef ; def data_mpo_file = "\MPdataMPOfile" enddef ; def data_mpy_file = "\MPdataMPYfile" enddef ; \stopMPextensions \chardef\currentMPgraphic\plusone \def\getMPdata {\let\MPdata\secondoftwoarguments \startreadingfile % \startnointerference % no, else we need to do all data global \readlocfile\MPdataMPDfile\donothing\donothing % \stopnointerference \stopreadingfile} %D \macros %D {MPrunfile} %D %D This one is more abstract and does not assume knowledge %D of buffer prefixes. \def\MPrunfile#1% {\bufferprefix mprun.#1} %D For the moment, the next one is a private macro: \def\processMPbuffer {\dosingleempty\doprocessMPbuffer} \def\doprocessMPbuffer[#1]% {\doifelsenothing{#1} {\dodoprocessMPbuffer{\jobname}} {\dodoprocessMPbuffer{#1}}} % we need to go via a toks because we have no multiline print in % luatex (i.e. tex.sprint does not interpret lines) and therefore % omits all after a comment token \newtoks\mpbuffertoks \def\doprocessMPbuffer[#1]% {\doifelsenothing{#1} {\doprocessMPbuffer[\jobname]} {\beginMPgraphicgroup{#1}% % we need this trick because tex.sprint does not interprets newlines and the scanner % stops at a newline; also, we do need to flush the buffer under a normal catcode % regime in order to expand embedded tex macros; #1 can be a list \processMPgraphic{\ctxlua{buffers.feedback("\currentMPgraphicname")}}% \endMPgraphicgroup}} \def\runMPbuffer {\dosingleempty\dorunMPbuffer} \def\dorunMPbuffer[#1]% processing only {\startnointerference\doprocessMPbuffer[#1]\stopnointerference} %D \macros %D {startMPenvironment, resetMPenvironment} %D %D In order to synchronize the main \TEX\ run and the runs %D local to \METAPOST, environments can be passed. \ifx\everyMPTEXgraphic\undefined \newtoks\everyMPTEXgraphic \fi %D A more general way of passing environments is: \def\startMPenvironment % second arg gobbles spaces, so that reset gives \emptytoks {\dodoubleempty\dostartMPenvironment} \long\def\dostartMPenvironment[#1][#2]#3\stopMPenvironment {\doif{#1}\s!reset\resetMPenvironment % reset mp toks \doif{#1}\v!global{#3}% % use in main doc too \doif{#1}+{#3}% % use in main doc too \ctxlua{metapost.tex.set(\!!bs\detokenize{#3}\!!es)}} \def\resetMPenvironment {\ctxlua{metapost.tex.reset()}} \resetMPenvironment \def\useMPenvironmentbuffer[#1]% {\ctxlua{metapost.tex.set(buffers.content("#1"))}} %D This command takes \type {[reset]} as optional %D argument. %D %D \starttyping %D \startMPenvironment %D \setupbodyfont[pos,14.4pt] %D \stopMPenvironment %D %D \startMPcode %D draw btex \sl Hans Hagen etex scaled 5 ; %D \stopMPcode %D \stoptyping %D %D The most simple case: \def\startMPcode{\dosinglegroupempty\dostartMPcode} \def\dostartMPcode {\iffirstargument \expandafter\dodostartMPcode \else \expandafter\nodostartMPcode \fi} \def\dodostartMPcode#1#2\stopMPcode {\beginMPgraphicgroup{#1::\s!dummy}% name does not matter \processMPgraphic{#2}% \endMPgraphicgroup} \def\nodostartMPcode#1#2\stopMPcode {\processMPgraphic{#2}} \let\stopMPcode\relax % a bit nasty (also needed for compatibility: % \startMPrun input mp-www.mp ; \stopMPrun % \externalfigure[mprun.3][width=10cm,height=8cm] % \startMPrun{mprun} input mp-www.mp ; \stopMPrun % instance % \externalfigure[mprun.4][width=10cm,height=8cm] \let\MPruninstance\defaultMPgraphicinstance \def\useMPrun#1#2% name n {\begingroup \def\MPaskedfigure{#2}% \doifelsenothing{#1} {\useMPgraphic{mprun}}% {\useMPgraphic{#1}}% \endgroup} \def\startMPrun {\dosinglegroupempty\dostartMPrun} \long\def\dostartMPrun#1#2\stopMPrun {\iffirstargument \startuseMPgraphic{#1}#2\stopuseMPgraphic \else \startuseMPgraphic{mprun}#2\stopuseMPgraphic \fi} % for old time sake \def\dostartMPgraphic {\iffirstargument \expandafter\dodostartMPgraphic \else \expandafter\nodostartMPgraphic \fi} \def\dodostartMPgraphic#1#2\stopMPgraphic {\beginMPgraphicgroup{#1::\s!dummy}% name does not matter \processMPgraphic{#2}% \endMPgraphicgroup} \def\nodostartMPgraphic#1#2\stopMPcode {\processMPgraphic{#2}} \let\stopMPcode\relax %D The \type {\resetMPenvironment} is a quick way to erase %D the token list. %D %D You should be aware of independencies. For instance, if you use a font %D in a graphic that is not used in the main document, you need to load the %D typescript at the outer level (either directly or by using the global %D option). %D %D \starttyping %D \usetypescript[palatino][texnansi] %D %D \startMPenvironment %D \usetypescript[palatino][texnansi] %D \enableregime[utf] %D \setupbodyfont[palatino] %D \stopMPenvironment %D %D \startMPpage %D draw btex aap‒noot coördinatie – één etex ; %D \stopMPpage %D \stoptyping %D Loading specific \METAPOST\ related definitions is %D accomplished by: \def\douseMPlibrary#1% {\ifcsname\c!file\f!metapostprefix#1\endcsname\else \letvalueempty{\c!file\f!metapostprefix#1}% \makeshortfilename[\truefilename{\f!metapostprefix#1}]% \startreadingfile \readsysfile\shortfilename{\showmessage\m!metapost1{#1}}\donothing \stopreadingfile \fi} \def\useMPlibrary[#1]% {\processcommalist[#1]\douseMPlibrary} %D \macros %D {setMPtext, MPtext, MPstring, MPbetex} %D %D To be documented: %D %D \starttyping %D \setMPtext{identifier}{text} %D %D \MPtext {identifier} %D \MPstring{identifier} %D \MPbetex {identifier} %D \stoptyping \def\@@MPT{@MPT@} \def\forceMPTEXgraphic {\long\def\checkMPTEXgraphic##1{\global\MPTEXgraphictrue}} \def\setMPtext#1#2% todo : #1 must be made : safe {%\forceMPTEXgraphic \defconvertedargument\ascii{#2}% \dodoglobal\letvalue{\@@MPT#1}\ascii} \def\MPtext #1{\executeifdefined{\@@MPT#1}\empty} \def\MPstring #1{"\executeifdefined{\@@MPT#1}\empty"} \def\MPbetex #1{btex \executeifdefined{\@@MPT#1}\empty\space etex} %D Unfortunately \METAPOST\ does not have \CMYK\ support %D built in, but by means of specials we can supply the %D information needed to handle them naturaly. % \newif\ifMPcmykcolors \MPcmykcolorstrue % \newif\ifMPspotcolors \MPspotcolorstrue \startMPinitializations cmykcolors:=\ifMPcmykcolors true\else false\fi; spotcolors:=\ifMPspotcolors true\else false\fi; \stopMPinitializations %D In order to communicate conveniently with the \TEX\ %D engine, we introduce some typesetting variables. \startMPextensions color OverlayColor,OverlayLineColor; \stopMPextensions \startMPinitializations OverlayWidth:=\overlaywidth; OverlayHeight:=\overlayheight; OverlayDepth:=\overlayheight; OverlayColor:=\MPcolor{\overlaycolor}; OverlayLineWidth:=\overlaylinewidth; OverlayLineColor:=\MPcolor{\overlaylinecolor}; % BaseLineSkip:=\the\baselineskip; LineHeight:=\the\baselineskip; BodyFontSize:=\the\bodyfontsize; % TopSkip:=\the\topskip; StrutHeight:=\strutheight; StrutDepth:=\strutdepth; % CurrentWidth:=\the\hsize; CurrentHeight:=\the\vsize; % EmWidth:=\the\emwidth; ExHeight:=\the\exheight; % PageNumber:=\the\pageno; RealPageNumber:=\the\realpageno; LastPageNumber:= \lastpage; \stopMPinitializations \appendtoks \disablediscretionaries \disablecompoundcharacters \to \everyMPgraphic \appendtoks % before color %\normalexpanded{\noexpand\definecolor[currentcolor][\currentcolorname]}% \doregistercolor{currentcolor}\currentcolorname \to \everyMPgraphic % \color[green]{abc \startMPcode % fill fullcircle scaled 3cm withoutcolor; % fill fullcircle scaled 2cm withcolor \MPcolor{currentcolor} ; % fill fullcircle scaled 1cm withcolor \MPcolor{red} ; % \stopMPcode def} % \appendtoks % \doactivatecolor\s!black\forcecolorhack % we can also move this to the backend % \to \everyMPgraphic \appendtoks \baselineskip1\baselineskip \lineheight 1\lineheight \topskip 1\topskip \to \everyMPgraphic \appendtoks \let \# \letterhash \let \_ \letterunderscore \let \& \letterampersand \let \{ \letteropenbrace \let \} \letterclosebrace \to \everyMPgraphic \startMPinitializations prologues:=0; mpprocset:=1; \stopMPinitializations %D \macros %D {PDFMPformoffset} %D %D In \PDF, forms are clipped and therefore we have to take %D precautions to get this right. Since this is related to %D objects, we use the same offset as used there. \def\PDFMPformoffset{\objectoffset} % %D \macros % %D {insertMPfile} % %D % %D Bypassing the special driver and figure mechanism is not % %D that nice but saves upto 5\% time in embedding \METAPOST\ % %D graphics by using the low level \PDF\ converter directly, % %D given of course that we use \PDFTEX. As a result we need to % %D fool around with the object trigger. \newtoks\everyinsertMPfile % removed in backend: % % \def\doinsertMPfile#1% % {\doiffileelse{./#1}{\includeMPasPDF{./#1}}{\message{[MP #1]}}} % % \let\insertMPfileARG\insertMPfile % % \def\insertMPfile#1#2% in context #2 is empty % {\doifelsenothing{#2}{\doinsertMPfile{#1}}{\insertMPfileARG{#1}{#2}}} % % \def\includeMPasEPS#1% untested !! % {\bgroup % \message{[MP as EPS #1]}% % \the\everyinsertMPfile % \dogetEPSboundingbox{#1}\!!widtha\!!heighta\!!widthb\!!heightb % \setbox\scratchbox\vbox to \!!heightb % {\vfill % \let \@@DriverImageType \c!mps % \def \@@DriverImageFile {#1}% % \edef\@@DriverImageWidth {\the\!!widthb }% % \edef\@@DriverImageHeight{\the\!!heightb}% % \doinsertfile}% % \wd\scratchbox\!!widthb % \dp\scratchbox\zeropoint % \box\scratchbox % \egroup} % % \def\includeMPasPDF#1% % {\bgroup % \the\everyinsertMPfile % \ifinobject \else \chardef\makeMPintoPDFobject\plustwo \fi % when needed % \convertMPtoPDF{#1}{1}{1}% no \plusone ! % \egroup} % % %D So, using a low level approach (thereby avoiding the slower % %D figure analysis macros) pays off. This kind of % %D optimizations are a bit tricky since we must make sure that % %D special resources end up in the (PDF) files. Because the % %D \METAPOST\ to \PDF\ can handle objects itself, it is not % %D that complicated. % % %D We hook a couple of initializations into the graphic % %D macros. % % \appendtoks % \let\figuretypes\c!mps % \runutilityfilefalse % \consultutilityfilefalse % \to \everyinsertMPfile % % %D One more: (still needed?) \startMPextensions def initialize_form_numbers = do_initialize_numbers; enddef; \stopMPextensions \startMPinitializations HSize:=\the\hsize ; VSize:=\the\vsize ; \stopMPinitializations \startMPextensions vardef ForegroundBox = unitsquare xysized(HSize,VSize) enddef ; vardef PageFraction = if \lastpage>1: (\realfolio-1)/(\lastpage-1) else: 1 fi enddef ; \stopMPextensions %D And some more. These are not really needed since we %D don't use the normal figure inclusion macros any longer. \appendtoks \externalfigurepostprocessors\emptytoks % safeguard \to \everyinsertMPfile %D We also take care of disabling fancy figure features, that %D can terribly interfere when dealing with symbols, %D background graphics and running (postponed) graphics. %D You won't believe me if I tell you what funny side effects %D can occur. One took me over a day to uncover when %D processing the screen version of the \METAFUN\ manual. %D For my eyes only: \def\doifelseMPgraphic#1{\doifdefinedelse{\@@MPG#1}} %D \macros %D {startMPcolor} \long\unexpanded\def\startMPcolor#1\stopMPcolor {\writestatus \m!metapost % eventually this placeholder will go away {\string\startMPcolor...\stopMPcolor\space is obsolete,\space use \string\defineintermediatecolor\space instead}} \let\stopMPcolor\relax %D New: \definelayerpreset % no dx,dy - else nasty non-mp placement [mp] [\c!y=-\MPury bp, \c!x=\MPllx bp, \c!method=\v!fit] \definelayer [mp] [\c!preset=mp] %D Usage: %D %D \starttyping %D \defineproperty[one][layer][state=start] %D \defineproperty[two][layer][state=stop] %D %D \startuseMPgraphic{step-1} %D fill fullcircle scaled 10cm withcolor red ; %D \stopuseMPgraphic %D %D \startuseMPgraphic{step-2} %D fill fullcircle scaled 5cm withcolor green ; %D \stopuseMPgraphic %D %D \setlayer[mp]{\property[one]{\useMPgraphic{step-1}}} %D \setlayer[mp]{\property[two]{\useMPgraphic{step-2}}} %D %D \ruledhbox{\flushlayer[mp]} %D \stoptyping %D %D Reusing graphics is also possible (now): %D %D \starttyping %D \startreusableMPgraphic{axis} %D tickstep := 1cm ; ticklength := 2mm ; %D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ; %D tickstep := tickstep/2 ; ticklength := ticklength/2 ; %D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ; %D \stopreusableMPgraphic %D %D \startuseMPgraphic{demo} %D drawpoint "1cm,1.5cm" ; %D \stopuseMPgraphic %D %D \definelayer[mp][preset=mp] %D \setlayer[mp]{\reuseMPgraphic{axis}} %D \setlayer[mp]{\useMPgraphic{demo}} %D \ruledhbox{\flushlayer[mp]} %D \stoptyping %D \macros %D {startstaticMPfigure,useMPstaticfigure} %D %D Static figures are processed only when there has been %D something changed. Here is Aditya Mahajan's testcase: %D %D \startbuffer %D \startstaticMPfigure{circle} %D fill fullcircle scaled 1cm withcolor blue; %D \stopstaticMPfigure %D %D \startstaticMPfigure{axis} %D drawarrow (0,0)--(2cm,0) ; %D drawarrow (0,0)--(0,2cm) ; %D label.llft(textext("(0,0)") ,origin) ; %D \stopstaticMPfigure %D \stopbuffer %D %D \typebuffer \getbuffer \def\usestaticMPfigure {\dodoubleempty\dousestaticMPfigure} \def\dousestaticMPfigure[#1][#2]% {\ifsecondargument \scale[#2]{\reuseMPgraphic{\@@MPG#1@S@}}% \else \reuseMPgraphic{\@@MPG#1@S@}% \fi} \unexpanded\def\startstaticMPfigure#1#2\stopstaticMPfigure {\startreusableMPgraphic{\@@MPG#1@S@}#2\stopreusableMPgraphic} \long\unexpanded\def\startstaticMPgraphic {\dodoublegroupempty\dostartstaticMPgraphic} \long\def\dostartstaticMPgraphic#1#2#3\stopstaticMPgraphic {\long\setgvalue{\@@MPG#1@S@}{\handlereusableMPgraphic{#1}{#2}{#3}}} %D New: \newconditional\manyMPspecials % when set to true, > 1000 specials can be used \settrue \manyMPspecials % per 1/4/2006 \prependtoks _special_div_ := 1000\ifconditional\manyMPspecials0\fi ; \to \MPextensions %D Needed too. \let\initializeMPgraphics\relax %D Goody for preventing overflows: \def\MPdivten[#1]{\withoutpt\the\dimexpr#1pt/10\relax} %D There is no way to distinguish the black color that you get when %D you issue a \type {draw} without color specification from a color %D that has an explicit black specification unless you set the %D variable \type {defaultcolormodel} to 1. Hoewever, in that case %D you cannot distinguish that draw from one with a \type %D {withoutcolor} specification. This means that we have to provide %D multiple variants of inheritance. %D %D In any case we need to tell the converter what the inherited color %D is to start with. Case~3 is kind of unpredictable as it closely %D relates to the order in which paths are flushed. If you want to %Dinherit automatically from the surrounding, you can best stick to %D variant 1. Variant 0 (an isolated graphic) is the default. %D %D \startbuffer %D \startuseMPgraphic{test} %D drawoptions(withpen pencircle scaled 1pt) ; %D def shift_cp = currentpicture := currentpicture shifted (-15pt,0) ; enddef ; %D draw fullcircle scaled 10pt withoutcolor ; shift_cp ; %D fill fullcircle scaled 10pt ; shift_cp ; %D draw fullcircle scaled 10pt withoutcolor ; shift_cp ; %D fill fullcircle scaled 10pt withcolor red ; shift_cp ; %D draw fullcircle scaled 10pt withoutcolor ; shift_cp ; %D fill fullcircle scaled 10pt ; shift_cp ; %D \stopuseMPgraphic %D %D \starttabulate %D \NC 0\quad \NC \chardef\MPcolormethod0 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR %D \NC 1\quad \NC \chardef\MPcolormethod1 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR %D \NC 2\quad \NC \chardef\MPcolormethod2 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR %D \NC 3\quad \NC \chardef\MPcolormethod3 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR %D \stoptabulate %D \stopbuffer %D %D \typebuffer \getbuffer \chardef\MPcolormethod\zerocount % can be faster, just \appendtoks \ctxlua{metapost.set_outer_color(\number\MPcolormethod,\number\currentcolormodel,\number\dogetattribute{color},\number\dogetattribute{transparency})}% \to \everyMPgraphic \startMPinitializations defaultcolormodel := \ifcase\MPcolormethod1\or1\or3\else3\fi; \stopMPinitializations %D \macros %D {setupMPgraphics} %D %D Here is a generic setup command: \newtoks \everysetupMPgraphics \unexpanded\def\setupMPgraphics[#1]% {\getparameters[\??mp][#1]% \the\everysetupMPgraphics} %D Here we hook in the outer color. When \type {color} is set to \type %D {global} we get the outer color automatically. If you change this %D setting, you should do it grouped in order not to make other graphics %D behave in unexpected ways. \appendtoks \doifelse\@@mpcolor\v!global{\chardef\MPcolormethod\plusone}{\chardef\MPcolormethod\zerocount}% \to \everysetupMPgraphics \setupMPgraphics [\c!color=\v!local] %D Done. \protect \endinput