6

I am making a conversation and I need to draw some shapes, and place them properly along the page. The shapes are the following:

  • A white rectangle with a little crest (called mestart): mestart shape
  • A white rectangle without a crest (called me): me shape
  • A green rectangle with a little crest (called youstart): youstart shape
  • A green rectangle without a crest (called you): you shape
  • A blue rectangle with rounded corners (called exnumber): exnumber shape

What I want

I want to produce the following conversation:

What I want

To consider:

  1. All the rectangles (except exnumber) can have inside:
    • Only text (normal text, bulleted list, numbered list etc.), or
    • Only one image (it can be a tikzpicture), or
    • Text & sample code (for instance listings package can be a good example).
  2. These rectangles must have a max width and a space between them: Max width (also the images should have the same max width).
  3. The blue rectangle i.e. exnumber should be placed centered on the page with an automatic numeration and restarted when the section ends. For example: in Section 1 Exercise 1, Exercise 2, Exercise 3. In Section 2: Exercise 1, Exercise 2.

What I have done

Please consider this MWE:

\documentclass{article}
\usepackage[a4paper,margin=1in,footskip=0.25in]{geometry}

\usepackage{tikz}
\usetikzlibrary{shapes.misc, positioning}
\usetikzlibrary{decorations.text}
\usetikzlibrary{shapes.symbols}

\begin{document}

\begin{tikzpicture}
    \node (1) [rounded corners=.2cm,inner sep=.3cm,align=right,fill=blue] {Exercise 1};
\end{tikzpicture}

\begin{tikzpicture}
    \node (1) [draw,rounded corners=.2cm,inner sep=.5cm,align=left] {rounded rectangle\\asas};
\end{tikzpicture}

\begin{tikzpicture}
    \node (1) [rounded corners=.2cm,inner sep=.5cm,align=right,fill=green] {This is a rounded rectangle\\Text\\ a \\ a \\ a};
\end{tikzpicture}

\end{document}

What I have done

EDIT Some changes to edit #4 of the amazing Schrödinger's cat's answer with some implementations:

  1. Added \maxwidth and \maxheight.
  2. Since I need to add a lot of images to the conversation, I have created four new types of shapes: the 4 ones but with the word Image after the names. This includes \includegraphics[max height=\maxheight,max width=\maxwidth]{#2}.
  3. \begin{varwidth}{\maxwidth} added to the normal 4 shapes.
  4. Added tabs space and some information to the code.

Final result:

\documentclass{article}
\usepackage{blindtext}
\def\maxwidth{16cm}
\def\maxheight{20cm}

\usepackage[a4paper,margin=.25in,footskip=0.25in]{geometry}

\usepackage[export]{adjustbox} % Loads also graphicx
\usepackage{varwidth}

\usepackage{tikz}
\usetikzlibrary{positioning}
% From https://tex.stackexchange.com/revisions/529773/4
\tikzset{basic/.style={rounded corners=.2cm,inner sep=.5cm},
    basic L/.style={basic,align=left,fill=white,anchor=north west,
        font=\sffamily,outer sep=0pt},
    my callout L/.style={basic L,
        append after command={pic[fill=white]{callout corner L}}},
    basic R/.style={basic,align=right,fill=green!60!black,anchor=north east,
        font=\sffamily,outer sep=0pt},
    my callout R/.style={basic R,
        append after command={pic[fill=green!60!black]{callout corner R}}},
    pics/callout corner L/.style={code={
    \path[pic actions] ([xshift=3mm]\tikzlastnode.north west) -- ++ (-9mm,0) 
    -- ([yshift=-6mm]\tikzlastnode.north west);}},
    pics/callout corner R/.style={code={
    \path[pic actions] ([xshift=-3mm]\tikzlastnode.north east) -- ++ (9mm,0) 
    -- ([yshift=-6mm]\tikzlastnode.north east);}},
    exercise/.style={rounded corners=.2cm,inner sep=.3cm,align=right,
        fill=blue,anchor=north,font=\sffamily,text=white},
    whatsapp/.cd,vdist/.initial=3mm,hdist/.initial=6mm
}
% Added varwidth to set a max width for each of the shapes. From https://tex.stackexchange.com/a/46479/152550
% MeStart
\newcommand{\MeStart}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[my callout L,alias=tmp,#1] {\begin{varwidth}{\maxwidth}#2\end{varwidth}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% Me
\newcommand{\Me}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[basic L,alias=tmp,#1] {\begin{varwidth}{\maxwidth}#2\end{varwidth}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% YouStart
\newcommand{\YouStart}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\textwidth-\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[my callout R,alias=tmp,#1] {\begin{varwidth}{\maxwidth}#2\end{varwidth}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% You
\newcommand{\You}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\textwidth-\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[basic R,alias=tmp,#1] {\begin{varwidth}{\maxwidth}#2\end{varwidth}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% Exercise
\newcommand{\Exercise}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\textwidth/2,0) node[exercise,alias=tmp,#1] {#2};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% max height/width for includegraphics from https://tex.stackexchange.com/a/47252/152550
% MeStartImage
\newcommand{\MeStartImage}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[my callout L,alias=tmp,#1] {\includegraphics[max height=\maxheight,max width=\maxwidth]{#2}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% MeImage
\newcommand{\MeImage}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[basic L,alias=tmp,#1] {\includegraphics[max height=\maxheight,max width=\maxwidth]{#2}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% YouStartImage
\newcommand{\YouStartImage}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\textwidth-\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[my callout R,alias=tmp,#1] {\includegraphics[max height=\maxheight,max width=\maxwidth]{#2}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% YouImage
\newcommand{\YouImage}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\textwidth-\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[basic R,alias=tmp,#1] {\includegraphics[max height=\maxheight,max width=\maxwidth]{#2}};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}

\begin{document}

\begin{tikzpicture}[overlay,remember picture]
    \fill[blue!20] (current page.south west) rectangle (current page.north east);
\end{tikzpicture}

\MeStart{\blindtext[1]\\ Text}

\MeImage[scale=0.5]{example-image}

\YouStartImage[scale=2]{example-image-duck}

\Exercise{How many marmots?}

\You{\Blindtext[1]}

\end{document}

Example

manooooh
  • 3,203
  • 2
  • 21
  • 46
  • Tik has the callout shapes which look similar but not identical to what you have. Do you want the exact shape, or is something similar OK? –  Feb 24 '20 at 05:35
  • @Schrödinger'scat I want the exact shapes (it is like a WhatsApp Messenger conversation). Thanks for pointing it out. – manooooh Feb 24 '20 at 05:39

1 Answers1

6

This defines such shapes. Note that I did not really simplify positioning too much because probably you want some macros for the dialogue. They can take care of that. The following code is based on the newly added routines of your question. However, rather than defining many macros, it uses pgf keys. For instance, instead of

 \MeStart{\blindtext[1]\\ Text}

you can use

 \Me[start]{\blindtext[1]\\ Text}

or

 \You[start,image={scale=2}]{example-image-duck}

and so on. This has the advantage of being extendable very easily while keeping backwards compatibility.

\documentclass{article}
\usepackage{blindtext}
\def\maxwidth{16cm}
\def\maxheight{20cm}

\usepackage[a4paper,margin=.25in,footskip=0.25in]{geometry}

\usepackage[export]{adjustbox} % Loads also graphicx
\usepackage{varwidth}
\newif\ifStart
\Startfalse
\newif\ifImage
\Imagefalse
\usepackage{tikz}
\usetikzlibrary{positioning}
% From https://tex.stackexchange.com/revisions/529773/4
\tikzset{basic/.style={rounded corners=.2cm,inner sep=.5cm},
    basic L/.style={basic,align=left,fill=white,anchor=north west,
        font=\sffamily,outer sep=0pt},
    my callout L/.style={basic L,
        append after command={pic[fill=white]{callout corner L}}},
    basic R/.style={basic,align=right,fill=green!60!black,anchor=north east,
        font=\sffamily,outer sep=0pt},
    my callout R/.style={basic R,
        append after command={pic[fill=green!60!black]{callout corner R}}},
    pics/callout corner L/.style={code={
    \path[pic actions] ([xshift=3mm]\tikzlastnode.north west) -- ++ (-9mm,0) 
    -- ([yshift=-6mm]\tikzlastnode.north west);}},
    pics/callout corner R/.style={code={
    \path[pic actions] ([xshift=-3mm]\tikzlastnode.north east) -- ++ (9mm,0) 
    -- ([yshift=-6mm]\tikzlastnode.north east);}},
    exercise/.style={rounded corners=.2cm,inner sep=.3cm,align=right,
        fill=blue,anchor=north,font=\sffamily,text=white},
    whatsapp/.cd,vdist/.initial=3mm,hdist/.initial=6mm,
    start/.is if=Start,
    image/.code=\Imagetrue\tikzset{whatsapp/graphics pars/.cd,#1},
    graphics pars/.cd,scale/.initial=1 %add additional keys here

}
% Added varwidth to set a max width for each of the shapes. From https://tex.stackexchange.com/a/46479/152550
% Me
\newcommand{\Me}[2][]{\noindent\begin{tikzpicture}
\tikzset{whatsapp/.cd,#1}
\ifStart
    \path (0,0) (\pgfkeysvalueof{/tikz/whatsapp/hdist},0) 
    node[my callout L,alias=tmp] {\ifImage
     \includegraphics[max height=\maxheight,max width=\maxwidth,
        scale=\pgfkeysvalueof{/tikz/whatsapp/graphics pars/scale}]{#2}%
    \else
    \begin{varwidth}{\maxwidth}#2\end{varwidth}%
    \fi};
\else
    \path (0,0) (\pgfkeysvalueof{/tikz/whatsapp/hdist},0) 
    node[basic L,alias=tmp] {\ifImage
     \includegraphics[max height=\maxheight,max width=\maxwidth,
        scale=\pgfkeysvalueof{/tikz/whatsapp/graphics pars/scale}]{#2}%
    \else
    \begin{varwidth}{\maxwidth}#2\end{varwidth}%
    \fi};
\fi 
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
% You
\newcommand{\You}[2][]{\noindent\begin{tikzpicture}
\tikzset{whatsapp/.cd,#1}
\ifStart
    \path (0,0) (\textwidth-\pgfkeysvalueof{/tikz/whatsapp/hdist},0) 
    node[my callout R,alias=tmp] {\ifImage
     \includegraphics[max height=\maxheight,max width=\maxwidth,
        scale=\pgfkeysvalueof{/tikz/whatsapp/graphics pars/scale}]{#2}%
    \else
    \begin{varwidth}{\maxwidth}#2\end{varwidth}%
    \fi};
\else
    \path (0,0) (\textwidth-\pgfkeysvalueof{/tikz/whatsapp/hdist},0) 
    node[basic R,alias=tmp] {\ifImage
     \includegraphics[max height=\maxheight,max width=\maxwidth,
        scale=\pgfkeysvalueof{/tikz/whatsapp/graphics pars/scale}]{#2}%
    \else
    \begin{varwidth}{\maxwidth}#2\end{varwidth}%
    \fi};
\fi 
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
\newcommand{\Exercise}[2][]{\noindent\begin{tikzpicture}
    \path (0,0) (\textwidth/2,0) node[exercise,alias=tmp,#1] {#2};
    \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist});
\end{tikzpicture}\par}
\begin{document}

\begin{tikzpicture}[overlay,remember picture]
    \fill[blue!20] (current page.south west) rectangle (current page.north east);
\end{tikzpicture}

\Me[start]{\blindtext[1]\\ Text}

\Me[image={scale=0.25}]{example-image}

\You[start,image={scale=2}]{example-image-duck}

\Exercise{How many marmots?}

\You{\Blindtext[1]}

\end{document}

enter image description here

  • Looks good, thank you! As you mention, I surely will need macros for the 5 shapes since we are talking about like >40 pages. – manooooh Feb 24 '20 at 06:09
  • 1
    @manooooh I added some sample macros. –  Feb 24 '20 at 06:24
  • I am wondering how did you get the space between shapes. That's awesome! Some inmediate comments: 1) when adding images wider than example-image or example-image-duck then picture is cropped, so I found a solution here and wrote a new command \YouStartImage which has {\includegraphics[max height=20cm,max width=13cm]{#2}} (the maximums can vary, it's just an example); so I call this \YouStartImage{example-image}. – manooooh Feb 24 '20 at 16:08
  • The Start shapes have a small imperfections wrt the crest: see here, I will see if I can fix this or you can help me if you want.
  • – manooooh Feb 24 '20 at 16:10
  • I am not able to move the white shapes more to the left and the green shapes more to the right (I want more space); I have tried changing both numbers in \path (0,0) (1.5,0) node[... but the maximum the white shapes can move to the left is when I change (0,0) to (2,0); they don't move if I write a >2 number in the first component. Could you see this problem, please?
  • – manooooh Feb 24 '20 at 16:14
  • 1
    @manooooh As for 1), I do not fully understand. As for 2), good catch! I forgot to set the outer sep to 0. As for 3), I introduced keys for that, now you can change the vertical and horizontal distances. The horizontal one cannot become smaller than 6mm at this point because the callouts have the corner of that length. However, you can use geometry to reduce the let and right margins. –  Feb 24 '20 at 16:30
  • Please take a look to my question edit! Do you like it? I love your code, that helped me to create the edit! More seriously, I hope with my edit you understand my comment 1). I realized that if the image is big, the edges get thicker (look the duck on the green shape). Can you achieve, starting from my code, the edges as thin as those of example-image have in the white rectangle if the image is big? – manooooh Feb 24 '20 at 17:56
  • For aligning text on the right for the green rectangles we have to use \raggedleft inside the commands. – manooooh Feb 24 '20 at 23:08
  • 1
    @manooooh Yes I like the output. The fact that the boundaries increase comes from scale=2 in \YouStartImage[scale=2]{example-image-duck}, which scales everything. If you do not want to have this, you need to pass the optional argument to \includegraphics, not \node. –  Feb 24 '20 at 23:33
  • Thanks. Uh, but I can have images that don't need to be scaled. I understand your proposal, is there a way to scale some images but not all images? – manooooh Feb 24 '20 at 23:37
  • 1
    @manooooh I mean simply \newcommand{\YouStartImage}[2][]{\noindent\begin{tikzpicture} \path (0,0) (\textwidth-\pgfkeysvalueof{/tikz/whatsapp/hdist},0) node[my callout R,alias=tmp] {\includegraphics[max height=\maxheight,max width=\maxwidth,#1]{#2}}; \path (tmp.south) ++ (0,-\pgfkeysvalueof{/tikz/whatsapp/vdist}); \end{tikzpicture}\par}. (Note the position of #1.) –  Feb 24 '20 at 23:40
  • I was going to indicate that (but I have used 3 arguments), so the argument that is inside node is useless for the 4 image shapes? – manooooh Feb 24 '20 at 23:41
  • @manooooh I think that if you want to really do this, you should not have so many macros. Rather you should have pgf keys and automatization. What are the rules of this game? If I say something for the first time, is should be \MeStart, if the previous bubble was by me or an exercise, just \Me? –  Feb 24 '20 at 23:46
  • I don't know how to automate, that's why I created 8 commands + Exercise. But yes, if someone starts an exercise (i.e. after the blue rectangle) then we put Me/YouStart, the rest of the conversation (until another exercise) we only put Me or You. But I was planning to write the document manually... Don't worry! – manooooh Feb 24 '20 at 23:49
  • 1
    @manooooh I added an example. It achieves what you achieve but with two commands and some pgf keys. The advantage is that you can keep adding options as needed and won't lose backwards compatibility. (Notice that one could add start automatically if this is the first post by "Me" or "You" in a thread.) –  Feb 25 '20 at 00:50
  • It looks better, you have removed unnecessary stuff. Why I can't change the image scale on \Me[image={scale=<x>}]{example-image} and \You[start,image={scale=<x>}]{example-image-duck}? (Remember to add \raggedleft for align text to the right.) – manooooh Feb 25 '20 at 01:04
  • 1
    @manooooh My bad! Sorry! I thought I had understood how \setkeys{Gin}{...} works but apparently I do not. Added a temporary fix, will try to improve it later. –  Feb 25 '20 at 01:35
  • I am trying to include a tabular inside \Me box but when the context is too long the tabular does not break line. Try to add the following code to yours: \Me[start]{Example:\\\begin{tabular}{|c|l|}\hline Text & This is a very very very very very very very very very very very very very very very very very very very very very very very very very very very very long text \\\hline\end{tabular}}. – manooooh Mar 12 '20 at 23:03
  • 1
    @manooooh Is using longtable something that you could consider? (I did not try out myself yet but I will only try if you are open to using it.) –  Mar 12 '20 at 23:06
  • Yes, why not? I just changed \begin{tabular}{|c|l|} by \begin{longtable}{|c|p{\maxwidth}|} (added \usepackage{longtable}) but the width of the longtable is still out of bounds. :( – manooooh Mar 12 '20 at 23:13
  • @manooooh How about \Me[start]{Example:\\\begin{tabular}{|c|p{\maxwidth}|}\hline Text & This is a very very very very very very very very very very very very very very very very very very very very very very very very very very very very long text \\\hline\end{tabular}}? –  Mar 12 '20 at 23:16
  • 1
  • 1
    @manooooh Sorry, my bad. Use \usepackage{tabularx} and \Me[start]{Example:\\\begin{tabularx}{\maxwidth}{|c|X|}\hline Text & This is a very very very very very very very very very very very very very very very very very very very very very very very very very very very very long text \\\hline\end{tabularx}}. –  Mar 12 '20 at 23:26