page-bck.mkiv / last modification: 2020-01-30 14:16
%D \module
%D   [       file=page-bck, % copied from main-001
%D        version=1997.03.31,
%D          title=\CONTEXT\ Page Macros,
%D       subtitle=Backgrounds,
%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.

% Currently the text cells are fakes and no (foreground) frames which makes sense
% as order might matter e.g. is text sticks in other cells. The page, text etc
% areas do support foreground order change.

\writestatus{loading}{ConTeXt Page Macros / Backgrounds}

\unprotect

% maybe use \currentframedhash here

%D For special purposes, users can question the \type {*background} mode. This mode
%D is only available when typesetting the pagebody.
%D
%D \starttyping
%D \startmode[*background] ...
%D \stoptyping

\newconditional\c_page_backgrounds_new
\newconditional\c_page_backgrounds_new_right
\newconditional\c_page_backgrounds_new_left
\newconditional\c_page_backgrounds_some

\appendtoks
    \ifconditional\c_page_backgrounds_some
        \ifconditional\c_page_backgrounds_new
            \setsystemmode\v!background
        \fi
    \fi
\to \everybeforepagebody

\unexpanded\def\initializepagebackgrounds
  {\setfalse\c_page_backgrounds_new
   \setfalse\c_page_backgrounds_new_right
   \setfalse\c_page_backgrounds_new_left
   \setfalse\c_page_backgrounds_some}

%D We keep calculations and checks to a minimum and also try to minimize
%D the amount of tracing due to expansion.

\let\currentotrbackground\empty

%D This is the only spot where we have a low level dependency on the way
%D parent chains are defined but we want the speed.

\unexpanded\def\page_backgrounds_check_background
  {\ifcsname\??framed\currentotrbackground:\c!background\endcsname
    %\edef\page_background_temp{\csname\??framed\currentotrbackground:\c!background\endcsname}%
     \edef\page_background_temp{\lastnamedcs}%
     \ifx\page_background_temp\empty
       \expandafter\expandafter\expandafter\page_backgrounds_check_frame
     \else
       \page_backgrounds_set_yes
     \fi
   \else
     \expandafter\page_backgrounds_check_frame
   \fi}

\def\page_backgrounds_check_frame
  {\ifcsname\??framed\currentotrbackground:\c!frame\endcsname
    %\edef\page_background_temp{\csname\??framed\currentotrbackground:\c!frame\endcsname}%
     \edef\page_background_temp{\lastnamedcs}%
     \ifx\page_background_temp\v!on
       \page_backgrounds_set_yes
     \else
       \expandafter\expandafter\expandafter\page_backgrounds_check_leftframe
     \fi
   \else
     \expandafter\page_backgrounds_check_leftframe
   \fi}

\def\page_backgrounds_check_leftframe
  {\ifcsname\??framed\currentotrbackground:\c!leftframe\endcsname
    %\edef\page_background_temp{\csname\??framed\currentotrbackground:\c!leftframe\endcsname}%
     \edef\page_background_temp{\lastnamedcs}%
     \ifx\page_background_temp\v!on
       \page_backgrounds_set_yes
     \else
       \expandafter\expandafter\expandafter\page_backgrounds_check_rightframe
     \fi
   \else
     \expandafter\page_backgrounds_check_rightframe
   \fi}

\def\page_backgrounds_check_rightframe
  {\ifcsname\??framed\currentotrbackground:\c!rightframe\endcsname
    %\edef\page_background_temp{\csname\??framed\currentotrbackground:\c!rightframe\endcsname}%
     \edef\page_background_temp{\lastnamedcs}%
     \ifx\page_background_temp\v!on
       \page_backgrounds_set_yes
     \else
       \expandafter\expandafter\expandafter\page_backgrounds_check_topframe
     \fi
   \else
     \expandafter\page_backgrounds_check_topframe
   \fi}

\def\page_backgrounds_check_topframe
  {\ifcsname\??framed\currentotrbackground:\c!topframe\endcsname
    %\edef\page_background_temp{\csname\??framed\currentotrbackground:\c!topframe\endcsname}%
     \edef\page_background_temp{\lastnamedcs}%
     \ifx\page_background_temp\v!on
       \page_backgrounds_set_yes
     \else
       \expandafter\expandafter\expandafter\page_backgrounds_check_bottomframe
     \fi
   \else
     \expandafter\page_backgrounds_check_bottomframe
   \fi}

\def\page_backgrounds_check_bottomframe
  {\ifcsname\??framed\currentotrbackground:\c!bottomframe\endcsname
    %\edef\page_background_temp{\csname\??framed\currentotrbackground:\c!bottomframe\endcsname}%
     \edef\page_background_temp{\lastnamedcs}%
     \ifx\page_background_temp\v!on
       \page_backgrounds_set_yes
     \else
       \page_backgrounds_set_nop
     \fi
   \else
     \page_backgrounds_set_nop
   \fi}

%D We don't use the commandhandler code as we want these multitude of backgrounds to be
%D as fast as possible.

\installcorenamespace{layoutbackgrounds}
\installcorenamespace{layoutbackgroundcheck} % we need another hash as \??layoutbackgrounds<...> gets defined

\def\page_backgrounds_set_yes{\expandafter\let\csname\currentotrbackground\endcsname\relax    }
\def\page_backgrounds_set_nop{\expandafter\let\csname\currentotrbackground\endcsname\undefined}

\unexpanded\def\page_backgrounds_check#1%
  {\edef\currentotrbackground{\??layoutbackgrounds#1}%
   \page_backgrounds_check_background}

\def\doifelsesomebackground#1%
  {\ifcsname\??layoutbackgrounds#1\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\let\doifsomebackgroundelse\doifelsesomebackground

\def\doifsomebackground#1%
  {\ifcsname\??layoutbackgrounds#1\endcsname
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

%D The background mechanism falls back on the \type {\framed} macro. This means
%D that all normal frame and overlay features can be used.

\def\page_backgrounds_add_to_box#1% area
  {\ifcsname\??layoutbackgrounds#1\endcsname
     \expandafter\page_backgrounds_add_to_box_indeed
   \else
     \expandafter\gobblefourarguments
   \fi#1}

%D We don't need the dimensions here as this is a real framed but the question is:
%D do we indeed need a real framed or can we use a fake (i.e. no foreground, only
%D for hidden).

\def\page_backgrounds_add_to_box_indeed#1#2#3#4% area box width height / always non zero
  {\edef\p_page_backgrounds_setups{\namedframedparameter{\??layoutbackgrounds#1}\c!setups}%
   \ifx\p_page_backgrounds_setups\empty \else
     \doprocesslocalsetups\p_page_backgrounds_setups % should not produce funny spaces !
   \fi
   % #2 has the right dimensions already
   \setbox#2\hpack{\localbackgroundframed{\??layoutbackgrounds#1}#1#2}}% a real framed (including foreground)


%D There are quite some backgrounds. At the bottom layer, there is the {\em
%D paper} background. This one is only used for special purposes, like
%D annotations to documents.

\def\page_backgrounds_add_to_print#1%
  {\page_backgrounds_add_to_box\v!paper#1\printpaperwidth\printpaperheight}

%D The page backgrounds can be put behind the {\em left page}, the {\em
%D right page} or {\em each page}. As with the paper background, these are
%D calculated on each page.

\def\page_backgrounds_add_to_paper#1%
  {\doifbothsidesoverruled
     {\page_backgrounds_add_to_box\v!rightpage#1\paperwidth\paperheight}%
     {\page_backgrounds_add_to_box\v!rightpage#1\paperwidth\paperheight}%
     {\page_backgrounds_add_to_box\v!leftpage #1\paperwidth\paperheight}%
   \page_backgrounds_add_to_box\v!page#1\paperwidth\paperheight}

%D Then there are the 25 areas that make up the layout: {\em top, header, text,
%D footer, bottom} times {\em left edge, left margin, text, right margin, right
%D edge}. These are only recalculated when they change or when the \type {status}
%D is set to \type {repeat}.

\newbox\leftbackground  % todo: rename
\newbox\rightbackground % todo: rename

%D Finaly there is an aditional {\em text} background, again useful for
%D special purposes only. This one is calculated each time. The hidden
%D backgrounds are not meant for users!

\newconditional\c_page_backgrounds_hidden_enabled

\def\page_backgrounds_add_to_text#1%
  {\ifconditional\c_page_backgrounds_hidden_enabled
     \page_backgrounds_add_to_box\v!hidden#1\makeupwidth\textheight % mine !
   \fi
   \page_backgrounds_add_to_box\v!text#1\makeupwidth\textheight}

%D The next couple of macros implement the area backgrounds. As said, these
%D are cached in dedicated boxes. The offsets and depth of the page are used
%D for alignment purposes.

%newdimen\pageoffset % bleed
%newdimen\pagedepth  % built-in

%D We need a bit more clever mechanism in order to handle layers well.
%D This means that we cannot calculate both background at the same time
%D since something may have changed halfway a page.

%D Margin swapping has been simplified: see mkii code in case of regression.
%D Calculation is delayed till the page anyway so the state is known.

\def\page_backgrounds_recalculate
  {\global\settrue\c_page_backgrounds_new}

\def\page_backgrounds_set_boxes
  {\ifconditional\c_page_backgrounds_new
     \page_backgrounds_set_boxes_r
   \fi
   \doifbothsides
     \page_backgrounds_set_boxes_a
     \page_backgrounds_set_boxes_b
     \page_backgrounds_set_boxes_c
   \ifx\p_page_backgrounds_state\v!repeat\else
     \global\setfalse\c_page_backgrounds_new
   \fi}

\def\page_backgrounds_set_boxes_r
  {\global\settrue\c_page_backgrounds_new_right
   \global\settrue\c_page_backgrounds_new_left
   \global\setbox\leftbackground\emptybox
   \global\setbox\rightbackground\emptybox}

\def\page_backgrounds_set_boxes_a
  {\ifconditional\c_page_backgrounds_new_left
     % \showmessage\m!layouts8\empty
     \page_backgrounds_set_box\leftbackground % \conditionalfalse
     \global\setfalse\c_page_backgrounds_new_left
     \global\setfalse\c_page_backgrounds_new_right
   \fi}

\def\page_backgrounds_set_boxes_b
  {\ifconditional\c_page_backgrounds_new_left
     % \showmessage\m!layouts8\empty
     \page_backgrounds_set_box\leftbackground % \conditionalfalse
     \global\setfalse\c_page_backgrounds_new_left
   \fi}

\def\page_backgrounds_set_boxes_c
  {\ifconditional\c_page_backgrounds_new_right
     % \showmessage\m!layouts8\empty
     \page_backgrounds_set_box\rightbackground % \conditionaltrue
     \global\setfalse\c_page_backgrounds_new_right
   \fi}

\def\page_backgrounds_add_to_main#1% todo: dimension spec
  {\ifconditional\c_page_backgrounds_some
     \page_backgrounds_set_boxes
     \setbox#1\vpack
       {\offinterlineskip
        \doifelsemarginswap{\copy\leftbackground}{\copy\rightbackground}%
        \box#1}%
   \fi}

\newdimen\pagebackgroundhoffset  % THESE WILL BECOME OBSOLETE
\newdimen\pagebackgroundvoffset
\newdimen\pagebackgroundoffset   % used elsewhere
\newdimen\pagebackgrounddepth
\newdimen\pagebackgroundcompensation

\def\page_backgrounds_set_offsets % used in menus (we can use ifcsname's here)
  {\ifconditional\c_page_backgrounds_some \ifconditional\c_page_backgrounds_new
     \page_backgrounds_set_offsets_indeed % indirect, less tracing
   \fi \fi}

\def\page_backgrounds_set_offsets_indeed
  {\ifcsname\??layoutbackgrounds\v!text\v!text\endcsname
     \page_backgrounds_set_offsets_yes
   \else\ifcsname\??layoutbackgrounds\v!text\endcsname
     \page_backgrounds_set_offsets_yes
   \else
     \page_backgrounds_set_offsets_nop
   \fi\fi}

\def\page_backgrounds_set_offsets_nop
  {\global\pagebackgroundhoffset     \zeropoint
   \global\pagebackgroundvoffset     \zeropoint
   \global\pagebackgrounddepth       \zeropoint
   \global\pagebackgroundcompensation\zeropoint}

\def\page_backgrounds_set_offsets_yes
  {\global\pagebackgroundoffset      \d_page_backgrounds_depth
   \global\pagebackgroundcompensation\d_page_backgrounds_offset\relax
   \ifzeropt\pagebackgroundcompensation
     \page_backgrounds_set_offsets_nop
   \else
     \ifcsname\??layoutbackgrounds\v!top\v!text\endcsname
       \global\pagebackgroundhoffset\zeropoint
     \else\ifcsname\??layoutbackgrounds\v!bottom\v!text\endcsname
       \global\pagebackgroundhoffset\zeropoint
     \else
       \global\pagebackgroundhoffset\pagebackgroundcompensation
     \fi\fi
     \ifcsname\??layoutbackgrounds\v!text\v!rightedge\endcsname
       \global\pagebackgroundvoffset\zeropoint
       \global\pagebackgrounddepth  \zeropoint
     \else\ifcsname\??layoutbackgrounds\v!text\v!leftedge\endcsname
       \global\pagebackgroundvoffset\zeropoint
       \global\pagebackgrounddepth  \zeropoint
     \else
       \global\pagebackgroundvoffset\pagebackgroundcompensation
       \global\pagebackgrounddepth  \d_page_backgrounds_depth
     \fi\fi
   \fi}

\appendtoks
    \page_backgrounds_set_offsets
\to \everybeforepagebody

\newconditional\swapbackgroundmargins \settrue\swapbackgroundmargins

\def\page_backgrounds_set_box#1% #2%
  {\global\setbox#1\vpack
     {\dontcomplain
      \swapmargins
      \ifconditional\swapbackgroundmargins
        \doifelsemarginswap \donothing
          {\swapmacros\v!rightmargin\v!leftmargin
           \swapmacros\v!rightedge  \v!leftedge}%
      \fi
      \calculatereducedvsizes
      \offinterlineskip
    % \ifconditional#2\relax
    %   \doswapmargins % hm, this one gets nilled in \swapmargins anyway
    % \fi
      \ifdim\topheight>\zeropoint
        \kern\dimexpr-\topheight-\topdistance\relax
        \page_backgrounds_set_box_row\v!top\topheight
        \kern\topdistance
      \fi
      \ifdim\headerheight>\zeropoint
        \page_backgrounds_set_box_row\v!header\headerheight
        \kern\headerdistance
      \fi
      \ifdim\textheight>\zeropoint
        \page_backgrounds_set_box_row\v!text\textheight
      \fi
      \ifdim\footerheight>\zeropoint
        \kern\footerdistance
        \page_backgrounds_set_box_row\v!footer\footerheight
      \fi
      \ifdim\bottomheight>\zeropoint
        \kern\bottomdistance
        \page_backgrounds_set_box_row\v!bottom\bottomheight
      \fi
      \vfilll}%
   \smashbox#1}

\def\page_backgrounds_set_box_row#1#2% maybe helper
  {\setbox\scratchbox\vpack to #2
     \bgroup\hpack\bgroup
       \goleftonpage
       \ifdim\leftedgewidth>\zeropoint
         \ifcsname\??layoutbackgrounds#1\v!leftedge\endcsname
           \page_backgrounds_set_box_cell#1\v!leftedge\leftedgewidth#2%
         \else
           \kern\leftedgewidth
         \fi
         \kern\leftedgedistance
       \fi
       \ifdim\leftmarginwidth>\zeropoint
         \ifcsname\??layoutbackgrounds#1\v!leftmargin\endcsname
           \page_backgrounds_set_box_cell#1\v!leftmargin\leftmarginwidth#2%
         \else
           \kern\leftmarginwidth
         \fi
         \kern\leftmargindistance
       \fi
       \ifcsname\??layoutbackgrounds#1\v!text\endcsname
         \page_backgrounds_set_box_cell#1\v!text\makeupwidth#2%
       \else
         \kern\makeupwidth
       \fi
       \ifdim\rightmarginwidth>\zeropoint
         \kern\rightmargindistance
         \ifcsname\??layoutbackgrounds#1\v!rightmargin\endcsname
           \page_backgrounds_set_box_cell#1\v!rightmargin\rightmarginwidth#2%
         \else
           \kern\rightmarginwidth
         \fi
       \fi
       \ifdim\rightedgewidth>\zeropoint
         \kern\rightedgedistance
         \ifcsname\??layoutbackgrounds#1\v!rightedge\endcsname
           \page_backgrounds_set_box_cell#1\v!rightedge\rightedgewidth#2%
         \else
           \kern\rightedgewidth
         \fi
       \fi
     \egroup\egroup
   \wd\scratchbox\zeropoint
   \box\scratchbox\relax}

% these are fake framed .. maybe it's nicer to honor foreground here as well
% but it's probably a slow downer

\def\page_backgrounds_set_box_cell#1#2#3#4% pos pos width height
  {\begingroup
   \edef\p_page_backgrounds_setups{\namedframedparameter{\??layoutbackgrounds#1#2}\c!setups}%
   \ifx\p_page_backgrounds_setups\empty \else
     \doprocesslocalsetups\p_page_backgrounds_setups % should not produce funny spaces !
   \fi
   \edef\p_page_backgrounds_command{\namedframedparameter{\??layoutbackgrounds#1#2}\c!command}%
   \ifx\p_page_backgrounds_command\empty
     \expandafter\page_backgrounds_set_box_cell_nop
   \else
     \expandafter\page_backgrounds_set_box_cell_yes
   \fi#3#4%
   \localbackgroundframed{\??layoutbackgrounds#1#2}{#1:#2}\scratchbox
   \endgroup}

\def\page_backgrounds_set_box_cell_nop#1#2%
  {\setbox\scratchbox\emptyvbox
   \wd\scratchbox#1%
   \ht\scratchbox#2}

\def\page_backgrounds_set_box_cell_yes#1#2%
  {\setbox\scratchbox\vpack to #2{\vss\hpack to#1{\hss\p_page_backgrounds_command\hss}\vss}%
   \dp\scratchbox\zeropoint}

%D The background mechanism is quite demanding in terms or resources. We used to
%D delay these definitions till runtime usage, but since today's \TEX's are large,
%D we now do the work on forehand.
%D
%D \starttyping
%D \setupbackgrounds [settings]
%D \setupbackgrounds [paper,page,text,..] [settings]
%D \setupbackgrounds [top,...] [leftedge,...] [settings]
%D \stoptyping
%D
%D \showsetup{setupbackgrounds}
%D
%D Because the number of arguments runs from one to three, we need to check
%D for it.

\newtoks\everybackgroundssetup

\unexpanded\def\setupbackgrounds
  {\dotripleempty\page_backgrounds_setup}

\def\page_backgrounds_setup
  {\ifthirdargument
     \expandafter\page_backgrounds_setup_double
   \else\ifsecondargument
     \doubleexpandafter\page_backgrounds_setup_single
   \else\iffirstargument
     \tripleexpandafter\page_backgrounds_setup_basics
   \fi\fi\fi}

\newdimen\d_page_backgrounds_offset
\newdimen\d_page_backgrounds_depth

\appendtoks
   \edef\p_page_backgrounds_offset{\namedframedparameter{\??layoutbackgrounds\v!page}\c!offset}%
   \edef\p_page_backgrounds_depth {\namedframedparameter{\??layoutbackgrounds\v!page}\c!depth }%
   \edef\p_page_backgrounds_state {\namedframedparameter{\??layoutbackgrounds       }\c!state }%
   \global\d_page_backgrounds_offset\ifx\p_offset\empty\zeropoint\else\p_page_backgrounds_offset\fi
   \global\d_page_backgrounds_depth \ifx\p_depth \empty\zeropoint\else\p_page_backgrounds_depth \fi
   \global\pagebackgroundoffset\d_page_backgrounds_offset\relax
   \global\pagebackgrounddepth \d_page_backgrounds_depth \relax
   \ifx\p_page_backgrounds_state\v!stop
     \global\setfalse\c_page_backgrounds_new
   \else
     \global\settrue \c_page_backgrounds_new
   \fi
\to \everybackgroundssetup

\def\v_page_backgrounds_double_set{\v!paper,\v!page,\v!leftpage,\v!rightpage}
\def\v_page_backgrounds_single_set{\v!text,\v!hidden,\v!paper,\v!page,\v!leftpage,\v!rightpage}
\def\v_page_backgrounds_common_set{\v!leftedge,\v!leftmargin,\v!text,\v!rightmargin,\v!rightedge}

\unexpanded\def\page_backgrounds_setup_double[#1][#2][#3]% if needed we can speed this up
  {\global\settrue\c_page_backgrounds_some
   \def\page_backgrounds_setup_step##1%
     {\doifelseinset{##1}\v_page_backgrounds_double_set
        {\page_backgrounds_setup_and_check{##1}{#3}}
        {\def\page_backgrounds_setup_step_nested####1{\page_backgrounds_setup_and_check{##1####1}{#3}}%
         \processcommacommand[#2]\page_backgrounds_setup_step_nested}}%
   \processcommacommand[#1]\page_backgrounds_setup_step
   \the\everybackgroundssetup}

\unexpanded\def\page_backgrounds_setup_single[#1][#2][#3]%
  {\global\settrue\c_page_backgrounds_some
   \doifelsecommon{#1}\v_page_backgrounds_single_set
     {\def\page_backgrounds_setup_step##1{\page_backgrounds_setup_and_check{##1}{#2}}%
      \processcommacommand[#1]\page_backgrounds_setup_step
      \the\everybackgroundssetup}%
     {\page_backgrounds_setup_double[#1][\v_page_backgrounds_common_set][#2]}}

\unexpanded\def\page_backgrounds_setup_basics[#1][#2][#3]%
  {\setupframed[\??layoutbackgrounds][#1]%
   \the\everybackgroundssetup}

\unexpanded\def\page_backgrounds_setup_and_check#1#2% tag settings
  {\edef\currentotrbackground{\??layoutbackgrounds#1}%
   \setupframed[\currentotrbackground][#2]%
   \page_backgrounds_check_background}

%D Each areas (currently there are $1+3+25+1=30$ of them) has its own low level
%D framed object associated.

\definesimplifiedframed[\??layoutbackgrounds\v!paper]
\definesimplifiedframed[\??layoutbackgrounds\v!page]
\definesimplifiedframed[\??layoutbackgrounds\v!leftpage]
\definesimplifiedframed[\??layoutbackgrounds\v!rightpage]

\definesimplifiedframed[\??layoutbackgrounds\v!text]
\definesimplifiedframed[\??layoutbackgrounds\v!hidden]

\definesimplifiedframed[\??layoutbackgrounds\v!top\v!leftedge]
\definesimplifiedframed[\??layoutbackgrounds\v!top\v!leftmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!top\v!text]
\definesimplifiedframed[\??layoutbackgrounds\v!top\v!rightmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!top\v!rightedge]

\definesimplifiedframed[\??layoutbackgrounds\v!header\v!leftedge]
\definesimplifiedframed[\??layoutbackgrounds\v!header\v!leftmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!header\v!text]
\definesimplifiedframed[\??layoutbackgrounds\v!header\v!rightmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!header\v!rightedge]

\definesimplifiedframed[\??layoutbackgrounds\v!text\v!leftedge]
\definesimplifiedframed[\??layoutbackgrounds\v!text\v!leftmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!text\v!text]
\definesimplifiedframed[\??layoutbackgrounds\v!text\v!rightmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!text\v!rightedge]

\definesimplifiedframed[\??layoutbackgrounds\v!footer\v!leftedge]
\definesimplifiedframed[\??layoutbackgrounds\v!footer\v!leftmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!footer\v!text]
\definesimplifiedframed[\??layoutbackgrounds\v!footer\v!rightmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!footer\v!rightedge]

\definesimplifiedframed[\??layoutbackgrounds\v!bottom\v!leftedge]
\definesimplifiedframed[\??layoutbackgrounds\v!bottom\v!leftmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!bottom\v!text]
\definesimplifiedframed[\??layoutbackgrounds\v!bottom\v!rightmargin]
\definesimplifiedframed[\??layoutbackgrounds\v!bottom\v!rightedge]

\setupbackgrounds
  [\v!page]
  [\c!offset=\zeropoint, % hm, so we need to force overlay elsewhere
   \c!depth=\zeropoint]

%D General setup:

\setupbackgrounds
  [\c!state=\c!start]

%D The hidden layer can be populated by extending the following comma separated
%D list. This only happens in core modules.

% todo page-2   .. page+2   achter pagina -> bleed
%      spread-2 .. spread+2 achter spread -> spread (repeat 2 times)

\unexpanded\def\enablehiddenbackground
  {\global\settrue\c_page_backgrounds_hidden_enabled
   \global\settrue\c_page_backgrounds_some
   \page_backgrounds_recalculate}

\unexpanded\def\disablehiddenbackground
  {\global\setfalse\c_page_backgrounds_hidden_enabled}

\def\hiddenbackgroundlist
  {\v!text-2,\v!text-1,\v!foreground,\v!text+1,\v!text+2}

\defineoverlay[\v!text-2][\positionregionoverlay\textanchor{\v!text-2}] % no new anchor, we share text
\defineoverlay[\v!text-1][\positionregionoverlay\textanchor{\v!text-1}]
\defineoverlay[\v!text+1][\positionregionoverlay\textanchor{\v!text+1}]
\defineoverlay[\v!text+2][\positionregionoverlay\textanchor{\v!text+2}]

\setupbackgrounds
  [\v!hidden]
  [\c!background=\hiddenbackgroundlist]

%D Because we haven't really set up backgrounds yet, we set the main efficiency
%D switch to false.

\setfalse\c_page_backgrounds_some

%D Sometimes you have a document wide (page) background but need to overload it
%D locally. In such case (at least in my experience) the only values that get set
%D are the background and backgroundcolor (if set at all). A full inheritance chain
%D would complicate things because then we need to use named backgrounds which in
%D turn will make this mechanism slower. I considered independent local backgrounds
%D but that also complicates the code (not that much) but isolation means that we
%D need to set more parameters each time. The following simple approach proabbly
%D suits most usage.
%D
%D \starttyping
%D \starttext
%D     \setupbackgrounds[page][background=color,backgroundcolor=red]
%D     \input tufte \page
%D     \setupbackgrounds[page][background=,backgroundcolor=]
%D     \input tufte \page
%D     \setupbackgrounds[page][background=color,backgroundcolor=red]
%D     \input tufte \page
%D     \pushbackground[page]
%D         \setupbackgrounds[page][background=color,backgroundcolor=green]
%D         \input tufte \page
%D     \popbackground
%D     \input tufte \page
%D \stoptext
%D \stoptyping

\unexpanded\def\pushbackground[#1]%
  {\pushmacro\popbackground
   \edef\currentotrbackground{\??layoutbackgrounds#1}%
   \unexpanded\edef\popbackground
     {\setupframed
        [\currentotrbackground]
        [\c!background=\namedframedparameter{\currentotrbackground}\c!background,
         \c!backgroundcolor=\namedframedparameter{\currentotrbackground}\c!backgroundcolor]%
      \page_backgrounds_check_background
      \popmacro\popbackground}%
   \setupframed
     [\currentotrbackground]
     [\c!background=,\c!backgroundcolor=]%
   \page_backgrounds_check_background}

\let\popbackground\relax

\protect \endinput

% %D The next series is used in local (for instance floating) backgrounds.
%
% \installsimplifiedframed{\??layoutbackgrounds\v!local}
%
% \getparameters
%   [\??layoutbackgrounds\v!local]
%   [\c!component=local,
%    \c!background=\localbackgroundlist]
%
% \def\localbackgroundlist
%   {\v!local-2,\v!local-1,\v!foreground,\v!local+1,\v!local+2}
%
% \defineoverlay[\v!local-2][\positionoverlay{\v!local-2}] % todo share
% \defineoverlay[\v!local-1][\positionoverlay{\v!local-1}]
% \defineoverlay[\v!local+1][\positionoverlay{\v!local+1}]
% \defineoverlay[\v!local+2][\positionoverlay{\v!local+2}]
%
% \def\page_backgrounds_add_local_to_box
%   {\ifconditional\c_page_backgrounds_hidden_enabled
%      \expandafter\page_backgrounds_add_local_to_box_indeed
%    \else
%      \expandafter\gobbleoneargument
%    \fi}
%
% \def\page_backgrounds_add_local_to_box_indeed#1%
%   {\setbox#1\hbox{\localbackgroundframed{\??layoutbackgrounds\v!local}\v!local#1}%
%    \global\advance\localpositionnumber\plusone} % afterwards !
%
% \let\page_backgrounds_add_local_to_box\gobbleoneargument

% Test how previous macro behaves with depth:
%
% \startcolumnset
% \input tufte
% \placefigure{none}{\framed[lines=5]{xxx}}
% \input tufte
% \placefigure{none}{\starttabulate\NC test\nc test\NC\NR\stoptabulate}
% \input tufte
% \stopcolumnset