% Copyright 2018-2026 by Romano Giannetti % Copyright 2015-2026 by Stefan Lindner % Copyright 2013-2026 by Stefan Erhardt % Copyright 2007-2026 by Massimo Redaelli % % This file may be distributed and/or modified % % 1. under the LaTeX Project Public License and/or % 2. under the GNU Public License. % % See the files gpl-3.0_license.txt and lppl-1-3c_license.txt for more details. \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{ctikzmanutils}[2026/02/15 utilities for formatting the circuitikz manual] \RequirePackage{ifthen} \RequirePackage{iftex} \RequirePackage{etoolbox}% easier lwarp support \RequirePackage{listings} \RequirePackage{ragged2e} \RequirePackage{textcomp} \RequirePackage{booktabs} \renewcommand{\arraystretch}{1.2} \RequirePackage{a4wide} % smaller borders \RequirePackage{titling} \RequirePackage{titlesec} % clear page on section break \newcommand{\sectionbreak}{\clearpage} \setcounter{secnumdepth}{4} \setcounter{tocdepth}{4} % for some example we need them... \usetikzlibrary{calc, fit, decorations, decorations.pathmorphing, tikzmark} \RequirePackage{upgreek} % % Example definitions using `enverb` % \RequirePackage{enverb,varwidth} \newcommand*\ctikz@ex@lstopts{} % collect options meant for lstlisting \newcommand*\ctikz@ex@codeOutside{} % collect code to execute after the env \newdimen\ctikz@ex@width % width available to the code \newsavebox\ctikz@ex@box % temporary box register % handle the 'store' key. % #1: the name of the storage % saves the contents currently in \enverbBody to the named storage. \newcommand*\ctikz@ex@dostore[1] {% \@ifundefined{ctikz@ex@storage@#1}% {\global\expandafter\let\csname ctikz@ex@storage@#1\endcsname\@empty}% {}% \expandafter\gappto\csname ctikz@ex@storage@#1\expandafter\endcsname \expandafter{\enverbBody}% } % handle the 'restore' key. % #1: the name of the storage % prepends \enverbBody with the contents of the named storage. \newcommand*\ctikz@ex@dorestore[1] {% \@ifundefined{ctikz@ex@storage@#1} {\PackageError{ctikz}{Unknown storage #1}{}}% {% \epreto\enverbBody {% \unexpanded\expandafter\expandafter\expandafter {\csname ctikz@ex@storage@#1\endcsname}% }% }% } \ekvdefinekeys{ctikz/examples} { % pos= % where to output the results % t: on top of the code % b: below the code % l: left of the code choice-store pos = \ctikz@ex@pos{t,b,l} ,initial pos = l % hsep= % how much separation to put between the results and the code for pos=l ,dimen hsep = \ctikz@ex@hsep ,initial hsep = 1.5\columnsep % vsep= % how much separation to put between the results and the code for pos=t/b ,dimen vsep = \ctikz@ex@vsep ,initial vsep = \bigskipamount % aboveskip= % how much space to put above the environment ,dimen aboveskip = \ctikz@ex@aboveskip ,initial aboveskip = \medskipamount % belowskip= % how much space to put below the environment ,dimen belowskip = \ctikz@ex@belowskip ,initial belowskip = \medskipamount % width= (late evaluation) % the width of the results box for box=varwidth/minipage, if this is 0pt % the default values will be % pos=l: 0.5\linewidth % pos=t/b: \linewidth ,store width = \ctikz@ex@reswd ,initial width = 0pt % box= % the type of box put around the results box (not visually but how to % determine the width) % hbox: simply use a \hbox (so natural width, no \par, no vertical % material) % varwidth: Use a `varwidth` environment around it % minipage: Use a `minipage` environment around it % default: the used boxing mechanism depends on pos: % pos=l: hbox % pos=t/b: minipage ,choice-store box = \ctikz@ex@boxtype {hbox=h, varwidth=v, minipage=m, default=d} ,initial box = default % varwidth=[] % backwards compatibility, sets box=varwidth without a value or with % true/t, sets box=default with false/f. ,nmeta varwidth = box=varwidth ,choice varwidth = { true=\ekvmorekv{box=varwidth}, t=\ekvmorekv{box=varwidth}, false=\ekvmorekv{box=default}, f=\ekvmorekv{box=default} } % only code=[] % true/-NoValue-: there'll be no results box % false: revert the setting ,boolTF only code = \ctikz@ex@onlycodeTF % exec outside=[] % true/-NoValue-: the code will be executed outside the environment (using % the generic env//after hook). % false: revert this setting % This will also call 'only code' with the same value! ,boolTF exec outside = \ctikz@ex@execOutsideTF ,also meta exec outside = {only code={#1}} ,also nmeta exec outside = only code % store= % if used the code will be stored in a named storage for later use (see % 'restore'). Multiple environments using the same storage name will % result in the code being appended to the existing stored code in this % storage. ,dataT store = \ctikz@ex@store % restore= % restore the code of the named storage, meaning it'll be prepended to the % code of this environment for the results box (but not for the listing!) ,dataT restore = \ctikz@ex@restore % clear storage= % forget the contents of the named storage (handled on the spot, so a key % combination `store=foo, clear storage=foo` would first clear `foo` and % then store the environment contents into `foo` after the environment was % processed. ,code clear storage = \global\expandafter\let\csname ctikz@ex@storage@#1\endcsname\ctikz@undef % dollar=[] % Whether to fix the dollar category code while code is executed. We set % the boolean globally but if used it's turned to false again in the % after-block. Will only take effect during lwarp's HTML creation. ,gboolTF dollar = \ctikz@ex@dollarTF % collect unknown keys for lstlisting ,unknown code = \appto\ctikz@ex@lstopts{,#1={#2}} ,unknown noval = \appto\ctikz@ex@lstopts{,#1} } % wrap enverbExecute to handle 'dollar=true' \newcommand*\ctikz@ex@execute {% \ctikz@ex@dollarTF{\pushdollarcat}{}% \enverbExecute \ctikz@ex@dollarTF{\popdollarcat}{}% } % handle the boxing inside the results box % #1: default box type if 'box=default' % This will call \ctikz@ex@fbox with the argument based on the current % box-setting. \newcommand*\ctikz@ex@handleboxtype[1] % #1 = default case {% \if\ctikz@ex@boxtype d% \def\ctikz@ex@boxtype{#1}% \fi \if\ctikz@ex@boxtype h% \ctikz@ex@fbox{\ctikz@ex@execute}% \else\if\ctikz@ex@boxtype v% \ctikz@ex@fbox {\begin{varwidth}{\dimeval\ctikz@ex@reswd}\ctikz@ex@execute\end{varwidth}}% \else\if\ctikz@ex@boxtype m% \ctikz@ex@fbox {\begin{minipage}{\dimeval\ctikz@ex@reswd}\ctikz@ex@execute\end{minipage}}% \else \PackageError{ctikz}{Unknown example box type \ctikz@ex@boxtype}{}% \fi\fi\fi } % print the result of the collected code % Control will first be given to \ctikz@ex@handleboxtype which will call % \ctikz@ex@fbox eventually. But first we need to set a suitable default width % for 'width=0pt' (or anything that evaluates to 0pt inside \dimexpr). \newcommand*\ctikz@ex@printresult {% \if\ctikz@ex@pos l% \ifdim\dimeval\ctikz@ex@reswd=\z@ \def\ctikz@ex@reswd{.5\linewidth}% \fi \ctikz@ex@handleboxtype{h}% \else \ifdim\dimeval\ctikz@ex@reswd=\z@ \def\ctikz@ex@reswd{\linewidth}% \fi \ctikz@ex@handleboxtype{m}% \fi } % output a vcentered framed box for the results % additionally the output (together with the framed box) will be in the box % register \ctikz@ex@box % #1: the contents to box up (should be \enverbExecute nested in a suitable box % construct based on the 'box' key). \newcommand*\ctikz@ex@fbox[1] {% \sbox\ctikz@ex@box {% % fboxsep=6pt, fboxrule=0.8pt -> 13.6pt less for linewidth \advance\linewidth-13.6pt \ctikz@ex@restore\ctikz@ex@dorestore \ignorespaces#1\unskip }% \sbox\ctikz@ex@box {% \fboxsep=6pt \fboxrule=0.8pt \rlap{\fcolorbox{cyan}{white}{\phantom{\usebox\ctikz@ex@box}}}% \kern\fboxrule \kern\fboxsep \usebox\ctikz@ex@box }% $\vcenter{\copy\ctikz@ex@box}$% vcenter matches minipage [c] } % output a vcentered code listing if pos=l, otherwise output a code listing \newcommand*\ctikz@ex@printcode {% \ctikz@ex@onlycodeTF{\@firstofone}% {% \if\ctikz@ex@pos l% only box up the code if necessary \expandafter\@secondoftwo \fi \@secondoftwo{\parbox[c]{\ctikz@ex@width}}% }% {% \ExpandArgs{ne}\enverbListing{lstlisting}% {[% style=expl-code ,aboveskip=6pt% we don't want skips but need to compensate listings ,belowskip=0pt% \unexpanded\expandafter{\ctikz@ex@lstopts}% ]}% }% } % \begin{ctikzExample}[] % the front level environment. can be any keys as described inside % \ekvdefinekeys{ctikz/examples}. The following paragraph will be indented if % there's a blank line between \end{ctikzExample} and the first line of the % paragraph (as with lists in LaTeX). \newenvironment{ctikzExample} {\enverb{key-set=ctikz/examples, oarg-not-enverb, more-ignore=0}} {% \par \vskip\ctikz@ex@aboveskip \noindent \ctikz@ex@width=\linewidth \ctikz@ex@onlycodeTF {}% {% \if\ctikz@ex@pos b \else \ctikz@ex@printresult \if\ctikz@ex@pos t \par \vskip\ctikz@ex@vsep \noindent \else \hfill \advance\ctikz@ex@width-\wd\ctikz@ex@box \advance\ctikz@ex@width-\ctikz@ex@hsep \fi \fi }% \ctikz@ex@printcode \ctikz@ex@onlycodeTF {}% {% \if\ctikz@ex@pos b \par \vskip\ctikz@ex@vsep \noindent \ctikz@ex@printresult \fi }% \par \vskip\ctikz@ex@belowskip \ctikz@ex@store\ctikz@ex@dostore \ctikz@ex@execOutsideTF {\global\let\ctikz@ex@codeOutside\enverbBody}% {}% \@endparenv } % handling of the 'exec outside' key. If there are contents inside % \ctikz@ex@codeOutside the key was used and we should rerun an \enverbExecute % (which only works on \enverbBody contents, so we restore those outside of the % environment). \AddToHook{env/ctikzExample/after} {% \ifx\ctikz@ex@codeOutside\@empty \else \let\enverbBody\ctikz@ex@codeOutside \global\let\ctikz@ex@codeOutside\@empty \ctikz@ex@execute \fi \ctikz@ex@dollarTF{\global\let\ctikz@ex@dollarTF\@secondoftwo}{}% } % % --- Style for the code part --- % cyan block, no numbers % \lstdefinestyle{expl-code}{ language=[LaTeX]TeX, basicstyle=\small\ttfamily, columns=fullflexible, keepspaces=true, breaklines=true, showstringspaces=false, tabsize=3, numbers=none, frame=single, % using none make framesep=0 which is ugly framerule=0pt,% no frame but keep separation framesep=4pt, backgroundcolor=\color{cyan!10}, xleftmargin=0.5em, aboveskip=\bigskipamount, belowskip=\bigskipamount, } \lstset{style=expl-code} % in lwarp's warpingprint-false case we need to temporarily change the category % code of $ to be mathshift again. These macros will do that in that case % (they're redefined in `ctikz-lwarp-late.tex`). \newcommand*\pushdollarcat{} \newcommand*\popdollarcat{} \newcommand{\email}[1]{\href{mailto:#1}{#1}} \long\def\comment#1{} \RequirePackage{framed} \RequirePackage{xtab} \RequirePackage{hyperref} \hypersetup{ pdftitle={CircuiTikZ \pgfcircversion\ - manual}, % title pdfauthor={Massimo Redaelli, Stefan Lindner, Stefan Erhardt, Romano Giannetti}, % authors pdfsubject={CircuiTikZ manual}, % subject of the document pdfkeywords={}, % list of keywords colorlinks=true, % false: boxed links; true: colored links linkcolor=blue, % color of internal links citecolor=blue, % color of links to bibliography filecolor=blue, % color of file links urlcolor=blue % color of external links } % There are a lot of boxes in the document; let's try to give TeX % a bit of leverage... do not use parindent (which looks strange between examples) % and add stretch between paragraph, to avoid a lot of sections and subsections % starting at the end of the page. \parindent=0pt \parskip=4pt plus 6pt minus 2pt % % names % \def\TikZ{Ti\emph{k}Z} \def\Circuitikz{Circui\TikZ} \def\ConTeXt{Con\TeX t} % % Start of special macros for component descriptions % % draw the shape without affecting anything \newcommand{\drawphantomshape}[1] {% {\tikz [overlay, color=blue] \path (0,0) node[#1]{};} } %% New circuit description macros \newcommand{\twopartbox}[2]{% \leavevmode\null\par\noindent\fbox{\parbox[c]{0.32\linewidth}{#1}\hfill \parbox[c]{0.66\linewidth}{\RaggedRight\hbadness=9500 #2}\par\noindent}% } % filling color for filled-enabled component \colorlet{fillcol}{cyan!30!white} % find the class for the element. Thanks to Symbol 1 % https://tex.stackexchange.com/a/501389/38080 \def\checkclass#1{% \csname pgf@sh@ma@#1\endcsname \ifdefined\ctikzclass Class: \texttt{\ctikzclass}.% \else No class.% \fi } % description of a node component: % optional star for fillable % optional: scale of the component in the entry % mandatory shape name, description, node text: % optional between (): anchor specification list % optional between []: internal nodes specification list \NewDocumentCommand{\circuitdesc}{s O{1} m m m d() d[]} { \twopartbox{% \begin{circuitikz}[] \IfBooleanTF{#1}{% \draw (0,0) node[#3,scale=#2, fill=fillcol](N){#5}; }{ % if it's non-fillable, red should not go through \draw (0,0) node[#3,scale=#2, % fill=red ](N){#5}; } \IfValueT{#6}{% \foreach \n/\a/\d in {#6} \path(N.\n) \showcoord(\n)<\a:\d>; } \IfValueT{#7}{% \foreach \n/\a/\d in {#7} \path(N-\n) \showcoordb(N-\n)<\a:\d>; } \end{circuitikz}% }{\sloppy {#4, type: node\IfBooleanT{#1}{, fillable}% } (\texttt{node[\detokenize{#3}]\IfValueT{#7}{(N)}\{\detokenize{#5}\}}). \index{#3}% \checkclass{N}% }% } % description of a path-style bipole component: % optional: main name, if different from above % mandatory component name % optional between <>: shapename, if note "nodeshape" % mandatory description, comma separated alias % optional between (): anchor specification list % optional between []: internal nodes specification list % 1 2 3 4 5 6 7 8 \NewDocumentCommand{\circuitdescbip}{s o m d<> m m d() d[]} {% \index{#3}% \foreach \i in {#6} {\index{\i|seealso{#3}} }% \twopartbox{% \begin{circuitikz} \IfBooleanTF{#1}{% \draw (0,0) to[#3, name=B, fill=fillcol] (2,0); }{ % if it's non-fillable, red should not go through \draw (0,0) to[#3, name=B, %fill=red ] (2,0); } \IfValueT{#7}{% \foreach \n/\a/\d in {#7} \path(B.\n) \showcoord(\n)<\a:\d>; } \IfValueT{#8}{% \foreach \n/\a/\d in {#8} \path(B-\n) \showcoordb(B-\n)<\a:\d>; } \end{circuitikz}% }{\sloppy \texttt{\textbf{#3}}: #5, \texttt{type: path-style\IfBooleanT{#1}{, fillable}% \IfValueT{#8}{, \texttt{name=B}}% \IfValueTF{#4}{, nodename: #4.}{% \IfValueTF{#2}{, nodename: #2shape.%\drawphantomshape{#2shape}% }{, nodename: #3shape.%\drawphantomshape{#3shape}% }}% } \ifthenelse{\equal{#6}{}}{ }{ Aliases: \texttt{#6}. }\checkclass{B}% }% } % command to add the content to the index \NewDocumentCommand{\IndexKey}{O{#2} m}{% \index{\detokenize{#1}|textit}\texttt{#2}% } %new environment for grouping descriptions \newenvironment{groupdesc}{\medskip\begingroup}{\endgroup\par\medskip\par\noindent} % command to show anchors: (name) % usage in path: \path (anchor) \coord(anchor)<60> \makeatletter % we use the internal circuitikz base length \def\showcoord(#1)<#2:#3>{% node[circle, red, draw, inner sep=1pt,pin={% [red, inner sep=0.5pt, font=\small, pin distance=#3\pgf@circ@Rlen, pin edge={red, }% ]#2:#1}](#1){}} \def\showcoordb(#1)<#2:#3>{% node[circle, blue, draw, inner sep=1pt,pin={% [blue, inner sep=0.5pt, font=\small, pin distance=#3\pgf@circ@Rlen, pin edge={blue, }% ]#2:#1}](#1){}} \def\showcoordwc[#1](#2)<#3:#4>{% node[circle, #1, draw, inner sep=1pt,pin={% [#1, inner sep=0.5pt, font=\small, pin distance=#4\pgf@circ@Rlen, pin edge={#1, }% ]#3:#2}](#2){}} \makeatother % show anchors of a node component: % optional: options of the circuitikz environment % mandatory node spec, node text % optional between (): anchor specification list \NewDocumentCommand{\showanchors}{O{} m m d()} { \begin{circuitikz}[#1] \draw (0,0) node[#2](N){#3}; \IfValueT{#4}{% \foreach \n/\a/\d in {#4} \path(N.\n) \showcoord(\n)<\a:\d>; } \end{circuitikz}% } \newcommand{\geolrcoord}[2][]{\showanchors[#1]{#2}{text}(north/90/0.4, north east/45/0.4, east/0/0.4, south east/-45/0.4, south/-90/0.4, south west/-135/0.4, west/180/0.4, north west/135/0.4, left/160/0.4, right/30/0.4, center/-120/0.3 ) } \newcommand{\geocoord}[2][]{\showanchors[#1]{#2}{text}(north/90/0.4, north east/45/0.4, east/0/0.4, south east/-45/0.4, south/-90/0.4, south west/-135/0.4, west/180/0.4, north west/135/0.4, center/-120/0.3 ) }