% Copyright 2010-2022 Louis Paternault % % 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 Louis Paternault % % This work consists of the files thalie.tex and thalie.sty. \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{thalie} [2022/12/11 v0.13a A package to typeset drama plays] \RequirePackage{pgfkeys} \RequirePackage{etoolbox} \RequirePackage{suffix} \RequirePackage{tabularx} \RequirePackage{xspace} \RequirePackage{translations} \LoadDictionary{thalie} \LoadDictionaryFor{fallback}{thalie} \newcommand{\playname}{\GetTranslation{Play}} \newcommand{\actname}{\GetTranslation{Act}} \newcommand{\scenename}{\GetTranslation{Scene}} \newcommand{\interludename}{\GetTranslation{Interlude}} \newcommand{\curtainname}{\GetTranslation{Curtain}} \newcommand{\pausename}{\GetTranslation{Pause}} \newcommand{\playmark}[1]{% \markboth{\MakeUppercase{#1}}{}% } \newcommand{\actmark}[1]{% \markright{\MakeUppercase{% \GetTranslation{Act}\ \theact% \ifdefempty{#1}{}{: #1}% }}% } \newcommand{\scenemark}[1]{% } \newcounter{play} \renewcommand{\theplay}{\arabic{play}} \newcounter{act}[play] \renewcommand{\theact}{\Roman{act}} \newcounter{scene}[act] \renewcommand{\thescene}{\arabic{scene}} \newcommand{\@displaytitle}[3]{ % Arguments: % - Style % - Label (none = not in toc) % - Title \ifdefstring{#1}{center}{ \begin{center} \textsc{#2} #3 \end{center} }{\ifdefstring{#1}{bigcenter}{ \begin{center} \Large \textsc{#2} #3 \end{center} }{\ifdefstring{#1}{box}{ \begin{center} \framebox{\begin{minipage}{0.7\textwidth} \begin{center} \Large \bfseries \vspace{0.5em} #2 \ifboolexpr{test{\ifstrempty{#3}} or test{\ifstrempty{#2}}}{}{---} #3 \vspace{0.5em} \end{center} \end{minipage}} \end{center} \vspace{1em} }{}}}% } \newcommand\@clearpage[1]{% % Clear page if necessary \ifboolexpr{test{\ifdefstring{#1}{part}} or test{\ifdefstring{#1}{chapter}}}{ \cleardoublepage \thispagestyle{empty} }{}% } \newcommand{\play}[2][]{% \refstepcounter{play} \ifstrempty{#1}{ \def\@short{#2} }{ \def\@short{#1} } \@clearpage{\@playlevel} \playmark{\@short} \addcontentsline{toc}{\@playlevel}{\@short} \ifdefstring{\@playstyle}{custom}{ \customplay{\theplay}{#2} }{ \@displaytitle{\@playstyle}{}{#2} } } \WithSuffix\newcommand\play*[1]{% \@clearpage{\@playlevel} \ifdefstring{\@playstyle}{custom}{ \customplay*{#1} }{ \@displaytitle{\@playstyle}{}{#1} } } \newcommand{\act}[2][]{% \refstepcounter{act} \ifstrempty{#1}{ \def\@short{#2} }{ \def\@short{#1} } \ifdefempty{\@short}{ \def\@label{\GetTranslation{Act} \theact{}} }{ \def\@label{\GetTranslation{Act} \theact{}\xspace: } } \@clearpage{\@actlevel} \actmark{\@short} \addcontentsline{toc}{\@actlevel}{\@label\@short} \ifdefstring{\@actstyle}{custom}{ \customact{\theact}{#2} }{ \@displaytitle{\@actstyle}{\GetTranslation{Act} \theact}{#2} } } \WithSuffix\newcommand\act*[1]{% \@clearpage{\@actlevel} \ifdefstring{\@actstyle}{custom}{ \customact*{#1} }{ \@displaytitle{\@actstyle}{}{#1} } } \newcommand{\scene}[2][]{% \refstepcounter{scene} \ifstrempty{#1}{ \def\@short{#2} }{ \def\@short{#1} } \ifdefempty{\@short}{ \def\@label{\GetTranslation{Scene} \thescene{}} }{ \def\@label{\GetTranslation{Scene} \thescene{}\xspace: } } \@clearpage{\@scenelevel} \scenemark{\@short} \addcontentsline{toc}{\@scenelevel}{\@label\@short} \ifdefstring{\@scenestyle}{custom}{ \customscene{\thescene}{#2} }{ \@displaytitle{\@scenestyle}{\GetTranslation{Scene} \thescene}{#2} } } \WithSuffix\newcommand\scene*[1]{% \@clearpage{\@scenelevel} \ifdefstring{\@scenestyle}{custom}{ \customscene*{#1} }{ \@displaytitle{\@scenestyle}{}{#1} } } \newcommand{\interlude}[2][]{% \ifstrempty{#1}{ \def\@short{#2} }{ \def\@short{#1} } \ifdefempty{\@short}{ \def\@label{\GetTranslation{Interlude}} }{ \def\@label{\GetTranslation{Interlude}\xspace: } } \ifdefstring{\@interludelevel}{play}{ \@clearpage{\@playlevel} \playmark{\@short} \addcontentsline{toc}{\@playlevel}{\@label\@short} \@displaytitle{\@playstyle}{\GetTranslation{Interlude}}{#2} }{\ifdefstring{\@interludelevel}{act}{ \@clearpage{\@actlevel} \actmark{\@short} \addcontentsline{toc}{\@actlevel}{\@label\@short} \@displaytitle{\@actstyle}{\GetTranslation{Interlude}}{#2} }{% \@interludelevel is scene \@clearpage{\@scenelevel} \scenemark{\@short} \addcontentsline{toc}{\@scenelevel}{\@label\@short} \@displaytitle{\@scenestyle}{\GetTranslation{Interlude}}{#2} }} } \WithSuffix\newcommand\interlude*[1]{% \ifdefstring{\@interludelevel}{play}{ \@clearpage{\@playlevel} \@displaytitle{\@playstyle}{\GetTranslation{Interlude}}{#1} }{\ifdefstring{\@interludelevel}{act}{ \@clearpage{\@actlevel} \@displaytitle{\@actstyle}{\GetTranslation{Interlude}}{#1} }{% \@interludelevel is scene \@clearpage{\@scenelevel} \@displaytitle{\@scenestyle}{\GetTranslation{Interlude}}{#1} }} } \newcommand\curtain{ \begin{center} \Large\textsc{\GetTranslation{Curtain}} \end{center} } \newcommand{\@maybexspace}{% \if@xspace% \xspace% \fi% } \newcommand{\@speaks}[2][]{% \ifstrempty{#1}{% \speakswithoutdirection{#2}% }{% \speakswithdirection{#2}{#1}% }\@maybexspace% } \newenvironment{@smallcenter} {\par\smallskip\centering} {\par\nopagebreak\ignorespacesafterend} \providecommand{\speakswithdirection}{} \providecommand{\speakswithoutdirection}{} \newcommand{\@setcharacterstyle}[1]{ \ifstrequal{#1}{bold}{% % Bold style \renewcommand\speakswithdirection[2]{% \noindent% {\bfseries\sffamily ##1} \emph{(##2)}\xspace:% } \renewcommand\speakswithoutdirection[1]{% \noindent% {\bfseries\sffamily ##1\xspace:}% }% }{}% \ifstrequal{#1}{center}{% % Center style \renewcommand\speakswithdirection[2]{% \begin{center}% \textsc{##1},\\\emph{##2}% \end{center}% \par\ignorespacesafterend% }% \renewcommand\speakswithoutdirection[1]{% \begin{center}% \textsc{##1}% \end{center}% \par\ignorespacesafterend% }% }{}% \ifstrequal{#1}{imprimerie-verse}{% % Style for verse plays defined by the French Imprimerie nationale \renewcommand\speakswithdirection[2]{% \begin{@smallcenter}% \textsc{##1}, \emph{##2}% \end{@smallcenter}% }% \renewcommand\speakswithoutdirection[1]{% \begin{@smallcenter}% \textsc{##1}% \end{@smallcenter}% }% }{}% \ifstrequal{#1}{imprimerie-prose}{% % Style for prose plays defined by the French Imprimerie nationale \renewcommand\speakswithdirection[2]{% \noindent\hspace*{-\parindent}\textsc{##1}, \emph{##2}\xspace:% }% \renewcommand\speakswithoutdirection[1]{% \noindent\hspace*{-\parindent}\textsc{##1}\xspace:% }% }{}% \ifstrequal{#1}{arden}{% \renewcommand\speakswithdirection[2]{% \noindent\hspace*{-\parindent}\textsc{\MakeLowercase{##1}} [\emph{##2}]\quad% }% \renewcommand\speakswithoutdirection[1]{% \noindent\hspace*{-\parindent}\textsc{\MakeLowercase{##1}}\quad% }% }{}% \ifstrequal{#1}{simple}{% % Simple style \renewcommand\speakswithdirection[2]{% \indent\textsc{##1}, \emph{##2}\xspace:% }% \renewcommand\speakswithoutdirection[1]{% \indent\textsc{##1}\xspace:% }% }{}% \ifstrequal{#1}{margin}{% % Margin style \setlength{\leftskip}{3cm} \renewcommand\speakswithdirection[2]{% \hspace{-3cm} ##1 ##2 } \renewcommand\speakswithoutdirection[1]{% \hspace{-3cm} ##1 }% }{}% } \providebool{@dramatis@hidden} \pgfkeys{ % Character definition /THALIE/DRAMATIS/.is family, /THALIE/DRAMATIS, hidden/.default=true, hidden/.is choice, hidden/true/.code=\booltrue{@dramatis@hidden}, hidden/false/.code=\boolfalse{@dramatis@hidden}, defaultcast/.default={}, defaultcast/.value required, defaultcast/.store in=\@defaultcast, } \newcommand{\@dramatis@clear}{} \newcommand{\@empty@}{} \newenvironment{dramatis}[1][]{ \@dramatis@clear{} \undef{\@dramatis@clear} \pgfkeys{/THALIE/DRAMATIS/.cd, #1} \ifbool{@dramatis@hidden}{% % Nothing }{% \dramatisenv% }% }{% \notbool{@dramatis@hidden}{% \enddramatisenv }{}% } \newenvironment{dramatisenv}{% \list{}{\rightmargin1cm\leftmargin2cm}\item[] }{% \endlist% } \newcommand{\dramatischaractername}[1]{\textbf{#1}} \newcommand{\dramatischaracterdescription}[1]{#1} \newcommand{\dramatischaractercast}[1]{#1} \newcommand{\characterspace}{ % \notbool{@dramatis@hidden}{% \smallskip\newline % }{}% } \newcommand{\dramatischaracter}[3]{ % \hspace*{-1cm} % \ifboolexpr{(not test {\ifdefempty{#1}}) and test {\ifdefempty{#2}}}{% \dramatischaractername{#1} % }{}% \ifboolexpr{ test{\ifdefempty{#1}} and not test{\ifdefempty{#2}}}{% \dramatischaracterdescription{#2} % }{}% \ifboolexpr{ (not test{\ifdefempty{#1}}) and (not test{\ifdefempty{#2}})}{% \dramatischaractername{#1}, \dramatischaracterdescription{#2} % }{}% \ifdefempty{#3}{}{\dotfill\dramatischaractercast{#3}}% \newline % } \newlength{\@spaceaftergroup} \newenvironment{dramatischaractergroup}[2]{ \gdef\@groupname{#2} % \gdef\@grouplength{#1} % \hspace*{-1.3pt}\math\left. % \minipage[c]{#1} % \vspace*{2pt} % }{% \vspace*{-8pt} % \endminipage % \right\} \endmath % % \setlength{\@spaceaftergroup}{\linewidth} \addtolength\@spaceaftergroup{-\@grouplength} \addtolength\@spaceaftergroup{-20pt} \begin{minipage}[c]{\@spaceaftergroup} \@groupname % \end{minipage} \newline % } \newenvironment{charactergroup}[2][5cm]{% \notbool{@dramatis@hidden}{% \dramatischaractergroup{#1}{#2} }{}% }{% \notbool{@dramatis@hidden}{% \enddramatischaractergroup }{}% } \newenvironment{dramatischaractercastgroup}[3]{% \ifdefempty{#3}{ \hspace*{-1cm} % \ifboolexpr{(not test {\ifdefempty{#1}}) and test {\ifdefempty{#2}}}{% \dramatischaractername{#1} % }{}% \ifboolexpr{ test{\ifdefempty{#1}} and not test{\ifdefempty{#2}}}{% \dramatischaracterdescription{#2} % }{}% \ifboolexpr{ (not test{\ifdefempty{#1}}) and (not test{\ifdefempty{#2}})}{% \dramatischaractername{#1}, \dramatischaracterdescription{#2} % }{}% \hfill% }{ \ClassError{thalie}{% Environment "castgroup" cannot have a non-empty "cast" argument.% }{}% }% }{} \newenvironment{castgroup}[2][]{% \@thalie@parsecharacter{#1}{#2}{dramatischaractercastgroup}% \notbool{@dramatis@hidden}{% \math\left\{% \array{r}% }{}% }{% \notbool{@dramatis@hidden}{% \endarray% \right.\endmath% \newline% }{}% \enddramatischaractercastgroup } \newcommand{\dramatiscast}[1]{% % Command used to display cast inside a castgroup. % Can be redefined by user. \notbool{@dramatis@hidden}{% \hbox{\dramatischaractercast{#1}\hspace*{-6pt}}\tabularnewline% }{}% } \newcommand{\cast}[1]{% % "Public" command, used by author in the dramatis personae. % Does nothing fancy right now, but how knows? \dramatiscast{#1}% } \newcommand{\setcharactername}[2]{% \expandafter\gdef\csname#1name\endcsname{% #2\@maybexspace% }% \expandafter\gdef\csname#1\endcsname{% \@ifnextchar[{% \defcharcommand@with{#2}% }{% \defcharcommand@without{#2}% }% }% \xappto{\@dramatis@clear}{% \global\noexpand\csundef{#1}% \global\noexpand\csundef{#1name}% }% } \newcommand{\@definecharactercommand}[2]{% \ifcsdef{#1}{% \ClassError{thalie}{% A command named \@backslashchar#1 already exists. We cannot define a new one.% }{% Choose another command name to introduce character #2's lines.% }% }{% }% \ifcsdef{#1name}{% \ClassError{thalie}{% A command named \@backslashchar#1name already exists. We cannot define a new one.% }{% Choose another command name to introduce character #2's lines, such that when a new command is defined by adding "name" to it, it does not conflict with an existing one. }% }{% }% \setcharactername{#1}{#2}% } \def\defcharcommand@with#1[#2]{\@speaks[#2]{#1}} \def\defcharcommand@without#1{\@speaks{#1}} \pgfkeys{ % Character definition /THALIE/CHARACTER/.is family, /THALIE/CHARACTER, cmd/.value required, cmd/.store in=\@cmd, cast/.value required, cast/.store in=\@cast, drama/.value required, drama/.store in=\@drama, desc/.value required, desc/.store in=\@desc, } \newcommand{\@thalie@parsecharacter}[3]{% % Parse a character definition. Arguments are: % #1: Optional arguments of \character: [drama={foo}, cast={bar}] % #2: Mandatory argument of \character (character name) % #3: Name of the command to call to display this character definition. \undef{\@drama} \undef{\@cmd} \undef{\@cast} \undef{\@desc} \pgfkeys{/THALIE/CHARACTER, #1}% \ifcsundef{@cast}{% \ifcsdef{@defaultcast}{% \gdef\@cast{\@defaultcast}% }{% \gdef\@cast{}% }% }{}% % Forbidden combinations \ifboolexpr{ ( ( test{\ifdef{\@cmd}} and not test{\ifdefempty{\@cmd}} ) and test{\ifstrempty{#2}} ) or ( ( test{\ifundef{\@cmd}} or test{\ifdefempty{\@cmd}} ) and not test{\ifstrempty{#2}} ) or ( test{\ifdefempty{\@drama}} and ( test{\ifdef{\@desc}} and not test{\ifdefempty{\@desc}} ) ) or ( test{\ifundef{\@cmd}} and test{\ifundef{\@desc}} and test{\ifundef{\@drama}} and test{\ifstrempty{#2}} ) or %( ( test{\ifundef{\@cmd}} or test{\ifdefempty{\@cmd}} ) and test{\ifstrempty{#2}} and ( test{\ifdefempty{\@drama}} or test{\ifundef{\@drama}} )) ( ( test{\ifundef{\@desc}} or test{\ifdefempty{\@desc}} ) and test{\ifstrempty{#2}} and ( test{\ifdefempty{\@drama}} or test{\ifundef{\@drama}} )) }{ \ClassError{thalie}{Invalid character definition.}{All combination of omitted arguments are not allowed. See the documentation for more information} }{}% % Defining character command \ifboolexpr{ test{\ifdef{\@cmd}} and (not test{\ifstrempty{#2}}) }{% \@definecharactercommand{\@cmd}{#2} }{}% \ifboolexpr{ bool{@dramatis@hidden} or test{\ifdefempty{\@drama}} }{% % Hidden character. Nothing added to dramatis personae }{% \ifcsundef{@desc}{\gdef\@desc{}}{}% \ifcsundef{@drama}{\gdef\@drama{#2}}{}% \csuse{#3}{\@drama}{\@desc}{\@cast}% }% } \newcommand{\character}[2][]{% \@thalie@parsecharacter{#1}{#2}{dramatischaracter}% } \newcommand{\disposablecharacter}[2][]{% \@speaks[#1]{#2}% } \newcommand{\onstage}[1]{{\centering \emph{#1}\par\medskip}} \newcommand{\did}[1]{\emph{(#1)}\@maybexspace} \newenvironment{dida}{% \begin{quote} \begin{em} }{% \end{em} \end{quote} } \newcommand\pause{\did{\GetTranslation{Pause}}} \newlength{\@verseadjust} \setlength{\@verseadjust}{0pt} \newcommand{\adjustverse}[1]{\setlength{\@verseadjust}{#1}} \newcommand{\pauseverse}{{\abovedisplayshortskip\z@\abovedisplayskip\z@ \belowdisplayshortskip\z@\belowdisplayskip\z@ $$\global\dimen\@ne\predisplaysize \xdef\tmp{% \predisplaysize\the\predisplaysize \prevgraf\the\prevgraf\relax}% $$\vskip\dimexpr-\parskip-\baselineskip\relax}\tmp } \newcommand{\resumeverse}{% \hspace{\@verseadjust}\hspace{\the\dimen\@ne} } \RequirePackage{pgfopts} \pgfkeys{ % Character style /THALIE/.cd, characterstyle/.value required, characterstyle/.default=simple, characterstyle/.is choice, characterstyle/bold/.code=\@setcharacterstyle{bold}, characterstyle/center/.code=\@setcharacterstyle{center}, characterstyle/margin/.code=\@setcharacterstyle{margin}, characterstyle/simple/.code=\@setcharacterstyle{simple}, characterstyle/arden/.code=\@setcharacterstyle{arden}, characterstyle/imprimerie-verse/.code=\@setcharacterstyle{imprimerie-verse}, characterstyle/imprimerie-prose/.code=\@setcharacterstyle{imprimerie-prose}, characterstyle, } \pgfkeys{ % play style /THALIE/.cd, playstyle/.value required, playstyle/.default=box, playstyle/.is choice, playstyle/center/.code=\def\@playstyle{center}, playstyle/bigcenter/.code=\def\@playstyle{bigcenter}, playstyle/box/.code=\def\@playstyle{box}, playstyle/custom/.code=\def\@playstyle{custom}, playstyle, } \pgfkeys{ % act style /THALIE/.cd, actstyle/.value required, actstyle/.default=bigcenter, actstyle/.is choice, actstyle/center/.code=\def\@actstyle{center}, actstyle/bigcenter/.code=\def\@actstyle{bigcenter}, actstyle/box/.code=\def\@actstyle{box}, actstyle/custom/.code=\def\@actstyle{custom}, actstyle, } \pgfkeys{ % scene style /THALIE/.cd, scenestyle/.value required, scenestyle/.default=center, scenestyle/.is choice, scenestyle/center/.code=\def\@scenestyle{center}, scenestyle/bigcenter/.code=\def\@scenestyle{bigcenter}, scenestyle/box/.code=\def\@scenestyle{box}, scenestyle/custom/.code=\def\@scenestyle{custom}, scenestyle, } \pgfkeys{ % play level /THALIE/.cd, playlevel/.value required, playlevel/.default=chapter, playlevel/.store in=\@playlevel, playlevel, } \pgfkeys{ % act level /THALIE/.cd, actlevel/.value required, actlevel/.default=section, actlevel/.store in=\@actlevel, actlevel, } \pgfkeys{ % scene level /THALIE/.cd, scenelevel/.value required, scenelevel/.default=subsection, scenelevel/.store in=\@scenelevel, scenelevel, } \pgfkeys{ % interlude level /THALIE/.cd, interludelevel/.value required, interludelevel/.default=act, interludelevel/.is choice, interludelevel/play/.code=\def\@interludelevel{play}, interludelevel/act/.code=\def\@interludelevel{act}, interludelevel/scene/.code=\def\@interludelevel{scene}, interludelevel, } \newif\if@xspace \pgfkeys{ % xspace option /THALIE/.cd, xspace/.value required, xspace/.is if=@xspace, xspace/.default=true, xspace, } \ProcessPgfPackageOptions{/THALIE} \newcommand{\setthalieoptions}[1]{% \pgfkeys{/THALIE/.cd, #1}% } \endinput %% %% End of file `thalie.sty'.