In the interest of archiving the answer I ended up simply redefining the p_label function:

# Overwrite the point label function to allow specifying
# style and label level
layout custom_label
        code metapost
                # Set the maximum label level that will appear
                max_level := 100;
                vardef set_label_level (expr mylevel)=
                        max_level := scantokens(mylevel);
                enddef;

                vardef p_label@#(expr txt,pos,rot,mode_)=

                        # Allow specifiying the style on a single label
                        if known ATTR_style:
                                mode := scantokens(ATTR_style);
                        else:
                                mode := mode_;
                        fi;

                        # Specify the level at which this label should appear
                        if known ATTR_level:
                                level := scantokens(ATTR_level);
                        else:
                                level := 0;
                        fi;

                        if (level <= max_level):
                                if (mode=1) or (mode=7):
                                        interim labeloffset:=(u/8);
                                fi;
                                lab:=thelabel@#(txt, pos);
                                if mode>1:
                                        pickup PenD
                                fi;
                                if mode=1:
                                        pickup pencircle scaled (u/6);
                                        drawdot(pos);
                                        process_label(pos,0);
                                elseif mode=2:
                                        process_uplabel;
                                elseif mode=3:
                                        process_downlabel;
                                elseif mode=4:
                                        process_updownlabel;
                                elseif mode=5:
                                        process_circledlabel;
                                elseif mode=6:
                                        process_boxedlabel;
                                elseif mode=7:
                                        process_label(pos,rot);  % station name
                                elseif mode=8:
                                        process_filledlabel(pos, rot);
                                else:
                                        process_label(pos,rot);
                                fi;
                        else:
                                # Metapost is expecting some sort of drawing so
                                # we just draw an empty string
                                lab:=thelabel@#("", pos);
                                process_label(pos,rot);
                        fi;
                enddef;
        endcode
endlayout

This has the levels functionality as well as displaying all text using the correct fonts and characters.


On Sun, 17 Apr 2022 at 22:00, Rhys Tyers <rhystyers1@gmail.com> wrote:

Just in case a simplification makes the question/answer clearer, I'll retry my question from above:

I define a user label:

def p_u_label (expr P,R,S,A)=
    lab:=thelabel(ATTR_text, P)
    process_label(P, R)
enddef;
initsymbol("p_u_label");

This for example will not print a Č character, but the standard Therion label will.

How do I make this display text the same way that a normal Therion label does?

I’ve read through a lot of the Therion source trying to find out where this happens but in the relevant bit there seems to be no extra magic happening.

Thanks,
Rhys


On Wed, 13 Apr 2022 at 21:18, Rhys Tyers <rhystyers1@gmail.com> wrote:

Hello again,

I’m hoping someone can help me work out a metapost problem. The code is available here and pasted below.

None of us know anything about metapost so this is a copy/paste job of this code with some extensions. We want a label that can be turned displayed or hidden depending on a level variable. In a system survey I turn off lots of labels because there is lots of overlapping passage, but on more detailed ones I turn them back on. This level thing works well.

What does not work is new lines or any non-ascii character. I have played around with this for a while and can’t work out how to make it work.

I.e. this point:

point 174.2178 755.6161 u:label_MY -attr lvl 1 -attr text "Hoover<br>Dam" -align tr -scale l

The <br> is not replaced by a new line and in fact the < and > are rendered as question marks. 

image.png


I think Therion does a substitution of <br> and it’s not real html or tex but if I try to use tex in there like Hoover \\ Dam then it just errors during compilation:

