Last active
February 2, 2022 00:33
-
-
Save xziyue/879009a25e96e2710afa9d54345573dc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% https://tex.stackexchange.com/questions/632271/chat-like-text-bock-in-tikz-environment | |
\documentclass{article} | |
\usepackage[T1]{fontenc} | |
\usepackage{mathpazo} | |
\usepackage{tikz} | |
\usepackage{xcolor} | |
\usepackage{xparse} | |
\usepackage{calc} | |
\usepackage{varwidth} | |
\usetikzlibrary{positioning,calc} | |
\ExplSyntaxOn | |
\def\ChatBlockWidth{8cm} | |
\def\UserMinWidth{2cm} | |
\def\UserMaxWidth{6cm} | |
\def\NumberOfBubbles{8} | |
\def\SmallestBubbleDiameter{2pt} | |
\def\ChatInterval{0.3cm} | |
\def\BubbleScaleCoef{1.3} | |
\def\BubbleHeight{2cm} | |
\def\BubbleHShift{1.5cm} | |
\definecolor{user-1-color}{HTML}{CCF4C6} | |
\definecolor{user-2-color}{HTML}{FDE9A9} | |
\definecolor{user-frame-color}{HTML}{5D89B0} | |
\definecolor{face-eye-color-1}{HTML}{A3C39E} | |
\definecolor{face-eye-color-2}{HTML}{CABA87} | |
\newcommand{\ExtractCoordinate}[1]{\path (#1); \pgfgetlastxy{\XCoord}{\YCoord};}% | |
\tikzset{ | |
chatnode/.style={ | |
draw=user-frame-color, | |
rounded~corners=4pt, | |
inner~sep=6pt, | |
} | |
} | |
\tikzset{ | |
pics/smiley-face/.style~n~args={3}{ | |
code={ | |
\begin{scope}[scale=#1] | |
\draw[draw=user-frame-color, fill=#2] (0,0) circle (1cm); | |
\draw[draw=user-frame-color, fill=#3] (-0.32,0.2) ellipse (0.08cm~and~0.15cm); | |
\draw[draw=user-frame-color, fill=#3] (0.32,0.2) ellipse (0.08cm~and~0.15cm); | |
\draw[draw=user-frame-color] (-0.6, -0.3) to[out=-60, in=-120] (0.6, -0.3); | |
\end{scope} | |
} | |
} | |
} | |
% template for bubbles | |
\cs_set:Npn \__chat_node_template:nnnnn #1#2#3#4#5 { | |
\exp_not:n { | |
node[ | |
pos=#1, | |
fill=#3, | |
draw=user-frame-color, | |
circle, | |
inner~sep=0pt, | |
outer~sep=0pt, | |
minimum~width=#2, | |
xshift={#4}, | |
yshift={#5} | |
] | |
{} | |
} | |
} | |
\cs_generate_variant:Nn \__chat_node_template:nnnnn {eennn} | |
\cs_set:Npn \__chat_pic_template:nnnnnn #1#2#3#4#5#6 { | |
\exp_not:n { | |
pic[ | |
pos=#1, | |
xshift={#5}, | |
yshift={#6} | |
] | |
{smiley-face={#2}{#3}{#4}} | |
} | |
} | |
\fp_new:N \l_chat_tmpa_fp | |
\fp_new:N \l_chat_tmpb_fp | |
\fp_new:N \l_chat_tmpc_fp | |
\fp_new:N \l_chat_tmpa_tl | |
% pos1, pos2, color, in, out, last scale, last x offset , last y offset, eye color | |
\newcommand{\ChatBubble}[9]{ | |
\fp_set:Nn \l_chat_tmpa_fp {\dim_to_fp:n {\SmallestBubbleDiameter}} | |
\fp_set:Nn \l_chat_tmpb_fp {1/(\NumberOfBubbles-1)} | |
\tl_clear:N \l_chat_tmpa_tl | |
\tl_set:Nn \l_chat_tmpa_tl {\path (#1) to[in=#4,out=#5]} | |
\int_step_inline:nn {\NumberOfBubbles - 1} { | |
\tl_put_right:Nx \l_chat_tmpa_tl { | |
\__chat_node_template:eennn {\fp_eval:n {(##1 - 1) * \l_chat_tmpb_fp}} | |
{\fp_use:N \l_chat_tmpa_fp~pt} | |
{#3} {0pt} {0pt} | |
} | |
\fp_set:Nn \l_chat_tmpa_fp {\BubbleScaleCoef * \l_chat_tmpa_fp} | |
} | |
% the last bubble | |
\fp_set:Nn \l_chat_tmpa_fp {#6 * \l_chat_tmpa_fp} | |
% compute the relative scale for the face | |
\fp_set:Nn \l_chat_tmpc_fp {\l_chat_tmpa_fp~pt/(2cm)} | |
\tl_put_right:Nx \l_chat_tmpa_tl { | |
\__chat_pic_template:nnnnnn {1.0} {\fp_use:N \l_chat_tmpc_fp} {#3} {#9} | |
{#7} {#8} | |
} | |
\tl_put_right:Nn \l_chat_tmpa_tl {(#2);} | |
\tl_use:N \l_chat_tmpa_tl | |
} | |
\int_new:N \l_chat_box_index_int | |
\tl_new:N \l_chat_user_a_last_node_tl | |
\tl_new:N \l_chat_user_b_last_node_tl | |
\dim_new:N \l_chat_tmpa_dim | |
\dim_new:N \l_chat_tmpb_dim | |
\dim_new:N \l_chat_tmpc_dim | |
\dim_new:N \l_chat_tmpd_dim | |
\dim_new:N \l_chat_tmpe_dim | |
\dim_new:N \l_chat_last_vert_dim | |
\dim_new:N \l_chat_width_dim | |
\box_new:N \l_chat_tmpa_box | |
\newcommand{\GetLastVertPos}{ | |
\tl_if_empty:NTF \l_chat_user_a_last_node_tl { | |
\dim_set:Nn \l_chat_tmpa_dim {-\ChatInterval} | |
} { | |
\ExtractCoordinate{\l_chat_user_a_last_node_tl.south} | |
%\GetSouthY{\l_chat_user_a_last_node_tl} | |
\dim_set:Nn \l_chat_tmpa_dim {\YCoord} | |
\iow_term:x {y~coord~is~\YCoord} | |
} | |
\tl_if_empty:NTF \l_chat_user_b_last_node_tl { | |
\dim_set:Nn \l_chat_tmpb_dim {-\ChatInterval} | |
} { | |
\ExtractCoordinate{\l_chat_user_b_last_node_tl.south} | |
\dim_set:Nn \l_chat_tmpb_dim {\YCoord} | |
} | |
\dim_compare:nNnTF \l_chat_tmpa_dim < \l_chat_tmpb_dim { | |
\dim_set_eq:NN \l_chat_last_vert_dim \l_chat_tmpa_dim | |
} { | |
\dim_set_eq:NN \l_chat_last_vert_dim \l_chat_tmpb_dim | |
} | |
} | |
\newcommand{\CalcChatWidth}[1]{ | |
\hbox_set:Nn \l_chat_tmpa_box {\pgfinterruptpicture #1 \endpgfinterruptpicture} | |
\dim_compare:nNnTF {\box_wd:N \l_chat_tmpa_box} < {\UserMinWidth} { | |
\dim_set:Nn \l_chat_width_dim {\UserMinWidth} | |
} { | |
\dim_compare:nNnTF {\box_wd:N \l_chat_tmpa_box} < {\UserMaxWidth} { | |
\dim_set:Nn \l_chat_width_dim { | |
\dim_min:nn {\box_wd:N \l_chat_tmpa_box + 0.2cm} {\UserMaxWidth} | |
} | |
} { | |
\dim_set:Nn \l_chat_width_dim {\UserMaxWidth} | |
} | |
} | |
} | |
\NewDocumentEnvironment{ChatBox}{}{ | |
\tl_clear:N \l_chat_user_a_last_node_tl | |
\tl_clear:N \l_chat_user_b_last_node_tl | |
\int_set:Nn \l_chat_box_index_int {1} | |
\newcommand{\UserA}[1]{ | |
\GetLastVertPos | |
\CalcChatWidth{##1} | |
\node[chatnode, fill=user-1-color, anchor=north~west, text~width=\l_chat_width_dim] | |
(chat-\int_use:N \l_chat_box_index_int) | |
at ($(0pt, \dim_use:N \l_chat_last_vert_dim)-(0pt, \ChatInterval)$) | |
{##1}; | |
\tl_set:Nx \l_chat_user_a_last_node_tl {chat-\int_use:N \l_chat_box_index_int} | |
\int_incr:N \l_chat_box_index_int | |
} | |
\newcommand{\UserB}[1]{ | |
\GetLastVertPos | |
\CalcChatWidth{##1} | |
\node[chatnode, fill=user-2-color, anchor=north~east, text~width=\l_chat_width_dim] | |
(chat-\int_use:N \l_chat_box_index_int) | |
at ($(\ChatBlockWidth, \dim_use:N \l_chat_last_vert_dim)-(0, \ChatInterval)$) | |
{##1}; | |
\tl_set:Nx \l_chat_user_b_last_node_tl {chat-\int_use:N \l_chat_box_index_int} | |
\int_incr:N \l_chat_box_index_int | |
} | |
\begin{tikzpicture} | |
}{ | |
\ChatBubble{\l_chat_user_a_last_node_tl.south~west} | |
{$(\l_chat_user_a_last_node_tl.south~west)+(\BubbleHShift,-\BubbleHeight)$} | |
{user-1-color}{120}{-120}{2.0}{0.5cm}{0em}{face-eye-color-1} | |
\ChatBubble{\l_chat_user_b_last_node_tl.south~east} | |
{$(\l_chat_user_b_last_node_tl.south~east)+(-\BubbleHShift,-\BubbleHeight)$} | |
{user-2-color}{30}{-30}{2.0}{-0.5cm}{0em}{face-eye-color-2} | |
\end{tikzpicture} | |
} | |
\ExplSyntaxOff | |
\begin{document} | |
\begin{ChatBox} | |
\UserA{Hello, it's me!} | |
\UserA{I was wondering if after all these years you'd like to meet.} | |
\UserB{\emph{Hi...but who are you?}} | |
\UserA{S'up} | |
\UserA{dude?} | |
\UserB{\emph{Well nothing man...}} | |
\UserB{\emph{Who is it?}} | |
\UserA{Well, of course as usual brother.} | |
\end{ChatBox} | |
% | |
%This is the environment | |
%\begin{tikzpicture} | |
%\node[chatnode] {hello}; | |
%%\ChatBubble{0,0}{1,-3}{user-1-color}{120}{-120}{2.0}{3em}{0em} | |
%\end{tikzpicture} | |
\end{document} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment