1

In cases when input text to be typeset is separate from the structured template, can the input determine the height and width of its containing box?

An example input. Question marks (?) to be substituted (Lua or TeX).

The width of the parent box is ?

The height of the parent box is ?

Several possible templates:

\ruledhbox to 10cm{\vbox to 4cm{ \input input }} % 10cm by 4cm
\ruledvbox to 4cm{\hsize=10cm \input input } % 10cm by 4cm
\framed
    [width=10cm,
     height=4cm,
     align={middle,lohi},
     offset=0.5cm]
    { \input input } % 9cm by 3cm

Dimensions are meaningless until the box has been stored, so that's probably the place to start.


My expansion of the \aftergroup+\lastbox answer:

\typeset{\hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}}
{   \let\parht\askparent\let\parwd\askparent\let\pardp\askparent
    \setbox0=\hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}
    \hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}
}
{   \let\parht\askparent\let\parwd\askparent\let\pardp\askparent
    \setbox0=\hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}
    \hbox to50pt{\vbox to40pt{\hbox to30pt{width: \askparent }}}
}
{   \let\parht\askparent\let\parwd\askparent\let\pardp\askparent
    \setbox0=\hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}
    \hbox to50pt{\vbox to40pt{\hbox to30pt{width: } \afterafter }}
}
{   \let\parht\askparent\let\parwd\askparent\let\pardp\askparent
    \setbox0=\hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}
    \hbox to50pt{\vbox to40pt{\hbox to30pt{width: }} \after }
}
{   \let\parht\askparent\let\parwd\askparent\let\pardp\askparent
    \setbox0=\hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}
    \hbox to50pt{
        \setbox\storelast=\vbox to40pt{\hbox to30pt{width: }}
        \xdef\parht{\the\ht\storelast}
        \xdef\parwd{\the\wd\storelast}
        \xdef\pardp{\the\dp\storelast}
        \ifvmode\nointerlineskip\fi\box\storelast}
}
{   \let\parht\askparent\let\parwd\askparent\let\pardp\askparent
    \setbox0=\hbox to50pt{\vbox to40pt{\hbox to30pt{width: \parwd }}}
    \hbox to50pt{
        \setbox\storelast=\vbox to40pt{\hbox to30pt{width: }}
        \xdef\parht{\the\ht\storelast}
        \xdef\parwd{\the\wd\storelast}
        \xdef\pardp{\the\dp\storelast}
        \vbox to40pt{\hbox to30pt{width: }}}
}
7
  • I thought I had seen a similar question a few years ago but I can't find it.
    – user19087
    Commented Mar 23, 2020 at 4:36
  • 1
    With bare TeX boxes I don't think it is possible, but within a \framed you can just query \framedparameter{width} to get the width. Commented Mar 23, 2020 at 6:42
  • Just waiting for someone from LuaTeX to chime in. "Why yes, we do have pointers for backtracking up the node tree". So many good answer.
    – user19087
    Commented Mar 23, 2020 at 20:18
  • @user19087 the mistake you made with the expansion is that the \setbox0 assignment is carried out before anything in the following line is evaluated, including the call to \parwd in the assignment. therefore, everything you did afterwards is actually done in the \setbox0 line first, and after that the rest is expanded, but this time \parwd is the width of the parent box.
    – wave
    Commented Mar 23, 2020 at 21:21
  • 1
    Can you show with a real example what you're trying to achive because there are other ways to determine the width and height of the box size, e.g. many of ConTeXts tabl environment use multiple passes to determine the size of each cell. When you do something similar in combination with a buffer to store the content of the box you can get the size of the box and show it afterwards in the box. Commented Mar 24, 2020 at 2:08

2 Answers 2

3

When you use \framed for your texts you can get the width of the content in the box with the \framedwidth and \framedheight commands. A restriction here is that you get only usable value when the width or height settings contains a length larger than 0pt.

\starttext

\startframed[width=200pt,height=80pt,offset=10pt,rulethickness=0.5pt]
     Width: \framedwidth \par
    Height: \framedheight
\stopframed

\stoptext

enter image description here

To get the values of the width and height keys you can use the \localwidth and \localheight commands. Here you should be ware of that ConTeXt delivers whathever value was set with the key, i.e. when you set width=fit the \localwidth commands gives you fit as argument.

\starttext

\startframed[width=200pt,height=80pt,offset=10pt,rulethickness=0.5pt]
     Width: \localwidth \par
    Height: \localheight
\stopframed

\stoptext

enter image description here

The last possible value can be used for the background of a frame but unlike the previous methods you get the correct width or height of the frame even with settings like width=fit.

\defineoverlay
  [boxdimensions]
  [\vbox\bgroup
     \hbox {Width: \overlaywidth}
     \hbox{Height: \overlayheight}
   \egroup]

\setupframed % don't make global framed settings in a document
  [background=boxdimensions]

\starttext

\startframed[width=200pt,height=80pt,offset=10pt,rulethickness=0.5pt]
    %
\stopframed

\stoptext

enter image description here

