2

I'm building a gallery using tabularx and tikz, similar to image-gallery. Here's a snippet:

\documentclass{article}                                               
\usepackage{tikz}                                                     
\usepackage{tabularx}                                                 

\begin{document}                                                      

\begin{tabularx}{\textwidth}{@{} *4{>{\centering\arraybackslash}X}@{}}
  \begin{tikzpicture}                                                 
    \node{\includegraphics[width=2cm]{kitty}};                        
  \end{tikzpicture}                                                   
  & & & \\                                                            
  Mr. Whiskas                                                         
  & & & \\                                                            
  \textbf{Programmer}                                                 
  & & & \\                                                            
\end{tabularx}                                                        

\end{document}  

Result:

enter image description here

As this is done using a table, it's a bit annoying for the user to insert each member manually. If it has any changes, then one has to change each line accordingly, which is annoying when the gallery is large.

I'd like to wrap this snippet within a new environment (or command), to make it easier for the user to insert and move members (and I'm also using this opportunity to learn a bit of Latex programming). I had something like this in mind:

\begin{gallery}
  \member{Mr. Whiskas}{\textbf{Programmer}}{image/path/kitty}
  \member{Catalie Portman}{\textbf{CEO}}{image/path/kitty2}
\end{gallery}

However, I'm a bit lost in Latex programming. If anyone could give me any pointers.

Questions:

  • Is \newenvironment the best way of doing this or should I be using a \newcommand?

  • The way I thought in storing the data would be having a list of tuples (or struct/object). How do I store this structured data in Latex in a list and then iterate over names first, then over profession, to fill each line in tabularx?

Despite I'm asking how to make "a list of structs", I actually would like to know the more latexian way of doing it, even if doesn't use abstractions such as the ones I mentioned.

If anyone could point me to a source code that does something in a similar way and a beginner could grasp, that would be great.

Scope of the answer: The answer doesn't need to provide an implementation of this environment (as I said, I'd like to do it myself). What I want is the pointers of what I should use, and how to make the basic stuff, such as looping through a list of tuples/structs.

  • 1
    First of all: An environment seems to be a good fit. It will be simple with expl3: Llet each of the member commands append some text to a sequence and then just step the sequence appropriately. Alternatively pgf has object-oriented programming facilities you might use. – TeXnician Dec 27 '18 at 17:53
  • @TeXnician: thanks! So, that is the way to go. I was a bit afraid if I were asking a "XY problem" type of question, that's why I tried to give more context. – Yamaneko Dec 27 '18 at 17:59
3

I do not see the need of use of use tabularx and tikz or anything else except graphicx. A simple macro without any environment can manage reasonably well even with unequal names, titles and photo shapes:

mwe

(of course, if you test this MWE with real user images, please remove "angle=90," of the macro)

\documentclass[a4paper]{article}                                               
\usepackage{graphicx}

\newcommand\member[3][example-image-empty]{%
\noindent\parbox[t]{.245\linewidth}{\centering%
\includegraphics[angle=90,width=.6\linewidth,height=.8\linewidth,
keepaspectratio]{#1}\par#2\par\bfseries#3\bigskip}%
\hspace{10pt minus 10pt}}


\begin{document}                                                      

\member[example-image-a]{Mr. Whiskas}{Programmer}
\member[example-image-b]{Catherine of Aragon}{Queen of England and Princess of Wales}
\member[example-image-c]{Tomás de Zumalacárregui e Imaz}{General}
\member[example-image]{Dr. Whatson}{Detective Assistant}
\member[example-image-1x1]{Dr. Pigmy}{A short guy}%
\member[example-image-16x9]{Dr. Slender}{A tall guy}%
\member[example-image-16x10]{Mr. Pau Gasol}{Basketball player}%
\member[example-image-4x3]{Mr. John Doe}{Homeless}%
\member[example-image]{Mr. Thompson}{Police}
\member[example-image]{Mr. Thomson}{Police}
\member{next\ldots}{}
\member{}{}

\end{document}  
2

The following is an unfinished implementation of your environment. You'd have to solve an issue with more than 4 elements.

The macros used to implement something like a list are \appendto, that takes a name of a macro which should act as the list (and has to be already defined at this point) and adds a marker \q@mark to it to separate the elements (which should never be fully expanded, because it'd result in an infinite loop -- same for \q@stop). The other one is \printlist which takes 3 arguments. The first can be a formatting argument. Each element of the list will be supplied as an argument to the first argument of \printlist. The second is a separator which should be inserted between each element (but not after the last one). The third argument is the list macro.

The implementation of such lists doesn't rely on any packages, but is rather primitive. I hope this doesn't kill your procrastination because you can't do it yourself, but you don't have to use this implementation.

If you need any explanations to the code, feel free to ask.

\documentclass[]{article}

\usepackage{tabularx}
\usepackage[]{graphicx}

\makeatletter
%% primitive implementation of lists
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\q@mark{\q@mark}
\def\q@stop{\q@stop}
\long\def\afterfi#1\fi{\fi#1}
\newcommand\appendto[2]
  {%
    \edef#1{\unexpanded\expandafter{#1#2\q@mark}}%
  }
\newcommand*\printlist[3]
  {%
    \expandafter\printlist@i\expandafter{#3}{#1}{#2}%
  }
\newcommand*\printlist@i[3]
  {%
    \if\relax\detokenize{#1}\relax
    \else
      \afterfi
      {\printlist@ii{#2}{#3}#1\q@stop}%
    \fi
  }
\long\def\printlist@ii#1#2#3\q@mark#4%
  {%
    \if\relax\detokenize{#3}\relax
    \else
      \afterfi
      {#1{#3}}%
    \fi
    \ifx\q@stop#4%
    \else
      \afterfi
      % Tricky bit here, `&` is not allowed as argument of \afterfi for some
      % reason, so I have to hide it. The braces are stripped here because it's
      % the only group/token between \afterfi and \fi.
      {#2\printlist@ii{#1}{#2}#4}%
    \fi
  }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% basic implementation of your environment
\newcommand\member[3]
  {%
    \appendto\memberlist@name{#1}%
    \appendto\memberlist@desc{#2}%
    \appendto\memberlist@file{#3}%
  }
\newcommand*\printmemberlist@file
  {%
    \printlist\memberlist@file@format&\memberlist@file
  }
\newcommand*\printmemberlist@name
  {%
    \printlist\memberlist@name@format&\memberlist@name
  }
\newcommand*\printmemberlist@desc
  {%
    \printlist\memberlist@desc@format&\memberlist@desc
  }
\newcommand\memberlist@file@format[1]
  {%
    \includegraphics[width=2cm]{#1}%
  }
\newcommand\memberlist@name@format[1]
  {%
    #1%
  }
\newcommand\memberlist@desc@format[1]
  {%
    \textbf{#1}%
  }
\newenvironment{gallery}
  {%
    \def\memberlist@name{}%
    \def\memberlist@desc{}%
    \def\memberlist@file{}%
  }
  {%
    \begin{tabularx}{\textwidth}{ @{} *4{>{\centering\arraybackslash}X} @{} }
      \printmemberlist@file \\
      \printmemberlist@name \\
      \printmemberlist@desc
    \end{tabularx}
  }
\makeatother

\begin{document}
\noindent
\begin{gallery}
  \member{Mr. Whiskas}{Programmer}{example-image}
  \member{Catalie Portman}{CEO}{example-image-a}
  \member{Ducktective M.}{Detective}{example-image-duck}
  \member{Anne Example}{Person}{example-image-b}
\end{gallery}
\end{document}

Forgot to post result:

enter image description here

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.