%D \module
%D   [       file=mp-abck.mpiv,
%D        version=2012.02.19, % was mp-core: 1999.08.01, anchoring
%D          title=\CONTEXT\ \METAPOST\ graphics,
%D       subtitle=anchored background macros,
%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 mreadme.pdf for
%C details.

if known metafun_loaded_abck : endinput ; fi ;

newinternal boolean metafun_loaded_abck ; metafun_loaded_abck := true ; immutable metafun_loaded_abck ;

path    multiregs[],    % region used for multipar (tracing only)
        multipars[],    % effective area (shape)
        multibox ;      % main boundingbox (of main region)

string  multikind[] ;   % region state: single | first | middle | last (new method)

numeric multilocs[],    % 1=begin 2=between 3=end (old method)
        nofmultipars ;  % number of calculated areas

numeric par_strut_height,
        par_strut_depth,
        par_line_height ;

nofmultipars     := 0 ;
par_strut_height := 0 ;
par_strut_depth  := 0 ;
% par_line_height  := 0 ;

pair    boxgriddirection ; boxgriddirection := up ;   % to be interfaced
numeric boxgriddistance  ; boxgriddistance  := .5cm ; % to be interfaced

def boxgridtype     = (runscript mfid_mpvarn "gridtype") enddef ;
def boxgridwidth    = (runscript mfid_mpvard "gridwidth") enddef ;
def boxgridshift    = (runscript mfid_mpvard "gridshift") enddef ;
def boxgridcolor    = (runscript mfid_mpvars "gridcolor") enddef ;

def boxlinetype     = (runscript mfid_mpvarn "linetype") enddef ;
def boxlinewidth    = (runscript mfid_mpvard "linewidth") enddef ;
def boxlineradius   = (runscript mfid_mpvard "lineradius") enddef ;
def boxlineoffset   = (runscript mfid_mpvard "lineoffset") enddef ;
def boxlinecolor    = (runscript mfid_mpvars "linecolor") enddef ;

def boxfilltype     = (runscript mfid_mpvarn "filltype") enddef ;
def boxfilloffset   = (runscript mfid_mpvard "filloffset") enddef ;
def boxfillcolor    = (runscript mfid_mpvars "fillcolor") enddef ;

def boxdashtype     = (runscript mfid_mpvarn "dashtype") enddef ;

def boxalternative  = (runscript mfid_mpvarn "alternative") enddef;
def boxdistance     = (runscript mfid_mpvard "distance") enddef;
def boxlocation     = (runscript mfid_mpvarn "location") enddef ;
def boxtopoffset    = (runscript mfid_mpvard "topoffset") enddef;
def boxbottomoffset = (runscript mfid_mpvard "bottomoffset") enddef;

vardef boxatright  =
    save b ; b := boxlocation ;
    if b = 1 :
        false
    elseif b = 2 :
        true
    elseif OnRightPage :
        if b = 4 : % outer
            true
        else : % inner
            false
        fi
    else :
        if b = 4 : % inner
            false
        else : % inner
            true
        fi
    fi
enddef ;

def boxgridoptions  = withcolor boxgridcolor enddef ;
def boxlineoptions  = withcolor boxlinecolor enddef ;
def boxfilloptions  = withcolor boxfillcolor enddef ;

mutable
    multipars, multiregs, multibox, multikind, multilocs, nofmultipars,
    boxgridtype, boxgridwidth, boxgridshift, boxgridcolor,
    boxlinetype, boxlinewidth, boxlineradius, boxlineoffset, boxlinecolor,
    boxfilltype, boxfilloffset, boxfillcolor, boxdashtype,
    boxalternative, boxdistance, boxtopoffset, boxbottomoffset,
    boxgridoptions, boxlineoptions, boxfilloptions ;

vardef abck_draw_path(expr p) =
    if (length p > 2) and (bbwidth(p) > 1) and (bbheight(p) > 1) :
        save pp ; path pp ;
        pp := p if (boxlineradius>0) and (boxlinetype=2) : cornered boxlineradius fi ;
        if boxfilltype > 0 :
            if boxfilloffset > 0 :
                interim linejoin := mitered ;
                filldraw pp boxfilloptions withpen pencircle scaled (2*boxfilloffset) ;
            else :
                fill pp boxfilloptions ;
            fi ;
        fi ;
        if boxlinetype > 0 :
            draw pp boxlineoptions withpen pencircle scaled boxlinewidth ;
        fi ;
    fi ;
enddef ;

def abck_grid_line(expr start, width) =
    % 1 = normal, 2 = with background (i.e. no shine-through)
    if boxdashtype = 2 :
        draw start -- start shifted (width,0)
            withpen pencircle scaled boxgridwidth
            boxfilloptions ;
    fi ;
    draw start -- start shifted (width,0)
        if boxdashtype > 0 :
            dashed evenly
        fi
        withpen pencircle scaled boxgridwidth
        boxgridoptions ;
enddef ;

vardef abck_baseline_grid(expr pxy, pdir, at_baseline) =
    save width ; width := bbwidth(pxy) ;
    save height ; height := bbheight(pxy) ;
    if (par_line_height > 0) and (height > 1) and (width > 1) and (boxgridwidth > 0) :
        save i, grid, bb ; picture grid ; pair start ; path bb ;
        grid := image ( % fails with inlinespace
            if pdir = up :
                for i = if at_baseline : par_strut_depth else : 0 fi step par_line_height until max(height,par_line_height) :
                    abck_grid_line(llcorner pxy shifted (0,+i),width) ;
                endfor ;
            else :
                for i = if at_baseline : par_strut_height else : 0 fi step par_line_height until height :
                    abck_grid_line(ulcorner pxy shifted (0,-i),width) ;
                endfor ;
            fi ;
        ) ;
        clip grid to pxy ;
        bb := boundingbox grid ;
        grid := grid shifted (0,boxgridshift) ;
        setbounds grid to bb ;
        grid
    else :
        nullpicture
    fi
enddef ;

vardef abck_graphic_grid(expr pxy, dx, dy, x, y) =
    if (bbheight(pxy) > dy) and (bbwidth(pxy) > dx) and (boxgridwidth > 0) :
        save grid ; picture grid ;
        grid := image (
            for i = xpart llcorner pxy step dx until xpart lrcorner pxy :
                draw (i,ypart llcorner pxy) -- (i,ypart ulcorner pxy) withpen pencircle scaled boxgridwidth ;
            endfor ;
            for i = ypart llcorner pxy step dy until ypart ulcorner pxy :
                draw (xpart llcorner pxy,i) -- (xpart lrcorner pxy,i) withpen pencircle scaled boxgridwidth ;
            endfor
        ) shifted (x,y) ;
        clip grid to pxy ;
        grid
    else :
        nullpicture
    fi
enddef ;

def draw_multi_pars =
    for i=1 upto nofmultipars :
        abck_draw_path(multipars[i]) ;
        if boxgridtype = 1 :
            draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) ;
        elseif boxgridtype = 2 :
            draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,false) ;
        elseif boxgridtype = 3 :
            draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) ;
            draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight) ;
        elseif boxgridtype = 4 :
            draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight/2) ;
        elseif boxgridtype = 11 :
            draw abck_graphic_grid(multipars[i],boxgriddistance,boxgriddistance,boxgriddistance/2,boxgriddistance/2) ;
        elseif boxgridtype = 12 :
            draw abck_graphic_grid(multipars[i],boxgriddistance,boxgriddistance,0,0) ;
        fi ;
    endfor ;