3
  • I assume \local<key> command is a subset of \framedparameter{<key>}? If the key is missing, ConTeXt complains ! Missing number, treated as zero. Is it possible to fallback to other values, i.e. loffset -> offset -> 0?
    – user19087
    Commented Mar 23, 2020 at 14:54
  • If I have width, offset, and loffset then framedwidth = width - 2*offset - loffset. Is this right? I assumed it would be framedwidth = width - offset - loffset? Is this the way ConTeXt has always worked, or is \framedwidth wrong?
    – user19087
    Commented Mar 23, 2020 at 14:56
  • The offset value is applied on all four sides while the loffset etc. values are only applied on the requested in addition to the global offset value. When you use the \local<key> commands for a calculation you have to check first if it's empty or contain a valid dimension. The value of \framedwidth is width - 2*offset - loffset - roffset - 2*rulethickness. Commented Mar 23, 2020 at 15:08
1

This "solution" is surely not universal and well thought through, but it works for me in simple cases, with plain TeX:

\newbox\storelast
\def\after{\setbox\storelast=\lastbox
  {\globaldefs=1
  \edef\parht{\the\ht\storelast}
  \edef\parwd{\the\wd\storelast}
  \edef\pardp{\the\dp\storelast}}
  \ifvmode\nointerlineskip\fi\box\storelast}
\def\afterafter{\aftergroup\after}
\def\askparent{\aftergroup\afterafter}

\def\typeset#1{\let\parht\askparent\let\parwd\askparent\let\pardp\askparent
  {\globaldefs=-1 \setbox0#1}#1}

Afterwards, you can typeset the template with \typeset{...}. In the input, you can use \parwd, \parht and \pardp to get the width, height and depth of the parent box, respectively. The argument of \typeset has to be a box (it has to start with \hbox, \vbox ...).

For example, I have a file called input.tex that contains

width \parwd\ height \parht.

Then, the following lines

\typeset{\hbox to50pt{\vbox to40pt{\hbox to30pt{\input input }}}}
\typeset{\vbox to50pt{\hbox to40pt{\vbox to30pt{\input input }}}}

print (apart from many over/underfull boxes)

width 30.0pt height 40.0pt
width 40.0pt height 30.0pt

correctly. However,

  • I have no idea how well this behaves for more complex constructs;
  • Edit: As pointed out by Henri Menke in the comments, typesetting the box twice (with \setbox0#1 followed by #1) might lead to unexpected side effects, for example if counters are increased in the box. I tried to reduce that problem by evaluating the \setbox0#1 in a group with \globaldefs=-1, but this might change the dimensions of the box if packages relying on global definitions are used, such as tikz, yielding incorrect results;
  • it assumes that the commands \parht etc. are not used inside a group other than the ones created by the boxes;
  • it will only work if the parent box is not on the main vertical list as it uses \lastbox to determine the box dimensions, which is empty in external vertical mode.

For the last point, consider the example above, but now we are interested in the dimensions of the outermost box:

\typeset{\hbox to50pt{\vbox to40pt{\hbox to30pt{\input input }}}}
\typeset{\vbox to50pt{\hbox to40pt{\vbox to30pt{\input input }}}}

would print

width 0.0pt height 0.0pt
width 0.0pt height 0.0pt

because the outermost box is set in external vertical mode. In this case, you would have to wrap your template with another box, like

\typeset{\hbox{\hbox to50pt{\vbox to40pt{\hbox to30pt{}\input input }}}}
\typeset{\hbox{\vbox to50pt{\hbox to40pt{\vbox to30pt{}\input input }}}}

printing

width 50.0pt height 40.0pt
width 40.0pt height 50.0pt

as expected.

13
  • I understand where this is going but can't match the output when expanding by hand. What is the point of \setbox0? The \parwd in width \parwd is expanded to the xdefs two boxes upwards, leaving nothing after "width". And why not just call \after before \input, allowing \parht etc to be used within nested groups?
    – user19087
    Commented Mar 23, 2020 at 20:00
  • I will edit temporarily edit my question to show my expansion.
    – user19087
    Commented Mar 23, 2020 at 20:02
  • the problem is that if you would just use the template as it is and call \after before \input, the \xdef assignments are carried out only after the input was read, so that \parwd does not have an effect (as you observed). so I do it in two passes: \setbox0#1 serves to have the assignments carried out (and the use of \setbox hides the result), and then the argument is set again, but this time \parwd has its final meaning.
    – wave
    Commented Mar 23, 2020 at 20:25
  • 1
    This is not a good idea. You are typesetting the box twice, i.e. you are evaluating the content twice. If you, for example, increase a counter inside the box, you will increase it twice. Commented Mar 25, 2020 at 0:11
  • 1
    @wave There is no way to do this without side-effects. If you set \globaldefs=-1 you can no longer use TikZ patterns, shadings, or fadings inside, because it uses global variables to count and deduplicate the corresponding PDF objects (other packages might do similar things, maybe hyperref?). Commented Mar 25, 2020 at 0:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .