\NeedsTeXFormat{LaTeX2e}[2020/10/01] \ProvidesClass{cccbform}[2024/12/08 In the Beginning, There Was Chaos] \LoadClass{scrartcl} \RequirePackage[ngerman]{babel} \RequirePackage{geometry, calc, fontspec, tikz, hyperref, changepage, letltxmacro, csquotes} \MakeOuterQuote{"} \usetikzlibrary{calc} \geometry{a4paper, margin=1.5cm, inner=2.5cm} \pagestyle{empty} % allow disabling PDF forms in case they cause printing problems % (*most* viewers don't print them, so we need "fake" fields below them anyways… % but some do, and always put the form field on top (even if explicitly placed % below other elements), which then obscures the label text…) \newif\if@DoPdfForm \@DoPdfFormtrue \DeclareOption{noform}{\@DoPdfFormfalse} \newif\if@Example \@Examplefalse \DeclareOption{example}{ % for embedded examples in the documentation \geometry{a6paper, margin=1ex} \@Exampletrue } \DeclareOption{shortexample}{ \geometry{a6paper, margin=2ex} \@Exampletrue \AtEndDocument{% \pageheight=\pagetotal \advance\pageheight by 4ex } } \ProcessOptions\relax % address \newcommand{\address}{% Chaos Computer Club Berlin~/ CCC~(B)~e.~V.\\ Marienstr.~11\\ 10117~Berlin } \setmainfont[ Renderer=HarfBuzz, ItalicFont=Recursive, BoldFont=Recursive, BoldItalicFont=Recursive, Scale=0.9, UprightFeatures={ RawFeature={+ss01,+ss02,+ss08,+case}, RawFeature={+axis={MONO=0.0,CASL=0.2,slnt=0,CRSV=0,wght=400}} }, BoldFeatures={RawFeature={+axis={MONO=0.0,CASL=0.2,slnt=0,CRSV=0,wght=700}}}, BoldItalicFeatures={RawFeature={+axis={MONO=0.0,CASL=0.2,slnt=-15,CRSV=1,wght=700}}}, ItalicFeatures={RawFeature={+axis={MONO=0.0,CASL=0.2,slnt=-15,CRSV=1,wght=400}}} ]{Recursive} \setmonofont[ Renderer=HarfBuzz, ItalicFont=Recursive, BoldFont=Recursive, BoldItalicFont=Recursive, Scale=0.9, UprightFeatures={ RawFeature={+ss01,+ss02,+ss08,+case}, RawFeature={+axis={MONO=1.0,CASL=0.2,slnt=0,CRSV=0,wght=400}} }, BoldFeatures={RawFeature={+axis={MONO=1.0,CASL=0.2,slnt=0,CRSV=0,wght=700}}}, BoldItalicFeatures={RawFeature={+axis={MONO=1.0,CASL=0.2,slnt=-15,CRSV=1,wght=700}}}, ItalicFeatures={RawFeature={+axis={MONO=1.0,CASL=0.2,slnt=-15,CRSV=1,wght=400}}} ]{Recursive} \renewfontfamily\titlefont[ Renderer=HarfBuzz, ItalicFont=Recursive, BoldFont=Recursive, BoldItalicFont=Recursive, Scale=0.9, UprightFeatures={ RawFeature={+ss01,+ss02,+ss08,+case}, RawFeature={+axis={MONO=0.0,CASL=0.4,slnt=0,CRSV=1,wght=500}} }, BoldFeatures={RawFeature={+axis={MONO=0.0,CASL=0.4,slnt=0,CRSV=1,wght=800}}}, BoldItalicFeatures={RawFeature={+axis={MONO=0.0,CASL=0.4,slnt=-15,CRSV=1,wght=800}}}, ItalicFeatures={RawFeature={+axis={MONO=0.0,CASL=0.4,slnt=-15,CRSV=1,wght=500}}} ]{Recursive} % colors \definecolor{fieldcolor}{gray}{0.85} \definecolor{bordercolor}{gray}{0.1} % lengths \def\deflength#1#2{\newlength{#1}\setlength{#1}{#2}} \setlength{\parindent}{0pt} \setlength{\fboxsep}{0pt} \deflength{\normaltextheight}{\dimexpr \ht\strutbox + \dp\strutbox \relax} % XXX design-relevant lengths \deflength{\formfieldheight}{1.25\normaltextheight} \deflength{\formskip}{0.75em} \deflength{\colsep}{1.0em} \deflength{\indentstep}{1cm} \deflength{\borderwidth}{0.5pt} % YYY these might need adjustments after changes \deflength{\formshrink}{4pt} \def\checkboxtextshrink{\dimexpr \formfieldheight % width of checkbox +1em % the \quad separator's width +\formshrink % wild guess, -2\borderwidth leaves 1pt overfull \relax} \deflength{\htweak}{0.5pt} % manual adjustment of horizontal alignment of form elements \deflength{\hadj}{\dimexpr -0.5\formshrink - 0.5\fontdimen2\font + \htweak \relax} % XXX length factors (as percentage of \linewidth) \def\normalfieldwidth{0.65} \def\shortfieldwidth{0.35} % XXX rotation angle \def\labelangle{4.20} % counters \newcounter{fieldnum} \def\@autofieldname{field\thefieldnum} % conditional flags \newif\ifMultiColumn % abbreviations \def\@formdefaults{% backgroundcolor=fieldcolor,bordercolor=fieldcolor,% borderwidth=0pt,charsize=\formfieldheight% } % address placement helper \newcommand{\@dinaddress}{% \begin{tikzpicture}[remember picture, overlay] \node[anchor=north west] at (current page.north west) [xshift=2.35cm, yshift=-5cm] {% \begin{minipage}{10cm} \emph{an den} \par \addvspace{\formskip} \noindent\address \end{minipage} }; \end{tikzpicture} } % % % form@, fake@, and full@ variants of the form elements: % % (raw@: renamed / prefixed hyperref command) % form@: PDF form element (some viewers don't print it) % fake@: A colored box, non-interactive (but will be printed!) % full@: a stack of fake@ and form@ on top of each other % % The general parameter convention here is: height, width multiplier % - height is optional and defaults to \formfieldheight, giving the right size % for a single-line text field % - width is "mandatory" but always used followed by \linewidth, so passing an % empty argument works and is effectively equivalent to passing 1 % rename commands to make nice names available \LetLtxMacro\raw@TextField\TextField \LetLtxMacro\raw@CheckBox\CheckBox \let\CheckBox\relax % wrapped form fields with defaults filled in \NewDocumentCommand{\form@TextField}{D<>{\formfieldheight} O{1.0}}{% \stepcounter{fieldnum} \expandafter\raw@TextField\expandafter[\@formdefaults, name=\@autofieldname, width=\dimexpr #2\linewidth - \formshrink \relax, height=\dimexpr #1 - \formshrink \relax ]{}% } \NewDocumentCommand{\form@MultilineTextField}{D<>{\formfieldheight} O{1.0}}{% \stepcounter{fieldnum} \expandafter\raw@TextField\expandafter[\@formdefaults, name=\@autofieldname, multiline=true, width=\dimexpr #2\linewidth - \formshrink \relax, height=\dimexpr #1 - \formshrink \relax ]{}% } \NewDocumentCommand{\form@CheckBox}{}{% \stepcounter{fieldnum} \expandafter\raw@CheckBox\expandafter[\@formdefaults, name=\@autofieldname, width=\dimexpr \normaltextheight - \formshrink \relax, height=\dimexpr \normaltextheight - \formshrink \relax ]{}% } % fake form fields to put *under* the PDF form fields \NewDocumentCommand{\fake@TextField}{D<>{\formfieldheight} O{1.0}}{% \begin{tikzpicture}[baseline=0.6ex] \fill[fieldcolor] (0,0) rectangle (#2\linewidth - 2\borderwidth,#1); \draw[dash pattern=on 0.5\borderwidth off 5\borderwidth,bordercolor, line width=\borderwidth, line cap=round] (0,0) -- (#2\linewidth - 2\borderwidth,0); \end{tikzpicture}% } \LetLtxMacro\fake@MultilineTextField\fake@TextField \NewDocumentCommand{\fake@CheckBox}{}{% \begin{tikzpicture}[baseline=0.6ex] \fill[fieldcolor] (0,0) rectangle (\normaltextheight,\normaltextheight); \draw[bordercolor,line width=\borderwidth] (0,0) rectangle (\normaltextheight,\normaltextheight); \end{tikzpicture}% } % "full" stacked version of fake + actual form field \NewDocumentCommand{\full@TextField}{D<>{\formfieldheight} O{1.0}}{% \begin{tikzpicture}[baseline] \node (background) [anchor=base west, inner sep=0pt, outer sep=0pt] at (0,0) { \fake@TextField<#1>[#2] }; \if@DoPdfForm \node[anchor=center, inner sep=0pt, outer sep=0pt] at (background.center) { \kern\hadj\form@TextField<#1>[#2] }; \fi \end{tikzpicture} } \NewDocumentCommand{\full@MultilineTextField}{D<>{\formfieldheight} O{1.0}}{% \begin{tikzpicture}[baseline] \node (background) [anchor=base west, inner sep=0pt, outer sep=0pt] at (0,0) { \fake@MultilineTextField<#1>[#2] }; \if@DoPdfForm \node[anchor=center, inner sep=0pt, outer sep=0pt] at (background.center) { \kern\hadj\form@MultilineTextField<#1>[#2] }; \fi \end{tikzpicture} } \NewDocumentCommand{\full@CheckBox}{}{% \begin{tikzpicture}[baseline] \node (background) [anchor=base west, inner sep=0pt, outer sep=0pt] at (0,0) { \fake@CheckBox }; \if@DoPdfForm \node [anchor=center, inner sep=0pt] at (background.center) { \kern\hadj\form@CheckBox }; \fi \end{tikzpicture} } % % % exposed form elements % Text{text…} - just text, with proper spacing \NewDocumentCommand{\Text}{+m}{% \par\addvspace{2\formskip}#1\par\addvspace{\formskip} } % TextField*{label} - a single-line input (starred version uses all available space) \RenewDocumentCommand{\TextField}{s m}{% \par\addvspace{1.5\formskip}% \ifMultiColumn% \pgfmathsetmacro{\@tlen}{1.0}% \else% \IfBooleanTF{#1}% {\pgfmathsetmacro{\@tlen}{1.0}}% {\pgfmathsetmacro{\@tlen}{\normalfieldwidth}}% \fi% \begin{tikzpicture}[baseline] \useasboundingbox (0,0) rectangle (\@tlen\textwidth,\formfieldheight); \node[anchor=base west] at (0, 0) { \full@TextField[\@tlen] }; \node[anchor=base west,rotate=\labelangle] at (-1em,0.6\formfieldheight) { \ttfamily\footnotesize #2\strut }; \end{tikzpicture}% \par\addvspace{\formskip}% } % ShortTextField[width]{label} - a single-line input with reduced width \NewDocumentCommand{\ShortTextField}{o m}{% \par\addvspace{1.5\formskip}% \IfValueTF{#1}{\pgfmathsetmacro{\@tlen}{#1}}{% \ifMultiColumn% \pgfmathsetmacro{\@tlen}{\normalfieldwidth}% \else% \pgfmathsetmacro{\@tlen}{\shortfieldwidth}% \fi% }% \begin{tikzpicture}[baseline] \useasboundingbox (0,0) rectangle (\@tlen\textwidth,\formfieldheight); \node[anchor=base west] at (0,0) { \full@TextField[\@tlen] }; \node[anchor=base west,rotate=\labelangle] at (-1em,0.6\formfieldheight) { \ttfamily\footnotesize #2\strut }; \end{tikzpicture}% \par\addvspace{\formskip}% } % MultilineTextField*[height]{label} - a multi-line input, starred version uses all available width \NewDocumentCommand{\MultilineTextField}{s O{\formfieldheight} m}{% \par\addvspace{1.5\formskip}% \ifMultiColumn% \pgfmathsetmacro{\@tlen}{1.0}% \else% \IfBooleanTF{#1}% {\pgfmathsetmacro{\@tlen}{1.0}}% {\pgfmathsetmacro{\@tlen}{\normalfieldwidth}}% \fi% \begin{tikzpicture}[baseline] \useasboundingbox (0,0) rectangle (\@tlen\textwidth, #2); \node[anchor=base west] at (0,0) { \full@MultilineTextField<#2>[\@tlen] }; \node[anchor=base west,rotate=\labelangle] at (-1em,#2 - 0.4\formfieldheight) { \ttfamily\footnotesize #3\strut }; \end{tikzpicture} \par\addvspace{\formskip}% } % Signature[label] - a field not fillable on the computer, big enough for a signature \NewDocumentCommand{\Signature}{O{Datum, Unterschrift}}{% \par\addvspace{2\formskip}% \ifMultiColumn% \pgfmathsetmacro{\@tlen}{\normalfieldwidth}% \else% \pgfmathsetmacro{\@tlen}{\shortfieldwidth}% \fi% \begin{tikzpicture}[baseline] \useasboundingbox (0,0) rectangle (\@tlen\textwidth,1.0cm); \node[anchor=base west] at (0,0) { \fake@MultilineTextField<1.0cm>[\@tlen] }; \node[anchor=base west,rotate=\labelangle] at (-1em,1cm - 0.4\formfieldheight) { \ttfamily\footnotesize #1\strut }; \end{tikzpicture} \par\addvspace{\formskip}% } % Notes[label] - a slightly taller fake field that fills the whole width \NewDocumentCommand{\Notes}{O{Vermerke}}{% \par\addvspace{1.5\formskip}% \pgfmathsetmacro{\@tlen}{1.0} \begin{tikzpicture}[baseline] \useasboundingbox (0,0) rectangle (\@tlen\textwidth,1.5cm); \node[anchor=base west] at (0,0) { \fake@MultilineTextField<1.5cm>[\@tlen] }; \node[anchor=base west,rotate=\labelangle] at (-1em,1.5cm - 0.4\formfieldheight) { \ttfamily\footnotesize #1\strut }; \end{tikzpicture} \par\addvspace{\formskip}% } % InlineTextField[width]{label} \NewDocumentCommand{\InlineTextField}{o m}{% \IfValueTF{#1}% {\pgfmathsetmacro{\@tlen}{#1}}% {\ifMultiColumn% \pgfmathsetmacro{\@tlen}{\normalfieldwidth}% \else% \pgfmathsetmacro{\@tlen}{\shortfieldwidth}% \fi}% \begin{tikzpicture}[baseline] \useasboundingbox (0,0) rectangle (\@tlen\textwidth,\formfieldheight); \node[anchor=base west] at (0,0) { \full@TextField[\@tlen] }; \IfBlankTF{#2}{}{ \node[anchor=base west, rotate=\labelangle] at (-1em,0.6\formfieldheight) { \ttfamily\footnotesize #2\strut }; } \end{tikzpicture} } % Checkbox{label} - a checkbox; label can be long and will linebreak reasonably pretty \NewDocumentCommand{\Checkbox}{m}{% \par% \full@CheckBox\quad% \begin{minipage}[t]{\dimexpr \linewidth - \checkboxtextshrink \relax}% #1% \end{minipage}% \par\addvspace{\formskip}% } % InlineCheckbox - just the box \NewDocumentCommand{\InlineCheckbox}{}{\full@CheckBox} % CheckboxOther[width]{label} - a checkbox for a write-in option \NewDocumentCommand{\CheckboxOther}{O{\shortfieldwidth} m}{% \par% \full@CheckBox\quad\IfBlankTF{#2}{}{#2\quad}\smash{\full@TextField[#1]}% \par\addvspace{\formskip}% } % high-level structure % Section{title} - a form section \NewDocumentCommand{\Section}{m}{% \addvspace{1.5cm}% {\Large\bfseries #1}% \par\addvspace{2\formskip}% } % Subsection{title} - slightly smaller than section \NewDocumentCommand{\Subsection}{m}{% \addvspace{1.0cm}% {\large\bfseries #1}% \par\addvspace{\formskip}% } \NewDocumentCommand{\full@rule}{}{% \noindent\makebox[\linewidth]{\rule{\maxdimen}{\borderwidth}}% } \NewDocumentCommand{\text@rule}{}{% \hfill\rule{0.75\textwidth}{\borderwidth}\hfill\hfill\null% } % Rule - a horizontal rule, with correct spacing \NewDocumentCommand{\Rule}{}{% \par% \text@rule% \par\addvspace{\formskip}% } % RuleSection - rule followed by a small note *immediately* below, before the spacing % (e.g. to separate public / internal sections of a form) \NewDocumentCommand{\RuleSection}{m}{% \par\addvspace{\formskip}% \leavevmode\full@rule\\[-1ex]% {\details{(#1)}}% \par\addvspace{\formskip} } % \begin{Indented}[factor] ... \end{Indented} - indent a section \NewDocumentEnvironment{Indented}{O{}}{% \vspace{-1\formskip} \begin{adjustwidth}{#1\indentstep}{0pt}% }{% \end{adjustwidth}% \addvspace{2\formskip} } % TwoColumns{left}{right} - put two sections side-by-side \NewDocumentCommand{\TwoColumns}{+m +m}{% \begin{minipage}[t]{0.5\linewidth - 0.5\colsep}% \MultiColumntrue% #1% \MultiColumnfalse% \end{minipage}% \hfill \begin{minipage}[t]{0.5\linewidth - 0.5\colsep}% \MultiColumntrue% #2% \MultiColumnfalse% \end{minipage}% \par\addvspace{\formskip}% } \NewDocumentCommand{\ThreeColumns}{+m +m +m}{% \begin{minipage}[t]{0.333\linewidth - 0.66\colsep}% \MultiColumntrue% #1% \MultiColumnfalse% \end{minipage}% \hfill \begin{minipage}[t]{0.333\linewidth - 0.66\colsep}% \MultiColumntrue% #2% \MultiColumnfalse% \end{minipage}% \hfill \begin{minipage}[t]{0.333\linewidth - 0.66\colsep}% \MultiColumntrue% #3% \MultiColumnfalse% \end{minipage}% \par\addvspace{\formskip}% } \NewDocumentCommand{\FiveColumns}{+m +m +m +m +m}{% \begin{minipage}[t]{0.2\linewidth - 0.8\colsep}% \MultiColumntrue% #1% \MultiColumnfalse% \end{minipage}% \hfill \begin{minipage}[t]{0.2\linewidth - 0.8\colsep}% \MultiColumntrue% #2% \MultiColumnfalse% \end{minipage}% \hfill \begin{minipage}[t]{0.2\linewidth - 0.8\colsep}% \MultiColumntrue% #3% \MultiColumnfalse% \end{minipage}% \hfill \begin{minipage}[t]{0.2\linewidth - 0.8\colsep}% \MultiColumntrue% #4% \MultiColumnfalse% \end{minipage}% \hfill \begin{minipage}[t]{0.2\linewidth - 0.8\colsep}% \MultiColumntrue% #5% \MultiColumnfalse% \end{minipage}% \par\addvspace{\formskip}% } % details{text} - (use instead of font sizes, small text) \NewDocumentCommand{\details}{m}{% {\scriptsize #1}% } % ul{text} - underline a single word or short phrase \NewDocumentCommand{\ul}{m}{% \tikz[baseline=(word.base)]{% \node[inner sep=1pt] (word) {#1}; \draw[thick] (word.south west) -- (word.south east); }% } % ensure line height is enough to fit a form field \NewDocumentCommand{\formstrut}{}{\rule{0pt}{\formfieldheight}\strut} % % % common title patterns % put the logo in the top right corner \NewDocumentCommand{\@logo}{}{ \if@Example \begin{tikzpicture}[remember picture, overlay] \node[anchor=north east] at (current page.north east) [xshift=-0.5cm, yshift=-0.5cm] {% \includegraphics[width=1.5cm]{logo.pdf}% }; \end{tikzpicture}% \else \begin{tikzpicture}[remember picture, overlay] \node[anchor=north east] at (current page.north east) [xshift=-1.5cm, yshift=-1.5cm] {% \includegraphics[width=3cm]{logo.pdf}% }; \end{tikzpicture}% \fi } % LogoTitle{title} - logo on the right, title on the left \NewDocumentCommand{\LogoTitle}{m}{ \@logo \if@Example \\[0.5cm]{\titlefont\huge\bfseries #1}\\[1cm] \else \\[1cm]{\titlefont\huge\bfseries #1}\\[1.5cm] \fi } % AddressTitle{title} - title at the top, address, then the form below % AddressTitle*{title} - same, plus logo \NewDocumentCommand{\AddressTitle}{s m}{ \IfBooleanT{#1}{\@logo} \@dinaddress \\[1cm]\smash{{\titlefont\huge\bfseries #2}}\\[4.5cm] } % need to emit \Form ; hyperref generates incomplete CheckBox appearance data, % which causes problems with some viewers - so it's currently better not to % generate any at all \AtBeginDocument{ \Form[NeedAppearances=false] \PageFoldMarks } \NewDocumentCommand{\PageFoldMarks}{}{ \if@Example \else \begin{tikzpicture}[remember picture,overlay] \draw ($(current page.north west)!0.33!(current page.south west)$) -- ++(7.5mm,0cm); \draw ($(current page.north west)!0.50!(current page.south west)$) -- ++(1.25cm,0cm); \draw ($(current page.north west)!0.66!(current page.south west)$) -- ++(7.5mm,0cm); \end{tikzpicture} \fi } % fold markers \AddToHook{shipout/background}{% \PageFoldMarks }