You can use zref
with the abspos
and user
modules (e.g. load the zref-abspos
and zref-user
packages) and add a \zlabel{labelname}
to the \tikzmark
at the beginning of the paragraph as well one at the end of the paragraph. If you using an environment simply place one at begin
and end
. Then you can check at the end of the environment if the absolute page numbers of both are identical or not. For this you can use:
\ifnum\zref@extract{<begin-label>}{abspage}=\zref@extract{<end-label>}{abspage}\relax
<same page>
\else
<different page>
\fi
(Note: Maybe \zref@extractdefault
is better because you can provide a default value used for the first runs when the label is not set yet.)
See also my answer to How to draw text-anchored tikz line below text instead of above? where I do something very similar!
Here a solution I now come up with. It draws the first border half in the begin-macro if the end-macro is not at the same page. Also the case where the environment spans more than two pages, e.g. starts at page 1 and ends at page 3, is covered by extra code.
\documentclass[twoside]{book}
\usepackage{zref-abspage}
\usepackage{zref-user}
\usepackage{tikz}
\usepackage{atbegshi}
\usetikzlibrary{calc}
\makeatletter
\newcommand{\currentsidemargin}{%
\ifodd\zref@extract{textarea-\thetextarea}{abspage}%
\oddsidemargin%
\else%
\evensidemargin%
\fi%
}
\newcounter{textarea}
\newcommand{\settextarea}{%
\stepcounter{textarea}%
\zlabel{textarea-\thetextarea}%
\begin{tikzpicture}[overlay,remember picture]
% Helper nodes
\path (current page.north west) ++(\hoffset, -\voffset)
node[anchor=north west, shape=rectangle, inner sep=0, minimum width=\paperwidth, minimum height=\paperheight]
(pagearea) {};
\path (pagearea.north west) ++(1in+\currentsidemargin,-1in-\topmargin-\headheight-\headsep)
node[anchor=north west, shape=rectangle, inner sep=0, minimum width=\textwidth, minimum height=\textheight]
(textarea) {};
\end{tikzpicture}%
}
\tikzset{tikzborder/.style={line width=1mm,red,double=blue}}
\newcounter{tikzborder}
\newcounter{tikzborderpages}
\newenvironment{tikzborder}[1][]{%
\medskip\par
% Allow user to overwrite the used style locally
\ifx&\else
\tikzset{tikzborder/.style={#1}}%
\fi
\settextarea
\stepcounter{tikzborder}%
\tikz[overlay,remember picture] \coordinate (tikzborder-\thetikzborder);% Modified \tikzmark macro
\zlabel{tikzborder-begin-\thetikzborder}%
% Test if end-label is at the same page and draw first half of border if not
\ifnum\zref@extract{tikzborder-begin-\thetikzborder}{abspage}=\zref@extract{tikzborder-end-\thetikzborder}{abspage} \else
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
let \p0 = (textarea.north west), \p1 = (tikzborder-\thetikzborder), \p2 = (textarea.south east) in
(\x0-\fboxsep-.5\pgflinewidth,\y2-\fboxsep-.5\pgflinewidth)
|-
(\x2+\fboxsep+.5\pgflinewidth,\ht\strutbox+\fboxsep+.5\pgflinewidth)
--
(\x2+\fboxsep+.5\pgflinewidth,\y2-\fboxsep-.5\pgflinewidth)
;
\end{tikzpicture}%
% If it spreads over more than two pages:
\setcounter{tikzborderpages}{\numexpr-\zref@extract{tikzborder-begin-\thetikzborder}{abspage}+\zref@extract{tikzborder-end-\thetikzborder}{abspage}}
\ifnum\value{tikzborderpages}>1
\AtBeginShipoutNext{\tikzborderpage}%
\fi
\fi
}{%
\zlabel{tikzborder-end-\thetikzborder}%
% Test if begin-label is at the same page and draw while border if so
\ifnum\zref@extract{tikzborder-begin-\thetikzborder}{abspage}=\zref@extract{tikzborder-end-\thetikzborder}{abspage}
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
let \p0 = (textarea.north west), \p1 = (tikzborder-\thetikzborder), \p2 = (textarea.south east) in
(\x0-\fboxsep-.5\pgflinewidth,\y1+\ht\strutbox+\fboxsep+.5\pgflinewidth)
|-
(\x2+\fboxsep+.5\pgflinewidth,-\dp\strutbox-\fboxsep-.5\pgflinewidth)
|-
(\x0-\fboxsep-.5\pgflinewidth,\y1+\ht\strutbox+\fboxsep+.5\pgflinewidth)
-- cycle
;
\end{tikzpicture}%
% Otherwise draw second half of border
\else
\settextarea
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
let \p0 = (textarea.north west), \p1 = (tikzborder-\thetikzborder), \p2 = (textarea.south east) in
(\x0-\fboxsep-.5\pgflinewidth,\y0+\fboxsep+.5\pgflinewidth)
|-
(\x2+\fboxsep+.5\pgflinewidth,-\dp\strutbox-\fboxsep-.5\pgflinewidth)
--
(\x2+\fboxsep+.5\pgflinewidth,\y0+\fboxsep+.5\pgflinewidth)
;
\end{tikzpicture}%
\fi
\par\medskip
}
\newcommand{\tikzborderpage}{%
\settextarea
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
([shift={(-\fboxsep-.5\pgflinewidth, \fboxsep+.5\pgflinewidth)}]textarea.north west)
--
([shift={(-\fboxsep-.5\pgflinewidth,-\fboxsep-.5\pgflinewidth)}]textarea.south west)
;
\draw [tikzborder]
([shift={( \fboxsep+.5\pgflinewidth, \fboxsep+.5\pgflinewidth)}]textarea.north east)
--
([shift={( \fboxsep+.5\pgflinewidth,-\fboxsep-.5\pgflinewidth)}]textarea.south east)
;
\end{tikzpicture}%
\addtocounter{tikzborderpages}{-1}%
\ifnum\value{tikzborderpages}>1
\AtBeginShipoutNext{\tikzborderpage}%
\fi
\vspace{-\baselineskip}% Compensate for the generated extra line at begin of the page. No idea why exactly this happens. Also \baselineskip seems not to be 100% right.
}
\makeatother
\usepackage{lipsum}
\newcommand\xlipsum[1][]{{\let\par\relax\lipsum*[#1]}}
\begin{document}
\begin{tikzborder}
\xlipsum[1]
\end{tikzborder}
\lipsum[2-4]
\begin{tikzborder}
\xlipsum[1]
\end{tikzborder}
\lipsum[2-4]
\begin{tikzborder}
\xlipsum[1-9]
\end{tikzborder}
\lipsum[2-4]
\begin{tikzborder}
\xlipsum[1-20]
\end{tikzborder}
\end{document}
(The frame is not displayed fully right in the picture because of the low resolution etc.
Click to enlarge)
You need to incorporate the use of the needspace
package. It provides \needspace{<length>}
to check whether vertical length <length>
is available on the page. If not, it issues a \break
to flush the page content. Otherwise it does nothing (\relax
).
You could use it in the following way - a very simple example:
\documentclass{article}
\usepackage{needspace}% http://ctan.org/pkg/needspace
...
\begin{document}
...
\needspace{6em}% Require at least 6em on the page
\section{This is a heading of some sort}
Here is the first paragraph after the heading...
\end{document}
You could even incorporate this command in the sectional heading command of the style you are using. This way there's no need to specify \needspace
before the problem (or all) sectional heading.
needspace
also provides \Needspace{<length>}
. However, I've always found it sufficient to use \needspace{<length>}
.
Best Answer
You could hide the ornament with a discardable item: