Wednesday, March 31, 2010

Global font size changes

The question of how to change the font size for a row in a table came up recently. It's tricky since each cell in a tabular is in its own group. My thought was a global font size change for the row that needed it and then a global change back. Since commands like \tiny actually perform many different assignments, \global\tiny does not do what we need. TeX provides an \afterassignment primitive that takes the next token and places it after the next assignment. For example,
\afterassignment\TeX
\count255=3
\the\count255
acts like
\count255=3
\TeX
\the\count255
The basic idea is to use \afterassignment with a helper macro which uses \afterassignment and \global.
\def\helper{\afterassignment\helper\global}
This doesn't quite work since there's no good way to stop it. Modifying it slightly to make it conditional allows us to turn it off:
\newif\ifhelper
\def\helper{\ifhelper\afterassignment\helper\global\fi}
Two more snags remain. First, the font size changing macros actually make use of \afterassignment to allow default units (a neat trick in its own right) and \global\afterassignment is an error so we need to reimplement it. Similarly, vrule is used and \global \vrule is an error so we have to work around that. The final snag is that the first time TeX executes one of the font size commands like \tiny it performs extra work and that extra work doesn't play so nicely with our hack. The workaround for this is to simply execute the font size changing macro first. The complete code looks like this.
\newif\ifhelper
\makeatletter
\def\unithelper#1\@nnil{\global\helpertrue\helper}
\def\helper{\ifhelper\afterassignment\helper\global\fi}
\newcommand*\globalfontsize[1]{%
\begingroup
       #1%
       \def\@defaultunits{\helperfalse\afterassignment\unithelper\global}%
       \let\realvrule\vrule
       \def\vrule{\helperfalse\global\helpertrue\afterassignment\helper\realvrule}%
       \global\helpertrue
       \helper#1%
       \helperfalse
\endgroup}
\makeatother
\newcommand*\globaltiny{\globalfontsize\tiny}
\newcommand*\globalnormalsize{\globalfontsize\normalsize}
Now we can use \globaltiny and \globalnormalsize in the table to change the font for the whole row.

7 comments:

  1. While LaTeX learns calculating via LuaTeX, tabulars become more important. Changing the font size of a whole line would be very welcome, if the vertical skips between the "tiny" lines were small, too.

    Is there a way to adapt the space between the lines beginning with \globaltiny, except writing something like "\\[-.5\normalbaselineskip]" at the end of each line?

    Alexander

    ReplyDelete
  2. There is one way to make everything global in one block: \def\doglobal#1{\advance\globaldefs by 1\relax#1\relax\advance\globaldefs by -1\relax}

    ReplyDelete
  3. Yep. I've been meaning to post a follow up about this for quite some time. I just never got around to it. I think I'd use \begingroup\globaldefs1 #1\endgroup instead though.

    ReplyDelete
  4. Um, whut?

    Would you mind to elaborate where to put this \globaldefs1 #1\endgroup ?

    I'd really be interested to use your idea instead of tabulars inside tabulars.

    ReplyDelete
  5. Anon, you use \newcommand*\globalfontsize[1]{\begingroup\globaldefs1 #1\endgroup}. All of the rest of the code is not needed.

    ReplyDelete
  6. TH,

    thanks, but that leades to small glyphs and large skips as you can see in my example:

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \documentclass[pagesize, fontsize=12pt, ngerman]{scrartcl}
    \usepackage[utf8]{inputenc}
    \usepackage[T1]{fontenc}
    \usepackage{babel}

    \newcommand*\globalfontsize[1]{\begingroup\globaldefs1 #1\endgroup}

    \newcommand*\globaltiny{\globalfontsize\tiny}
    \newcommand*\globalnormal{\globalfontsize\normalsize}
    \newcommand*{\globallarge}{\globalfontsize\Large}

    \begin{document}\sffamily

    \begin{tabular}{lr}
    Bezeichnung & Betrag \\
    \globaltiny Stand 31.12.2010 & Nettobetrag\\
    \globalnormal Kostenposition 1 & 1.000.000\\
    Kostenposition 2 & 3.123.123\\
    \globaltiny
    aus JA 2009: & gilt auch 2010\\
    Bankdarlehen & 1\\
    Forderungen geg. Gesellschafter & 123\\
    Erinnerungsposten & 456\\
    \globalnormal Kostenposition 3 & 1.234.567\\
    \globallarge Summe & 4.567.890\\
    \end{tabular}


    \end{document}
    %%%%%%%%%%%%%%%%%%%%%%%%%%%

    It would be nice to adapt the baselineskip to the size of the font.

    If I needle you, ignore the questions,

    Regards,
    Alexander

    ReplyDelete
  7. Alex, that's actually due to how the tabular (actually array) works. It does

    \setbox \@arstrutbox \hbox {\vrule \@height \arraystretch \ht \strutbox \@depth \arraystretch \dp \strutbox \@width \z@ }

    It also sets the \baselineskip to 0pt and the \lineskip to 0pt. \@arstrutbox is inserted in each line. If you want to change the height of the line, you need to reset the height and depth of that box.

    ReplyDelete