# TikZ frame paragraph span across pages in ConTeXt

I tried to reproduce the following example in ConTeXt:
http://www.texample.net/tikz/examples/framed-tikz/

How can I substitute the LaTeX framed package, that is make the frame span across multiple pages?
(Resigning from TikZ is not an option as I have already designed my own frame.)

• The mdframed packaged – dustin Jul 13 '13 at 8:10
• @dustin: It's context – Marco Daniel Jul 13 '13 at 8:18
• Take a look at textbackgrounds in the ConTeXt garden. – Gonzalo Medina Jul 13 '13 at 17:42
• @GonzaloMedina The textbackground's backgrounds key does not accept overlays. MetaPost overlays can be hooked in using the mp and method keys. I don't see any simple way to use TikZ graphics with the textbackground mechanism. – Marco Jul 13 '13 at 19:07
• @Aditya Actually I cannot confirm that backgrounds worked with overlays in textbackgrounds, I just checked some old code. It might be by design since textbackgrounds allow for page breaks. But I'll move the discussion to the mailing list. – Marco Jul 14 '13 at 18:47

You can use background mechanism for this. You can get the width and height of the box using \overlaywidth and \overlayheight. Here is an example:

\usemodule[tikz]

\startsetups tikz:frame
\starttikzpicture
\filldraw[fill=lightgray] (0,0) -- (0, \overlayheight) -- (\overlaywidth, \overlayheight) -- (\overlaywidth,0) -- cycle;
\stoptikzpicture
\stopsetups

\defineoverlay[tikzframe][\setups{tikz:frame}]

\definebackground[tikzframe][background=tikzframe]

\starttext

\starttikzframe
\dorecurse{10}{\input knuth \endgraf}
\stoptikzframe

\stoptext


which gives

EDIT: In a comment, @user19041 asked if it is possible to change the background depending on the state of the splitting. ConTeXt does have an internal macro \backgroundsplitmode that keeps track of how the \vbox is being split. Unfortunately, it does not differentiate between the case when the vbox does not need to be split, and the case when the vbox is split but we are at the last page. It is easy to differentiate between these two (provided you are not nesting such frames; in that case, we'll need to define a new counter for each nested level). The example below illustrates how this is done. I have just changed the background color to illustrate the concept.

\usemodule[tikz]

\setnewconstant\tikzbackgroundstate\zerocount

\definecolor[backgroundcolor][lightgray]

\startsetups tikz:frame
\starttikzpicture
\ifcase \backgroundsplitmode
% Case 0: no split or last page
\ifcase\tikzbackgroundstate
% The frame does not split across pages
\definecolor[backgroundcolor][lightgray]
\else
% Last page of a split frame
\definecolor[backgroundcolor][red]
\fi \or
% Case 1: split to max height, always middle page
\definecolor[backgroundcolor][yellow]
\global\tikzbackgroundstate=\plusone
\else
% Case 2: split to partial height. Always first page
\definecolor[backgroundcolor][green]
\global\tikzbackgroundstate=\plustwo
\fi
\filldraw[fill=backgroundcolor] (0,0) -- (0, \overlayheight) -- (\overlaywidth, \overlayheight) -- (\overlaywidth,0) -- cycle;
\stoptikzpicture
\stopsetups

\defineoverlay[tikzframe][\setups{tikz:frame}]

\definebackground[tikzinternalframe][background=tikzframe]

\define\starttikzframe
{\dosingleargument\dostarttikzframe}

\def\dostarttikzframe[#1]%
{\tikzbackgroundstate=\zerocount
\starttikzinternalframe[#1]}

\define\stoptikzframe{\stoptikzinternalframe}

\starttext

\starttikzframe
\input ward
\stoptikzframe

\blank[big]

\starttikzframe
\dorecurse{11}{\input knuth \endgraf}
\stoptikzframe

\stoptext


which gives

• The other solution (posted by myself) makes it quite easy to implement different frame shapes in different contexts (to be specific: lack of top and/or bottom frame if the content starts/ends on another page). Is there any way to do it with the background mechanism? Edit: I figured out that I can manually add horizontal lines at the beginning and the end of the content (and get rid of them anywhere else), but is there a more elegant solution? – user19041 Jul 15 '13 at 19:58
• Changing the frame depending on context is easy to do with metapost backgrounds (e.g., see this thread in the mailing list). I'll have to check if there are other hooks that can be used with tikz. – Aditya Jul 15 '13 at 22:12
• @user19041: See my edit – Aditya Jul 15 '13 at 22:52

My current draft solution is based on the answer to Breakable vboxes:

\usemodule[tikz]
\pgfdeclarelayer {background}
\pgfsetlayers {background,main}

\newbox\totalbox
\newbox\partialbox
\newdimen\partialboxdim

\def\startframedbox{\par\bigskip
\def\endframedbox{\egroup\splitframedbox}

\def\splitframedbox{\ifvoid\totalbox\finishframedbox
\else\continuesplitting\fi}
\def\finishframedbox{\bigskip}

\newdimen\Distance

\def\continuesplitting{\null%
\Distance=\dimexpr\pagegoal-\pagetotal-\pageshrink-6pt\relax
\ifdim\ht\totalbox<\Distance
\setbox\partialbox=\box\totalbox
\framethisbox
\else
\setbox\partialbox=\vsplit\totalbox to\dimexpr\Distance-5pt\relax
\framethisbox
\vfill\page
\fi
\splitframedbox}

\def\framethisbox{%
\starttikzpicture
\node (A) {\hbox{\vbox{\unvbox\partialbox}}};
\startpgfonlayer{background}
\filldraw[draw=black,fill=lightgray] (A.north east) -- (A.north west) -- (A.south west) -- (A.south east) -- cycle;
\stoppgfonlayer{background}
\stoptikzpicture%
}

\starttext

\input knuth

\startframedbox
\dorecurse{15}{\input knuth\par}
\endframedbox

\input knuth

\stoptext


This code draws a thin frame around the text and adds a gray background, but any valid TikZ code should work.

• Also see pack-bck.mkvi for a different vbox splitting algorithm. – Aditya Jul 15 '13 at 23:01