summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/ifoddpage/ifoddpage.dtx
blob: fe0720777a2e7aecb303c848f44ffd79f77a994f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
% \iffalse meta-comment
%<=*COPYRIGHT>
%% Copyright (C) 2011-2012 by Martin Scharrer <martin@scharrer-online.de>
%% ----------------------------------------------------------------------
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%%   http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `maintained'.
%%
%% The Current Maintainer of this work is Martin Scharrer.
%%
%% This work consists of the files ifoddpage.dtx and ifoddpage.ins
%% and the derived filebase ifoddpage.sty.
%%
%<=/COPYRIGHT>
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{ifoddpage.dtx}[%
%<=*DATE>
    2016/04/23
%<=/DATE>
%<=*VERSION>
    v1.1
%<=/VERSION>
    DTX file for ifoddpage package]
\documentclass{ydoc}
\GetFileInfo{ifoddpage.dtx}
\usepackage{ifoddpage}[\filedate]
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{ifoddpage.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{90}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{v1.0}{2011/09/13}{First version.}
% \changes{v1.1}{2016/04/23}{Fixed misspelled macro name.}
%
%
% \DoNotIndex{\newcommand,\newenvironment}
%
% \GetFileInfo{ifoddpage.dtx}
% \author{Martin Scharrer}
% \email{martin@scharrer.me}
% \repository{https://bitbucket.org/martin_scharrer/ifoddpage}
% \maketitle
%
% \section{Introduction}
% Sometimes it is required to know if a macro is placed on an odd or even page.
% Simply testing the value of the \texttt{page} counter is not reliable, because \TeX\ reads and processes often more material than fits on the currently processed
% page in order to decide where to place the page break. Also moving material like floats can be placed on completely different pages than where the surrounding material
% is placed. The only reliable way to determine the correct page number is to write it to the auxiliary file using a label and read it back in the next compiler run.
% Labels use a so called \emph{whatsit}s (see \emph{The TeXBook}) to write the given code to the auxiliary file \emph{just when the material is shipped out}, i.e.\ a full page has
% been filled and is written to the output file. This way ensures that the determined page number is always correct, but adds an overhead.
%
% This package implements the described technique. A macro must be used to generate and read-back the label before the conditional can be used.
% A counter is used internally to provide unique names to the labels.
%
%
% \section{Usage}
% The following macros are provided for \LaTeX\ document authors:
%
% \DescribeMacro{\checkoddpage}
% This macro checks if the current page is odd or even by placing a label to the auxiliary file and reading it back in.
% This requires a second compiler run to work perfectly, but the code falls back to use the \texttt{page} counter value
% if the label is not yet defined, i.e.\ the label was just added or no auxiliary file existed.
% This fallback code might return wrong values for material just around page breaks, but
% is better than using a constant.
%
% Note that this macro inserts an invisible element (a so called \emph{whatsit}) which is placed on the page.
% It is possible that this happens to be at the very end of the last line of the page and any other code following it would then be placed
% on the next page. Some code like |\checkoddpage \ifoddpage odd\else even\fi| might then place the first macro on the current, say even, page but
% print `|even|' at the top of the next page which is odd. In order to avoid this both the check macro and the output text can be placed in the same
% box (e.g.\ |\mbox|). If the full content can't be placed in a box, e.g.\ because line breaking is required a |\mbox| can also be substituded by
% |\leavevmode| (to start a paragraph if required) and |\hbox| where the |{}| are replaced by |\bgroup| and |\egroup| so two alternative box ends can be specified:
%
% \begin{lstlisting}[gobble=2,numbers=none,basicstyle=\ttfamily]
%    \leavevmode\hbox\bgroup
%    \checkoddpage
%    \ifoddpage
%      odd\egroup\ more text
%    \else
%      even\egroup\ other text
%    \fi
% \end{lstlisting}
%
% \noindent
% This boxes the \Macro\checkoddpage with the first word of both clauses. Note that in this case it the settings are local to the box scope and \Macro\ifoddpage should
% be used outside of it again (without another \Macro\checkoddpage).
%
% \DescribeMacro{ifoddpage}
% This \TeX\ conditional is set (locally) by \Macro\checkoddpage.
% It is true if the current page is odd, or false if it is even. This is independent from whether the \texttt{oneside} or \texttt{twoside} mode is used.
%
% \DescribeMacro{ifoddpageoroneside}
% This \TeX\ conditional is set (locally) by \Macro\checkoddpage.
% Like the previous conditional it is true if the current page is odd, or false if it is even.
% However, if the \texttt{oneside} mode is active it is always true.
% This is useful for code which needs to check if the odd or even page layout is used, because in \texttt{oneside} mode the odd page layout is used for all pages.
%
% \par\medskip\par\noindent
% The following macros are intended for package authors:
%
% \DescribeMacro{\@ifoddpage}{<true>}{<false>}
% This \LaTeX\ macro uses \Macro{ifoddpage} and executes its first argument if that conditional is true but the second argument if it is false.
% The \Macro\checkoddpage must be used closely beforehand to get correct results.
%
% \DescribeMacro{\@ifoddpageoroneside}{<true>}{<false>}
% This \LaTeX\ macro uses \Macro{ifoddpageoroneside} and executes its first argument if that conditional is true but the second argument if it is false.
% The \Macro\checkoddpage must be used closely beforehand to get correct results.
%
% \DescribeMacro{\oddpage@page}
% This macro expands (using multiple steps) to a text representation of the page number for the last \Macro\checkoddpage.
% It is used in this macro together with \Macro\ifodd to set the provided conditionals.
%
%
% \section{Similar packages}
% The \pkg{changepage} package and the \pkg{memoir} class also provide the core functionality of this package, i.e.\ they define \Macro\checkoddpage and \Macro\ifoddpage but no other of the mentioned macros.
% That package uses this conditional internally in order to allow the user to change the page layout for odd or even pages, which is its main function.
% The \pkg{ifoddpage} should work together with that package and class, but should be loaded last to ensure the correct functionality of \Macro{ifoddpageoroneside}.
% It also uses labels if it is loaded using the \texttt{strict} option.
% The \pkg{ifoddpage} has the following benefits over \pkg{changepage} (if the page layout doesn't have to be changed):
%
% \begin{itemize}
%   \item Smaller code base, because no additional functionality is provided.
%   \item The \Macro{ifoddpageoroneside} conditional is also provided which simplifies code which has to handle odd/even margins.
%   \item The label code uses the same internal \LaTeX-core code as the normal \Macro\label and generates identical error, warning and info messages.
%   \item The fallback page number is not constant (0) but the current \texttt{page} counter value is used, which is a good approximation.
% \end{itemize}
%
% \StopEventually{}
%
% \clearpage
% \section{Implementation}
%
% \iffalse
%<*ifoddpage.sty>
% \fi
%    \begin{macrocode}
%<!COPYRIGHT>
\NeedsTeXFormat{LaTeX2e}[1999/12/01]
\ProvidesPackage{ifoddpage}[%
%<!DATE>
%<!VERSION>
%<*DRIVER>
    2099/01/01 develop
%</DRIVER>
    Conditionals for odd/even page detection]
%    \end{macrocode}
%
%
%    \begin{macrocode}
\newcount\c@checkoddpage
%    \end{macrocode}
%
% \begin{macro}{\thecheckoddpage}
%    \begin{macrocode}
\def\thecheckoddpage{\number\c@checkoddpage}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\newif\ifoddpage
\newif\ifoddpageoroneside
\let\oddpage@checkpage\relax
%    \end{macrocode}
%
% \begin{macro}{\oddpage@page}
%    \begin{macrocode}
\def\oddpage@page{1}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\oddpage@label}
%    \begin{macrocode}
\def\oddpage@label{%
    \@newl@bel{checkoddpage}%
}%
\write\@auxout{\noexpand\providecommand\noexpand\oddpage@label[2]{}}%
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\oddpage@checkpage}
%    \begin{macrocode}
\def\oddpage@checkpage#1{%
    \@bsphack
    \write\@auxout{\string\oddpage@label{#1}{\the\c@page}}%
    \@esphack
}%
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\oddpage@page}
%    \begin{macrocode}
\def\oddpage@page{%
    \expandafter\ifx\csname checkoddpage@\thecheckoddpage\endcsname\relax
        \the\c@page
    \else
        \csname checkoddpage@\thecheckoddpage\endcsname
    \fi
}%
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\checkoddpage}
%    \begin{macrocode}
\DeclareRobustCommand\checkoddpage{%
    \stepcounter{checkoddpage}%
    \expandafter\oddpage@checkpage\expandafter{\number\c@checkoddpage}%
    \ifodd\oddpage@page\relax
        \oddpagetrue
        \oddpageoronesidetrue
    \else
        \oddpagefalse
        \oddpageoronesidefalse
    \fi
    \if@twoside\else
        \oddpageoronesidetrue
    \fi
}%
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@ifoddpage}
%    \begin{macrocode}
\def\@ifoddpage{%
    \ifoddpage
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@ifoddpageoroneside}
%    \begin{macrocode}
\def\@ifoddpageoroneside{%
    \iftwosideoddside
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi
}
%    \end{macrocode}
% \end{macro}
%
% \iffalse
%</ifoddpage.sty>
% \fi
%
% \Finale
% \endinput