%D \module
%D   [       file=mp-page.mpiv,
%D        version=1999.03.10,
%D          title=\CONTEXT\ \METAPOST\ graphics,
%D       subtitle=page enhancements,
%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.

%D This module is rather preliminary and subjected to changes.In the process of
%D moving to \METAFUN2\ this might change.

if known metafun_loaded_page : endinput ; fi ;

newinternal boolean metafun_loaded_page ; metafun_loaded_page := true ; immutable metafun_loaded_page ;

def LoadPageState = enddef ; % just in case some old style uses it

% Next we implement the the page area model. First some constants. We use a
% matrix approach as we do at the TeX end but we could have gone for a period
% separated variant. Too late.

LeftEdge             :=  -4 ; Top             := -40 ;
LeftEdgeSeparator    :=  -3 ; TopSeparator    := -30 ;
LeftMargin           :=  -2 ; Header          := -20 ;
LeftMarginSeparator  :=  -1 ; HeaderSeparator := -10 ;
Text                 :=   0 ; Text            :=   0 ;
RightMarginSeparator :=  +1 ; FooterSeparator := +10 ;
RightMargin          :=  +2 ; Footer          := +20 ;
RightEdgeSeparator   :=  +3 ; BottomSeparator := +30 ;
RightEdge            :=  +4 ; Bottom          := +40 ;

numeric HorPos ; HorPos := 0 ;
numeric VerPos ; VerPos := 0 ;

immutable % permanent
    Text, HorPos, VerPos,
    LeftEdge, LeftEdgeSeparator, LeftMargin, LeftMarginSeparator,
    RightMarginSeparator, RightMargin, RightEdgeSeparator, RightEdge,
    Top, TopSeparator, Header, HeaderSeparator,
    FooterSeparator, Footer, BottomSeparator, Bottom ;

% Because metapost > 1.50 has dynamic memory management and is less efficient than
% before we now delay calculations ... (on a document with 150 pages the time spent
% in mp was close to 5 seconds which was only due to initialising the page related
% areas, something that was hardly noticeable before. At least now we're back to
% half a second for such a case.

% We could go for just setting them (:=):

path    mfun_page_area[][] ;
pair    mfun_page_location[][] ;
path    mfun_page_field[][] ;
numeric mfun_page_vsize[] ;
numeric mfun_page_hsize[] ;
numeric mfun_page_vstep[] ;
numeric mfun_page_hstep[] ;

newinternal mfun_page_done ; mfun_page_done := 0 ;

def mfun_page_check_vsize =
    mfun_page_vsize[Top]             := TopHeight ;
    mfun_page_vsize[TopSeparator]    := TopDistance ;
    mfun_page_vsize[Header]          := HeaderHeight ;
    mfun_page_vsize[HeaderSeparator] := HeaderDistance ;
    mfun_page_vsize[Text]            := TextHeight ;
    mfun_page_vsize[FooterSeparator] := FooterDistance ;
    mfun_page_vsize[Footer]          := FooterHeight ;
    mfun_page_vsize[BottomSeparator] := BottomDistance ;
    mfun_page_vsize[Bottom]          := BottomHeight ;
enddef ;

def mfun_page_check_hsize =
    mfun_page_hsize[LeftEdge]             := LeftEdgeWidth ;
    mfun_page_hsize[LeftEdgeSeparator]    := LeftEdgeDistance ;
    mfun_page_hsize[LeftMargin]           := LeftMarginWidth ;
    mfun_page_hsize[LeftMarginSeparator]  := LeftMarginDistance ;
    mfun_page_hsize[Text]                 := MakeupWidth ;
    mfun_page_hsize[RightMarginSeparator] := RightMarginDistance ;
    mfun_page_hsize[RightMargin]          := RightMarginWidth ;
    mfun_page_hsize[RightEdgeSeparator]   := RightEdgeDistance ;
    mfun_page_hsize[RightEdge]            := RightEdgeWidth ;
enddef ;

def mfun_page_check_vstep =
    mfun_page_vstep[TopSeparator]    := PaperHeight-TopSpace ;
    mfun_page_vstep[Top]             := mfun_page_vstep[TopSeparator]   +mfun_page_vsize[TopSeparator] ;
    mfun_page_vstep[Header]          := mfun_page_vstep[TopSeparator]   -mfun_page_vsize[Header] ;
    mfun_page_vstep[HeaderSeparator] := mfun_page_vstep[Header]         -mfun_page_vsize[HeaderSeparator] ;
    mfun_page_vstep[Text]            := mfun_page_vstep[HeaderSeparator]-mfun_page_vsize[Text] ;
    mfun_page_vstep[FooterSeparator] := mfun_page_vstep[Text]           -mfun_page_vsize[FooterSeparator] ;
    mfun_page_vstep[Footer]          := mfun_page_vstep[FooterSeparator]-mfun_page_vsize[Footer] ;
    mfun_page_vstep[BottomSeparator] := mfun_page_vstep[Footer]         -mfun_page_vsize[BottomSeparator] ;
    mfun_page_vstep[Bottom]          := mfun_page_vstep[BottomSeparator]-mfun_page_vsize[Bottom] ;
enddef ;

def mfun_page_check_hstep =
    mfun_page_hstep[Text]                 := BackSpace ;
    mfun_page_hstep[LeftMarginSeparator]  := mfun_page_hstep[Text]                -mfun_page_hsize[LeftMarginSeparator] ;
    mfun_page_hstep[RightMarginSeparator] := mfun_page_hstep[Text]                +mfun_page_hsize[Text] ;
    mfun_page_hstep[LeftMargin]           := mfun_page_hstep[LeftMarginSeparator] -mfun_page_hsize[LeftMargin] ;
    mfun_page_hstep[RightMargin]          := mfun_page_hstep[RightMarginSeparator]+mfun_page_hsize[RightMarginSeparator] ;
    mfun_page_hstep[LeftEdgeSeparator]    := mfun_page_hstep[LeftMargin]          -mfun_page_hsize[LeftEdgeSeparator] ;
    mfun_page_hstep[LeftEdge]             := mfun_page_hstep[LeftEdgeSeparator]   -mfun_page_hsize[LeftEdge] ;
    mfun_page_hstep[RightEdgeSeparator]   := mfun_page_hstep[RightMargin]         +mfun_page_hsize[RightMargin] ;
    mfun_page_hstep[RightEdge]            := mfun_page_hstep[RightEdgeSeparator]  +mfun_page_hsize[RightEdgeSeparator] ;
enddef ;

def mfun_check_page_dimensions =
    if mfun_page_done <> RealPageNumber :
        if LayoutHasChanged :
            mfun_page_check_vsize ;
            mfun_page_check_hsize ;
            mfun_page_check_vstep ;
            mfun_page_check_hstep ;
        fi ;
        mfun_page_done := RealPageNumber ;
    fi ;
enddef;


def mfun_check_page_area =
    mfun_check_page_dimensions ;
    for VerPos=Top step 10 until Bottom:
        for HorPos=LeftEdge step 1 until RightEdge:
            mfun_page_area[HorPos][VerPos] := unitsquare xscaled mfun_page_hsize[HorPos] yscaled mfun_page_vsize[VerPos] ;
            mfun_page_area[VerPos][HorPos] := mfun_page_area[HorPos][VerPos] ;
        endfor ;
    endfor ;
enddef ;

def mfun_check_page_location =
    mfun_check_page_dimensions ;
    for VerPos=Top step 10 until Bottom:
        for HorPos=LeftEdge step 1 until RightEdge:
            mfun_page_location[HorPos][VerPos] := (mfun_page_hstep[HorPos],mfun_page_vstep[VerPos]) ;
            mfun_page_location[VerPos][HorPos] := mfun_page_location[HorPos][VerPos] ;
        endfor ;
    endfor ;
enddef ;

def mfun_check_page_field =
    mfun_check_page_dimensions ;
    for VerPos=Top step 10 until Bottom:
        for HorPos=LeftEdge step 1 until RightEdge:
            mfun_page_field[HorPos][VerPos] := unitsquare xscaled mfun_page_hsize[HorPos] yscaled mfun_page_vsize[VerPos] shifted (mfun_page_hstep[HorPos],mfun_page_vstep[VerPos]) ;
            mfun_page_field[VerPos][HorPos] := mfun_page_field[HorPos][VerPos] ;
        endfor ;
    endfor ;
enddef ;

def Area     = hide(mfun_check_page_area       ;) mfun_page_area     enddef ;
def Location = hide(mfun_check_page_location   ;) mfun_page_location enddef ;
def Field    = hide(mfun_check_page_field      ;) mfun_page_field    enddef ;
def Vsize    = hide(mfun_check_page_dimensions ;) mfun_page_vsize    enddef ;
def Hsize    = hide(mfun_check_page_dimensions ;) mfun_page_hsize    enddef ;
def Vstep    = hide(mfun_check_page_dimensions ;) mfun_page_vstep    enddef ;
def Hstep    = hide(mfun_check_page_dimensions ;) mfun_page_hstep    enddef ;

immutable % permanent
    Area, Location, Field, Vsize, Hsize, Vstep, Hstep ;

vardef FrontPageWidth  = PaperWidth enddef ;
vardef BackPageWidth   = PaperWidth enddef ;
vardef CoverWidth      = 2 * PaperWidth + SpineWidth enddef ;
vardef CoverHeight     = PaperHeight enddef ;

vardef FrontPageHeight = PaperHeight enddef ;
vardef BackPageHeight  = PaperHeight enddef ;
vardef SpineHeight     = PaperHeight enddef ;

path mfun_page_page, mfun_page_cover, mfun_page_spine, mfun_page_back, mfun_page_front ;

def mfun_check_page  = mfun_page_page  := unitsquare xscaled PaperWidth     yscaled PaperHeight ; enddef ;
def mfun_check_cover = mfun_page_cover := unitsquare xscaled CoverWidth     yscaled CoverHeight ; enddef ;
def mfun_check_spine = mfun_page_spine := unitsquare xscaled SpineWidth     yscaled CoverHeight shifted (BackPageWidth,0) ; enddef ;
def mfun_check_back  = mfun_page_back  := unitsquare xscaled BackPageWidth  yscaled CoverHeight ; enddef ;
def mfun_check_front = mfun_page_front := unitsquare xscaled FrontPageWidth yscaled CoverHeight shifted (BackPageWidth+SpineWidth,0) ; enddef ;

def Page      = hide(mfun_check_page  ;) mfun_page_page  enddef ;
def CoverPage = hide(mfun_check_cover ;) mfun_page_cover enddef ;
def Spine     = hide(mfun_check_spine ;) mfun_page_spine enddef ;
def BackPage  = hide(mfun_check_back  ;) mfun_page_back  enddef ;
def FrontPage = hide(mfun_check_front ;) mfun_page_front enddef ;

% pages

def StartPage =
    begingroup ;
    setbounds currentpicture to Page ;
enddef ;

def StopPage =
    setbounds currentpicture to Page ;
    endgroup ;
enddef ;

% cover pages

def StartCover =
    begingroup ;
    setbounds currentpicture to CoverPage enlarged PaperBleed ;
enddef ;

def StopCover =
    setbounds currentpicture to CoverPage enlarged PaperBleed ;
    endgroup ;
enddef ;

immutable % permanent
    FrontPageWidth, BackPageWidth, CoverWidth, FrontPageHeight, BackPageHeight, CoverHeight,
    SpineHeight, Page, CoverPage, Spine, BackPage, FrontPage,
    StartPage, StopPage, StartCover, StopCover ;

% overlays:

def OverlayBox =
    (unitsquare xyscaled (OverlayWidth,OverlayHeight))
enddef ;

def BoundToOverlayBox =
    setbounds currentpicture to OverlayBox;
enddef ;

immutable % permanent
    OverlayBox ;

permanent
    BoundToOverlayBox ;

% handy

def innerenlarged =
    if OnRightPage : leftenlarged  else : rightenlarged fi
enddef ;

def outerenlarged =
    if OnRightPage : rightenlarged else : leftenlarged  fi
enddef ;

permanent
    innerenlarged, outerenlarged ;

% obsolete

% def llEnlarged (expr p,d) = (llcorner p shifted (-d,-d)) enddef ;
% def lrEnlarged (expr p,d) = (lrcorner p shifted (+d,-d)) enddef ;
% def urEnlarged (expr p,d) = (urcorner p shifted (+d,+d)) enddef ;
% def ulEnlarged (expr p,d) = (ulcorner p shifted (-d,+d)) enddef ;

% def Enlarged (expr p, d) =
%     (
%         llEnlarged (p,d) --
%         lrEnlarged (p,d) --
%         urEnlarged (p,d) --
%         ulEnlarged (p,d) --
%         cycle
%     )
% enddef ;

% for the moment we put these here:

string  RuleDirection ; RuleDirection := "" ;
string  RuleOption    ; RuleOption    := "" ;
numeric RuleWidth     ; RuleWidth     := 0 ;
numeric RuleHeight    ; RuleHeight    := 0 ;
numeric RuleDepth     ; RuleDepth     := 0 ;
numeric RuleH         ; RuleH         := 0 ;
numeric RuleV         ; RuleV         := 0 ;
numeric RuleThickness ; RuleThickness := 0 ;
numeric RuleFactor    ; RuleFactor    := 0 ;
numeric RuleOffset    ; RuleOffset    := 0 ;
                    def RuleColor      = (.5white) enddef ; % yet undecided, might become a string

def FakeWord(expr RuleWidth, RuleHeight, RuleDepth, RuleThickness) (text RuleColor) =
    fill unitsquare
        xscaled RuleWidth
        yscaled (RuleDepth-RuleThickness/2)
        withcolor RuleColor ;
    fill unitsquare
        xscaled RuleWidth
        yscaled (RuleHeight-RuleDepth-RuleThickness/2)
        shifted (0,RuleDepth+RuleThickness)
        withcolor RuleColor ;
enddef ;

def FakeRule(expr RuleWidth, RuleHeight, RuleDepth, RuleThickness) (text RuleColor) =
    fill unitsquare
        xscaled RuleWidth
        yscaled RuleHeight
        withcolor RuleColor ;
enddef ;

mutable
    RuleDirection, RuleOption, RuleWidth, RuleHeight, RuleDepth, RuleH, RuleV, RuleThickness,
    RuleFactor, RuleOffset, RuleColor;

permanent
    FakeWord, FakeRule ;
