%D \module
%D   [       file=mp-mlib.mpiv,
%D        version=2008.03.21,
%D          title=\CONTEXT\ \METAPOST\ graphics,
%D       subtitle=plugins,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
%C details.

if unknown mplib        : endinput ; fi ;
if known   context_mlib : endinput ; fi ;

boolean context_mlib ; context_mlib := true ;

%D Color and transparency
%D
%D Separable:

newinternal normaltransparent     ; normaltransparent     :=  1 ;
newinternal multiplytransparent   ; multiplytransparent   :=  2 ;
newinternal screentransparent     ; screentransparent     :=  3 ;
newinternal overlaytransparent    ; overlaytransparent    :=  4 ;
newinternal softlighttransparent  ; softlighttransparent  :=  5 ;
newinternal hardlighttransparent  ; hardlighttransparent  :=  6 ;
newinternal colordodgetransparent ; colordodgetransparent :=  7 ;
newinternal colorburntransparent  ; colorburntransparent  :=  8 ;
newinternal darkentransparent     ; darkentransparent     :=  9 ;
newinternal lightentransparent    ; lightentransparent    := 10 ;
newinternal differencetransparent ; differencetransparent := 11 ;
newinternal exclusiontransparent  ; exclusiontransparent  := 12 ;

%D Nonseparable:

newinternal huetransparent        ; huetransparent        := 13 ;
newinternal saturationtransparent ; saturationtransparent := 14 ;
newinternal colortransparent      ; colortransparent      := 15 ;
newinternal luminositytransparent ; luminositytransparent := 16 ;

vardef transparency_alternative_to_number(expr name) =
    if string name :
        if expandafter known scantokens(name & "transparent") :
            scantokens(name & "transparent")
        else :
            0
        fi
    elseif name < 17 :
        name
    else :
        0
    fi
enddef ;

def namedcolor (expr n) =
    1
    withprescript "sp_type=named"
    withprescript "sp_name=" & n
enddef ;

def spotcolor(expr n, v) =
    1
    withprescript "sp_type=spot"
    withprescript "sp_name="  & n
    withprescript "sp_value=" & v
enddef ;

def multitonecolor(expr name, fractions, components, value) =
    1
    withprescript "sp_type=multitone"
    withprescript "sp_name="       & name
    withprescript "sp_fractions="  & decimal fractions
    withprescript "sp_components=" & components
    withprescript "sp_value="      & value
enddef ;

def transparent(expr alternative, transparency)(text c) =
    1 % this permits withcolor x intoshade y
    withprescript "tr_alternative="  & decimal transparency_alternative_to_number(alternative)
    withprescript "tr_transparency=" & decimal transparency
    withcolor c
enddef ;

def withtransparency(expr alternative, transparency) =
    withprescript "tr_alternative="  & decimal transparency_alternative_to_number(alternative)
    withprescript "tr_transparency=" & decimal transparency
enddef ;

def cmyk(expr c, m, y, k) = % provided for downward compability
    (c,m,y,k)
enddef ;

% Texts (todo: better strut ratio, now .7 hardcoded, should be passed)

newinternal textextoffset ; textextoffset := 0 ;

numeric mfun_tt_w[], mfun_tt_h[], mfun_tt_d[] ; % we can consider using colors (less hash space)
numeric mfun_tt_n ; mfun_tt_n := 0 ;
picture mfun_tt_p ; mfun_tt_p := nullpicture ;

if unknown mfun_trial_run :
    boolean mfun_trial_run ;
    mfun_trial_run := false ;
else :
    % already defined before the format is loaded
fi ;

if unknown mfun_first_run :
    boolean mfun_first_run ;
    mfun_first_run := true ;
else :
    % already defined before the format is loaded
fi ;

def mfun_reset_tex_texts =
    mfun_tt_n := 0 ;
    mfun_tt_p := nullpicture ;
enddef ;

def mfun_flush_tex_texts =
    addto currentpicture also mfun_tt_p
enddef ;

extra_endfig   := "mfun_flush_tex_texts ;" & extra_endfig ;
extra_beginfig := extra_beginfig & "mfun_reset_tex_texts ;" ;

% We collect and flush them all, as we can also have temporary textexts
% that gets never really flushed but are used for calculations. So, we
% flush twice: once in location in order to pick up e.g. color properties,
% and once at the end because we need to flush missing ones.

vardef rawtextext(expr str) =
    if str = "" :
        nullpicture
    elseif mfun_trial_run :
        mfun_tt_n := mfun_tt_n + 1 ;
        addto mfun_tt_p doublepath unitsquare
            withprescript "tx_number=" & decimal mfun_tt_n
            withprescript "tx_stage=extra"
            withpostscript str ;
        image (
            addto currentpicture doublepath unitsquare
                withprescript "tx_number=" & decimal mfun_tt_n
                withprescript "tx_stage=trial"
                withpostscript str
        )
    else :
        mfun_tt_n := mfun_tt_n + 1 ;
        if known mfun_tt_d[mfun_tt_n] :
            image (
                addto currentpicture doublepath unitsquare
                    xscaled mfun_tt_w[mfun_tt_n]
                    yscaled (mfun_tt_h[mfun_tt_n] + mfun_tt_d[mfun_tt_n])
                    withprescript "tx_number=" & decimal mfun_tt_n
                    withprescript "tx_stage=final"
                    ; % withpostscript str ;
            ) shifted (0,-mfun_tt_d[mfun_tt_n])
        else :
            image (
                addto currentpicture doublepath unitsquare ;
            )
        fi
    fi
enddef ;

% More text

defaultfont := "Mono" ; % was cmr10, could be lmmono10-regular, but is fed into context anyway

vardef fontsize expr name =
    save size ; numeric size ;
    size := bbwidth(textext("\MPfontsizehskip{" & name & "}")) ;
    if size = 0 :
        12pt
    else :
        size
    fi
enddef ;

pair mfun_laboff        ; mfun_laboff        := (0,0)            ;
pair mfun_laboff.lft    ; mfun_laboff.lft    := (-1,0)           ;
pair mfun_laboff.rt     ; mfun_laboff.rt     := (1,0)            ;
pair mfun_laboff.bot    ; mfun_laboff.bot    := (0,-1)           ;
pair mfun_laboff.top    ; mfun_laboff.top    := (0,1)            ;
pair mfun_laboff.ulft   ; mfun_laboff.ulft   := (-.7,.7)         ;
pair mfun_laboff.urt    ; mfun_laboff.urt    := (.7,.7)          ;
pair mfun_laboff.llft   ; mfun_laboff.llft   := -(.7,.7)         ;
pair mfun_laboff.lrt    ; mfun_laboff.lrt    := (.7,-.7)         ;

pair mfun_laboff.d      ; mfun_laboff.d      := mfun_laboff      ;
pair mfun_laboff.dlft   ; mfun_laboff.dlft   := mfun_laboff.lft  ;
pair mfun_laboff.drt    ; mfun_laboff.drt    := mfun_laboff.rt   ;
pair mfun_laboff.origin ; mfun_laboff.origin := origin           ;
pair mfun_laboff.raw    ; mfun_laboff.raw    := origin           ;

pair mfun_laboff.l      ; mfun_laboff.l      := mfun_laboff.lft  ;
pair mfun_laboff.r      ; mfun_laboff.r      := mfun_laboff.rt   ;
pair mfun_laboff.b      ; mfun_laboff.b      := mfun_laboff.bot  ;
pair mfun_laboff.t      ; mfun_laboff.t      := mfun_laboff.top  ;
pair mfun_laboff.l_t    ; mfun_laboff.l_t    := mfun_laboff.ulft ;
pair mfun_laboff.r_t    ; mfun_laboff.r_t    := mfun_laboff.urt  ;
pair mfun_laboff.l_b    ; mfun_laboff.l_b    := mfun_laboff.llft ;
pair mfun_laboff.r_b    ; mfun_laboff.r_b    := mfun_laboff.lrt  ;
pair mfun_laboff.t_l    ; mfun_laboff.t_l    := mfun_laboff.ulft ;
pair mfun_laboff.t_r    ; mfun_laboff.t_r    := mfun_laboff.urt  ;
pair mfun_laboff.b_l    ; mfun_laboff.b_l    := mfun_laboff.llft ;
pair mfun_laboff.b_r    ; mfun_laboff.b_r    := mfun_laboff.lrt  ;

mfun_labxf                                              := 0.5 ;
mfun_labxf.lft      := mfun_labxf.l                     := 1   ;
mfun_labxf.rt       := mfun_labxf.r                     := 0   ;
mfun_labxf.bot      := mfun_labxf.b                     := 0.5 ;
mfun_labxf.top      := mfun_labxf.t                     := 0.5 ;
mfun_labxf.ulft     := mfun_labxf.l_t := mfun_labxf.t_l := 1   ;
mfun_labxf.urt      := mfun_labxf.r_t := mfun_labxf.t_r := 0   ;
mfun_labxf.llft     := mfun_labxf.l_b := mfun_labxf.b_l := 1   ;
mfun_labxf.lrt      := mfun_labxf.r_b := mfun_labxf.b_r := 0   ;

mfun_labxf.d        := mfun_labxf      ;
mfun_labxf.dlft     := mfun_labxf.lft  ;
mfun_labxf.drt      := mfun_labxf.rt   ;
mfun_labxf.origin   := 0               ;
mfun_labxf.raw      := 0               ;

mfun_labyf                                              := 0.5 ;
mfun_labyf.lft      := mfun_labyf.l                     := 0.5 ;
mfun_labyf.rt       := mfun_labyf.r                     := 0.5 ;
mfun_labyf.bot      := mfun_labyf.b                     := 1   ;
mfun_labyf.top      := mfun_labyf.t                     := 0   ;
mfun_labyf.ulft     := mfun_labyf.l_t := mfun_labyf.t_l := 0   ;
mfun_labyf.urt      := mfun_labyf.r_t := mfun_labyf.t_r := 0   ;
mfun_labyf.llft     := mfun_labyf.l_b := mfun_labyf.b_l := 1   ;
mfun_labyf.lrt      := mfun_labyf.r_b := mfun_labyf.b_r := 1   ;

mfun_labyf.d        := mfun_labyf      ;
mfun_labyf.dlft     := mfun_labyf.lft  ;
mfun_labyf.drt      := mfun_labyf.rt   ;
mfun_labyf.origin   := 0               ;
mfun_labyf.raw      := 0               ;

mfun_labtype                                                 :=  0 ;
mfun_labtype.lft    := mfun_labtype.l                        :=  1 ;
mfun_labtype.rt     := mfun_labtype.r                        :=  2 ;
mfun_labtype.bot    := mfun_labtype.b                        :=  3 ;
mfun_labtype.top    := mfun_labtype.t                        :=  4 ;
mfun_labtype.ulft   := mfun_labtype.l_t :=  mfun_labtype.t_l :=  5 ;
mfun_labtype.urt    := mfun_labtype.r_t :=  mfun_labtype.t_r :=  6 ;
mfun_labtype.llft   := mfun_labtype.l_b :=  mfun_labtype.b_l :=  7 ;
mfun_labtype.lrt    := mfun_labtype.r_b :=  mfun_labtype.b_r :=  8 ;
mfun_labtype.d                                               := 10 ;
mfun_labtype.dlft                                            := 11 ;
mfun_labtype.drt                                             := 12 ;
mfun_labtype.origin                                          :=  0 ;
mfun_labtype.raw                                             :=  0 ;

vardef thetextext@#(expr p,z) =
  % interim labeloffset := textextoffset ;
    if string p :
        thetextext@#(rawtextext(p),z)
    else :
        p
            if (mfun_labtype@# >= 10) :
                shifted (0,ypart center p)
            fi
            shifted (z + textextoffset*mfun_laboff@# - (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
    fi
enddef ;

vardef textext@#(expr p) = % no draw here
    thetextext@#(p,origin)
enddef ;

vardef thelabel@#(expr p,z) =
    if string p :
        thelabel@#(rawtextext("\definedfont[" & defaultfont & "]" & p) scaled defaultscale,z)
    else :
        p shifted (z + labeloffset*mfun_laboff@# - (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
    fi
enddef;

def label = % takes two arguments, contrary to textext that takes one
    draw thelabel
enddef ;

vardef anchored@#(expr p, z) = % beware: no "+ mfun_laboff@#" here (never!)
    p
        if (mfun_labtype@# >= 10) :
            shifted (0,ypart center p)
        fi
        shifted (z + (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
enddef ;

let normalinfont = infont ;

primarydef str infont name = % nasty hack
    if name = "" :
        textext(str)
    else :
        textext("\definedfont[" & name & "]" & str)
    fi
enddef ;

% Shades

newinternal shadefactor  ; shadefactor  := 1 ;
pair        shadeoffset  ; shadeoffset  := origin ;
boolean     trace_shades ; trace_shades := false ;

def set_linear_vector (suffix a,b)(expr p,n) =
    if     (n=1) : a := llcorner p ; b := urcorner p ;
    elseif (n=2) : a := lrcorner p ; b := ulcorner p ;
    elseif (n=3) : a := urcorner p ; b := llcorner p ;
    elseif (n=4) : a := ulcorner p ; b := lrcorner p ;
    elseif (n=5) : a := .5[ulcorner p,llcorner p] ; b := .5[urcorner p,lrcorner p] ;
    elseif (n=6) : a := .5[llcorner p,lrcorner p] ; b := .5[ulcorner p,urcorner p] ;
    elseif (n=7) : a := .5[lrcorner p,urcorner p] ; b := .5[llcorner p,ulcorner p] ;
    elseif (n=8) : a := .5[urcorner p,ulcorner p] ; b := .5[lrcorner p,llcorner p] ;
    else         : a := .5[ulcorner p,llcorner p] ; b := .5[urcorner p,lrcorner p] ;
    fi ;
enddef ;

def set_circular_vector (suffix ab, r)(expr p,n) =
    if     (n=1) : ab := llcorner p ;
    elseif (n=2) : ab := lrcorner p ;
    elseif (n=3) : ab := urcorner p ;
    elseif (n=4) : ab := ulcorner p ;
    else         : ab := center   p ; r := .5r ;
    fi ;
enddef ;

def circular_shade (expr p, n, ca, cb) =
    begingroup ;
        save ab, r ; pair ab ; numeric r ;
        r := (xpart lrcorner p - xpart llcorner p) ++ (ypart urcorner p - ypart lrcorner p) ;
        set_circular_vector(ab,r)(p,n) ;
        fill p withcircularshade(ab,ab,0,r,ca,cb) ;
        if trace_shades :
            drawarrow ab -- ab shifted (0,r) withpen pencircle scaled 1pt withcolor .5white ;
        fi ;
    endgroup ;
enddef ;

def linear_shade (expr p, n, ca, cb) =
    begingroup ;
        save a, b, sh ; pair a, b ;
        set_linear_vector(a,b)(p,n) ;
        fill p withlinearshade(a,b,ca,cb) ;
        if trace_shades :
            drawarrow a -- b withpen pencircle scaled 1pt withcolor .5white ;
        fi ;
    endgroup ;
enddef ;

def withcircularshade (expr a, b, ra, rb, ca, cb) =
    withprescript "sh_type=circular"
    withprescript "sh_domain=0 1"
    withprescript "sh_factor="   & decimal shadefactor
    withprescript "sh_color_a="  & colordecimals ca
    withprescript "sh_color_b="  & colordecimals cb
    withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
    withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
    withprescript "sh_radius_a=" & decimal ra
    withprescript "sh_radius_b=" & decimal rb
enddef ;

def withlinearshade (expr a, b, ca, cb) =
    withprescript "sh_type=linear"
    withprescript "sh_domain=0 1"
    withprescript "sh_factor="   & decimal shadefactor
    withprescript "sh_color_a="  & colordecimals ca
    withprescript "sh_color_b="  & colordecimals cb
    withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
    withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
enddef ;

string mfun_defined_cs_pre[] ; numeric mfun_defined_cs ; mfun_defined_cs := 0 ;

string mfun_prescript_separator ; mfun_prescript_separator := char(13) ;

vardef define_circular_shade (expr a, b, ra, rb, ca, cb) =
    mfun_defined_cs := mfun_defined_cs + 1 ;
    mfun_defined_cs_pre[mfun_defined_cs] := "sh_type=circular"
      & mfun_prescript_separator & "sh_domain=0 1"
      & mfun_prescript_separator & "sh_factor="   & decimal shadefactor
      & mfun_prescript_separator & "sh_color_a="  & colordecimals ca
      & mfun_prescript_separator & "sh_color_b="  & colordecimals cb
      & mfun_prescript_separator & "sh_center_a=" & ddecimal (a shifted shadeoffset)
      & mfun_prescript_separator & "sh_center_b=" & ddecimal (b shifted shadeoffset)
      & mfun_prescript_separator & "sh_radius_a=" & decimal ra
      & mfun_prescript_separator & "sh_radius_b=" & decimal rb
    ;
    mfun_defined_cs
enddef ;

vardef define_linear_shade (expr a, b, ca, cb) =
    mfun_defined_cs := mfun_defined_cs + 1 ;
    mfun_defined_cs_pre[mfun_defined_cs] := "sh_type=linear"
      & mfun_prescript_separator & "sh_domain=0 1"
      & mfun_prescript_separator & "sh_factor=" & decimal shadefactor
      & mfun_prescript_separator & "sh_color_a=" & colordecimals ca
      & mfun_prescript_separator & "sh_color_b=" & colordecimals cb
      & mfun_prescript_separator & "sh_center_a=" & ddecimal (a shifted shadeoffset)
      & mfun_prescript_separator & "sh_center_b=" & ddecimal (b shifted shadeoffset)
    ;
    mfun_defined_cs
enddef ;

primarydef p withshade sc =
    p withprescript mfun_defined_cs_pre[sc]
enddef ;


vardef define_sampled_linear_shade(expr a,b,n)(text t) =
    mfun_defined_cs := mfun_defined_cs + 1 ;
    mfun_defined_cs_pre[mfun_defined_cs] := "ssh_type=linear"
      & mfun_prescript_separator & "ssh_center_a=" & ddecimal (a shifted shadeoffset)
      & mfun_prescript_separator & "ssh_center_b=" & ddecimal (b shifted shadeoffset)
      & mfun_prescript_separator & "ssh_nofcolors=" & decimal n
      & mfun_prescript_separator & "ssh_domain=" & domstr
      & mfun_prescript_separator & "ssh_extend=" & extstr
      & mfun_prescript_separator & "ssh_colors=" & colstr
      & mfun_prescript_separator & "ssh_bounds=" & bndstr
      & mfun_prescript_separator & "ssh_ranges=" & ranstr
    ;
    mfun_defined_cs
enddef ;

vardef define_sampled_circular_shade(expr a,b,ra,rb,n)(text t) =
    mfun_defined_cs := mfun_defined_cs + 1 ;
    mfun_defined_cs_pre[mfun_defined_cs] := "ssh_type=circular"
      & mfun_prescript_separator & "ssh_center_a=" & ddecimal (a shifted shadeoffset)
      & mfun_prescript_separator & "ssh_radius_a=" & decimal ra
      & mfun_prescript_separator & "ssh_center_b=" & ddecimal (b shifted shadeoffset)
      & mfun_prescript_separator & "ssh_radius_b=" & decimal rb
      & mfun_prescript_separator & "ssh_nofcolors=" & decimal n
      & mfun_prescript_separator & "ssh_domain=" & domstr
      & mfun_prescript_separator & "ssh_extend=" & extstr
      & mfun_prescript_separator & "ssh_colors=" & colstr
      & mfun_prescript_separator & "ssh_bounds=" & bndstr
      & mfun_prescript_separator & "ssh_ranges=" & ranstr
    ;
    mfun_defined_cs
enddef ;

% vardef predefined_linear_shade (expr p, n, ca, cb) =
%     save a, b, sh ; pair a, b ;
%     set_linear_vector(a,b)(p,n) ;
%     define_linear_shade (a,b,ca,cb)
% enddef ;
%
% vardef predefined_circular_shade (expr p, n, ca, cb) =
%     save ab, r ; pair ab ; numeric r ;
%     r := (xpart lrcorner p - xpart llcorner p) ++ (ypart urcorner p - ypart lrcorner p) ;
%     set_circular_vector(ab,r)(p,n) ;
%     define_circular_shade(ab,ab,0,r,ca,cb)
% enddef ;

% NEW EXPERIMENTAL CODE

def withlinearshading (expr a, b) =
    withprescript "sh_type=linear"
    withprescript "sh_domain=0 1"
    withprescript "sh_factor="   & decimal shadefactor
    withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
    withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
enddef ;

def withcircularshading (expr a, b, ra, rb) =
    withprescript "sh_type=circular"
    withprescript "sh_domain=0 1"
    withprescript "sh_factor="   & decimal shadefactor
    withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
    withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
    withprescript "sh_radius_a=" & decimal ra
    withprescript "sh_radius_b=" & decimal rb
enddef ;

def withfromshadecolor expr t =
    withprescript "sh_color=into"
    withprescript "sh_color_a=" & colordecimals t
enddef ;

def withtoshadecolor expr t =
    withprescript "sh_color=into"
    withprescript "sh_color_b=" & colordecimals t
enddef ;

def withshading (expr how)(text rest) =
    if how = "linear" :
        withlinearshading(rest)
    elseif how = "circular" :
        withcircularshading(rest)
    else :
        % nothing
    fi
enddef ;

primarydef a shadedinto b =
    1 % does not work with transparency
    withprescript "sh_color=into"
    withprescript "sh_color_a=" & colordecimals a
    withprescript "sh_color_b=" & colordecimals b
enddef ;

% Layers

def onlayer primary name =
    withprescript "la_name=" & name
enddef ;

% Figures

% def externalfigure primary filename =
%     doexternalfigure (filename)
% enddef ;
%
% def doexternalfigure (expr filename) text transformation =
%     if true : % a bit incompatible esp scaled 1cm now scaled the natural size
%         draw rawtextext("\externalfigure[" & filename & "]") transformation ;
%     else :
%         draw unitsquare transformation withprescript "fg_name=" & filename ;
%     fi ;
% enddef ;

def withmask primary filename =
    withprescript "fg_mask=" & filename
enddef ;

def externalfigure primary filename =
    if false :
        rawtextext("\externalfigure[" & filename & "]")
    else :
        image (
            addto currentpicture doublepath unitsquare
                withprescript "fg_name=" & filename ;
        )
%             unitsquare
%                 withpen pencircle scaled 0
%                 withprescript "fg_name=" & filename
    fi
enddef ;

def figure primary filename =
    rawtextext("\externalfigure[" & filename & "]")
enddef ;

% Positions

def register (expr label, width, height, offset) =
%     draw image (
        addto currentpicture doublepath unitsquare xscaled width yscaled height shifted offset
            withprescript "ps_label=" & label ;
%     ) ; % no transformations
enddef ;

% Housekeeping

extra_beginfig := extra_beginfig & "currentgraphictext := 0 ; " ;
extra_endfig   := extra_endfig   & "finishsavingdata ; " ;
extra_endfig   := extra_endfig   & "mfun_reset_tex_texts ; " ;

% Bonus

vardef verbatim(expr str) =
    ditto & "\detokenize{" & str & "}" & ditto
enddef ;

% New

def bitmapimage(expr xresolution, yresolution, data) =
    image (
        addto currentpicture doublepath unitsquare
            withprescript  "bm_xresolution=" & decimal xresolution
            withprescript  "bm_yresolution=" & decimal yresolution
            withpostscript data ;
    )
enddef ;

% Experimental:
%
% property p ; p = properties(withcolor (1,1,0,0)) ;
% fill fullcircle scaled 20cm withproperties p ;

let property = picture ;

vardef properties(text t) =
    image(draw unitcircle t)
enddef ;

if metapostversion < 1.770  :

    def withproperties expr p =
        if colormodel p = 3 :
            withcolor greypart p
        elseif colormodel p = 5 :
            withcolor (redpart p,greenpart p,bluepart p)
        elseif colormodel p = 7 :
            withcolor (cyanpart p,magentapart p,yellowpart p,blackpart p)
        fi
    enddef ;

else :

    def withproperties expr p =
        if colormodel p = 3 :
            withcolor greypart p
        elseif colormodel p = 5 :
            withcolor (redpart p,greenpart p,bluepart p)
        elseif colormodel p = 7 :
            withcolor (cyanpart p,magentapart p,yellowpart p,blackpart p)
        fi
        withprescript prescript p
        withpostscript postscript p
    enddef ;

fi ;

% Experimental:

primarydef t asgroup s = % s = isolated|knockout
    begingroup
    save grouppicture, wrappedpicture, groupbounds ;
    picture grouppicture, wrappedpicture ; path groupbounds ;
    grouppicture := if picture t : t else : image(draw t) fi ;
    groupbounds := boundingbox grouppicture ;
    wrappedpicture:= nullpicture ;
    addto wrappedpicture contour groupbounds
        withprescript "gr_state=start"
        withprescript "gr_type=" & s
        withprescript "gr_llx=" & decimal xpart llcorner groupbounds
        withprescript "gr_lly=" & decimal ypart llcorner groupbounds
        withprescript "gr_urx=" & decimal xpart urcorner groupbounds
        withprescript "gr_ury=" & decimal ypart urcorner groupbounds ;
    addto wrappedpicture also grouppicture ;
    addto wrappedpicture contour groupbounds
        withprescript "gr_state=stop" ;
    wrappedpicture
    endgroup
enddef ;

% Also experimental

string mfun_auto_align[] ;

mfun_auto_align[0] := "rt" ;
mfun_auto_align[1] := "urt" ;
mfun_auto_align[2] := "top" ;
mfun_auto_align[3] := "ulft" ;
mfun_auto_align[4] := "lft" ;
mfun_auto_align[5] := "llft" ;
mfun_auto_align[6] := "bot" ;
mfun_auto_align[7] := "lrt" ;
mfun_auto_align[8] := "rt" ;

def autoalign(expr n) =
    scantokens mfun_auto_align[round((n mod 360)/45)]
enddef ;

% draw textext.autoalign(60) ("\strut oeps 1") ;
% draw textext.autoalign(160)("\strut oeps 2") ;
% draw textext.autoalign(260)("\strut oeps 3") ;
% draw textext.autoalign(360)("\strut oeps 4") ;
