1

I'm trying to get my own generic title command I can use either to include a pdf file as a title page, is that file exists, or include a text subdivided in keys using the xkeyval package.

My question is to be able to use either \title[my_pdf_file.pdf] or \title[maintitle=My main title, subtitle=My subtitle] transparently.

The code I have for now in my class file is this one:

\AtBeginDocument{%

    % Use bullets in lists instead of large dashes. Must be inside the document scope to work.
    \renewcommand{\labelitemi}{\textbullet}

    % Redefine the title commmand

    % makeatletter and makeatother are unneeded in class files.
    %\makeatletter

    % Restrict the commands to the internals of this class file.
    \def\@maintitle{}
    \def\@subtitle{}
    \def\@author{}

    \define@key{title}{maintitle}{%
        \def\@maintitle{%
            \hrule%
            \vspace{0.4cm}
            % We always need to define \par in scope for a font size change, otherwise, if the title is ever longer than a line, it will wrap to the next line with huge characters on a normal baseline.
            {\Huge\textbf{#1}\par}%
            \vspace{0.4cm}%
            \hrule
        }%
    }
    \define@key{title}{subtitle}{%
        \def\@subtitle{%
            \vspace{1.5cm}
            {\Large{#1}\par}%
        }%
    }
    \define@key{title}{author}{%
        \def\@author{%
            {\emph{Author: #1}\par}%
        }%
    }

    % The outer bracket is the renewcommand syntax, the inner one is a group definition avoiding \@author to leak out and be the default in later uses.
    \renewcommand{\title}[1][]{{%

        \IfFileExists{./#1}{%
            \includepdf[pages={1}]{#1}%
        }%
        {%
            \setkeys{title}{#1}            
            \key@ifundefined{#1}{\PackageError{'#1' is not a valid key}}

            \begin{titlepage}
                \begin{center}
                    \renewcommand{\hrule}{\rule{\linewidth}{1mm}}
                    \@maintitle
                    \@subtitle
                    \vfill%
                    \@author
                \end{center}
            \end{titlepage}%
        }
    }}
}

The problems I'm experiencing are:

  1. when using \title[my_pdf_file.pdf], underscores are interpreted, and I don't want to have to escape them manually.
  2. when using a standard manual title written in text \title[maintitle=Some long\\main title], the \IfFileExists seems to be interpreted and the title is written two times: one unformatted on one page, and another on the next page, but that time in the correct format (big letters, centered, with lines above and below that text)
  3. I want to get an error risen if I specify a value which isn't a valid readable file, and that value isn't a valid key neither (nor maintitle, subtitle or author). I cannot get \key@ifundefined{#1}{\PackageError{'#1' is not a valid key}} working.
  • I'm not sure why you're defining the keys at begin document. – egreg May 28 '15 at 14:21
  • @egreg Indeed you are right. I implemented the whole thing this way, because, before, the document wasn't compiling when I specified the code outside the AtBeginDocument. I tested again and this is now compiling. Thanks for the optimization hint. – wget Jun 5 '15 at 9:06
0

Your questions have no easy answer, but I've found a different approach which works and can be of your interest. But first, your questions:

  1. I don't know how to properly deal with underscores in filenames using your approach. The general advice is to avoid them (but my proposed approach will allow them)
  2. I don't know why that happens, somehow the internals of \IfFileExists cause the expansion of its argument (I think it is because the "file" you specify when using maintitle etc keywords is not found, and then that filename is parsed again to see if it contains sub-folders).
  3. The macro \key@undefined is not part of package keyval. But you don't need it. Standard behaviour of keyval already provides this feature (i.e: to produce a compilation error when a key is specified which was not previously declared)

Admittedly, my previous answers were not very useful. So let's try a different approach.

Why don't you provide the filename of the external pdf as another keyword instead of giving it "directly"? My proposed soultion would be, either:

\title[maintitle=My main title, subtitle=My subtitle]

or

\title[externalpdf=wonderful_title.pdf]

Even, you can combine both, so that if the external pdf exists, it is used, but if not, the other keywords are used:

\title[externalpdf=wonderful_title.pdf, maintitle=My main title, subtitle=My subtitle]

Using this approach, you get as a bonus the unexpected ability to have underscores in the filename.

This is the implementation:

\documentclass[11pt, oneside]{report}
\usepackage{pdfpages}
\usepackage{keyval}

\makeatletter
\AtBeginDocument{%

    % Use bullets in lists instead of large dashes. Must be inside the document scope to work.
    \renewcommand{\labelitemi}{\textbullet}

    % Redefine the title commmand

    % makeatletter and makeatother are unneeded in class files.
    %\makeatletter

    % Restrict the commands to the internals of this class file.
    \def\@maintitle{}
    \def\@subtitle{}
    \def\@author{}
    \def\@filename{}

    \define@key{title}{maintitle}{%
        \def\@maintitle{%
            \hrule%
            \vspace{0.4cm}
            % We always need to define \par in scope for a font size change, otherwise, if the title is ever longer than a line, it will wrap to the next line with huge characters on a normal baseline.
            {\Huge\textbf{#1}\par}%
            \vspace{0.4cm}%
            \hrule
        }%
    }
    \define@key{title}{subtitle}{%
        \def\@subtitle{%
            \vspace{1.5cm}
            {\Large{#1}\par}%
        }%
    }
    \define@key{title}{author}{%
        \def\@author{%
            {\emph{Author: #1}\par}%
        }%
    }

    \define@key{title}{externalfile}{%
        \def\@filename{#1}%
    }


    \renewcommand{\title}[1][]{{%
        \setkeys{title}{#1}
        \IfFileExists{\@filename}{%
            \includepdf[pages={1}]{\@filename}%
        }%
        {%
            \begin{titlepage}
                \begin{center}
                    \renewcommand{\hrule}{\rule{\linewidth}{1mm}}
                    \@maintitle
                    \@subtitle
                    \vfill%
                    \@author
                \end{center}
            \end{titlepage}%
        }
    }}
}
\makeatother

\begin{document}
\title[externalfile=wonderful_title.pdf, maintitle=My main title, subtitle=My subtitle]
\chapter{Testing...}
\end{document}  
  • This was indeed not the answer I was looking for and probably won't help other StackExchange lurkers if they are in the same situation as me. But indeed, refactoring the problem did help. However, now I need to find a solution to have boolean values without the need to precise =true, the presence of the boolean option means its value is true. Maybe I'm gonna ask another question for that. – wget Jun 7 '15 at 22:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.