% \iffalse meta-comment % A LaTeX Class for Semantic Lectures Slides (originally developed for Michael Kohlhase) % Copyright (c) 2019 Michael Kohlhase, all rights reserved % this file is released under the % Gnu Library Public Licences (LGPL) % % The original of this file is in the public repository at % http://github.com/sLaTeX/sTeX/ % \fi % % \iffalse % %<*driver> \def\stexdocpath{../doc} \input{\stexdocpath/stex-docheader} \stextoptitle{NotesSlides -- Slides and Course Notes}{notesslides} \docmodule % % \fi % % % \begin{stexmanual} % \begin{sfragment}{NotesSlides Manual} % \input{\stexdocpath/packages/stex-notesslides} % \end{sfragment} % \end{stexmanual} % % \begin{documentation} % \begin{sfragment}{NotesSlides Documentation} % TODO % \end{sfragment} % \end{documentation} % % % \begin{implementation}\label{pkg:notesslides:impl} % % \begin{sfragment}{Implementation: The notesslides Package} % %\begin{sfragment}[id=sec:impl:init]{Class and Package Options} % % We define some Package Options and switches for the |notesslides| class and activate them % by passing them on to |beamer.cls| and |omdoc.cls| and the |notesslides| package. We pass % the |nontheorem| option to the |statements| package when we are not in notes mode, since % the |beamer| package has its own (overlay-aware) theorem environments. % % \begin{macrocode} %<*cls> %<@@=notesslides> \ProvidesExplClass{notesslides}{2023/10/13}{3.4.0}{notesslides Class} \RequirePackage{l3keys2e} \str_const:Nn \c_@@_class_str {article} \keys_define:nn{notesslides / cls}{ class .str_set_x:N = \c_@@_class_str, notes .bool_set:N = \c_notesslides_notes_bool , slides .code:n = { \bool_set_false:N \c_notesslides_notes_bool }, %docopt .str_set_x:N = \c_@@_docopt_str, unknown .code:n = { \PassOptionsToClass{\CurrentOption}{beamer} \PassOptionsToClass{\CurrentOption}{\c_@@_class_str} \PassOptionsToPackage{\CurrentOption}{notesslides} \PassOptionsToPackage{\CurrentOption}{stex} } } \ProcessKeysOptions{ notesslides / cls } \RequirePackage{stex} \stex_if_html_backend:T { \bool_set_true:N\c_notesslides_notes_bool } \bool_if:NTF \c_notesslides_notes_bool { \PassOptionsToPackage{notes=true}{notesslides} \message{notesslides.cls:~Formatting~document~in~notes~mode} }{ \PassOptionsToPackage{notes=false}{notesslides} \message{notesslides.cls:~Formatting~document~in~slides~mode} } \bool_if:NTF \c_notesslides_notes_bool { \LoadClass{\c_@@_class_str} }{ \LoadClass[10pt,notheorems,xcolor={dvipsnames,svgnames}]{beamer} %\newcounter{Item} %\newcounter{paragraph} %\newcounter{subparagraph} %\newcounter{Hfootnote} } \RequirePackage{notesslides} % % \end{macrocode} % now we do the same for the |notesslides| package. % \begin{macrocode} %<*package> \ProvidesExplPackage{notesslides}{2023/10/13}{3.4.0}{notesslides Package} \RequirePackage{l3keys2e} \keys_define:nn{notesslides / pkg}{ notes .bool_set:N = \c_notesslides_notes_bool , slides .code:n = { \bool_set_false:N \c_notesslides_notes_bool }, sectocframes .bool_set:N = \c_notesslides_sectocframes_bool , topsect .str_set_x:N = \c_notesslides_topsect_str, unknown .code:n = { \PassOptionsToPackage{\CurrentOption}{stex} \PassOptionsToPackage{\CurrentOption}{tikzinput} } } \ProcessKeysOptions{ notesslides / pkg } \RequirePackage{stex} \stex_if_html_backend:T { \bool_set_true:N\c_notesslides_notes_bool } \cs_set:Npn \sectiontitleemph #1 { \textbf{\Large #1} } \newif\ifnotes \bool_if:NTF \c_notesslides_notes_bool { \notestrue \PassOptionsToPackage{usenames,dvipsnames,svgnames}{xcolor} \RequirePackage[noamsthm,hyperref]{beamerarticle} \RequirePackage{mdframed} \str_if_empty:NTF \c_notesslides_topsect_str{ %\setsectionlevel{section} } { \exp_args:No \setsectionlevel \c_notesslides_topsect_str } }{ \notesfalse \cs_new_protected:Nn \_@@_do_sectocframes: { \cs_set_protected:Nn \_@@_do_label:n { \str_case:nnF{##1}{ {part} { \tl_set:Nx\l_@@_num{\thepart} \tl_set:cx{@ @ label}{ \cs_if_exist:NTF\parttitlename{\exp_not:N\parttitlename}{\exp_not:N\partname}{}~\l_@@_num\\} } {chapter} { \tl_set:Nx\l_@@_num{\thechapter} \tl_set:cx{@ @ label}{ \cs_if_exist:NTF\chaptertitlename{\exp_not:N\chaptertitlename}{\exp_not:N\chaptername}{}~\l_@@_num\\} } {section} { \tl_set:Nx\l_@@_num{\cs_if_exist:NT\thechapter{\thechapter.}\thesection} \tl_set:cx{@ @ label}{\l_@@_num\quad} } {subsection} { \tl_set:Nx\l_@@_num{\cs_if_exist:NT\thechapter{\thechapter.}\thesection.\thesubsection} \tl_set:cx{@ @ label}{\l_@@_num\quad} } {subsubsection} { \tl_set:Nx\l_@@_num{\cs_if_exist:NT\thechapter{\thechapter.}\thesection.\thesubsection.\thesubsubsection} \tl_set:cx{@ @ label}{\l_@@_num\quad} } {paragraph} { \tl_set:Nx\l_@@_num{\cs_if_exist:NT\thechapter{\thechapter.}\thesection.\thesubsection.\thesubsubsection.\theparagraph} \tl_set:cx{@ @ label}{\l_@@_num\quad} } }{ \tl_set:Nx\l_@@_num{\cs_if_exist:NT\thechapter{\thechapter.}\thesection.\thesubsection.\thesubsubsection.\theparagraph.\thesubparagraph} \tl_set:cx{@ @ label}{\l_@@_num\quad} } } \cs_set_protected:Nn \_sfragment_do_level:nn { \tl_if_exist:cT{c@##1}{\stepcounter{##1}} \addcontentsline{toc}{##1}{\protect\numberline{\use:c{the##1}}##2} \_@@_do_label:n{##1} \pdfbookmark[\int_use:N \l_stex_docheader_sect]{\l_@@_num\ ##2}{##1.\l_@@_num} \begin{frame}[noframenumbering] \vfill\centering \sectiontitleemph{ \use:c{@ @ label} ##2 } \end{frame} \int_incr:N \l_stex_docheader_sect \tl_set:Nn \stex_current_section_level{##1} } } \AtBeginDocument{ \str_if_empty:NTF \c_notesslides_topsect_str { \setsectionlevel{section} } { \exp_args:No \setsectionlevel \c_notesslides_topsect_str \exp_args:No \str_if_eq:nnTF \c_notesslides_topsect_str {chapter} { \_@@_define_chapter: }{ \exp_args:No \str_if_eq:nnT \c_notesslides_topsect_str {part} { \_@@_define_chapter: \_@@_define_part: } } } } \bool_if:NT \c_notesslides_sectocframes_bool { \_@@_do_sectocframes: } } \cs_new_protected:Nn \_@@_define_chapter: { \cs_if_exist:NF \chaptername { \cs_set_protected:Npn \chaptername {Chapter} } \cs_if_exist:NF \chapter { \cs_set_protected:Npn \chapter {INVALID} } \cs_if_exist:NF \c@chapter { \newcounter{chapter}\counterwithin*{section}{chapter} } } \cs_new_protected:Nn \_@@_define_part: { \cs_if_exist:NF \partname { \cs_set_protected:Npn \partname {Part} } \cs_if_exist:NF \part { \cs_set_protected:Npn \part {INVALID} } \cs_if_exist:NF \c@part { \newcounter{part}\counterwithin*{chapter}{part} } } % \end{macrocode} % % \begin{macro}{\prematurestop} % We initialize |\afterprematurestop|, and provide % |\prematurestop@endsfragment| which looks up |\sfragment@level| and recursively ends % enough |{sfragment}|s. % \begin{macrocode} \def \c_@@_document_str{document} \newcommand\afterprematurestop{} \def\prematurestop@endsfragment{ \unless\ifx\@currenvir\c_@@_document_str \expandafter\expandafter\expandafter\end\expandafter\expandafter\expandafter{\expandafter\@currenvir\expandafter} \expandafter\prematurestop@endsfragment \fi } \providecommand\prematurestop{ \stex_if_html_backend:F{ \message{Stopping~sTeX~processing~prematurely} \prematurestop@endsfragment \afterprematurestop \end{document} } } % \end{macrocode} % \end{macro} % % \end{sfragment} % \begin{sfragment}[id=sec:impl:noteslides]{Notes and Slides} % For the notes case, we also provide the |\usetheme| macro that would otherwise % come from the the |beamer| class. % \begin{macrocode} \bool_if:NT \c_notesslides_notes_bool { \renewcommand\usetheme[2][]{\usepackage[#1]{beamertheme#2}} } \NewDocumentCommand \libusetheme {O{} m} { \libusepackage[#1]{beamertheme#2} } % \end{macrocode} % We define the sizes of slides in the notes. Somehow, we cannot get by with the same % here. % \begin{macrocode} \newlength{\slidewidth}\setlength{\slidewidth}{13.5cm} \newlength{\slideheight}\setlength{\slideheight}{9cm} % \end{macrocode} % % We first set up the slide boxes in |notes| mode. We set up sizes and provide a % box register for the frames and a counter for the slides. % % \begin{macrocode} \ifnotes \newlength{\slideframewidth} \setlength{\slideframewidth}{1.5pt} % \end{macrocode} % % \begin{environment}{frame} % We first define the keys. % \begin{macrocode} \cs_new_protected:Nn \_@@_do_yes_param:Nn { \exp_args:Nx \str_if_eq:nnTF { \str_uppercase:n{ #2 } }{ yes }{ \bool_set_true:N #1 }{ \bool_set_false:N #1 } } \stex_keys_define:nnnn{notesslides / frame}{ \str_clear:N \l_@@_frame_label_str \bool_set_true:N \l_@@_frame_allowframebreaks_bool \bool_set_true:N \l_@@_frame_allowdisplaybreaks_bool \bool_set_true:N \l_@@_frame_fragile_bool \bool_set_true:N \l_@@_frame_shrink_bool \bool_set_true:N \l_@@_frame_squeeze_bool \bool_set_true:N \l_@@_frame_t_bool }{ label .str_set_x:N = \l_@@_frame_label_str, allowframebreaks .code:n = { \_@@_do_yes_param:Nn \l_@@_frame_allowframebreaks_bool { #1 } }, allowdisplaybreaks .code:n = { \_@@_do_yes_param:Nn \l_@@_frame_allowdisplaybreaks_bool { #1 } }, fragile .code:n = { \_@@_do_yes_param:Nn \l_@@_frame_fragile_bool { #1 } }, shrink .code:n = { \_@@_do_yes_param:Nn \l_@@_frame_shrink_bool { #1 } }, squeeze .code:n = { \_@@_do_yes_param:Nn \l_@@_frame_squeeze_bool { #1 } }, t .code:n = { \_@@_do_yes_param:Nn \l_@@_frame_t_bool { #1 } }, unknown .code:n = {} }{} % \end{macrocode} % % We redefine the |itemize| environment so that it looks more like the one in |beamer|. % % \begin{macrocode} \cs_new_protected:Nn \_@@_setup_itemize: { \def\itemize@level{outer} \def\itemize@outer{outer} \def\itemize@inner{inner} %\newcommand\metakeys@show@keys[2]{\marginnote{{\scriptsize ##2}}} \renewenvironment{itemize}{ \ifx\itemize@level\itemize@outer \def\itemize@label{$\rhd$} \fi \ifx\itemize@level\itemize@inner \def\itemize@label{$\scriptstyle\rhd$} \fi \begin{list} {\itemize@label} {\setlength{\labelsep}{.3em} \setlength{\labelwidth}{.5em} \setlength{\leftmargin}{1.5em} } \edef\itemize@level{\itemize@inner} }{ \end{list} } } % \end{macrocode} % % We create the box with the |mdframed| environment from the equinymous package. % % \begin{macrocode} \stex_if_html_backend:TF { \cs_new_protected:Nn \_@@_frame_box_begin: { \vbox\bgroup \begin{stex_annotate_env}{shtml:frame={}} \mdf@patchamsthm\notesslidesfont } \cs_new_protected:Nn \_@@_frame_box_end: { %^^A \notesslides@slidelabel \medskip\par\noindent\tiny\notesslidesfooter \end{stex_annotate_env}\egroup } }{ \cs_new_protected:Nn \_@@_frame_box_begin: { \begin{mdframed}[ linewidth=\slideframewidth, skipabove=1ex, skipbelow=1ex, userdefinedwidth=\slidewidth, align=center ]\notesslidesfont } \cs_new_protected:Nn \_@@_frame_box_end: { \medskip\par\noindent\tiny\notesslidesfooter%^^A\notesslides@slidelabel \end{mdframed} } } % \end{macrocode} % % We define the environment, read them, and construct the slide number and label. % % \begin{macrocode} \renewenvironment{frame}[1][]{ \stex_keys_set:nn{notesslides / frame}{#1} \stepcounter{framenumber} \renewcommand\newpage{\addtocounter{framenumber}{1}} \def\@currentlabel{\theframenumber} \str_if_empty:NF \l_@@_frame_label_str { \label{\l_@@_frame_label_str} } \_@@_setup_itemize: \_@@_frame_box_begin: }{ \_@@_frame_box_end: } % \end{macrocode} % \end{environment} % % Now, we need to redefine the frametitle (we are still in course notes mode). % \begin{macro}{\frametitle} % \begin{macrocode} \renewcommand{\frametitle}[1]{ \stexdoctitle { #1 } \notesslidestitleemph{#1}\medskip } % \end{macrocode} % \end{macro} % % \begin{macro}{\pause} % \begin{macrocode} \newcommand\pause{} % \end{macrocode} % \end{macro} % % We redefine the \env{columns} and \env{column} environments: % % \begin{macrocode} \renewenvironment{columns}[1][]{ \par\noindent \begin{minipage} \slidewidth\centering\leavevmode % \stex_if_html_backend:T{ % \cs_if_exist:NT \rustex_if:T { % \rustex_if:T {\par % \rustex_direct_HTML:n{
} % } % } % } }{ % \stex_if_html_backend:T{ % \cs_if_exist:NT \rustex_if:T { % \rustex_if:T {\par % \rustex_direct_HTML:n{
} % } % } % } \end{minipage}\par\noindent } \newsavebox\columnbox \renewenvironment<>{column}[2][]{ \begin{lrbox}{\columnbox} % \stex_if_html_backend:T{ % \cs_if_exist:NT \rustex_if:T { % \rustex_if:T {\par % \rustex_direct_HTML:n{} % } % } % } \begin{minipage}{#2} }{ \end{minipage} % \stex_if_html_backend:T{ % \cs_if_exist:NT \rustex_if:T { % \rustex_if:T {\par % \rustex_direct_HTML:n{} % } % } % } \end{lrbox}\usebox\columnbox } % \end{macrocode} % % % \begin{macrocode} \fi % \end{macrocode} % % \end{sfragment} % % \begin{sfragment}{Environment and Macro Patches} % % The \env{note} environment is used to leave out text in the |slides| mode. It does not have % a counterpart in OMDoc. So for course notes, we define the \env{note} environment to be a % no-operation otherwise we declare the \env{note} environment to produce no % output. % % \begin{macrocode} \bool_if:NTF \c_notesslides_notes_bool { \renewenvironment{note}{\ignorespaces}{} }{ \renewenvironment{note}{\setbox \l_tmpa_box\vbox\bgroup}{\egroup} } % \end{macrocode} % % For other environments we introduce variants prefixed with |n|, % which are excluded in |slides| mode. % % \begin{macrocode} \cs_new_protected:Nn \_@@_notes_env:nnnn { \bool_if:NTF \c_notesslides_notes_bool { \newenvironment{#1}#2{#3}{#4} }{ \newenvironment{#1}#2{ \cs_set:Npn \_@@_eat: ####1 \end ####2 { \str_if_eq:nnTF{#1}{####2}{ \end{#1} }{ \_@@_eat: } } \_@@_eat: %\setbox\l_tmpa_box\vbox\bgroup#3 }{ %#4\egroup } } } \_@@_notes_env:nnnn{nparagraph}{[1][]}{\begin{sparagraph}[#1]}{\end{sparagraph}} \_@@_notes_env:nnnn{nfragment}{[2][]}{\begin{sfragment}[#1]{#2}}{\end{sfragment}} \_@@_notes_env:nnnn{ndefinition}{[1][]}{\begin{sdefinition}[#1]}{\end{sdefinition}} \_@@_notes_env:nnnn{nassertion}{[1][]}{\begin{sassertion}[#1]}{\end{sassertion}} \_@@_notes_env:nnnn{nproof}{[2][]}{\begin{sproof}[#1]{#2}}{\end{sproof}} \_@@_notes_env:nnnn{nexample}{[1][]}{\begin{sexample}[#1]}{\end{sexample}} \RequirePackage{graphicx} \NewDocumentCommand\frameimage{s O{} m}{ \IfBooleanTF #1 { \begin{frame}[plain] }{ \begin{frame} } \bool_if:NTF \c_notesslides_notes_bool { \slidewidth=\dimexpr\slidewidth-(2\slideframewidth)\relax }{ \slidewidth=\textwidth\relax } \def\Gin@ewidth{}\setkeys{Gin}{#2} \tl_if_empty:NTF \Gin@ewidth { \mhgraphics[width=\slidewidth,#2]{#3} }{ \mhgraphics[#2]{#3} } \end{frame} } % \end{macrocode} % % hacking inputref: % % \begin{macro}{\inputref*} % \begin{macrocode} \cs_set_eq:NN\_@@_inputref:\inputref \cs_set_protected:Npn\inputref{\@ifstar\ninputref\_@@_inputref:} \bool_if:NTF \c_notesslides_notes_bool { \newcommand\ninputref[2][]{ \_@@_inputref:[#1]{#2} } }{ \newcommand\ninputref[2][]{} } % \end{macrocode} % \end{macro} % % \end{sfragment} % % \begin{sfragment}{Styling Across Notes/Slides} % \begin{macrocode} \def\notesslidestitleemph#1{ {\Large\bf\sf#1} \vskip0.1\baselineskip \leaders\vrule width \textwidth \vskip0.4pt% \nointerlineskip } \def\notesslidesfooter{} \let\notesslidesfont\sffamily % \end{macrocode} % \end{sfragment} % % \begin{sfragment}{Beamer Compatibility} % All of this should be removed and made part of a template % \begin{macrocode} \bool_if:NT \c_notesslides_notes_bool { \def\author{\@dblarg\ns@author} \long\def\ns@author[#1]#2{% \tl_if_empty:nTF{#1}{ \def\beamer@shortauthor{#2} }{ \def\beamer@shortauthor{#1} } \def\@author{#2} } \def\title{\@dblarg\ns@title} \long\def\ns@title[#1]#2{% \tl_if_empty:nTF{#1}{ \def\beamer@shorttitle{#2} }{ \def\beamer@shorttitle{#1} } \def\@title{#2} \stexdoctitle{#2} } \def\insertshortauthor{ \hbox\bgroup\def\\{}\cs_if_exist:NT\beamer@shortauthor\beamer@shortauthor\egroup } \def\insertshorttitle{ \hbox\bgroup\def\\{}\cs_if_exist:NT\beamer@shorttitle\beamer@shorttitle\egroup } \stex_if_html_backend:TF{ \def\insertframenumber{\stex_annotate:nn{shtml:framenumber={}}{}} }{ \def\insertframenumber{\@arabic\c@framenumber} } \def\insertshortdate{\today} } % \end{macrocode} % \end{sfragment} % % % \subsection{TODO Excursions}\label{sec:impl:excursions} % % \begin{macro}{\excursion} % The excursion macros are very simple, we define a new internal macro |\excursionref| and % use it in |\excursion|, which is just an |\inputref| that checks if the new macro is % defined before formatting the file in the argument. % \begin{macrocode} \gdef\printexcursions{} \newcommand\excursionref[2]{% label, text \bool_if:NT \c_notesslides_notes_bool { \begin{sparagraph}[title=Excursion] #2 \sref[fallback=the appendix]{#1}. \end{sparagraph} } } \newcommand\activate@excursion[2][]{ \tl_gput_right:Nn\printexcursions{\inputref[#1]{#2}} } \newcommand\excursion[4][]{% repos, label, path, text \bool_if:NT \c_notesslides_notes_bool { \activate@excursion[#1]{#3} \excursionref{#2}{#4} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\excursiongroup} % \begin{macrocode} \keys_define:nn{notesslides / excursiongroup }{ id .str_set_x:N = \l_@@_excursion_id_str, intro .tl_set:N = \l_@@_excursion_intro_tl, archive .str_set_x:N = \l_@@_excursion_mhrepos_str } \cs_new_protected:Nn \_@@_excursion_args:n { \tl_clear:N \l_@@_excursion_intro_tl \str_clear:N \l_@@_excursion_id_str \str_clear:N \l_@@_excursion_mhrepos_str \keys_set:nn {notesslides / excursiongroup }{ #1 } } \newcommand\excursiongroup[1][]{ \_@@_excursion_args:n{ #1 } \tl_if_empty:NF\printexcursions {\IfInputref{}{\begin{note} \begin{sfragment}{Excursions}% TODO pass on id \ifdefempty\l_@@_excursion_intro_tl{}{ \exp_args:NNe \use:nn \inputref{[\l_@@_excursion_mhrepos_str]{ \l_@@_excursion_intro_tl }} } \printexcursions% \end{sfragment} \end{note}}} } \ifcsname beameritemnestingprefix\endcsname\else\def\beameritemnestingprefix{}\fi % \end{macrocode} % \end{macro} % % \begin{macrocode} \prop_new:N \g_@@_variables_prop \cs_set_protected:Npn \setSGvar #1 #2 { \prop_gput:Nnn \g_@@_variables_prop {#1}{#2} } \cs_set_protected:Npn \useSGvar #1 { \prop_item:Nn \g_@@_variables_prop {#1} } \cs_set_protected:Npn \ifSGvar #1 #2 #3 { \prop_get:NnNF \g_@@_variables_prop {#1} \l_@@_tmp { \PackageError{document-structure} {The sTeX Global variable #1 is undefined} {set it with \protect\setSGvar}\TODO better error } \tl_if_eq:NnT \l_@@_tmp {#2}{ #3 } } % % \end{macrocode} % % \end{sfragment} % \end{implementation} \endinput % \endinput % Local Variables: % mode: doctex % TeX-master: t % End: