2

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.)

lockstep
  • 250,273
user19041
  • 103
  • The mdframed packaged – dustin Jul 13 '13 at 08:10
  • @dustin: It's context – Marco Daniel Jul 13 '13 at 08:18
  • 2
    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
  • Use the background mechansim. @Macro, in the past i have used textbackgrounds with overlays, so I don't know if something has changed recently. – Aditya Jul 14 '13 at 14:49
  • @Aditya It used to work in the past, yes. But I can't get it to work with a current MkIV. Maybe it's a bug or the interface has changed. – Marco Jul 14 '13 at 15:50
  • @Marco: If background key doesn't work with textbackground, then it is surely a bug. – Aditya Jul 14 '13 at 17:57
  • 1
    @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

2 Answers2

2

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

enter image description here

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

enter image description here

Aditya
  • 62,301
  • 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
1

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
\setbox\totalbox=\vbox\bgroup\advance\hsize by -8pt}
\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.

user19041
  • 103