%D \module
%D   [       file=mp-cell.mpiv, % mp-step.mpiv,
%D        version=2010.10.07,   % 2001.05.22,
%D          title=\CONTEXT\ \METAPOST\ graphics,
%D       subtitle=steps,
%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.

% step prefixes .. no save needed

if known context_cell : endinput ; fi ;

boolean context_cell ; context_cell := true ;

def initialize_step_variables =
    save
        text_fill_color, text_line_color, text_line_width, text_offset,
        cell_fill_color, cell_line_color, cell_line_width, cell_offset,
        line_line_color, line_line_width, line_alternative,
        line_distance, cell_distance_y, cell_distance_x,
        nofcells, chart_vertical ;

    color   text_line_color     ; text_line_color     := red ;
    color   cell_line_color     ; cell_line_color     := blue ;
    color   line_line_color     ; line_line_color     := green ;

    color   text_fill_color     ; text_fill_color     := white ;
    color   cell_fill_color     ; cell_fill_color     := white ;

    numeric text_line_width     ; text_line_width     := 2pt ;
    numeric cell_line_width     ; cell_line_width     := 2pt ;
    numeric line_line_width     ; line_line_width     := 2pt  ;

    numeric text_offset         ; text_offset         := 4pt ;
    numeric cell_offset         ; cell_offset         := 4pt ;

    numeric line_distance       ; line_distance       := 10pt ; % between line and text
    numeric line_offset         ; line_offset         :=  4pt ; % between center and start of line
    numeric line_height         ; line_height         := 20pt ;

    numeric cell_distance_y     ; cell_distance_y     := 20pt ;
    numeric cell_distance_x     ; cell_distance_x     := 20pt ;

    numeric text_distance_set   ; text_distance_set   :=  4pt ;

    boolean chart_vertical      ; chart_vertical      := false ;

    numeric nofcells            ; nofcells            := 0 ;

enddef ;

def step_cells (expr t, b) =
    nofcells := nofcells + 1 ;
    cells_t[nofcells] := textext.d(t) ;
    cells_b[nofcells] := textext.d(b) ;
    texts_t[nofcells] := nullpicture ;
    texts_m[nofcells] := nullpicture ;
    texts_b[nofcells] := nullpicture ;
enddef ;

def step_texts (expr t, b) =
    texts_t[nofcells] := textext.d(t) ;
    texts_m[nofcells] := textext.d(m) ;
    texts_b[nofcells] := textext.d(b) ;
enddef ;

def step_begin_cell =
    nofcells := nofcells + 1 ;
    cells_t[nofcells] := nullpicture ;
    cells_b[nofcells] := nullpicture ;
    texts_t[nofcells] := nullpicture ;
    texts_m[nofcells] := nullpicture ;
    texts_b[nofcells] := nullpicture ;
enddef ;

def step_end_cell =
enddef ;

def step_cell_top (expr t) = cells_t[nofcells] := textext.d(t) ; enddef ;
def step_cell_bot (expr b) = cells_b[nofcells] := textext.d(b) ; enddef ;
def step_text_top (expr t) = texts_t[nofcells] := textext.d(t) ; enddef ;
def step_text_mid (expr m) = texts_m[nofcells] := textext.d(m) ; enddef ;
def step_text_bot (expr b) = texts_b[nofcells] := textext.d(b) ; enddef ;

def step_begin_chart =
    begingroup ;
        initialize_step_variables ;
        save nofcells ; numeric nofcells ; nofcells := 0 ;
        save cells_t, cells_m, cells_b ; picture cells_t[], cells_m[], cells_b[] ;
        save texts_t, texts_m, texts_b ; picture texts_t[], texts_m[], texts_b[] ;
enddef ;

def step_end_chart =
    % we could combine some loops but this is cleaner
    save dx, delta ; numeric dx, delta ;
    save p ; path p ;
    save one_row_only ; boolean one_row_only ;
    save cell_t, next_t, text_t ; picture cell_t, next_t, text_t ;
    save cell_m, next_m, text_m ; picture cell_m, next_m, text_m ;
    save cell_b, next_b, text_b ; picture cell_b, next_b, text_b ;
    save height_t, width_t, max_height_t, max_width_t ; numeric height_t, width_t, max_height_t, max_width_t ;
    save height_m, width_m, max_height_m, max_width_m ; numeric height_m, width_m, max_height_m, max_width_m ;
    save height_b, width_b, max_height_b, max_width_b ; numeric height_b, width_b, max_height_b, max_width_b ;
    % check rows
    one_row_only := true ;
    for i=1 upto nofcells :
        if bbwidth(cells_b[i]) > 0 :
            one_row_only := false ;
        fi ;
    endfor ;
    % swap and rotate
    if chart_vertical :
        if one_row_only :
            % deal with mid_texts
            max_width_t := max_width_m := max_width_b := 0 ;
            for i=1 upto nofcells :
                width_t := bbwidth(texts_t[i]) ;
                width_m := bbwidth(texts_m[i]) ;
                width_b := bbwidth(texts_b[i]) ;
                if width_t > max_width_t : max_width_t := width_t fi ;
                if width_m > max_width_m : max_width_m := width_m fi ;
                if width_b > max_width_b : max_width_b := width_b fi ;
            endfor ;
            if max_width_m > 0 :
                for i=1 upto nofcells :
                    text_t := texts_t[i] ; width_t := bbwidth(text_t) ;
                    text_m := texts_m[i] ; width_m := bbwidth(text_m) ;
                    text_b := texts_b[i] ; width_b := bbwidth(text_b) ;
                    if width_t < max_width_t :
                        setbounds text_t to boundingbox text_t leftenlarged (max_width_t - width_t) ;
                    fi ;
                    if width_m < max_width_m :
                        setbounds text_m to boundingbox text_m leftenlarged  ((max_width_m - width_m)/2) ;
                        setbounds text_m to boundingbox text_m rightenlarged ((max_width_m - width_m)/2) ;
                    fi ;
                    if width_b < max_width_b :
                        setbounds text_b to boundingbox text_b rightenlarged (max_width_b - width_b) ;
                    fi ;
                    text_t := text_t shifted (- xpart llcorner text_t, 0) ;
                    text_m := text_m shifted (- xpart llcorner text_m, 0) ;
                    text_b := text_b shifted (- xpart llcorner text_b, 0) ;
                    texts_t[i] := image (
                        draw text_t ;
                        draw text_m shifted (max_width_t +                 text_distance_set,0) ;
                        draw text_b shifted (max_width_t + max_width_m + 2*text_distance_set,0) ;
                    ) rotated 90 ;
                    texts_m[i] := texts_b[i] := nullpicture ;
                    cells_t[i] := cells_t[i] rotated 90 ;
                endfor ;
            else :
                for i=1 upto nofcells :
                    cells_t[i] := cells_t[i] rotated 90 ;
                    texts_t[i] := texts_t[i] rotated 90 ;
                    texts_b[i] := texts_b[i] rotated 90 ;
                endfor ;
            fi ;
        else :
            for i=1 upto nofcells :
                cell_t := cells_t[i] ;
                cell_b := cells_b[i] ;
                cells_t[i] := cell_b rotated 90 ;
                cells_b[i] := cell_t rotated 90 ;
                text_t := texts_t[i] ;
                text_b := texts_b[i] ;
                texts_t[i] := text_b rotated 90 ;
                texts_b[i] := text_t rotated 90 ;
            endfor ;
        fi ;
    fi ;
    % align horizontal
    for i=1 upto nofcells :
        cell_t := cells_t[i] ;
        cell_b := cells_b[i] ;
        width_t := bbwidth(cell_t) ;
        width_b := bbwidth(cell_b) ;
        if (width_t = 0) and (width_b = 0) :
            % skip
        elseif (width_t > 0) and (width_t < width_b) :
            delta := (width_b-width_t)/2 ;
            setbounds cell_t to boundingbox cell_t leftenlarged delta rightenlarged delta ;
            cells_t[i] := cell_t ;
        elseif (width_b > 0) and (width_t > width_b) :
            delta := (width_t-width_b)/2 ;
            setbounds cell_b to boundingbox cell_b leftenlarged delta rightenlarged delta ;
            cells_b[i] := cell_b ;
        fi ;
    endfor ;
    % analyze vertical
    max_height_t := 0 ;
    max_height_b := 0 ;
    for i=1 upto nofcells :
        cell_t := cells_t[i] ;
        cell_b := cells_b[i] ;
        height_t := bbheight(cell_t) ;
        height_b := bbheight(cell_b) ;
        if height_t > 0 :
            setbounds cell_t to boundingbox cell_t enlarged cell_offset ;
            height_t := height_t + 2 * cell_offset ;
            cells_t[i] := cell_t ;
        fi ;
        if height_b > 0 :
            setbounds cell_b to boundingbox cell_b enlarged cell_offset ;
            height_b := height_b + 2 * cell_offset ;
            cells_b[i] := cell_b ;
        fi ;
        if height_t > max_height_t :
            max_height_t := height_t ;
        fi
        if height_b > max_height_b :
            max_height_b := height_b ;
        fi ;
    endfor ;
    % align vertical
    for i=1 upto nofcells :
        cell_t := cells_t[i] ;
        cell_b := cells_b[i] ;
        height_t := bbheight(cell_t) ;
        height_b := bbheight(cell_b) ;
        if height_t > 0 :
            delta := (max_height_t-height_t)/2 ;
            setbounds cell_t to boundingbox cell_t topenlarged delta bottomenlarged delta ;
        fi ;
        if height_b > 0 :
            delta := (max_height_b-height_b)/2 ;
            setbounds cell_b to boundingbox cell_b topenlarged delta bottomenlarged delta ;
        fi ;
        cells_t[i] := cell_t ;
        cells_b[i] := cell_b ;
    endfor ;
    % position
    dx := 0 ;
    for i=1 upto nofcells :
        cell_t := cells_t[i] ;
        cell_b := cells_b[i] ;
        cell_t := cell_t shifted -llcorner cell_t ;
        cell_b := cell_b shifted -llcorner cell_b ;
        cell_t := cell_t shifted (dx, 0) ;
        cell_b := cell_b shifted (dx,-cell_distance_y-max_height_b) ;
        cells_t[i] := cell_t ;
        cells_b[i] := cell_b ;
        width_t := bbwidth(cell_t) ;
        width_b := bbwidth(cell_b) ;
        if width_t > 0 :
            dx := dx + cell_distance_x + width_t ;
        elseif width_b > 0 :
            dx := dx + cell_distance_x + width_b ;
        fi ;
    endfor ;
    % flush
    for i=1 upto nofcells :
        cell_t := cells_t[i] ;
        cell_b := cells_b[i] ;
        width_t := bbwidth(cell_t) ;
        width_b := bbwidth(cell_b) ;
        if width_t > 0 :
            fill boundingbox cell_t withcolor cell_fill_color ;
            draw boundingbox cell_t withpen pencircle scaled cell_line_width withcolor cell_line_color ;
            draw cell_t ;
        fi ;
        if width_b > 0 :
            fill boundingbox cell_b withcolor cell_fill_color ;
            draw boundingbox cell_b withpen pencircle scaled cell_line_width withcolor cell_line_color ;
            draw cell_b ;
        fi ;
    endfor ;
    %
    def midtopboundary    expr p = 0.5[ulcorner boundingbox p, urcorner boundingbox p] enddef ;
    def midbottomboundary expr p = 0.5[llcorner boundingbox p, lrcorner boundingbox p] enddef ;
    % draw top and bottom text boxes
    for i=1 upto nofcells-1 :
        text_t := texts_t[i] ;
        text_b := texts_b[i] ;
        if bbwidth(text_t) > 0 :
            setbounds text_t to boundingbox text_t enlarged text_offset ;
            texts_t[i] := text_t ;
        fi ;
        if bbwidth(text_b) > 0 :
            setbounds text_b to boundingbox text_b enlarged text_offset ;
            texts_b[i] := text_b ;
        fi ;
    endfor ;
    % arrows
    for i=1 upto nofcells-1 :
        cell_t := cells_t[i] ;
        cell_b := cells_b[i] ;
        next_t := cells_t[i+1] ;
        next_b := cells_b[i+1] ;
        pair t_a, t_b, t_c, b_a, b_b, b_c ;
        t_a := midtopboundary cell_t ;
        t_b := midtopboundary next_t ;
        t_c := (xpart 0.5[t_a,t_b], ypart t_a+line_height+line_distance) ;
        if one_row_only :
            b_a := midbottomboundary cell_t ;
            b_b := midbottomboundary next_t ;
        else :
            b_a := midbottomboundary cell_b ;
            b_b := midbottomboundary next_b ;
        fi ;
        b_c := (xpart 0.5[b_a,b_b], ypart b_a-line_height-line_distance) ;
        texts_t[i] := thelabel.top(texts_t[i],t_c) ;
        texts_b[i] := thelabel.bot(texts_b[i],b_c) ;
    endfor ;
    %
    for i=1 upto nofcells-1 : % todo arrows when empty text
        cell_t := cells_t[i] ;
        cell_b := cells_b[i] ;
        next_t := cells_t[i+1] ;
        next_b := cells_b[i+1] ;
        text_t := texts_t[i] ;
        text_b := texts_b[i] ;
        if bbwidth(text_t) > 0 :
            if bbwidth(cell_t) > 0 :
                drawarrow midtopboundary cell_t
                    shifted (if i > 1 : line_offset else : 0 fi, cell_line_width) {up}  ..
                    midbottomboundary text_t shifted (0,-line_distance) ..
                    {down} midtopboundary next_t shifted(if i < nofcells - 1 : -line_offset else : 0 fi,cell_line_width)
                    withpen pencircle scaled line_line_width
                    withcolor line_line_color ;
            else :
            fi ;
        fi ;
        if bbwidth(text_b) > 0 :
            if one_row_only :
                cell_b := cell_t ;
                next_b := next_t ;
            fi ;
            if bbwidth(cell_b) > 0 :
                drawarrow midbottomboundary cell_b
                    shifted (if i > 1 : line_offset else : 0 fi, -cell_line_width) {down}  ..
                    midtopboundary text_b shifted (0, line_distance) ..
                    {up} midbottomboundary next_b shifted (if i < nofcells - 1 : -line_offset else : 0 fi,-cell_line_width)
                    withpen pencircle scaled line_line_width
                    withcolor line_line_color ;
            else :
            fi ;
        fi ;
    endfor ;
    % draw top and bottom text boxes
    for i=1 upto nofcells-1 :
        text_t := texts_t[i] ;
        text_b := texts_b[i] ;
        if bbwidth(text_t) > 0 :
            fill boundingbox text_t withcolor text_fill_color ;
            draw boundingbox text_t withpen pencircle scaled text_line_width withcolor text_line_color ;
            draw text_t ;
        fi ;
        if bbwidth(text_b) > 0 :
            fill boundingbox text_b withcolor text_fill_color ;
            draw boundingbox text_b withpen pencircle scaled text_line_width withcolor text_line_color ;
            draw text_b ;
        fi ;
    endfor ;
    if chart_vertical :
        % rotate back
        currentpicture := currentpicture rotated -90 ;
    fi ;
    endgroup ;
enddef ;

% start_begin_step ;
%     step_cells ("\strut test 0", "\strut test 0") ;
%     step_cells ("\strut test 1", "\vbox{\hsize3cm \strut oeps 1\crlf oeps 1}") ;
%     step_texts ("\strut 1",    "\strut 1") ;
%     step_cells ("\strut test 2", "\strut oeps 2 oeps 2") ;
%     step_cells ("\strut test X", "\strut test X") ;
%     step_texts ("\strut 2",    "\strut 2") ;
%     step_cells ("\strut test 3", "\strut oeps 3 oeps 3") ;
%     step_texts ("\strut 3",    "\strut 3") ;
%     step_cells ("\strut test 4", "\strut oeps 4 oeps 4") ;
%     step_texts ("\strut 4",    "\strut 4") ;
% stop_end_chart ;
