3

How do I make a special node out of the command \innblock?

\documentclass[tikz,border=5]{standalone}

\makeatletter
\newcommand\getwidthofnode[2]{%
    \pgfextractx{#1}{\pgfpointanchor{#2}{east}}%
    \pgfextractx{\pgf@xa}{\pgfpointanchor{#2}{west}}% \pgf@xa is a length defined by PGF for temporary storage. No need to create a new temporary length.
    \addtolength{#1}{-\pgf@xa}%
}
\makeatother

\newlength\IBheaderheight \setlength\IBheaderheight{1cm}
\newlength\IBwidth \setlength\IBwidth{8cm}
\newlength\IBheight \setlength\IBheight{6cm}

\newlength\blockroundedcorners\setlength\blockroundedcorners{0.5cm}
\newlength\blocklinewidth\setlength\blocklinewidth{3mm}

\colorlet{blocktitlebgcolor}{red}
\colorlet{blockbodybgcolor}{white}

\newcommand{\innblock}[4]{
    \node[minimum size=\IBheight, minimum width=\IBwidth] (IBnode) at (#1,#2) {};
    \begin{scope}[line width=\blocklinewidth, rounded corners=\blockroundedcorners, color=blocktitlebgcolor]
    \draw[fill=blocktitlebgcolor] (IBnode.north west) rectangle (IBnode.south east);
    \draw[fill=blockbodybgcolor] ([shift={(0,-\IBheaderheight)}]IBnode.north west) rectangle (IBnode.south east);
    \newlength\mywidth\getwidthofnode{\mywidth}{IBnode}
    \node[below right=\blocklinewidth, align=left, text=black, text width=\mywidth-3\blocklinewidth] at ([shift={(0,-\IBheaderheight)}]IBnode.north west) {#4};
    \node[align=center, text=white, text width=\mywidth-3\blocklinewidth] at ([shift={(0,-0.5\IBheaderheight)}]IBnode.north) {#3};
    \end{scope}
}

\begin{document}

\begin{tikzpicture}

\innblock{2}{1}{Header}{Body} % instead of this, I would like to have:

% \node[innblock = Header ] at (2,1) {Body};

\end{tikzpicture}

\end{document}

enter image description here

I considered Use node text as argument for a macro but was not able to get it done.

Make42
  • 1,772
  • Wouldn't it be easier to do this with something like tcolorbox? – cfr Dec 08 '15 at 22:41
  • @cfr: I'll have a look - however I nearly got it here... do you know how to get my second try right? – Make42 Dec 09 '15 at 10:48
  • @cfr: tcolorbox only gets me so far: The issue remains how to get the text from the node into the tcolorbox. – Make42 Dec 09 '15 at 11:03
  • Please ask your edit as a new question and delete it from this one. – Alenanno Dec 09 '15 at 13:21
  • @Alenanno: Good point. I already asked the question, but you are right, that the edit does not belong here. – Make42 Dec 09 '15 at 13:23
  • Why does it need to be in a node at all? Why not just put it in the box? – cfr Dec 09 '15 at 22:16
  • @cfr: What I want to, is that I define something (a node was my idea) and just say, this is the style (here: "innblock") and it gives me the design element. I was necessarily looking for a node, but that made sense to me. Besides that, in my actual work, the node is connected with other elements. I am not entirely sure how you "just put in the box", since I have two rectangles here. – Make42 Dec 10 '15 at 08:35

3 Answers3

5

You could use a multipart node. The white part inside is not rounded everywhere, but the rest works as your example in the question.

Output

example image

Code

\documentclass[tikz,border=10pt]{standalone}

\usetikzlibrary{shapes.multipart}

\newlength\IBheaderheight \setlength\IBheaderheight{1cm}
\newlength\IBwidth \setlength\IBwidth{8cm}
\newlength\IBheight \setlength\IBheight{6cm}

\newlength\blockroundedcorners\setlength\blockroundedcorners{0.5cm}
\newlength\blocklinewidth\setlength\blocklinewidth{3mm}

\tikzset{
    ib/.style={
    rectangle split, rectangle split parts=2,
    rectangle split draw splits=false,
    rounded corners=\blockroundedcorners,
    line width=\blocklinewidth,
    minimum height=\IBheight,
    minimum width=\IBwidth,
    text width=\IBwidth-\blocklinewidth*2,
    draw=#1,
    rectangle split part fill={#1, none},
    text=white, text centered
    },
    every two node part/.style={align=left, text=black},
}

\begin{document}
\begin{tikzpicture}

\node[ib={red}] {Header\nodepart{two}Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent gravida ligula non dolor sagittis, at sagittis felis gravida. Integer vitae lorem non sapien pellentesque euismod. Aliquam eleifend justo at eros vulputate pulvinar. Sed egestas felis massa, eu lacinia nisi vehicula vitae. Nunc molestie quis augue ut dictum. Mauris pellentesque purus id aliquet efficitur. Donec eget euismod quam. Fusce sed erat ligula. Quisque at dolor nisl. Ut eu gravida tellus, eget convallis mauris.};

\end{tikzpicture}
\end{document}
Alenanno
  • 37,338
3

I understand that OP wants to define some titled and colorful boxes which can be places like nodes on some tikzpicture. tcolorbox produces title and colorful boxes, and these boxes can be used as text in TikZ nodes. Therefore, I propose something like:

\documentclass[tikz,border=2mm]{standalone}
\usepackage{lmodern}
\usepackage[most]{tcolorbox}

\tcbset{colframe=red!85!black, fonttitle=\bfseries}

\newtcolorbox{mybox}[2][]{
    enhanced,
    colframe=red,
    fonttitle=\bfseries,
    halign title=center,
    boxrule=3mm,
    height=5cm,
    valign=top,
    width=7cm,
    interior titled code={
        \fill[rounded corners=3mm, fill=white] (interior.north west) rectangle (interior.south east);
    },
    #1,
    title=#2
    }

\begin{document}

\begin{tikzpicture}

\draw (0,0) grid (8,12);

\node[above right, inner sep=0pt] at (0,0) {%
\begin{mybox}{Header}
This is my new box made with \texttt{tcolorbox}.
\end{mybox}};

\node[above, inner sep=0pt] at (5,6) {%
\begin{mybox}[colframe=green, width=3cm, boxrule=1mm]{Header}
This is my tcolorbox
\end{mybox}};
\end{tikzpicture}

\end{document}

which results

enter image description here

Original not so good answer

Not exactly what OP wants but it inblock style is now a .style with two parameters (header and node contents) and node coordinates can be used as at (x,y):

\node[inblock={Header}{Some longer text}] at (2,1) {};

In this case only one node is drawn with header and contents being two node label. For contents label a parbox with defined height and width has been used. Margins and parbox dimensions still need some work but the code is just a proposal.

\documentclass[tikz,border=5]{standalone}

\makeatletter
\newcommand\getwidthofnode[2]{%
    \pgfextractx{#1}{\pgfpointanchor{#2}{east}}%
    \pgfextractx{\pgf@xa}{\pgfpointanchor{#2}{west}}% \pgf@xa is a length defined by PGF for temporary storage. No need to create a new temporary length.
    \addtolength{#1}{-\pgf@xa}%
}
\makeatother

\newlength\IBheaderheight \setlength\IBheaderheight{1cm}
\newlength\IBwidth \setlength\IBwidth{8cm}
\newlength\IBheight \setlength\IBheight{6cm}

\newlength\blockroundedcorners\setlength\blockroundedcorners{0.5cm}
\newlength\blocklinewidth\setlength\blocklinewidth{3mm}

\newlength\innerblocktextwidth
\setlength\innerblocktextwidth{\IBwidth}
\addtolength\innerblocktextwidth{-3\blocklinewidth}

\newlength\innerblocktextheight
\setlength\innerblocktextheight{\IBheight}
\addtolength\innerblocktextheight{-\IBheaderheight}

\colorlet{blocktitlebgcolor}{red}
\colorlet{blockbodybgcolor}{white}

\begin{document}

\begin{tikzpicture}[
    inblock/.style 2 args={
        draw=blue,
        minimum size=\IBheight,
        minimum width=\IBwidth,
        outstyle,
        label={[outstyle,anchor=north,text=white]#1},
        label={[instyle, anchor=south, yshift=.5\blocklinewidth]below:\parbox[t][\innerblocktextheight][t]{\innerblocktextwidth}{#2}},
    },
    outstyle/.style={
        line width=\blocklinewidth,
        color=blocktitlebgcolor,
        rounded corners=\blockroundedcorners,
        draw,
        fill
    },
    instyle/.style={
        rounded corners=\blockroundedcorners,
        draw=blocktitlebgcolor,
        fill=blockbodybgcolor
    }]      

\node[inblock={Header}{Some longer text}] at (2,1) {};
\end{tikzpicture}

\end{document}

enter image description here

Ignasi
  • 136,588
  • Interesting and valid alternative: +1. Long text (as my case has), is an issue though. But besides that I think it's pretty neat. – Make42 Dec 10 '15 at 09:09
  • @Make42: I've updated my answer with what I think is a better solution. – Ignasi Dec 11 '15 at 11:12
  • This is much improved. I think your code is more concise then mine. Both have different advantages. Yours wields the power of tcolorbox, mine the power of tikz (even more powerful, but more difficult). Yours has the advantage of being simpler, mine needs less code in the document... Hard to decide :-) (Don't think that I am biased.) – Make42 Dec 14 '15 at 18:31
1

I managed to do it. The opacity etc. is so you can see what is happening underneath easier:

\documentclass[tikz,border=5]{standalone}
\usepackage{blindtext}

\makeatletter
\newcommand\getwidthofnode[2]{%
    \pgfextractx{#1}{\pgfpointanchor{#2}{east}}%
    \pgfextractx{\pgf@xa}{\pgfpointanchor{#2}{west}}% \pgf@xa is a length defined by PGF for temporary storage. No need to create a new temporary length.
    \addtolength{#1}{-\pgf@xa}%
}
\makeatother

\newlength\IBheaderheight \setlength\IBheaderheight{1cm}
\newlength\IBwidth \setlength\IBwidth{8cm}
\newlength\IBheight \setlength\IBheight{1.7cm}

\newlength\blockroundedcorners\setlength\blockroundedcorners{0.5cm}
\newlength\blocklinewidth\setlength\blocklinewidth{3mm}

\colorlet{blocktitlebgcolor}{red}
\colorlet{blockbodybgcolor}{white}

\newlength\mywidth
\newcommand{\save}[1]{\gdef\lastsave{#1}#1}

\tikzset{
    innblock/.style = {
        alias=IBnode, minimum size=\IBheight, minimum width=\IBwidth, text width=\IBwidth-3\blocklinewidth,
        append after command = {\pgfextra{
                \begin{scope}[line width=\blocklinewidth, rounded corners=\blockroundedcorners, color=blocktitlebgcolor]
                \getwidthofnode{\mywidth}{IBnode}
                \draw[below right, fill=blocktitlebgcolor, opacity=0.5] ([shift={(0,\IBheaderheight+0.5\blocklinewidth)}]IBnode.north west) rectangle ([shift={(0,-0.5\blocklinewidth)}]IBnode.south east);
                \draw[below right, fill=blockbodybgcolor, opacity=0.5] ([shift={(0,0.5\blocklinewidth)}]IBnode.north west) rectangle ([shift={(0,-0.5\blocklinewidth)}]IBnode.south east);
                \node[below right=0mm, align=left, text=black, text width=\mywidth-2\blocklinewidth] at ([shift={(0,0.5\blocklinewidth)}]IBnode.north west) {\lastsave};
                \node[align=center, text=white, text width=\mywidth-3\blocklinewidth] at ([shift={(0,0.5\IBheaderheight+0.5\blocklinewidth)}]IBnode.north) {#1};
                \end{scope}
        }}
    }
}

\begin{document}

\begin{tikzpicture}

\node[innblock=Header1] at (0,0) {\save{asadfasdfasdf}};

\node[innblock=Header2] at (0,-4.25) {\save{asadfasdfasdf \\ asadfasdfasdf asadfasdfasdf \\ a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i \\ asadfasdfasdf \\ asadfasdfasdf}};

\node[innblock=Header3] at (0,-10) {\save{bsbdfbsdfbsdf \\ bsbdfbsdfbsdf bsbdfbsdfbsdf \\ b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i \\ bsbdfbsdfbsdf \\ bsbdfbsdfbsdf \\ asdfasdf \\ asdfasdf asdfa \\ asdfasd \\asdfasd }};

\end{tikzpicture}

\end{document}

enter image description here

Acknowledgements

Related questions that got the last roadblock out of the way for me (thanks to esdd):

Also essential:

Related questions (not contributing to this answer, but I am still thankful for the support, especially to percusse and Bordaigorl):

Make42
  • 1,772
  • This looks good. But you should attribute the code properly for the code you've borrowed from other authors. – cfr Dec 09 '15 at 22:19