1

First up, im relatively new to latex and completely new to tikz. What I'm trying to do is create a chat interface in latex with tikz. My desired result would be something like that:

\begin{chat}
Question
Answer
Question
Answer
\end{chat}

enter image description here

Regarding other threads here, the only thing I've found was this messenger interface document class, but I want to embedd it into my existing document and also this a little more than want (android gui, message input field, ...).

What I've done so far is create those nodes manually and adjust the coordinates manually (especially for multiline messages). The result of this code is the image above.

\begin{tikzpicture}
\definecolor{chatcolor1}{HTML}{5fedb7}
\definecolor{chatcolor2}{HTML}{b6b8b7}
\fontfamily{cmss}\selectfont
\node[align=left, text width=5cm, fill=chatcolor2, rounded corners=1mm, anchor=north west] at (0,0) {Question};
\node[align=right, text width=5cm,fill=chatcolor1, rounded corners=1mm, anchor=north west] at (2,-0.7) {Answer};
\node[align=left, text width=5cm, fill=chatcolor2, rounded corners=1mm, anchor=north west] at (0,-1.4) {Question};
\node[align=right, text width=5cm,fill=chatcolor1, rounded corners=1mm, anchor=north west] at (2,-2.1) {Answer};
\end{tikzpicture}

Now the idea was to make the code reusable, so that I don't have to copy paste that and adjust the coordinates manually every time. To do so I tried creating an environment with the environ package. This should iterate over the lines in the \BODY and create a node for each line.

\NewEnviron{chat}{%
        \definecolor{chatcolor1}{HTML}{5fedb7}
        \definecolor{chatcolor2}{HTML}{b6b8b7}
        \fontfamily{cmss}\selectfont    
        \begin{tikzpicture} 
            \foreach \line in \BODY
                {\node[align=left, text width=5cm, fill=chatcolor2, rounded corners=1mm, anchor=north west] at (0,0) {\line};}
        \end{tikzpicture}
}

However this does create a node, but all the content is seen as a single line. If I add linebreaks between each line in the \begin{chat} ... \end{chat} it throws the following error: Paragraph ended before \pgffor@normal@list was complete. \end{chat}

Does this approach sound reasonable for you? If yes how do I get it to work?

If not, I am thankful for any other approaches to the problem.

Thanks in advance.

1
1

Welcome!

I like to minimize markup if I can, and I also like to get TeX to do the heavy lifting ;).

NEW EDIT

You can input either:

\begin{newchat}
a which might go on for a bit and be quite long\\[10pt]with a line break
v
b
u
question
answer
How many existentialists does it take to change a light bulb?
That depends...
\end{newchat}

or you can use the form I suggested originally (notice the blank lines):

\begin{chat}
a which might go on for a bit and be quite long\\[10pt]with a line break

v

b

u

question

answer

How many existentialists does it take to change a light bulb?

That depends...

\end{chat}

I have also supplied a couple of missing % and ; as well as the use of \strut in the TikZ \nodes

\documentclass{article}

\usepackage{tikz}
\usepackage{xparse}

\newcounter{chatlinenum}

%% Adjust text width to suit
\tikzset{chatstyle/.style={text width=1.5in,rounded corners=2pt}}

%% Adjust width of minipage to suit, but greater than TikZ text width
\NewDocumentEnvironment{chat}{}{%
   \setcounter{chatlinenum}{0}
   \begin{minipage}{2.0in}
       \everypar={\chatline}
}{%
   \end{minipage}
}

\definecolor{mygreen}{HTML}{88EABB}

