Creating a table with FIXED length column widths

This seems to beg for a key-value interface:

enter image description here

\documentclass{article}

\usepackage{xkeyval}

\makeatletter
\define@cmdkey{rpg}[char@]{name}[]{}
\define@cmdkey{rpg}[char@]{class}[]{}
\define@cmdkey{rpg}[char@]{range}[]{}
\define@cmdkey{rpg}[char@]{rof}[]{}
\define@cmdkey{rpg}[char@]{damage}[]{}
\define@cmdkey{rpg}[char@]{pen}[]{}
\define@cmdkey{rpg}[char@]{clip}[]{}
\define@cmdkey{rpg}[char@]{reload}[]{}
\define@cmdkey{rpg}[char@]{weight}[]{}
\define@cmdkey{rpg}[char@]{availability}[]{}
\define@cmdkey{rpg}[char@]{special}[]{}
\define@cmdkey{rpg}[char@]{width}[\linewidth]{}

\newcommand{\setcharacterstats}[1]{%
  \begingroup
  \setkeys{rpg}{name,class,range,rof,damage,pen,clip,reload,weight,availability,special,width,#1}%
  \noindent
  \begin{tabular}{ @{} c @{} }
    \begin{tabular}{ | p{\dimexpr.69\char@width-2\tabcolsep} | p{\dimexpr.31\char@width-2\tabcolsep} | }
      \hline
      \statlabel{Name}: \char@name & \statlabel{Cls}: \char@class
    \end{tabular} \\
    \begin{tabular}{ | p{\dimexpr.23\char@width-2\tabcolsep} | p{\dimexpr.37\char@width-2\tabcolsep} | p{\dimexpr.4\char@width-2\tabcolsep} | }
      \hline
      \statlabel{Rng}: \char@range & \statlabel{RoF}: \char@rof & \statlabel{Dmg}: \char@damage
    \end{tabular} \\
    \begin{tabular}{ | p{\dimexpr.23\char@width-2\tabcolsep} | p{\dimexpr.20\char@width-2\tabcolsep} | p{\dimexpr.20\char@width-2\tabcolsep} |
                       p{\dimexpr.16\char@width-2\tabcolsep} | p{\dimexpr.21\char@width-2\tabcolsep} | }
      \hline
      \statlabel{Pen}: \char@pen & \statlabel{Clip}: \char@clip & \statlabel{Rld}: \char@reload & \statlabel{Wt}: \char@weight & \statlabel{Avl}: \char@availability
    \end{tabular} \\
    \begin{tabular}{ | p{\dimexpr\char@width-2\tabcolsep} | }
      \hline
      \statlabel{Special}: \char@special \\
      \hline
    \end{tabular}
  \end{tabular}\par
  \endgroup
}
\makeatletter

\newcommand{\statlabel}{\textsc}

\begin{document}

\setcharacterstats{
  name = The HuLK,
  class = Huge,
  range = Arm,
  rof = 5m,
  damage = 400,
  pen = 12,
  clip = 12.2,
  reload = 2s,
  weight = 7t,
  availability = 7,
  special = Green and very angry
  }

\end{document}

All the keys should be self-explanatory, including the possibility that you can adjust the width for each table. The default it \linewidth, and all the columns are specified in percentages of this.


Key-Value Version

Here's a version of my earlier answer which provides a key-value interface. I've used the LaTeX 3 code for handling the keys because I find this the most intuitive to use, although the syntax looks a bit alien at first. (That is, I've never understood how to use xkeyval etc. properly, so I can't do it in the difficult, non-alien-looking way.)

Also, since my original code used xparse, I didn't need to add any packages to use this approach. geometry is added just to get a wider page for the example.

\cardme[<list of key-value pairs>]

\cardme now takes one optional argument which is a list of key-value pairs.

Available keys are:

avl=, card width=, clip=, cls=, dmg=, name=, pen=, rld=, rng=, rof=, special=, wt=,

Apart from card width, these take text which is the value of the key in this case. In each case, the default is to typeset nothing as the value. The default for card width, which expects a dimension, is .75\textwidth, as in the original code.

Two additional macros are provided.

\cardnames{<list of key-value pairs>}

can be used to customise the labels used for each key-value pair. The keys are as before, except that there is no card width. The difference is that this macro doesn't typeset anything. It just changes the text which will be used when creating the label in each box if, and when, \cardme is later used.

Similarly

\cardunits{<list of key-value pairs>}

can be used to assign a unit to each type of value. By default these are empty except for rng and wt which are set to km and kg respectively.

For example, suppose we create the following cards:

\noindent
\cardme

This will be an empty card with default width and labels.

\noindent
\cardme[%
  card width=\textwidth,
  name=This One,
  cls=Aristocracy,
  rng=450,
  rof=RoF,
  dmg=Extensive,
  pen=Pen,
  clip=Y,
  rld=N,
  wt=1,
  avl=Y,
  special=Extraordinary powers,
]

This card uses the default labels but, this time, the card is completed with a value in each box and the width is increased to allow for this.

\cardnames{
  name=Enw,
  cls=Dth,
  rng=Pll,
  dmg=Dfd,
  clip=Cnf,
  rld=AilLl,
  wt=Pwys,
  avl=ArGl,
  special=Arbennig,
}

This doesn't typeset anything. Rather, it changes some of the labels, while leaving others untouched. Hence, when we typeset another empty card with

\noindent\cardme[card width=.85\textwidth]

we will get an empty card with a mixture of default and custom labels and width of .85\textwidth.

3 cards

Complete code:

\documentclass{article}
\usepackage{calc,xparse,geometry}
\ExplSyntaxOn
\dim_new:N \l_Archimedes_card_width_dim
\dim_set:Nn \l_Archimedes_card_width_dim { .75\textwidth }
\keys_define:nn { Archimedes / card }
{
  avl .tl_set:N = \l_Archimedes_avl_tl,
  card~width .dim_set:N = \l_Archimedes_card_width_dim,
  clip .tl_set:N = \l_Archimedes_clip_tl,
  cls .tl_set:N = \l_Archimedes_cls_tl,
  dmg .tl_set:N = \l_Archimedes_dmg_tl,
  name .tl_set:N = \l_Archimedes_name_tl,
  pen .tl_set:N = \l_Archimedes_pen_tl,
  rld .tl_set:N = \l_Archimedes_rld_tl,
  rng .tl_set:N = \l_Archimedes_rng_tl,
  rof .tl_set:N = \l_Archimedes_rof_tl,
  special .tl_set:N = \l_Archimedes_special_tl,
  wt .tl_set:N = \l_Archimedes_wt_tl,
  avl .initial:n = ,
  clip .initial:n = ,
  cls .initial:n = ,
  dmg .initial:n = ,
  name .initial:n = ,
  pen .initial:n = ,
  rld .initial:n = ,
  rng .initial:n = ,
  rof .initial:n = ,
  special .initial:n = ,
  wt .initial:n = ,
}
\keys_define:nn { Archimedes / card / names }
{
  avl .tl_set:N = \l_Archimedes_avlname_tl,
  clip .tl_set:N = \l_Archimedes_clipname_tl,
  cls .tl_set:N = \l_Archimedes_clsname_tl,
  dmg .tl_set:N = \l_Archimedes_dmgname_tl,
  name .tl_set:N = \l_Archimedes_namename_tl,
  pen .tl_set:N = \l_Archimedes_penname_tl,
  rld .tl_set:N = \l_Archimedes_rldname_tl,
  rng .tl_set:N = \l_Archimedes_rngname_tl,
  rof .tl_set:N = \l_Archimedes_rofname_tl,
  special .tl_set:N = \l_Archimedes_specialname_tl,
  wt .tl_set:N = \l_Archimedes_wtname_tl,
  avl .initial:n = Avl,
  clip .initial:n = Clip,
  cls .initial:n = Cls,
  dmg .initial:n = Dmg,
  name .initial:n = Name,
  pen .initial:n = Pen,
  rld .initial:n = Rld,
  rng .initial:n = Rng,
  rof .initial:n = RoF,
  special .initial:n = Special,
  wt .initial:n = Wt,
}
\keys_define:nn { Archimedes / card / units }
{
  avl .tl_set:N = \l_Archimedes_avlunit_tl,
  clip .tl_set:N = \l_Archimedes_clipunit_tl,
  cls .tl_set:N = \l_Archimedes_clsunit_tl,
  dmg .tl_set:N = \l_Archimedes_dmgunit_tl,
  name .tl_set:N = \l_Archimedes_nameunit_tl,
  pen .tl_set:N = \l_Archimedes_penunit_tl,
  rld .tl_set:N = \l_Archimedes_rldunit_tl,
  rng .tl_set:N = \l_Archimedes_rngunit_tl,
  rof .tl_set:N = \l_Archimedes_rofunit_tl,
  special .tl_set:N = \l_Archimedes_specialunit_tl,
  wt .tl_set:N = \l_Archimedes_wtunit_tl,
  avl .initial:n = ,
  clip .initial:n = ,
  cls .initial:n = ,
  dmg .initial:n = ,
  name .initial:n = ,
  pen .initial:n = ,
  rld .initial:n = ,
  rng .initial:n = km,
  rof .initial:n = ,
  special .initial:n = ,
  wt .initial:n = kg,
}
\cs_new_protected:Nn \Archimedes_pageme:nn
{
  \begin{minipage}{#1\l_Archimedes_card_width_dim}
    \centering
    \fbox{
      \parbox{\linewidth-2\fboxrule-2.5\fboxsep}
      {
        \strut
        \textsc{ \use:c { l_Archimedes_#2name_tl } } : ~ \skip_horizontal:n {\fill} \use:c { l_Archimedes_#2_tl } \skip_horizontal:n {\fill}  \hbox:n { \use:c { l_Archimedes_#2unit_tl } }
      }
    }
  \end{minipage}
}
\NewDocumentCommand \cardnames { m }{
  \keys_set:nn { Archimedes / card / names } { #1 }
}
\NewDocumentCommand \cardunits { m }{
  \keys_set:nn { Archimedes / card / units } { #1 }
}
\NewDocumentCommand \cardme { O {} }{%
  \group_begin:
  \keys_set:nn { Archimedes / card } { #1 }
  \dim_sub:Nn \l_Archimedes_card_width_dim { 2\fboxrule + 2\fboxsep }
  \fbox{
    \begin{minipage}{\l_Archimedes_card_width_dim}
      \centering
      \Archimedes_pageme:nn {.69 } { name }
      \Archimedes_pageme:nn {.31 } { cls }\par
      \Archimedes_pageme:nn { .22 } { rng }
      \Archimedes_pageme:nn { .38 } { rof }
      \Archimedes_pageme:nn { .4 } { dmg }\par
      \Archimedes_pageme:nn { .22 } { pen }
      \Archimedes_pageme:nn { .19 } { clip }
      \Archimedes_pageme:nn { .19 } { rld }
      \Archimedes_pageme:nn { .18 } { wt }
      \Archimedes_pageme:nn { .22 } { avl }\par
      \Archimedes_pageme:nn {  } { special }
    \end{minipage}
  }
  \group_end:
}
\ExplSyntaxOff
\begin{document}
\noindent
\cardme

\noindent
\cardme[%
  card width=\textwidth,
  name=This One,
  cls=Aristocracy,
  rng=450,
  rof=RoF,
  dmg=Extensive,
  pen=Pen,
  clip=Y,
  rld=N,
  wt=1,
  avl=Y,
  special=Extraordinary powers,
]

\cardnames{
  name=Enw,
  cls=Dth,
  rng=Pll,
  dmg=Dfd,
  clip=Cnf,
  rld=AilLl,
  wt=Pwys,
  avl=ArGl,
  special=Arbennig,
}

\noindent\cardme[card width=.85\textwidth]
\end{document}

Original Answer

This uses \fbox and minipage to create the boxes-in-a-box look. I adjusted some of the percentages so they added to 100 on each line.

\cardme[<width>]{<content>}

sets up the main box. The optional parameter specifies the width. The required argument specifies the content. The default width is three-quarters of the width of the text block.

\pageme[<width>][<content>]

constructs an inner box. The two optional arguments are, first, the width and, second, the content. The default is to create an empty box the entire (inner) width of the card.

Then

\cardme[.8\textwidth]{%
  \pageme[.69][Name]%
  \pageme[.31][Class]

  \pageme[.22][Range]%
  \pageme[.38][RoF]%
  \pageme[.4][Damage]

  \pageme[.22][Pen]%
  \pageme[.19][Clip]%
  \pageme[.19][Reload]%
  \pageme[.18][Weight]%
  \pageme[.22][Availability]

  \pageme[][Special]%
}

specifies the following card:

card

Complete code:

\documentclass{article}
\usepackage{calc,xparse}
\newlength\mycardwidth
\setlength\mycardwidth{.75\textwidth}
\NewDocumentCommand \boxme { O{} }{%
  \fbox{%
    \parbox{\linewidth-2\fboxrule-2.5\fboxsep}{\strut #1}%
  }%
}
\NewDocumentCommand \pageme { O{} O{} }{%
  \begin{minipage}{#1\mycardwidth}
    \centering\boxme[#2]
  \end{minipage}%
}
\NewDocumentCommand \cardme { O{.75\textwidth} +m }{%
  \setlength\mycardwidth{#1-2\fboxrule-2\fboxsep}%
  \fbox{%
    \begin{minipage}{\mycardwidth}
      \centering
      #2%
    \end{minipage}%
  }%
}
\begin{document}
\cardme[.8\textwidth]{%
  \pageme[.69][Name]%
  \pageme[.31][Class]

  \pageme[.22][Range]%
  \pageme[.38][RoF]%
  \pageme[.4][Damage]

  \pageme[.22][Pen]%
  \pageme[.19][Clip]%
  \pageme[.19][Reload]%
  \pageme[.18][Weight]%
  \pageme[.22][Availability]

  \pageme[][Special]%
}
\end{document}

Tags:

Tables