enddef ;

def show_multi_pars =
    for i=1 upto nofmultipars :
        drawpathwithpoints multipars[i] withcolor .5blue ;
    endfor ;
enddef ;

def show_multi_kind =
    for i=1 upto nofmultipars :
        fill multipars[i]
            withcolor
                if      multikind[i] = "single" : yellow
                elseif  multikind[i] = "first"  : red
                elseif  multikind[i] = "middle" : green
                elseif  multikind[i] = "last"   : blue
                fi
            withtransparency (1,.5)
        ;
    endfor ;
enddef ;

def multi_side_draw_options = enddef ;

def draw_multi_side =
    begingroup ; save p ; picture p ;
    for i=1 upto nofmultipars :
        p := image ( fill leftboundary multipars[i]
            shifted (-boxlineoffset,0)
            rightenlarged boxlinewidth boxlineoptions ;
        ) ;
        setbounds p to multipars[i] ;
        draw p ;
    endfor ;
    endgroup ;
enddef ;

def draw_multi_side_path text t =
    begingroup ; save p ; picture p ;
    for i=1 upto nofmultipars :
        p := image ( draw leftboundary multipars[i]
            shifted (-boxlineoffset,0)
            withpen pensquare scaled boxlinewidth boxlineoptions t ;
        ) ;
        setbounds p to multipars[i] ;
        draw p ;
    endfor ;
    endgroup ;