%% Alter colors to suit
\def\chatline#1\par{%
   \stepcounter{chatlinenum}%
   \noindent
   \ifodd\thechatlinenum
       \tikz[]{\node[fill=lightgray,chatstyle]{\strut#1\strut};}%
   \else
       \hfill
       \tikz[]{\node[fill=mygreen,chatstyle,align=right]{\strut#1\unskip\strut};}%
   \fi
   \par
   \smallskip
}

%% |=====8><-----| %% New solution:

%% Alter colors to suit
\begingroup
    \lccode`~=`\^^M
    \lowercase{%
\endgroup
    \def\newchatline#1~{%
        \stepcounter{chatlinenum}%
        \ifodd\thechatlinenum
            \tikz[]{\node[fill=lightgray,chatstyle]{\strut#1\strut};}%
        \else
            \hfill
            \tikz[]{\node[fill=mygreen,chatstyle,align=right]{\strut#1\strut};}%
        \fi
        ~
        \smallskip
    }%
}

\NewDocumentEnvironment{newchat}{}{%
    \setcounter{chatlinenum}{0}
    \begin{minipage}{2.0in}
        \obeylines
        \everypar={\newchatline}
}{%
    \end{minipage}
}

\begin{document}

%% The new answer (no empty lines between entries):

New chat:

\begin{newchat}
a which might go on for a bit and be quite long\\[10pt]with a line break
v
b
u
question
answer
How many existentialists does it take to change a light bulb?
That depends...
\end{newchat}

%% |=====8><-----| %%

%% The original answer:

\bigskip

Old chat:

\begin{chat}
a which might go on for a bit and be quite long\\[10pt]with a line break

v

b

u

question

answer

How many existentialists does it take to change a light bulb?

That depends...

\end{chat}

\end{document}

new sample

3
  • That's perfect, mate. Thanks very much. I definitely wouldn't have got there by myself. – Vale Boca May 27 '20 at 8:38
  • I made some minor changes to make the solution even more flexible for my use. I sometimes want to put 2 of those chats side by side. Therefore I added an optional argument to the environment with \NewDocumentEnvironment{chat}{ O{0.7\linewidth} and made tikz node width refer to linewidth as well \tikzset{chatstyle/.style={text width=0.7\linewidth .... So in the end I can provide the width of the minipage when using the environment and the nodes take 70% of the available width in the minipage. \begin{chat}[0.4\linewidth] ... – Vale Boca May 27 '20 at 9:22
  • Excellent! I'm glad that I could help. – sgmoye May 27 '20 at 9:30
0

Because i have no experiences with the environ package, i stuck to tikz. However,k it is only a first try, but i think it should be a good start for improvements.

\documentclass[tikz]{standalone}

\definecolor{chatcolor1}{HTML}{5fedb7}
\definecolor{chatcolor2}{HTML}{b6b8b7}
\fontfamily{cmss}\selectfont

\tikzset{
    msgBase/.style={align=left,
        minimum width=5cm, 
        minimum height=.5cm,
        rounded corners=1mm,
    },
    ownMsg/.style={msgBase, 
        anchor=north east,
        fill=chatcolor1,
        xshift=+5pt,
    },
    oppMsg/.style={msgBase, 
        anchor=north west,
        fill=chatcolor2,
        xshift=-5pt,
    },
}

\newcommand{\ownChat}[3]{
    \node[ownMsg,name=#1] at (#2) {#3};
}
\newcommand{\oppChat}[3]{%
    \node[oppMsg,name=#1] at (#2) {#3};
}

\begin{document}

that is looking nice ...
\begin{tikzpicture}
\node[ownMsg,name=own1] at (0,0) {Question};
\node[oppMsg,name=opp1] at (own1.south) {Answer};
\node[ownMsg,name=own2] at (opp1.south) {Question\\long};
\node[oppMsg,name=opp2] at (own2.south) {Answer};
\end{tikzpicture}


... but there is still work to do (an alternative to the code before)
\begin{tikzpicture} 
\ownChat{own1}{0,0}{Question}
\oppChat{opp1}{own1.south}{Answer}
\ownChat{own2}{opp1.south}{really long and detailed Question}
\oppChat{opp2}{own2.south}{Question}
\end{tikzpicture}

\end{document}

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.