I'm currently getting into ConTeXt, mainly to experiment with MetaFun. I want to get a feeling for how usable it would be to generate some sophisticated diagrams I have in mind. I have a hard time to wrap my head around some concepts, so I'll try to get started with a hopefully simple question:

Assuming I have a list of three strings: "short", "a bit longer", "a much much longer string". I want to plot those strings below each other from top to bottom, each having a box around them. All boxes should have the same size, so the longest string defines the box size for all of them. The strings in the boxes should be centered.

Obviously this requires the size of the longest string to define the width for the other ones. And then the size of those strings to center them.

Is that possible in MetaFun? I don't see how to solve that "inside" MetaFun, but with an "external" code generator I would not be able to determine the size of the rendered strings upfront. Is Lua the solution?

If that's possible at all, could somebody point me to an example or a good starting point in the docs?

3 Answers 3


Here is another method to draw such a figure in metapost using the boxes package:

  input boxes;

  boxit.A("\strut short");
  boxit.B("\strut a bit longer");
  boxit.C("\strut a much longer string");

  numeric maxwidth; 
  maxwidth := max(xpart lrcorner boxes_pic.A - xpart llcorner boxes_pic.A,
                  xpart lrcorner boxes_pic.B - xpart llcorner boxes_pic.B,
                  xpart lrcorner boxes_pic.C - xpart llcorner boxes_pic.C);

  % Specify that all boxes have the same width
  xpart A.e - xpart A.w = xpart B.e - xpart B.w 
                        = xpart C.e - xpart C.w 
                        = maxwidth + 10pt;

  % Specify the boxes should be placed vertically
  ypart A.s - ypart B.n = ypart B.s - ypart C.n = 5mm;


enter image description here


I have a feeling that there are better ways to do what you want to do, but here is a simple way to get what I guess you are looking for.

picture a,b,c ;
numeric maxwidth ;

a = textext("\strut short") ;
b = textext("\strut a bit longer") ;
c = textext("\strut a much much longer string") ;

maxwidth = max(xpart lrcorner a - xpart llcorner a, 
               xpart lrcorner b - xpart llcorner b, 
               xpart lrcorner c - xpart llcorner c) ;

draw boundingbox a xysized (maxwidth, ypart ulcorner a - ypart llcorner a) ;
draw a ;

draw image(
    draw boundingbox b xysized (maxwidth, ypart ulcorner b - ypart llcorner b) ;
    draw b ;
) yshifted -1.5(ypart ulcorner b - ypart llcorner b) ;

draw image(
    draw boundingbox c xysized (maxwidth, ypart ulcorner c - ypart llcorner c) ;
    draw c ;
) yshifted -3(ypart ulcorner c - ypart llcorner c) ;


Compile with context.

resulting picture


Instead of defining all of the strings up front and then drawing them, we can draw the strings as we go and save the maximum width to the .tuc file. This requires multiple passes, but most non-trivial ConTeXt files do anyways. I've also encapsulated most of the logic in the boxed_text macro, which makes it easier to add additional lines of text.

    % Constants
    numeric inneroffset ; inneroffset = 6pt ;
    numeric outeroffset ; outeroffset = 6pt ;

    % Variables
    numeric maxwidth ; maxwidth := lua(
        "job.passes.getcollected('userdata').maxwidth or 0"
    ) ;
    numeric vpos ; vpos := 0cm ;

    % Define the boxed_text macro:
    vardef boxed_text (text text) =
        picture p ; p = textext("\strut " & text) ;
        maxwidth := max(maxwidth, bbwidth(p)) ;

        draw image(
            draw boundingbox p xysized (
                maxwidth + inneroffset, bbheight(p) + inneroffset
            ) ;
            draw p ;
        ) yshifted vpos ;

        vpos := vpos - bbheight(p) - inneroffset - outeroffset ;
    enddef ;

    % Add the boxes
    boxed_text("short") ;
    boxed_text("a bit longer") ;
    boxed_text("a much much longer string") ;
    boxed_text("short again") ;

    % Must be last
    lua("job.passes.define('userdata').maxwidth = " & decimal maxwidth) ;


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.