enddef ;

% some extras

% For the moment we keep these as they can be in use but they will disappear.

pair    lxy[], rxy[], cxy[], llxy[], lrxy[], ulxy[], urxy[] ;
path    pxy[] ;
numeric hxy[], wxy[], dxy[], nxy[] ;

mutable lxy, rxy, cxy, llxy, lrxy, ulxy, urxy, pxy, hxy, wxy, dxy, nxy ;

def box_found (expr n,x,y,w,h,d) =
    not ((x=0) and (y=0) and (w=0) and (h=0) and (d=0))
enddef ;

def initialize_box_pos (expr pos,n,x,y,w,h,d) =
    pair lxy, rxy, cxy, llxy, lrxy, ulxy, urxy ;
    path pxy ; numeric hxy, wxy, dxy, nxy;
    lxy  := (x,y) ;
    llxy := (x,y-d) ;
    lrxy := (x+w,y-d) ;
    urxy := (x+w,y+h) ;
    ulxy := (x,y+h) ;
    wxy  := w ;
    hxy  := h ;
    dxy  := d ;
    rxy  := lxy shifted (wxy,0) ;
    pxy  := llxy--lrxy--urxy--ulxy--cycle ;
    cxy  := center pxy ;
    nxy  := n ;
    freeze_box(pos) ;
enddef ;

def freeze_box (expr pos) =
    lxy[pos]  := lxy  ;
    llxy[pos] := llxy ;
    lrxy[pos] := lrxy ;
    urxy[pos] := urxy ;
    ulxy[pos] := ulxy ;
    wxy[pos]  := wxy  ;
    hxy[pos]  := hxy  ;
    dxy[pos]  := dxy  ;
    rxy[pos]  := rxy  ;
    pxy[pos]  := pxy  ;
    cxy[pos]  := cxy  ;
    nxy[pos]  := nxy  ;
enddef ;

def initialize_box (expr n,x,y,w,h,d) =
    numeric bpos ; bpos := 0 ; initialize_box_pos(bpos,n,x,y,w,h,d) ;
enddef ;

def anchor_box (expr n,x,y,w,h,d) =
    currentpicture := currentpicture shifted (-x,-y) ;
enddef ;

def draw_box = % for old times sake
    draw pxy        boxlineoptions withpen pencircle scaled boxlinewidth ;
    draw lxy -- rxy boxlineoptions withpen pencircle scaled boxgridwidth ;
enddef ;

def draw_free_region(expr width, height, depth, loffset, roffset, toffset, boffset) =

    begingroup ; save b, o, l ; path b, o, l[] ; save d ;

    b := fullsquare
        xysized(width,height+depth) ;
    o := b
        topenlarged    toffset
        bottomenlarged boffset
        leftenlarged   loffset
        rightenlarged  roffset ;
    d := max(PaperWidth,PaperHeight) ;

    fill o withcolor .5white ;
    fill b withcolor .7white ;

    interim linecap := butt ;

    l[1] := topboundary    (topboundary    o leftenlarged d rightenlarged  d) ;
    l[2] := bottomboundary (bottomboundary o leftenlarged d rightenlarged  d) ;
    l[3] := leftboundary   (leftboundary   o topenlarged  d bottomenlarged d) ;
    l[4] := rightboundary  (rightboundary  o topenlarged  d bottomenlarged d) ;

    for i=1 upto 4 :
        draw l[i] withpen pencircle scaled 1bp withcolor white ;
        draw l[i] withpen pencircle scaled 1bp dashed (evenly scaled 1bp) withcolor black ;
    endfor ;

    setbounds currentpicture to b ;

    endgroup ;

enddef ;