[495] (./mptextmp.mp) [496] [497] [498] (./mptextmp.mpfatal: Command failed: etex --parse-first-line --interaction=nonstopmode mpTXLjoJ.tex; see mpxerr.log
>> mptextmp.mp
>> mptextmp.mpx
! ! Unable to read mpx file.
l.2 btex
         \mainfont \thframed {\thnormalsize Hoover \\ Dam} etex

I think this is because we are somehow not rendering with tex, and only rendering with metapost which has a limited character set, but I really have no idea.

Any help would be greatly appreciated!

The metapost code:

layout user_label

    code metapost

        def p_LABEL(expr pos)=
            T:=identity shifted pos;
            pickup PenD;
            p:=fullcircle scaled .1u;
            thclean p; thdraw p;

            if known ATTR_text:
                text := scantokens(ATTR_text);
                thdrawoptions(withcolor .8red + .4blue);
                txtm:=image(
                draw txt;
                interim labeloffset:=0;
                label.urt(btex text etex);
                );
                % draw label
                lab:=thelabel@#(txtm, pos);
                draw lab _thop_; % use color
                thdrawoptions();
                bboxmargin:=0.8bp;
                write_circ_bbox((bbox lab) smoothed 2);

            enddef;

            def p_altitude(expr pos)=
                T:=identity shifted pos;
                pickup PenD;
                p:=(-.3u,0)--(.3u,0);
                thdraw p; thdraw p rotated 90;
                p:=fullcircle scaled .2u;
                thclean p; thdraw p;
            enddef;


            vardef p_label@#(expr txt,pos,rot,mode) =
                if mode=1:
                    thdrawoptions(withcolor .8red + .4blue);
                    p_altitude(pos);
                    % append "m" to label
                    picture txtm;
                    txtm:=image(
                    draw txt;
                    interim labeloffset:=0;
                    label.urt(btex \thaltitude m etex, lrcorner txt);
                    );
                    % give extra offset in case of l/r/t/b alignment
                    pair ctmp;
                    ctmp:=center thelabel@#("x", (0,0));
                    if (xpart ctmp * ypart ctmp)=0:
                        interim labeloffset:=(.4u);
                    else: % diagonal alignment
                        interim labeloffset:=(.2u);
                    fi;
                    % draw label
                    lab:=thelabel@#(txtm, pos);
                    draw lab _thop_; % use color
                    thdrawoptions();
                    bboxmargin:=0.8bp;
                    write_circ_bbox((bbox lab) smoothed 2);
                else:
                    if mode=7:
                        interim labeloffset:=(u/8);
                    fi;
                    lab:=thelabel@#(txt, pos);
                    if mode>1:
                        pickup PenD
                    fi;
                    if mode=2:
                        process_uplabel;
                    elseif mode=3:
                        process_downlabel;
                    elseif mode=4:
                        process_updownlabel;
                    elseif mode=5:
                        process_circledlabel;
                    elseif mode=6:
                        process_boxedlabel;
                    elseif mode=7:
                        process_label(pos,rot);  % station name
                    elseif mode=8:
                        process_filledlabel(pos, rot);
                    else:
                        process_label(pos,rot);
                    fi;
                fi;
            enddef;

            vardef set_label_level (expr mylevel)=
                maxl := scantokens(mylevel);
            enddef;


            def p_u_label_MY (expr P,R,S,A)=
                T:=identity shifted P;
                U:=(0,0);
                save lvl;
                save style;
                if known ATTR_style:
                    style:= scantokens(ATTR_style);
                else:
                    style :=0;
                fi;
                if known ATTR_text:
                    if known ATTR_lvl:
                        lvl := scantokens(ATTR_lvl);
                    else: lvl :=0;
                    fi;
                    if lvl < maxl+1:
                        U:=(S*u*(length ATTR_text)/4,S*u*(length ATTR_text)/4);
                        create_styled_label(ATTR_text,P,R,S,A,style);
                    else:;
                    fi;
                fi;
            enddef;
            initsymbol("p_u_label_MY");


            % https://www.mail-archive.com/therion@speleo.sk/msg07234.html
            % define a custom attribute called label_mode

            vardef create_styled_label (expr plaintext,P,R,S,A,defaultstyle)=
                save textsize, style, thetext;
                string textsize;
                if S = 0.5:
                    textsize:="\thtinysize";
                elseif S = 0.7:
                    textsize:="\thsmallsize";
                elseif S = 1.4:
                    textsize:="\thlargesize";
                elseif S = 2:
                    textsize:="\thhugesize";
                else: % normal is 1
                    textsize:="\thnormalsize";
                fi;
                if known ATTR_labelstyle:
                    style:=scantokens(ATTR_labelstyle);
                else:
                    style:=defaultstyle;
                fi;
                picture thetext;
                thetext:=thTEX("\thframed {" & textsize & " " & plaintext & "}");
                if A = (-1,1):
                    p_label.ulft(thetext,P,R,style);

                elseif A = (0,1):
                    p_label.top(thetext,P,R,style);

                elseif A = (1,1):
                    p_label.urt(thetext,P,R,style);

                elseif A = (-1,0):
                    p_label.lft(thetext,P,R,style);

                elseif A = (1,0):
                    p_label.rt(thetext,P,R,style);

                elseif A = (-1,-1):
                    p_label.llft(thetext,P,R,style);

                elseif A = (0,-1):
                    p_label.bot(thetext,P,R,style);

                elseif A = (1,-1):
                    p_label.lrt(thetext,P,R,style);

                else:
                    p_label(thetext,P,R,style);

                fi;
            enddef;

        endcode
    endlayout