% 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'.