%D \module
%D   [       file=pack-rul, % was core-rul,
%D        version=1998.10.16,
%D          title=\CONTEXT\ Packaging Macros,
%D       subtitle=Ruled Content,
%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.

\writestatus{loading}{ConTeXt Packaging Macros / Ruled Content}

%D The code here is expanded lots of time as framed is used in many places. This is
%D why the code here is (and gets) optimized as much as possible. Also, by avoiding
%D packaging and expansion we also keep tracing reasonable. For instance, multiple
%D stacked backgrounds can slow down a run if not optimized this way.

\registerctxluafile{pack-rul}{optimize}

\unprotect

% \definesystemvariable {ol}   % OmLijnd -> check scrn-fld too

%D \macros
%D   {linewidth, setuplinewidth}
%D
%D This module deals with rules (lines) in several ways. First we introduce two
%D macros that can be used to set some common characteristics.
%D
%D \showsetup{setuplinewidth}
%D
%D The linewidth is available in \type{\linewidth}. The preset value of .4pt equals
%D the default hard coded \TEX\ rule width.

\newdimen\linewidth

\unexpanded\def\setuplinewidth
  {\dosingleargument\pack_framed_setup_line_width}

\def\pack_framed_setup_line_width[#1]%
  {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}

%D The parameter handler:

\installcorenamespace{framed}
\installcorenamespace{framedtop}
\installcorenamespace{framedbottom}
\installcorenamespace{framedleft}
\installcorenamespace{framedright}

\installcorenamespace{regularframed}
\installcorenamespace{simplifiedframed}

\installcommandhandler \??framed {framed} \??framed

\let\pack_framed_framedparameter    \framedparameter
\let\pack_framed_framedparameterhash\framedparameterhash
\let\pack_framed_setupcurrentframed \setupcurrentframed

\def\pack_framed_initialize
  {\let\framedparameter    \pack_framed_framedparameter
   \let\framedparameterhash\pack_framed_framedparameterhash
   \let\setupcurrentframed \pack_framed_setupcurrentframed
   \inframedtrue}

%D A helper:

\def\frameddimension#1{\the\dimexpr\framedparameter{#1}\relax}

%D Inheritance:

\def\installinheritedframed#1%
  {\normalexpanded{\doinstallinheritedframed
     \expandafter\noexpand\csname current#1\endcsname
     \expandafter\noexpand\csname #1parameter\endcsname
     \expandafter\noexpand\csname #1parameterhash\endcsname
     \expandafter\noexpand\csname do#1parameter\endcsname
     \expandafter\noexpand\csname do#1parentparameter\endcsname
     \expandafter\noexpand\csname do#1rootparameter\endcsname
     \expandafter\noexpand\csname setupcurrent#1\endcsname
     \expandafter\noexpand\csname inherited#1framed\endcsname
     \expandafter\noexpand\csname inherited#1framedbox\endcsname}} % new

\unexpanded\def\doinstallinheritedframed#1#2#3#4#5#6#7#8#9%
  {\def#5##1##2{\ifx##1\relax#6{##2}\else#4{##1}{##2}\fi}%
  %\def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\s!empty\fi}% root
   \def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\??empty\fi}% root
   \unexpanded\def#8%
     {\bgroup
      \bgroup
      \inframedtrue
      \let\currentframed      #1%
      \let\framedparameter    #2%
      \let\framedparameterhash#3%
      \let\setupcurrentframed #7%
      \pack_framed_process_indeed}%
   \unexpanded\def#9%
     {\bgroup
      \inframedtrue
      \let\currentframed      #1%
      \let\framedparameter    #2%
      \let\framedparameterhash#3%
      \let\setupcurrentframed #7%
      \pack_framed_process_box_indeed}}

\unexpanded\def\installframedcommandhandler#1#2#3%
  {\installcommandhandler{#1}{#2}{#3}%
   \installinheritedframed{#2}}

\unexpanded\def\installframedautocommandhandler#1#2#3%
  {\installautocommandhandler{#1}{#2}{#3}%
   \installinheritedframed{#2}}

\unexpanded\def\installsimpleframedcommandhandler#1#2#3%
  {\installsimplecommandhandler{#1}{#2}{#3}%
   \installinheritedframed{#2}}

% for regular framed

\setupframed
  [\c!width=\v!fit,
   \c!height=\v!broad,
  %\c!minheight=\zeropoint,
  %\c!lines=,
   \c!offset=.25\exheight,  % \defaultframeoffset
   \c!empty=\v!no,
   \c!frame=\v!on,
  %\c!topframe=,
  %\c!bottomframe=,
  %\c!leftframe=,
  %\c!rightframe=,
   \c!radius=.5\bodyfontsize,
   \c!rulethickness=\linewidth,
   \c!corner=\v!rectangular,
   \c!depth=\zeropoint,
  %\c!foregroundcolor=,
  %\c!foregroundstyle=,
  %\c!background=,
  %\c!backgroundcolor=,
   \c!backgroundoffset=\zeropoint,
  %\c!framecolor=,
   \c!frameoffset=\zeropoint,
   \c!backgroundcorner=\framedparameter\c!corner, % use \p_ here
   \c!backgroundradius=\framedparameter\c!radius,
   \c!backgrounddepth=\framedparameter\c!depth,
   \c!framecorner=\framedparameter\c!corner,
   \c!frameradius=\framedparameter\c!radius,
   \c!framedepth=\framedparameter\c!depth,
  %\c!component=,
  %\c!region=,
  %\c!align=,
   \c!bottom=\vss,
  %\c!top=,
   \c!strut=\v!yes,
   \c!autostrut=\v!yes,
   \c!location=\v!normal,
  %\c!orientation=,
  %\c!anchoring=,
   \c!autowidth=\v!yes,
  %\c!setups=,
   \c!loffset=\zeropoint,
   \c!roffset=\zeropoint,
   \c!toffset=\zeropoint,
   \c!boffset=\zeropoint]

%D For backgrounds and such:

\defineframed
  [\??simplifiedframed]
  [\c!frame=\v!off,
   \c!depth=\zeropoint,
   \c!offset=\v!overlay,
   \c!component=,
   \c!region=,
   \c!radius=.5\bodyfontsize,
   \c!rulethickness=\linewidth,
   \c!corner=\v!rectangular,
   \c!backgroundoffset=\zeropoint,
   \c!frameoffset=\zeropoint,
   \c!backgroundcorner=\framedparameter\c!corner,  % use \p_ here
   \c!backgroundradius=\framedparameter\c!radius,
   \c!backgrounddepth=\framedparameter\c!depth,
   \c!framecorner=\framedparameter\c!corner,
   \c!frameradius=\framedparameter\c!radius,
   \c!framedepth=\framedparameter\c!depth,
   \c!location=\v!normal,
   \c!loffset=\zeropoint,
   \c!roffset=\zeropoint,
   \c!toffset=\zeropoint,
   \c!boffset=\zeropoint]

\unexpanded\def\definesimplifiedframed[#1]% no settings
  {\defineframed[#1][\??simplifiedframed]%
   \expandafter\let\csname#1\endcsname\undefined}

\expandafter\let\csname\??simplifiedframed\endcsname\undefined

%D We will communicate through module specific variables, current framed
%D parameters and some reserved dimension registers.

\newdimen\d_framed_target_wd
\newdimen\d_framed_target_ht
\newdimen\d_framed_target_dp
\newdimen\d_framed_linewidth  \let\ruledlinewidth\d_framed_linewidth % needed at lua end

\let\p_framed_frame           \empty % \framedparameter\c!frame
\let\p_framed_backgroundoffset\empty
\let\p_framed_foregroundstyle \empty
\let\p_framed_autostrut       \empty
\let\p_framed_location        \empty
\let\p_framed_orientation     \empty
\let\p_framed_anchoring       \empty
\let\p_framed_autowidth       \empty
\let\p_framed_franalyze       \empty
\let\p_framed_backgroundcorner\empty
\let\p_framed_backgroundradius\empty
\let\p_framed_framecorner     \empty
\let\p_framed_frameradius     \empty
\let\p_framed_lines           \empty
\let\p_framed_empty           \empty
\let\p_framed_backgroundcolor \empty
\let\p_framed_framecolor      \empty
\let\p_framed_component       \empty
\let\p_framed_background      \empty
\let\p_framed_rulethickness   \empty
\let\p_framed_foregroundcolor \empty
\let\p_framed_setups          \empty

%D We don't have to stick to a \TEX\ drawn rule, but also can use rounded
%D or even fancier shapes, as we will see later on.

\def\pack_framed_filled_box
  {\edef\p_framed_backgroundcorner{\framedparameter\c!backgroundcorner}%
   \ifx\p_framed_backgroundcorner\v!rectangular
     \pack_framed_filled_box_normal
   \else
     \pack_framed_filled_box_radius
   \fi}

\def\pack_framed_filled_box_normal
  {\vrule
     \s!width \d_framed_target_wd
     \s!height\d_framed_target_ht
     \s!depth \d_framed_target_dp
   \relax}

\def\pack_framed_filled_box_radius
  {\edef\p_framed_backgroundradius{\framedparameter\c!backgroundradius}%
   \ifzeropt\dimexpr\p_framed_backgroundradius\relax % just in case of .x\bodyfontsize
     \pack_framed_filled_box_normal
   \else
     \pack_framed_filled_box_round
   \fi}

\def\pack_framed_filled_box_round
  {\raise\d_framed_target_dp\hpack{\frule
     type   fill
     width  \d_framed_target_wd
     height \d_framed_target_ht
     depth  \d_framed_target_dp
     line   \d_framed_linewidth
     radius \p_framed_backgroundradius\space
     corner {\p_framed_backgroundcorner}
   \relax}}

\def\pack_framed_stroked_box
  {\edef\p_framed_framecorner{\framedparameter\c!framecorner}%
   \ifx\p_framed_framecorner\v!rectangular
     \pack_framed_stroked_box_normal
   \else
     \pack_framed_stroked_box_radius
   \fi}

\def\pack_framed_stroked_box_radius
  {\edef\p_framed_frameradius{\framedparameter\c!frameradius}%
   \ifzeropt\dimexpr\p_framed_frameradius\relax % just in case of .x\bodyfontsize
     \pack_framed_stroked_box_normal
   \orelse\ifx\p_framed_frame\v!on
     \pack_framed_stroked_box_round
   \fi}

% \pack_framed_stroked_box_normal % later

\def\pack_framed_stroked_box_round
  {\raise\d_framed_target_dp\hpack{\frule
     width  \d_framed_target_wd
     height \d_framed_target_ht
     depth  \d_framed_target_dp
     line   \d_framed_linewidth
     radius \p_framed_frameradius\space
     corner {\p_framed_framecorner}
   \relax}}

% a lot of weird corners
%
% \startTEXpage
%     \dontleavehmode\framed
%         [corner=0,frame=on,framecolor=green,
%          background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green,
%          background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green,
%          background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse {9}{12}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse{13}{16}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse{17}{20}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse{21}{24}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
%     \vskip1em
%     \dontleavehmode\dostepwiserecurse{25}{28}{1}{\framed
%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
%         \quad}
% \stopTEXpage

%D It won't be a surprise that we not only provide gray boxes, but also colored
%D ones. Here it is:

\def\pack_framed_background_box_color
  {\edef\p_framed_backgroundcolor{\framedparameter\c!backgroundcolor}%
   \ifx\p_framed_backgroundcolor\empty \else
     \doifcolor\p_framed_backgroundcolor\pack_framed_background_box_color_indeed
   \fi}

\def\pack_framed_background_box_color_indeed
  {\hpack{\dousecolorparameter\p_framed_backgroundcolor\pack_framed_filled_box}}

%D \macros
%D   {defineoverlay, doifoverlayelse, overlayoffset,
%D    overlaywidth, overlayheight, overlaydepth,
%D    overlaycolor, overlaylinecolor, overlaylinewidth}
%D
%D Before we define the macro that actually takes card of the backgrounds, we
%D introduce overlays. An overlay is something that contrary to its name lays {\em
%D under} the text. An example of an overlay definition is:
%D
%D \startbuffer[tmp-1]
%D \defineoverlay
%D   [fancy]
%D   [{\externalfigure
%D       [mp-cont.502]
%D       [width=\overlaywidth,
%D        height=\overlayheight]}]
%D \stopbuffer
%D
%D \typebuffer[tmp-1]
%D
%D  That for instance can be uses in:
%D
%D  \startbuffer[tmp-2]
%D  \framed[backgroundachtergrond=fancy]{How Fancy!}
%D  \framed[backgroundachtergrond=fancy,frame=off]{Even More Fancy!}
%D  \stopbuffer
%D
%D  and looks like:
%D
%D  \startlinecorrection
%D  \vbox{\baselineskip24pt\getbuffer[tmp-1]\getbuffer[tmp-2]}
%D  \stoplinecorrection
%D
%D The formal definition is:
%D
%D \showsetup{defineoverlay}
%D
%D This macro's definition is a bit obscure, due the many non||used arguments and
%D the two step call that enable the setting of the width, height and depth
%D variables. Multiple backgrounds are possible and are specified as:
%D
%D \starttyping
%D \framed[background={one,two,three}]{Three backgrounds!}
%D \stoptyping
%D
%D Most drawing packages only know width and height. Therefore the dimensions have a
%D slightly different meaning here:
%D
%D \startitemize[packed]
%D \item \type{\overlaywidth }: width of the overlay
%D \item \type{\overlayheight}: height plus depth of the overlay
%D \item \type{\overlaydepth }: depth of the overlay
%D \stopitemize
%D
%D The resulting box is lowered to the right depth.

%def\overlaywidth      {\the\hsize\space} % We preset the variables
%def\overlayheight     {\the\vsize\space} % to some reasonable default
%def\overlaydepth      {0pt }             % values. The attributes
%let\overlayoffset     \overlaydepth      % of the frame can be (are)
%let\overlaylinewidth  \overlaydepth      % set somewhere else.
\let\overlaycolor      \empty
\let\overlaylinecolor  \empty

\def\overlayradius{\framedparameter\c!frameradius}

\newdimen\d_overlay_width
\newdimen\d_overlay_height
\newdimen\d_overlay_depth
\newdimen\d_overlay_offset
\newdimen\d_overlay_linewidth

\let\m_overlay_region\empty

% expandable ... in a future version the space will go (in mp one can use Overlay*)

\def\overlaywidth        {\the\d_overlay_width    \space} % We preset the variables
\def\overlayheight       {\the\d_overlay_height   \space} % to some reasonable default
\def\overlaydepth        {\the\d_overlay_depth    \space} % values.
\def\overlayoffset       {\the\d_overlay_offset   \space} % of the frame can be (are)
\def\overlaylinewidth    {\the\d_overlay_linewidth\space} % set somewhere else.
\def\overlayregion       {\m_overlay_region}

% public but kind of protected

\def\usedoverlaywidth    {\dimexpr\d_overlay_width    \relax}
\def\usedoverlayheight   {\dimexpr\d_overlay_height   \relax}
\def\usedoverlaydepth    {\dimexpr\d_overlay_depth    \relax}
\def\usedoverlayoffset   {\dimexpr\d_overlay_offset   \relax}
\def\usedoverlaylinewidth{\dimexpr\d_overlay_linewidth\relax}

%D The next register is used to initialize overlays.

\newtoks\everyoverlay

%D An example of an initialization is the following (overlays can contain text
%D and be executed under an regime where interlineskip is off).

\installcorenamespace{overlay}
\installcorenamespace{overlaybuiltin}

\appendtoks
    \oninterlineskip
\to \everyoverlay

\prependtoks
    \hsize\d_overlay_width
    \vsize\d_overlay_height
\to \everyoverlay

\unexpanded\def\defineoverlay
  {\dodoubleargument\pack_framed_define_overlay}

\def\pack_framed_define_overlay[#1][#2]%
  {\def\pack_framed_define_overlay_indeed##1{\setvalue{\??overlay##1}{\executedefinedoverlay{##1}{#2}}}%
   \processcommalist[#1]\pack_framed_define_overlay_indeed}

% \unexpanded\def\executedefinedoverlay#1#2% we can share the definitions
%   {\bgroup % redundant grouping
%    \setbox\scratchbox\hbox\bgroup
%      \ifzeropt\d_framed_target_dp
%        \the\everyoverlay#2% saves wrapping (and lua call)
%      \else
%        \lower\d_framed_target_dp
%        \hbox{\the\everyoverlay#2}%
%      \fi
%    \egroup
%    \setlayoutcomponentattribute{\v!overlay:#1}%
%    \setbox\scratchbox\hpack \layoutcomponentboxattribute
%      {\kern -.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \d_overlay_width
%       \raise-.5\dimexpr\ht\scratchbox-\d_framed_target_ht\relax % not \d_overlay_height !
%       \box\scratchbox}%
%    \wd\scratchbox\d_framed_target_wd
%    \ht\scratchbox\d_framed_target_ht
%    \dp\scratchbox\d_framed_target_dp
%    \box\scratchbox
%    \egroup}

% 20191231: moved from cont-exp:

\unexpanded\def\executedefinedoverlay#1#2% we can share the definitions
  {\bgroup % redundant grouping
   \setlayoutcomponentattribute{\v!overlay:#1}%
   \setbox\scratchbox\hbox \layoutcomponentboxattribute{\the\everyoverlay#2}%
   \boxxoffset\scratchbox-.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \d_overlay_width
   \boxyoffset\scratchbox-.5\dimexpr\ht\scratchbox-\d_framed_target_ht+\d_framed_target_dp\relax % not \d_overlay_height !
   \wd\scratchbox\d_framed_target_wd
   \ht\scratchbox\d_framed_target_ht
   \dp\scratchbox\d_framed_target_dp
   \box\scratchbox
   \egroup}

%D \macros
%D   {overlayfakebox}

% \unexpanded\def\overlayfakebox
%   {\hpack
%      {\setbox\scratchbox\emptyhbox
%       \wd\scratchbox\d_overlay_width
%       \ht\scratchbox\d_overlay_height
%       \box\scratchbox}}

\unexpanded\def\overlayfakebox
  {\hpack % redundant but needs testing
     {\novrule
        \s!width \d_overlay_width
        \s!height\d_overlay_height
        \s!depth \zeropoint}}

%D For testing we provide:

\def\doifelseoverlay#1% only tests external overlays
  {\ifcsname\??overlay#1\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\let\doifoverlayelse\doifelseoverlay

%D The content of the box will be (temporary) saved in a box. We also have an
%D extra box for backgrounds.

\newbox\b_framed_normal
\newbox\b_framed_extra

\newtoks\everybackgroundbox

\let\m_framed_background\empty % we might need a public name

\def\pack_framed_process_background
  {\ifcsname\??overlaybuiltin\m_framed_background\endcsname
     \expandafter\pack_framed_process_background_indeed_internal\lastnamedcs
   \orelse\ifcsname\??overlay\m_framed_background\endcsname
     \expandafter\pack_framed_process_background_indeed_external\lastnamedcs
   \fi}

\def\pack_framed_process_background_indeed_internal#1% % : in name
  {\bgroup
   \setbox\b_framed_extra\hpack\bgroup
     \ifzeropt\framedbackgroundoffset\else
       \kern-\framedbackgroundoffset
     \fi
     \hbox\bgroup#1\egroup
   \egroup
   \wd\b_framed_extra\zeropoint
   \ht\b_framed_extra\framedbackgroundheight
   \dp\b_framed_extra\framedbackgrounddepth
   \box\b_framed_extra
   \egroup}

\def\pack_framed_process_background_indeed_external
  {\pack_framed_overlay_initialize
   \pack_framed_process_background_indeed_internal}

\def\pack_framed_process_backgrounds#1,#2% #2 gobbles spaces (we could avoid one catch if we have nextbackground)
  {\edef\m_framed_background{#1}%
   \ifx\m_framed_background\s!unknown\else
     \pack_framed_process_background
     \expandafter\pack_framed_process_backgrounds
   \fi#2}

%D Beware, a backgroundbox can be empty which is another reason why we set the
%D width to zero instead of back-skipping.

\newdimen\framedbackgroundwidth
\newdimen\framedbackgroundheight
\newdimen\framedbackgrounddepth
\newdimen\framedbackgroundoffset

\def\pack_framed_background_box_content% fuzzy but needed hack, this \vss, otherwise
  {\vpack to \framedbackgroundheight{\vss\box\b_framed_normal\vss}} % vertical shift \backgroundheight

\def\pack_framed_set_region % experiment
  {\ifx\m_overlay_region\v!yes
     \edef\m_overlay_region{\reservedautoregiontag}%
   \fi}

\def\pack_framed_add_region % experiment
  {\anch_mark_tagged_box\b_framed_normal\m_overlay_region}

\def\pack_framed_add_background
  {\setbox\b_framed_normal\hpack % was vbox % see also *1*
     {%\pack_framed_forgetall % can be relaxed
      \boxmaxdepth\maxdimen
      \framedbackgroundoffset\d_framed_backgroundoffset
      \framedbackgroundwidth \wd\b_framed_normal
      \framedbackgroundheight\ht\b_framed_normal
      \framedbackgrounddepth \dp\b_framed_normal
      \d_framed_target_wd\dimexpr\framedbackgroundwidth +2\framedbackgroundoffset\relax
      \d_framed_target_ht\dimexpr\framedbackgroundheight+ \framedbackgroundoffset\relax
      \d_framed_target_dp\dimexpr\framedbackgrounddepth + \framedbackgroundoffset+\framedparameter\c!backgrounddepth\relax
      \let\pack_framed_overlay_initialize\pack_framed_overlay_initialize_indeed
      \ifx\p_framed_component\empty
        \resetlayoutcomponentattribute
      \else
        \setlayoutcomponentattribute{\v!background:\p_framed_component}%
      \fi
      \let\foregroundbox\pack_framed_background_box_content
      \hpack \layoutcomponentboxattribute to \framedbackgroundwidth\bgroup % width in case 'foreground' is used as overlay
         \the\everybackgroundbox % moved
         \expandafter\pack_framed_process_backgrounds\p_framed_background,\s!unknown,\relax % hm, messy .. look into it
         \box\b_framed_normal
         \hss
      \egroup}}

\def\pack_framed_overlay_initialize_indeed
  {\d_overlay_width     \d_framed_target_wd
   \d_overlay_height    \dimexpr\d_framed_target_ht+\d_framed_target_dp\relax
   \d_overlay_depth     \d_framed_target_dp
   \d_overlay_linewidth \d_framed_linewidth
   \d_overlay_offset    \framedbackgroundoffset\relax
   \edef\overlaycolor    {\framedparameter\c!backgroundcolor}% let ?
   \edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers
  %\edef\overlaycorner   {\framedparameter\c!backgroundcorner}%
  %\edef\overlayradius   {\framedparameter\c!backgroundradius}%
   \let\pack_framed_overlay_initialize\relax}

%D One can explictly insert the foreground box. For that purpose we introduce the
%D overlay \type {foreground}.
%D
%D We predefine two already familiar backgrounds:

%letvalue{\??overlaybuiltin\v!screen    }\pack_framed_background_box_gray
\letvalue{\??overlaybuiltin\v!color     }\pack_framed_background_box_color
\letvalue{\??overlaybuiltin\v!foreground}\pack_framed_background_box_content % replaces: \defineoverlay[\v!foreground][\foregroundbox]

%D We can specify overlays as a comma separated list of overlays, a sometimes
%D handy feature.
%D
%D Besides backgrounds (overlays) we also need some macros to draw outlines (ruled
%D borders). Again we have to deal with square and round corners. The first category
%D can be handled by \TEX\ itself, the latter one depends on the driver. This macro
%D also support a negative offset.

\def\pack_framed_add_outline
  {\setbox\b_framed_normal\hpack % rules on top of box
     {\d_framed_target_wd\dimexpr\wd\b_framed_normal+2\d_framed_frameoffset\relax
      \d_framed_target_ht\dimexpr\ht\b_framed_normal+ \d_framed_frameoffset\relax
      \d_framed_target_dp\dimexpr\dp\b_framed_normal+ \d_framed_frameoffset+\framedparameter\c!framedepth\relax
      \ifdim\d_framed_target_dp<\zeropoint
        \advance\d_framed_target_ht \d_framed_target_dp
        \scratchdimen-\d_framed_target_dp
        \d_framed_target_dp\zeropoint
      \else
        \scratchdimen\zeropoint
      \fi
      \edef\overlaylinecolor{\framedparameter\c!framecolor}% twice, also in background
      \setbox\b_framed_extra\hpack
        {\kern-\d_framed_frameoffset
         \raise\scratchdimen
         \hpack{\ifx\overlaylinecolor\empty\else\dousecolorparameter\overlaylinecolor\fi\pack_framed_stroked_box}}%
      \wd\b_framed_extra\wd\b_framed_normal
      \ht\b_framed_extra\ht\b_framed_normal
      \dp\b_framed_extra\dp\b_framed_normal
      \wd\b_framed_normal\zeropoint
      \box\b_framed_normal
      \box\b_framed_extra}}

\def\pack_framed_stroked_box_normal_opened
  {\setbox\scratchbox\vpack \bgroup
     \csname\??framedtop\p_framed_frame\framedparameter\c!topframe\endcsname
     \nointerlineskip % new (needed for fences)
     \hpack \bgroup
       \csname\??framedleft\p_framed_frame\framedparameter\c!leftframe\endcsname
       \novrule
         \s!width \d_framed_target_wd
         \s!height\d_framed_target_ht
         \s!depth \d_framed_target_dp
       \csname\??framedright\p_framed_frame\framedparameter\c!rightframe\endcsname
     \egroup
     \nointerlineskip % new (needed for fences)
     \csname\??framedbottom\p_framed_frame\framedparameter\c!bottomframe\endcsname
   \egroup
   \wd\scratchbox\d_framed_target_wd
   \ht\scratchbox\d_framed_target_ht
   \dp\scratchbox\d_framed_target_dp
   \box\scratchbox}

\def\pack_framed_stroked_box_normal_closed
  {\hpack\bgroup
     \scratchdimen.5\d_framed_linewidth
     \hskip\scratchdimen
     \clf_framedoutline
       \dimexpr\d_framed_target_wd-\d_framed_linewidth\relax
       \dimexpr\d_framed_target_ht-\scratchdimen\relax
       \dimexpr\d_framed_target_dp-\scratchdimen\relax
       \d_framed_linewidth
     \relax
   \egroup}

\def\pack_framed_stroked_box_normal
  {\ifx\p_framed_frame\v!closed
     \pack_framed_stroked_box_normal_closed
   \else
     \pack_framed_stroked_box_normal_opened
   \fi}

\def\pack_framed_t_rule{\hrule\s!height\d_framed_linewidth\kern-\d_framed_linewidth}
\def\pack_framed_b_rule{\kern-\d_framed_linewidth\hrule\s!height\d_framed_linewidth}
\def\pack_framed_r_rule{\kern-\d_framed_linewidth\vrule\s!width\d_framed_linewidth}
\def\pack_framed_l_rule{\vrule\s!width\d_framed_linewidth\kern-\d_framed_linewidth}

\letvalue{\??framedtop   \v!on \v!on}\pack_framed_t_rule
\letvalue{\??framedtop   \v!off\v!on}\pack_framed_t_rule
\letvalue{\??framedtop   \v!on      }\pack_framed_t_rule

\letvalue{\??framedbottom\v!on \v!on}\pack_framed_b_rule
\letvalue{\??framedbottom\v!off\v!on}\pack_framed_b_rule
\letvalue{\??framedbottom\v!on      }\pack_framed_b_rule

\letvalue{\??framedleft  \v!on \v!on}\pack_framed_l_rule
\letvalue{\??framedleft  \v!off\v!on}\pack_framed_l_rule
\letvalue{\??framedleft  \v!on      }\pack_framed_l_rule

\letvalue{\??framedright \v!on \v!on}\pack_framed_r_rule
\letvalue{\??framedright \v!off\v!on}\pack_framed_r_rule
\letvalue{\??framedright \v!on      }\pack_framed_r_rule

% no overlapping rules

\def\pack_framed_t_rules{\hpack{\kern\d_framed_linewidth\vrule\s!width\dimexpr\d_framed_target_wd-2\d_framed_linewidth\relax\s!height\d_framed_linewidth}\nointerlineskip\kern-\d_framed_linewidth}
\def\pack_framed_b_rules{\kern-\d_framed_linewidth\nointerlineskip\hpack{\kern\d_framed_linewidth\vrule\s!width\dimexpr\d_framed_target_wd-2\d_framed_linewidth\relax\s!height\d_framed_linewidth}}
\def\pack_framed_r_rules{\kern-\d_framed_linewidth\vrule\s!height\dimexpr\d_framed_target_ht-\d_framed_linewidth\relax\s!depth-\d_framed_linewidth\s!width\d_framed_linewidth}
\def\pack_framed_l_rules{\vrule\s!height\dimexpr\d_framed_target_ht-\d_framed_linewidth\relax\s!depth-\d_framed_linewidth\s!width\d_framed_linewidth\kern-\d_framed_linewidth}

\letvalue{\??framedtop   \v!small\v!small}\pack_framed_t_rules
\letvalue{\??framedtop   \v!off  \v!small}\pack_framed_t_rules
\letvalue{\??framedtop   \v!small        }\pack_framed_t_rules

\letvalue{\??framedbottom\v!small\v!small}\pack_framed_b_rules
\letvalue{\??framedbottom\v!off  \v!small}\pack_framed_b_rules
\letvalue{\??framedbottom\v!small        }\pack_framed_b_rules

\letvalue{\??framedleft  \v!small\v!small}\pack_framed_l_rules
\letvalue{\??framedleft  \v!off  \v!small}\pack_framed_l_rules
\letvalue{\??framedleft  \v!small        }\pack_framed_l_rules

\letvalue{\??framedright \v!small\v!small}\pack_framed_r_rules
\letvalue{\??framedright \v!off  \v!small}\pack_framed_r_rules
\letvalue{\??framedright \v!small        }\pack_framed_r_rules

% \framed
%   [width=4cm,height=3cm,rulethickness=3mm,
%    frame=off,rightframe=on,leftframe=on,topframe=on,bottomframe=on]
%   {}
% \framed
%   [width=4cm,height=3cm,rulethickness=3mm,
%    frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=small]
%   {}
% \framed
%   [width=4cm,height=3cm,rulethickness=3mm,
%    frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=on]
%   {}

%D The next few macros are probably the most misused ones in \CONTEXT. They deal
%D with putting rules around boxes, provide backgrounds, offer alignment features,
%D and some more. We start with defining some booleans. These give an impression of
%D what we are going to take into account.

% todo   : \c_framed_hasoffset
% faster : \let\c_framed_hasoffset\falseconditional

\newconditional\c_framed_has_offset
\newconditional\c_framed_has_width
\newconditional\c_framed_has_height
\newconditional\c_framed_has_format
\newconditional\c_framed_is_overlaid
\newconditional\c_framed_has_frame
\newconditional\c_framed_has_extra_offset
\newconditional\c_framed_text_location_none

\newconstant   \c_framed_has_strut  % 0=relaxes 1=pseudostruts 2=realstruts

%D \macros
%D   {framed, setupframed}
%D
%D Ruled boxes are typeset using \type{\framed}. This command is quite versatile
%D and, although some users will probably seldom use it, one cannot overlook its
%D features.
%D
%D  \showsetup{setupframed}
%D  \showsetup{framed}
%D
%D This general macro is a special version of an even more general case, that can
%D easily be linked into other macros that need some kind of framing. The local
%D version is called with an extra parameter: the variable identifier. The reason
%D for passing this identifier between brackets lays in the mere fact that this way
%D we can use the optional argument grabbers.

\def\defaultframeoffset{.25\exheight}

\installcorenamespace{regularframedlevel}

\unexpanded\def\installregularframed#1%
  {\defineframed[#1]}

\unexpanded\def\presetlocalframed[#1]%
  {\defineframed[#1]}

% \presetlocalframed[\??framed]

\newcount\c_pack_framed_nesting

\unexpanded\def\pack_framed_process_framed[#1]%
  {\bgroup
   \iffirstargument % faster
     \setupcurrentframed[#1]% here !
   \fi
   \pack_framed_process_indeed}

\unexpanded\def\framed
  {\bgroup
   \advance\c_pack_framed_nesting\plusone
   \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
   \edef\currentframed{>\the\c_pack_framed_nesting}%
   \pack_framed_initialize
   \dosingleempty\pack_framed_process_framed}

\unexpanded\def\startframed
  {\dosingleempty\pack_framed_start_framed}

\def\pack_framed_start_framed[#1]%
  {\bgroup
   \doifelseassignment{#1}\pack_framed_start_framed_yes\pack_framed_start_framed_nop{#1}}

\def\pack_framed_start_framed_yes#1%
  {\advance\c_pack_framed_nesting\plusone
   \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
   \iffirstargument\secondargumenttrue\fi % dirty trick
   \edef\currentframed{>\the\c_pack_framed_nesting}%
   \pack_framed_initialize
   \bgroup
   \iffirstargument
     \secondargumenttrue % dirty trick
     \setupcurrentframed[#1]% here !
   \fi
   \pack_framed_process_indeed
   \bgroup
   \ignorespaces}

\def\pack_framed_start_framed_nop#1%
  {\edef\currentframed{#1}%
   \dosingleempty\pack_framed_start_framed_nop_indeed}

\def\pack_framed_start_framed_nop_indeed[#1]%
  {\pack_framed_initialize
   \bgroup
   \iffirstargument
     \setupcurrentframed[#1]% here !
   \fi
   \pack_framed_process_indeed
   \bgroup
   \ignorespaces}

% till here

\unexpanded\def\stopframed
  {\removeunwantedspaces
   \egroup}

\unexpanded\def\normalframedwithsettings[#1]%
  {\bgroup
   \advance\c_pack_framed_nesting\plusone
   \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
   \bgroup
   \edef\currentframed{>\the\c_pack_framed_nesting}%
   \pack_framed_initialize
   \setupcurrentframed[#1]%
   \pack_framed_process_indeed}

%D \startbuffer
%D \setupframed [framecolor=yellow]          \framed{A}
%D \defineframed[myframed] [framecolor=blue] \myframed{B}
%D \setupframed [myframed] [framecolor=red]  \myframed{C}
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D \startbuffer
%D \presetlocalframed[myframed]
%D \localframed[myframed][framecolor=green]{oeps}
%D \stopbuffer
%D
%D \typebuffer \getbuffer

%D \macros
%D   {ifinframed}
%D
%D The normal case first presets all parameters and next starts looking for the user
%D supplied ones. The first step is omitted in the local case, because these are
%D preset at declaration time and keep their values unless explictly changed. By
%D presetting the variables everytime the normal command is called, we can use this
%D command nested, without the unwanted side effect of inheritance. The boolean is
%D used to speed up the color stack.

\newif\ifinframed

%D The next one is faster on multiple backgrounds per page. No
%D dimensions can be set, only frames and backgrounds.

\unexpanded\def\fastlocalframed[#1]#2[#3]#4% 3-4
  {\bgroup
   \edef\currentframed{#1}%
   \pack_framed_initialize
   \setbox\b_framed_normal\hbox{#4}%
   \iftrialtypesetting \else
     \edef\m_overlay_region{\framedparameter\c!region}%
     \ifx\m_overlay_region\empty\else
       \pack_framed_set_region
     \fi
   \fi
   \setupcurrentframed[#3]%
   \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}% also used in backgrounds
   \d_framed_frameoffset\framedparameter\c!frameoffset\relax     % also used in backgrounds
   \edef\p_framed_frame{\framedparameter\c!frame}%
   \edef\p_framed_background{\framedparameter\c!background}%
   % not here, in calling macro: setups
   \pack_framed_remove_depth
   \ifx\p_framed_frame\v!overlay \orelse \ifx\p_framed_frame\v!none \else
     \ifx\p_framed_rulethickness\empty\else
        \d_framed_linewidth\p_framed_rulethickness\relax
     \fi
     \pack_framed_add_outline % real or invisible frame
   \fi
   \ifx\p_framed_background\empty \else
     \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
     \d_framed_backgroundoffset
       \ifx\p_framed_backgroundoffset\v!frame
         \d_framed_frameoffset
       \else
         \p_framed_backgroundoffset
       \fi
     \edef\p_framed_component{\framedparameter\c!component}%
     \pack_framed_add_background
   \fi
   \pack_framed_restore_depth
   \iftrialtypesetting\orelse\ifx\m_overlay_region\empty\else
     \pack_framed_add_region
   \fi
   \box\b_framed_normal
   \egroup}

%D The next macro uses a box and takes its natural width and height so these
%D can better be correct.

\unexpanded\def\pack_framed_process_box_indeed#1#2% component box (assumes parameters set and grouped usage)
  {\setbox\b_framed_normal\box#2% could actually be \let\b_framed_normal#2
   \edef\m_overlay_region{\framedparameter\c!region}%
   \ifx\m_overlay_region\empty\else
     \pack_framed_set_region
   \fi
   \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}% also used in backgrounds
   \d_framed_frameoffset\framedparameter\c!frameoffset\relax     % also used in backgrounds
   \edef\p_framed_frame{\framedparameter\c!frame}%
   \edef\p_framed_background{\framedparameter\c!background}%
   \ifx\p_framed_frame\v!overlay \orelse \ifx\p_framed_frame\v!none \else
     \ifx\p_framed_rulethickness\empty \else
        \d_framed_linewidth\p_framed_rulethickness\relax
     \fi
     \pack_framed_add_outline % real or invisible frame
   \fi
   \ifx\p_framed_background\empty \else
     \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
     \d_framed_backgroundoffset
       \ifx\p_framed_backgroundoffset\v!frame
         \d_framed_frameoffset
       \else
         \p_framed_backgroundoffset
       \fi
     \edef\p_framed_component{#1}%
     \pack_framed_add_background
   \fi
   \ifx\m_overlay_region\empty\else
     \pack_framed_add_region
   \fi
   \box\b_framed_normal
   \egroup}

\unexpanded\def\localbackgroundframed#1% namespace component box
  {\bgroup
   \edef\currentframed{#1}%
   \pack_framed_initialize
   \pack_framed_process_box_indeed} % group ends here

\let\postprocessframebox\relax

%D A nice example by Aditya:
%D
%D \starttyping
%D \setupframed
%D   [loffset=\framedparameter{hoffset},
%D    roffset=\framedparameter{hoffset},
%D    hoffset=\zeropoint]
%D
%D \defineframed[test][hoffset=1cm]
%D \stoptyping

\newdimen\d_framed_width
\newdimen\d_framed_height
\newdimen\d_framed_frameoffset
\newdimen\d_framed_backgroundoffset
\newdimen\d_framed_local_offset

% todo: protect local \framednames

\unexpanded\def\localframed
  {\bgroup
   \dodoubleempty\pack_framed_local}

\unexpanded\def\pack_framed_local[#1][#2]%
  {\bgroup
   \edef\currentframed{#1}%
   \pack_framed_initialize
   \ifsecondargument % faster
     \setupcurrentframed[#2]% here !
   \fi
   \pack_framed_process_indeed}

\unexpanded\def\directlocalframed[#1]% no optional
  {\bgroup
   \bgroup
   \edef\currentframed{#1}%
   \pack_framed_initialize
   \pack_framed_process_indeed}

\unexpanded\def\localframedwithsettings[#1][#2]% no checking (so no spaces between)
  {\bgroup
   \bgroup
   \edef\currentframed{#1}%
   \pack_framed_initialize
   \setupcurrentframed[#2]% here !
   \pack_framed_process_indeed}

% done

\def\c!fr!analyze{fr:analyze} % private option

\let\delayedbegstrut\relax
\let\delayedendstrut\relax
\let\delayedstrut   \relax

\let\localoffset\empty
\let\localwidth \empty
\let\localheight\empty
\let\localformat\empty
\let\localstrut \empty

\unexpanded\def\pack_framed_process_indeed
  {\d_framed_frameoffset\framedparameter\c!frameoffset
   \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
   \d_framed_backgroundoffset
     \ifx\p_framed_backgroundoffset\v!frame
       \d_framed_frameoffset
     \else
       \p_framed_backgroundoffset
     \fi
   % new, experimental dirty hook
   \framedparameter\c!extras
   % to get the right spacing
   \edef\p_framed_foregroundstyle{\framedparameter\c!foregroundstyle}%
   \ifx\p_framed_foregroundstyle\empty\else\dousestyleparameter\p_framed_foregroundstyle\fi
   % beware, both the frame and background offset can be overruled
   %
   \edef\p_framed_setups{\framedparameter\c!setups}%
   % the next macros are visible
   \edef\localoffset{\framedparameter\c!offset}%
   \edef\localwidth {\framedparameter\c!width}%
   \edef\localheight{\framedparameter\c!height}%
   \edef\localformat{\framedparameter\c!align}%
   \edef\localstrut {\framedparameter\c!strut}%
   % these are not
   \edef\p_framed_autostrut  {\framedparameter\c!autostrut}%
   \edef\p_framed_frame      {\framedparameter\c!frame}%
   \edef\p_framed_location   {\framedparameter\c!location}%
   \edef\p_framed_orientation{\framedparameter\c!orientation}%
   \edef\p_framed_anchoring  {\framedparameter\c!anchoring}%
   %
   \edef\p_framed_autowidth  {\framedparameter\c!autowidth}%
   \edef\p_framed_franalyze  {\framedparameter\c!fr!analyze}% experimental option
   %
   \ifx\p_framed_frame\v!overlay   % no frame, no offset, no framewidth
     \setfalse\c_framed_has_frame
     \let\localoffset\v!overlay
   \orelse\ifx\p_framed_frame\v!none % no frame, no framewidth
     \setfalse\c_framed_has_frame
   \else
     \settrue\c_framed_has_frame
   \fi
   \ifconditional\c_framed_has_frame
     \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}%
     \ifx\p_framed_rulethickness\empty\else
        \d_framed_linewidth\p_framed_rulethickness\relax
     \fi
   \else
     \d_framed_linewidth\zeropoint
   \fi
   % 2013/03/12: a change of order (sizes before align
   \ifx\localwidth\v!local
     \setlocalhsize
   \fi
   %
   \forgetall % should happen after \localwidth but before align
   %
   \ifx\localformat\empty
     \setfalse\c_framed_has_format
   \else
     \settrue\c_framed_has_format
     \dosetraggedcommand\localformat % not that fast
   \fi
   %
   \ifcsname\??framedoffsetalternative\localoffset\endcsname
     \lastnamedcs
   \else
     \framed_offset_alternative_unknown
   \fi
   \ifcsname\??framedwidthalternative\localwidth\endcsname
     \lastnamedcs
   \else
     \framed_width_alternative_unknown
   \fi
   \ifcsname\??framedheightalternative\localheight\endcsname
     \lastnamedcs
   \else
     \framed_height_alternative_unknown
   \fi
   % the next check could move to heightalternative
   \ifconditional\c_framed_has_height
     % obey user set height, also downward compatible
   \else
     \edef\p_framed_lines{\framedparameter\c!lines}%
     \ifx\p_framed_lines\empty
     \orelse\ifcase\p_framed_lines
     \else
       \d_framed_height\p_framed_lines\lineheight
       \edef\localheight{\the\d_framed_height}%
       \settrue\c_framed_has_height
     \fi
   \fi
   % this is now an option: width=local
   %
   % \ifdim\d_framed_width=\hsize
   %   \parindent\zeropoint
   %   \setlocalhsize
   %   \d_framed_width\localhsize
   % \fi
   % i.e. disable (colsetbackgroundproblemintechniek)
   \advance\d_framed_width  -2\d_framed_local_offset
   \advance\d_framed_height -2\d_framed_local_offset
   \ifcsname\??framedstrutalternative\localstrut\endcsname
     \lastnamedcs
   \else
     \framed_offset_alternative_unknown
   \fi
   % the next check could move to strutalternative
   \ifcase\c_framed_has_strut % none (not even noindent)
     \let\localbegstrut\relax
     \let\localendstrut\relax
     \let\localstrut   \relax
   \or % no / overlay
     \let\localbegstrut\pseudobegstrut
     \let\localendstrut\pseudoendstrut
     \let\localstrut   \pseudostrut
   \else
     \let\localbegstrut\begstrut
     \let\localendstrut\endstrut
     \let\localstrut   \strut
   \fi
   \ifx\p_framed_autostrut\v!yes
     \let\delayedbegstrut\relax
     \let\delayedendstrut\relax
     \let\delayedstrut   \relax
   \else
     \let\delayedbegstrut\localbegstrut
     \let\delayedendstrut\localendstrut
     \let\delayedstrut   \localstrut
     \let\localbegstrut  \relax
     \let\localendstrut  \relax
     \let\localstrut     \relax
   \fi
   \ifconditional\c_framed_has_height
     \let\\\pack_framed_vboxed_newline
     \ifconditional\c_framed_has_width
       \let\hairline\pack_framed_vboxed_hairline
       \ifconditional\c_framed_has_format
         \let\next\pack_framed_format_format_yes
       \else
         \let\next\pack_framed_format_format_nop
       \fi
     \else
       \let\hairline\pack_framed_hboxed_hairline
       \ifconditional\c_framed_has_format
         \let\next\pack_framed_format_format_height
       \else
         \let\next\pack_framed_format_format_vsize
       \fi
     \fi
   \orelse\ifconditional\c_framed_has_width
     \ifconditional\c_framed_has_format
       \let\hairline\pack_framed_vboxed_hairline
       \let\\\pack_framed_vboxed_newline
       \let\next\pack_framed_format_format_width
     \else
       \let\hairline\pack_framed_hboxed_hairline
       \let\\\pack_framed_hboxed_newline
       \let\next\pack_framed_format_format_hsize
     \fi
   \else
     \let\hairline\pack_framed_hboxed_hairline
     \let\\\pack_framed_hboxed_newline
     \let\next\pack_framed_format_format_no_size
   \fi
   \pack_framed_check_extra_offsets
   \edef\p_framed_background{\framedparameter\c!background}%
%    \ifx\p_framed_background\empty
%      \let\pack_framed_forgetall\forgetall
%    \else
%      \let\pack_framed_forgetall\relax
%      \forgetall
%    \fi
   \edef\framedwidth {\the\ifdim\d_framed_width >\zeropoint         \d_framed_width \else\zeropoint\fi}% public
   \edef\framedheight{\the\ifdim\d_framed_height>\zeropoint         \d_framed_height\else\zeropoint\fi}% public
   \edef\framedoffset{\the\dimexpr\ifconditional\c_framed_has_offset\localoffset    \else\zeropoint\fi}% public
   \ifx\p_framed_orientation\empty
     \let\pack_framed_stop_orientation\relax
   \else
     \pack_framed_start_orientation
   \fi
   \afterassignment\pack_framed_restart
   \setbox\b_framed_normal\next}

% alternatives for width, height, strut and offset

\installcorenamespace{framedwidthalternative}
\installcorenamespace{framedheightalternative}
\installcorenamespace{framedstrutalternative}
\installcorenamespace{framedoffsetalternative}

% widths

\setvalue{\??framedwidthalternative\empty}%
  {\ifconditional\c_framed_has_format
     \settrue\c_framed_has_width
     \d_framed_width\hsize
   \else
     \setfalse\c_framed_has_width
     \d_framed_width\zeropoint
   \fi}

\setvalue{\??framedwidthalternative\v!fit}%
  {\ifconditional\c_framed_has_format
     \settrue\c_framed_has_width
     \d_framed_width\hsize
   \else
     \setfalse\c_framed_has_width
     \d_framed_width\zeropoint
   \fi}

\setvalue{\??framedwidthalternative\v!fixed}% equals \v!fit but no shapebox
  {\ifconditional\c_framed_has_format
     \settrue\c_framed_has_width
     \d_framed_width\hsize
   \else
     \setfalse\c_framed_has_width
     \d_framed_width\zeropoint
   \fi}

\setvalue{\??framedwidthalternative\v!broad}%
  {\settrue\c_framed_has_width
   \d_framed_width\hsize}

\setvalue{\??framedwidthalternative\v!max}% idem broad
  {\settrue\c_framed_has_width
   \d_framed_width\hsize}

\setvalue{\??framedwidthalternative\v!local}%
  {\settrue\c_framed_has_width
   %\setlocalhsize
   \d_framed_width\localhsize}

\setvalue{\??framedwidthalternative\s!unknown}%
  {\settrue\c_framed_has_width
   \d_framed_width\localwidth}

\def\framed_width_alternative_unknown
  {\settrue\c_framed_has_width
   \d_framed_width\localwidth}

% heights

\setvalue{\??framedheightalternative\empty}%
  {\setfalse\c_framed_has_height
   \d_framed_height\zeropoint}

\setvalue{\??framedheightalternative\v!fit}%
  {\setfalse\c_framed_has_height
   \d_framed_height\zeropoint}

\setvalue{\??framedheightalternative\v!broad}%
  {\setfalse\c_framed_has_height
   \d_framed_height\zeropoint}

\setvalue{\??framedheightalternative\v!max}%
  {\settrue\c_framed_has_height
   \d_framed_height\vsize}

\setvalue{\??framedheightalternative\s!unknown}%
  {\settrue\c_framed_has_height
   \d_framed_height\localheight}

\def\framed_height_alternative_unknown
  {\settrue\c_framed_has_height
   \d_framed_height\localheight}

% struts (use let instead?)

\setvalue{\??framedstrutalternative\v!no}%
  {\c_framed_has_strut\plusone}

\setvalue{\??framedstrutalternative\v!global}%
  {\setstrut}

\setvalue{\??framedstrutalternative\v!local}%
  {\setfontstrut}

\setvalue{\??framedstrutalternative\v!yes}%
  {\setstrut}

\setvalue{\??framedstrutalternative\s!unknown}%
  {\setstrut}

\def\framed_strut_alternative_unknown
  {\setstrut}

\setvalue{\??framedstrutalternative\v!none}% not even pseudo struts
  {\c_framed_has_strut\zerocount}

% offsets

\setvalue{\??framedoffsetalternative\v!none}%
  {\setfalse\c_framed_has_offset
   \c_framed_has_strut\plusone
   \setfalse\c_framed_is_overlaid
   \d_framed_local_offset\d_framed_linewidth}

\setvalue{\??framedoffsetalternative\v!overlay}%
  {% \ifx\p_framed_frame\v!no \setfalse\c_framed_has_frame \fi % test first
   \setfalse\c_framed_has_offset
   \c_framed_has_strut\plusone
   \settrue\c_framed_is_overlaid
   \d_framed_local_offset\zeropoint}

% \setvalue{\??framedoffsetalternative\v!strut}%
%   {\setfalse\c_framed_has_offset
%    \c_framed_has_strut\plustwo
%    \settrue\c_framed_is_overlaid
%    \d_framed_local_offset\zeropoint}

\setvalue{\??framedoffsetalternative\v!default}% new per 2-6-2000
  {\settrue \c_framed_has_offset
   \c_framed_has_strut\plustwo
   \setfalse\c_framed_is_overlaid
   \let\localoffset\defaultframeoffset
   \letframedparameter\c!offset\defaultframeoffset % brrr
   \d_framed_local_offset\dimexpr\localoffset+\d_framed_linewidth\relax}

\def\framed_offset_alternative_unknown
  {\settrue \c_framed_has_offset
   \c_framed_has_strut\plustwo
   \setfalse\c_framed_is_overlaid
   \let\defaultframeoffset\localoffset
   \d_framed_local_offset\dimexpr\localoffset+\d_framed_linewidth\relax}

\letvalue{\??framedoffsetalternative\s!unknown}\framed_offset_alternative_unknown

% so far for alternatives

\let\pack_framed_stop_orientation\relax

\def\pack_framed_restart
  {\aftergroup\pack_framed_finish}

\def\pack_framed_do_top
  {\raggedtopcommand
   \framedparameter\c!top
   \edef\p_blank{\framedparameter\c!blank}%
   \ifx\p_blank\v!yes\else % auto or no
     \doinhibitblank
   \fi}

\def\pack_framed_do_bottom
  {\framedparameter\c!bottom
   \raggedbottomcommand}

%D Careful analysis of this macro will learn us that not all branches in the last
%D conditionals can be encountered, that is, some assignments to \type{\next} will
%D never occur. Nevertheless we implement the whole scheme, if not for future
%D extensions.

%D \macros
%D   {doassigncheckedframeoffset}
%D
%D Offset helper (see menus):

\def\doassigncheckedframeoffset#1#2% could be a fast \csname .. \endcsname
  {\edef\checkedframeoffset{#2}%
   #1%
     \ifx\checkedframeoffset\empty    \zeropoint\orelse
     \ifx\checkedframeoffset\v!overlay\zeropoint\orelse
     \ifx\checkedframeoffset\v!none   \zeropoint\orelse
     \ifx\checkedframeoffset\v!frame  \zeropoint\orelse
     \ifx\checkedframeoffset\v!default\zeropoint\else
       #2%
     \fi
   \relax}

%D \macros
%D   {ifreshapeframebox}
%D
%D The last few lines tell what to do after the content of the box is collected and
%D passed to the next macro. In the case of a fixed width and centered alignment,
%D the content is evaluated and used to determine the most natural width. The rest
%D of the code deals with backgrounds and frames.

\newif\ifreshapeframebox \reshapeframeboxtrue

%D Beware: setting \type {top} and \type {bottom} to nothing, may
%D result in a frame that is larger that the given height! try:
%D
%D \starttyping
%D \framed
%D   [height=3cm,top=,bottom=,offset=overlay]
%D   {\strut test \shapefill \strut test}
%D \stoptyping
%D
%D This is intended behaviour and not a bug! One can always set
%D
%D \starttyping
%D ...,bottom=\kern0pt,...
%D \stoptyping

% experiment ... \p_framed_franalyze -> we could support 'first' as location key
% option but then we will always do an analysis and reimplement the location
% options (btw, beware of location settings of derived functionality that bleed
% into this

\def\pack_framed_finish_a
  {\ifreshapeframebox
     \pack_framed_reshape_process
   \orelse\ifx\p_framed_franalyze\v!yes
     \pack_framed_reshape_analyze
   \else
     \pack_framed_reshape_reset
   \fi
   \setfalse\c_framed_has_width}

\def\pack_framed_finish_b
  {\ifx\p_framed_franalyze\v!yes
     \pack_framed_reshape_analyze
   \else
     \pack_framed_reshape_reset
   \fi
   \setfalse\c_framed_has_width}

\def\pack_framed_finish_c
  {\ifx\p_framed_franalyze\v!yes
     \pack_framed_reshape_analyze
   \else
     \pack_framed_reshape_reset
   \fi}

\def\pack_framed_profile_box
  {\profilegivenbox\p_profile\b_framed_normal
   \setbox\b_framed_normal\vpack{\unvbox\b_framed_normal}}

\unexpanded\def\pack_framed_finish
  {%\pack_framed_stop_orientation % hm, wrong place ! should rotate the result (after reshape) .. moved down
   \pack_framed_locator_before\p_framed_location
   \ifconditional\c_framed_has_format
    %\ifconditional\c_framed_has_height \else
    %  \edef\p_profile{\framedparameter\c!profile}%
    %  \ifx\p_profile\empty\else
    %    \pack_framed_profile_box
    %  \fi
    %\fi
     \ifx\p_framed_autowidth\v!force
       \pack_framed_finish_a
     \orelse\ifx\localwidth\v!fit
       \ifx\p_framed_autowidth\v!yes
         \pack_framed_finish_a
       \else
         \pack_framed_finish_b
       \fi
     \orelse\ifx\localwidth\v!fixed
       \pack_framed_finish_b
     \else
       \pack_framed_finish_c
     \fi
     \ifconditional\c_framed_has_height \else
       \edef\p_profile{\framedparameter\c!profile}%
       \ifx\p_profile\empty\else
         \pack_framed_profile_box
       \fi
     \fi
     \ifconditional\page_postprocessors_needed_box
       % quite late
       \page_postprocessors_linenumbers_box\b_framed_normal
     \fi
   \else
     \pack_framed_finish_c
   \fi
   \ifconditional\c_framed_has_width
     \wd\b_framed_normal\d_framed_width
   \fi
   \ifconditional\c_framed_has_height
     \ht\b_framed_normal\d_framed_height
   \else
     \edef\p_framed_minheight{\framedparameter\c!minheight}%
     \ifx\p_framed_minheight\empty \else
       \ifdim\ht\b_framed_normal<\p_framed_minheight
         \ht\b_framed_normal\p_framed_minheight
       \fi
     \fi
   \fi
   \edef\p_framed_empty{\framedparameter\c!empty}%
   \ifx\p_framed_empty\v!yes
     \pack_framed_fake_box
   \fi
   \ifx\p_framed_anchoring\empty\else
     \pack_framed_handle_anchoring
   \fi
   \pack_framed_stop_orientation % moved here at 2014-05-25
   \iftrialtypesetting \else
     \edef\m_overlay_region{\framedparameter\c!region}%
     \ifx\m_overlay_region\empty\else
       \pack_framed_set_region
     \fi
   \fi
   \d_framed_applied_offset
     \ifconditional\c_framed_is_overlaid
       \zeropoint
     \else
       \d_framed_linewidth
     \fi
   \ifconditional\c_framed_has_offset
     \advance\d_framed_applied_offset\localoffset
   \fi
   \ifconditional\c_framed_has_extra_offset
     \pack_framed_apply_extra_offsets % includes \d_framed_applied_offset
   \else
     \ifzeropt\d_framed_applied_offset
     \else
       \pack_framed_widen_box
     \fi
   \fi
   %
   \ifx\postprocessframebox\relax \else
     \let\next\postprocessframebox
     \let\postprocessframebox\relax % prevent nesting
     \next\b_framed_normal
   \fi
   \iftrialtypesetting
     % new
   \else
     \ifconditional\c_framed_has_frame % real or invisible frame
       \pack_framed_add_outline
     \fi
     \ifx\p_framed_background\empty \else
       \edef\p_framed_component{\framedparameter\c!component}%
       \pack_framed_add_background
     \fi
   \fi
   \pack_framed_locator_after\p_framed_location
   \iftrialtypesetting \else
     \ifx\m_overlay_region\empty\else
       \pack_framed_add_region
     \fi
   \fi
   \box\b_framed_normal
   \global\frameddimensionstate % global so to be used directly afterwards !
     \ifconditional\c_framed_has_width
       \ifconditional\c_framed_has_height \plusthree \else \plusone   \fi
     \else
       \ifconditional\c_framed_has_height \plustwo   \else \zerocount \fi
     \fi
   \egroup
   \egroup}

%D Anchoring is experimental and was prototyped around the ctx meeting in 2018 but
%D never mede it into the core yet. It operates independent of the orientation
%D mechanism already present. It's a rather efficient feature. Best is to use
%D predefined orientations, like:
%D
%D \starttyping
%D \defineorientation[leftflushleft] [orientation=left,horizontal=flushleft]
%D
%D \framed [anchoring={leftflushleft}] {anchoring}
%D \stoptyping
%D
%D But this also works:
%D
%D \starttyping
%D \framed [anchoring={flushleft,top,up}] {anchoring}
%D \stoptyping
%D
%D When an anchoring is given (use \type {normal} for the default) you can also
%D use the \type {xanchor} and \type {yanchor} offsets.

% because we mess with the width later on, we need double wrapping:

\def\pack_framed_handle_anchoring
  {\scratchcounter\autoorientation\p_framed_anchoring\relax
   \edef\p_xanchor{\framedparameter\c!xanchor}%
   \edef\p_yanchor{\framedparameter\c!yanchor}%
   \setbox\b_framed_normal\hpack{\hpack % here
      % using the keyword approachs works ok, don't mess with orientation
      % directly here using \boxorientation ... it doesn't work that well
      \s!orientation\scratchcounter
      \ifx\p_xanchor\empty\else \s!xoffset \p_xanchor\fi
      \ifx\p_yanchor\empty\else \s!yoffset \p_yanchor\fi
     {\box\b_framed_normal}}}

\installcorenamespace{framedlocatorbefore}
\installcorenamespace{framedlocatorafter}

\newconstant\frameddimensionstate % global state: 0=unknown 1=width 2=height 3=both

\def\pack_framed_fake_box
  {\setbox\scratchbox\emptyhbox
   \wd\scratchbox\wd\b_framed_normal
   \ht\scratchbox\ht\b_framed_normal
   \dp\scratchbox\dp\b_framed_normal
   \setbox\b_framed_normal\box\scratchbox}

\def\installframedlocator#1#2#3%
  {\setvalue{\??framedlocatorbefore#1}{#2}%
   \setvalue{\??framedlocatorafter #1}{#3}}

\def\pack_framed_locator_before#1{\begincsname\??framedlocatorbefore#1\endcsname}
\def\pack_framed_locator_after #1{\begincsname\??framedlocatorafter #1\endcsname}

\newdimen\d_framed_locator_ht
\newdimen\d_framed_locator_dp
\newdimen\d_framed_locator_lo
\newdimen\d_framed_locator_ro

\def\pack_framed_locator_set#1%
  {\d_framed_locator_ht\dimexpr
     #1+\d_framed_linewidth
     \ifconditional\c_framed_has_offset
       +\framedparameter\c!offset
     \fi
     +\framedparameter\c!toffset
   \relax
   \d_framed_locator_dp\dimexpr\ht\b_framed_normal-\d_framed_locator_ht\relax}

\def\pack_framed_locator_set_lo
  {\global\d_framed_locator_lo\dimexpr
     \d_framed_linewidth
     \ifconditional\c_framed_has_offset
       +\framedparameter\c!offset
     \fi
     +\framedparameter\c!loffset
   \relax}

\def\pack_framed_locator_set_ro
  {\global\d_framed_locator_ro\dimexpr
     \d_framed_linewidth
     \ifconditional\c_framed_has_offset
       +\framedparameter\c!offset
     \fi
     +\framedparameter\c!roffset
   \relax}

% \ruledhbox
%   {A
%    \framed[width=2cm,align=middle,location=hanging]{location\\equals\\hanging}
%    \framed[width=2cm,align=middle,location=depth]  {location\\equals\\depth}
%    \framed[width=2cm,align=middle,location=height] {location\\equals\\height}
%    B}
% \vskip2cm
% \ruledhbox
%   {A
%    \framed[width=2cm,align=middle,location=low]    {location\\equals\\low}
%    \framed[width=2cm,align=middle,location=line]   {location\\equals\\line}
%    \framed[width=2cm,align=middle,location=high]   {location\\equals\\high}
%    B}
% \vskip2cm
% \ruledhbox
%  {A
%   \framed[width=2cm,align=middle,location=top]    {location\\equals\\top}
%   \framed[width=2cm,align=middle,location=bottom] {location\\equals\\bottom}
%   \framed[width=2cm,align=middle,location=lohi]   {location\\equals\\lohi}
%   \framed[width=2cm,align=middle,location=middle] {location\\equals\\middle}
%   B}

% \installframedlocator \v!hanging % best with strut=no
%   {}
%   {\dp\b_framed_normal\ht\b_framed_normal
%    \ht\b_framed_normal\zeropoint}
%
% \installframedlocator \v!depth
%   {}
%   {\ht\b_framed_normal\dimexpr\ht\b_framed_normal-\strutdp\relax
%    \dp\b_framed_normal\strutdp
%    \box\b_framed_normal}
%
% \installframedlocator \v!height
%   {}
%   {\dp\b_framed_normal\dimexpr\ht\b_framed_normal-\strutht\relax
%    \ht\b_framed_normal\strutht
%    \box\b_framed_normal}

\installframedlocator \v!hanging % best with strut=no *1* / see mail to list by SB
  {}
  {\scratchdimen\ht\b_framed_normal
   \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
   \dp\b_framed_normal\scratchdimen
   \ht\b_framed_normal\zeropoint
   \box\b_framed_normal}

\installframedlocator \v!depth % *1*
  {}
  {\setbox\b_framed_normal\hpack{\lower\strutdp\box\b_framed_normal}%
   \ht\b_framed_normal\dimexpr\ht\b_framed_normal-\strutdp\relax
   \dp\b_framed_normal\strutdp
   \box\b_framed_normal}

\installframedlocator \v!height % *1*
  {}
  {\scratchdimen\dimexpr \ht\b_framed_normal - \strutht \relax
   \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
   \dp\b_framed_normal\dimexpr\ht\b_framed_normal-\strutht\relax
   \ht\b_framed_normal\strutht
   \box\b_framed_normal}

\installframedlocator \v!high
  {}
  {\pack_framed_locator_set\strutht
   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
   \ht\b_framed_normal\strutht
   \dp\b_framed_normal\strutdp
   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?

\installframedlocator \v!line
  {}
  {\setbox\b_framed_normal\hpack{\lower.5\ht\b_framed_normal\box\b_framed_normal}%
   \ht\b_framed_normal.5\lineheight
   \dp\b_framed_normal.5\lineheight
   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?

\installframedlocator \v!low
  {}
  {\pack_framed_locator_set\strutdp
   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}%
   \ht\b_framed_normal\strutht
   \dp\b_framed_normal\strutdp
   \box\b_framed_normal}

\installframedlocator \v!top
  {}
  {\pack_framed_locator_set\strutht
   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
   \ht\b_framed_normal\d_framed_locator_ht
   \dp\b_framed_normal\d_framed_locator_dp
   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?

\installframedlocator \v!middle
  {}
  {\scratchdimen.5\ht\b_framed_normal
   \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
   \ht\b_framed_normal\scratchdimen
   \dp\b_framed_normal\scratchdimen
   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?

\installframedlocator \v!lohi % maybe also \v!center
  {\pack_framed_locator_before\v!middle}
  {\pack_framed_locator_after \v!middle}

\installframedlocator \v!bottom
  {}
  {\pack_framed_locator_set\strutdp
   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}%
   \ht\b_framed_normal\d_framed_locator_dp
   \dp\b_framed_normal\d_framed_locator_ht
   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?

\installframedlocator \v!keep % retains height/depth
  {\pack_framed_remove_depth}
  {\pack_framed_restore_depth}

\newdimen\d_framed_formula

\installframedlocator \v!formula % private, will become a more generic name
  {}
  {\pack_framed_locator_set\d_framed_formula
   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
   \ht\b_framed_normal\d_framed_locator_ht
   \dp\b_framed_normal\d_framed_locator_dp
   \hpack{\box\b_framed_normal}} %  why do we pack .. danger of loosing?

% also used in fastlocalframed

\newdimen\d_framed_original_wd
\newdimen\d_framed_original_ht
\newdimen\d_framed_original_dp

\def\pack_framed_remove_depth
  {\d_framed_original_wd\wd\b_framed_normal
   \d_framed_original_ht\ht\b_framed_normal
   \d_framed_original_dp\dp\b_framed_normal
   \ifzeropt\d_framed_original_dp\else
     \setbox\b_framed_normal\hpack{\raise\d_framed_original_dp\box\b_framed_normal}%
   \fi
   \wd\b_framed_normal\d_framed_original_wd
   \ht\b_framed_normal\dimexpr\d_framed_original_ht+\d_framed_original_dp\relax
   \dp\b_framed_normal\zeropoint}

\def\pack_framed_restore_depth
  {\ifzeropt\d_framed_original_dp \else
     \setbox\b_framed_normal\hpack{\lower\d_framed_original_dp\box\b_framed_normal}%
   \fi
   \wd\b_framed_normal\d_framed_original_wd
   \ht\b_framed_normal\d_framed_original_ht
   \dp\b_framed_normal\d_framed_original_dp}

% \framed[width=12cm,height=3cm,orientation=0]{\input ward\relax}
% \framed[width=12cm,height=3cm,orientation=90]{\input ward\relax}
% \framed[width=12cm,height=3cm,orientation=180]{\input ward\relax}
% \framed[width=12cm,height=3cm,orientation=270]{\input ward\relax}
% \framed[width=12cm,height=3cm,orientation=-90]{\input ward\relax}
% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax}
% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax}

\def\pack_framed_start_orientation
  {\ifcase\p_framed_orientation
     \let\pack_framed_stop_orientation\relax
   \else
     \let\pack_framed_stop_orientation\pack_framed_stop_orientation_indeed
   \fi}

\def\pack_framed_stop_orientation_indeed
  {\setbox\b_framed_normal\hpack{\dorotatebox\p_framed_orientation\hpack{\box\b_framed_normal}}%
   \d_framed_height\ht\b_framed_normal
   \d_framed_width \wd\b_framed_normal}

%D The last conditional takes care of the special situation of in||line \inframed
%D [height=3cm] {framed} boxes. Such boxes have to be \inframed {aligned} with the
%D running text.

\unexpanded\def\inframed
  {\dosingleempty\pack_framed_inline}

% \def\pack_framed_inline[#1]%
%   {\framed[\c!location=\v!low,#1]}
%
% or:

\def\pack_framed_inline[%
  {\framed[\c!location=\v!low,}

%D When we set \type{empty} to \type{yes}, we get ourselves a frame and/or background,
%D but no content, so actually we have a sort of phantom framed box.

%D \macros
%D   {mframed, minframed}
%D
%D When Tobias asked how to frame mathematical elements in formulas, Taco's posted the
%D next macro:
%D
%D \starttyping
%D \def\mframed#1%
%D   {\relax
%D    \ifmmode
%D      \vcenter{\hbox{\framed{$\ifinner\else\displaystyle\fi#1$}}}%
%D    \else
%D      \framed{$#1$}%
%D    \fi}
%D \stoptyping
%D
%D Because \type {\ifinner} does not (always) reports what one would expect, we move the
%D test to the outer level. We also want to pass arguments,
%D
%D \starttyping
%D \def\mframed%
%D   {\dosingleempty\domframed}
%D
%D \def\domframed[#1]#2% % tzt \dowithnextmathbox ?
%D   {\relax
%D    \ifmmode
%D      \ifinner
%D        \inframed[#1]{$#2$}%
%D      \else
%D        \vcenter{\hbox{\framed[#1]{$\displaystyle#2$}}}%
%D      \fi
%D    \else
%D      \inframed[#1]{$#2$}%
%D    \fi}
%D \stoptyping
%D
%D Still better is the next alternative, if only because it takes care of setting the super-
%D and subscripts styles

\newcount\c_framed_mstyle

\unexpanded\def\pack_framed_math_strut
  {\Ustartmath
   \triggermathstyle\c_framed_mstyle
   \vphantom{(}%
   \Ustopmath}

\installcorenamespace{mathframed}

\installframedcommandhandler \??mathframed {mathframed} \??mathframed

\appendtoks
    \setuevalue{\currentmathframed}{\pack_framed_mathframed{\currentmathframed}}%
\to \everydefinemathframed

\unexpanded\def\pack_framed_mathframed#1%
  {\begingroup
   \edef\currentmathframed{#1}%
   \dosingleempty\pack_framed_mathframed_indeed}

\newcount\c_pack_framed_mathframed
\newtoks \t_pack_framed_mathframed

\def\pack_framed_math_pos
  {\global\advance\c_pack_framed_mathframed\plusone
   \xdef\pack_framed_mc_one{mcf:1:\number\c_pack_framed_mathframed}%
   \xdef\pack_framed_mc_two{mcf:2:\number\c_pack_framed_mathframed}%
   \xypos\pack_framed_mc_two}

\def\pack_framed_mathframed_indeed[#1]#2% no fancy nesting supported here
  {\iffirstargument
      \setupcurrentmathframed[#1]%
   \fi
   \c_framed_mstyle\mathstyle
   \edef\m_framed_location{\mathframedparameter\c!location}%
   \ifx\m_framed_location\v!mathematics
     \let\normalstrut\pack_framed_math_pos
   \orelse\ifx\m_framed_location\v!low\else
     \let\normalstrut\pack_framed_math_strut
   \fi
   \inheritedmathframedframed\bgroup
     \Ustartmath
     \triggermathstyle\c_framed_mstyle
     \the\t_pack_framed_mathframed
     #2%
     \Ustopmath
   \egroup
   \endgroup}

\appendtoks
    \mathraggedstatus\plustwo   % makes \startalign work
    \eqalignmode     \zerocount % makes \startalign fit
\to \t_pack_framed_mathframed

\installframedlocator \v!mathematics
  {}
  {\lower\dimexpr\MPy\pack_framed_mc_two-\MPy\pack_framed_mc_one\relax
   \hpack{\xypos\pack_framed_mc_one\box\b_framed_normal}}

\definemathframed[mframed]
\definemathframed[inmframed][\c!location=\v!low]
\definemathframed[mcframed] [\c!location=\v!mathematics]

%D So instead of the rather versatile \type {\framed}, we use \type {\mframed}:
%D
%D \startbuffer
%D \startformula
%D   x \times   \mframed{y} \times y^{z_z}
%D   x \times \inmframed{y} \times y^{z_z}
%D \stopformula
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D And:
%D
%D \startbuffer
%D \startformula
%D   x \times \mframed{y} \times y^{\mframed{z}_{\mframed{z}}}
%D \stopformula
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D As usual, one can specify in what way the text should be framed. One should be
%D aware of the fact that, inorder to preserve the proper spacing, the \type
%D {offset} is set to \type {overlay} and \type {frameoffset} is used used instead.
%D
%D \startbuffer
%D \startformula
%D   x \times y^{\mframed[framecolor=red]{z}_{z}}
%D \stopformula
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D For inline use, we also provide the \type {\inmframed} alternative: we want $x
%D \times \inmframed{y}$ in inline math, right?

%D This previous framing macros needs a lot of alternatives for putting rules around
%D boxes, inserting offsets and aligning text. Each step is handled by separate macros.

\newdimen\d_framed_applied_offset
\newdimen\d_framed_loffset
\newdimen\d_framed_roffset
\newdimen\d_framed_toffset
\newdimen\d_framed_boffset

\def\pack_framed_check_extra_offsets % we could check h and v indepently
  {\setfalse\c_framed_has_extra_offset
   \d_framed_loffset\framedparameter\c!loffset\relax
   \d_framed_roffset\framedparameter\c!roffset\relax
   \d_framed_toffset\framedparameter\c!toffset\relax
   \d_framed_boffset\framedparameter\c!boffset\relax
   \ifzeropt\d_framed_loffset\else \advance\d_framed_width -\d_framed_loffset \settrue\c_framed_has_extra_offset \fi
   \ifzeropt\d_framed_roffset\else \advance\d_framed_width -\d_framed_roffset \settrue\c_framed_has_extra_offset \fi
   \ifzeropt\d_framed_toffset\else \advance\d_framed_height-\d_framed_toffset \settrue\c_framed_has_extra_offset \fi
   \ifzeropt\d_framed_boffset\else \advance\d_framed_height-\d_framed_boffset \settrue\c_framed_has_extra_offset \fi}

\def\pack_framed_apply_extra_offsets
  {\setbox\b_framed_normal\vpack\bgroup
     \advance\d_framed_toffset\d_framed_applied_offset
     \advance\d_framed_boffset\d_framed_applied_offset
     \advance\d_framed_loffset\d_framed_applied_offset
     \advance\d_framed_roffset\d_framed_applied_offset
     \kern\d_framed_toffset
     \hpack\bgroup
        \kern\d_framed_loffset
        \box\b_framed_normal
        \kern\d_framed_roffset
     \egroup
     \kern\d_framed_boffset
   \egroup}

\def\pack_framed_widen_box
  {\setbox\b_framed_normal\vpack
     {\kern\d_framed_applied_offset
      \hpack{\kern\d_framed_applied_offset\box\b_framed_normal\kern\d_framed_applied_offset}%
      \kern\d_framed_applied_offset}}

%D Let's hope that the next few examples show us enough of what needs to be
%D done by the auxiliary macros.
%D
%D \startbuffer
%D \framed[height=1cm,offset=.5cm]   {rule based learning}
%D \framed[height=1cm,offset=0cm]    {rule based learning}
%D \framed[height=1cm,offset=none]   {rule based learning}
%D \framed[height=1cm,offset=overlay]{rule based learning}
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlinecorrection
%D \hbox{\getbuffer}
%D \stoplinecorrection
%D
%D \startbuffer
%D \framed[offset=.5cm]   {rule based learning}
%D \framed[offset=0cm]    {rule based learning}
%D \framed[offset=none]   {rule based learning}
%D \framed[offset=overlay]{rule based learning}
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlinecorrection
%D \hbox{\getbuffer}
%D \stoplinecorrection
%D
%D \startbuffer
%D \framed[strut=no,offset=.5cm]   {rule based learning}
%D \framed[strut=no,offset=0cm]    {rule based learning}
%D \framed[strut=no,offset=none]   {rule based learning}
%D \framed[strut=no,offset=overlay]{rule based learning}
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlinecorrection
%D \hbox{\getbuffer}
%D \stoplinecorrection
%D
%D \startbuffer
%D \framed[width=3cm,align=left]   {rule\\based\\learning}
%D \framed[width=3cm,align=middle] {rule\\based\\learning}
%D \framed[width=3cm,align=right]  {rule\\based\\learning}
%D \framed[width=fit,align=middle] {rule\\based\\learning}
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlinecorrection
%D \hbox{\dontcomplain\getbuffer}
%D \stoplinecorrection
%D
%D So now we're ready for the complicated stuff. We distinguish between borders with
%D straight lines and those with round corners. When using the first alternative it
%D is possible to turn off one or more lines. More fancy shapes are also possible by
%D specifying dedicated backgrounds. Turning lines on and off is implemented as
%D efficient as possible and as a result is interface language dependant. This next
%D implementation evolved from simpler ones. It puts for instance the rules on top
%D of the content and provides additional offset capabilities. The lot of calls to
%D other macros makes this mechanism not that easy to comprehend.
%D
%D We handle left, right or middle alignment as well as fixed or free widths and
%D heights. Each combination gets its own macro.
%D
%D The following code handles one-liners: \type {align={line,flushright}}. Beware,
%D since we entered a group and either or not grab the next bgroup token, we need to
%D finish the group in the oneliner mode.

\ifdefined\raggedonelinerstate \else \newconditional\raggedonelinerstate \fi

\def\doformatonelinerbox % beware: assumes explicit preceding bgroup
  {\ifconditional\raggedonelinerstate
     \expandafter\dodoformatonelinerbox
   \else
     \expandafter\nodoformatonelinerbox
   \fi}

\def\dodoformatonelinerbox
  {\afterassignment\redoformatonelinerbox
   \setbox\nextbox\hbox} % maybe \hpack

\def\redoformatonelinerbox
  {\aftergroup\dododoformatonelinerbox
   \ignorespaces}

\def\dododoformatonelinerbox
  {\hpack to \hsize % was \hbox
     {\ifcase\raggedstatus\or\hss\or\hss       \fi
      \unhbox\nextbox \removeunwantedspaces
      \ifcase\raggedstatus\or    \or\hss\or\hss\fi}%
   \egroup}

\def\nodoformatonelinerbox % grabs {
  {\let\next=}

%D The handlers:

% Beware, we have a \noindent so an empty line is indeed an empty line and
% the \synchronizeinlinedirection triggers a vbox instead of a line.
%
% \startTEXpage[offset=0.5ex,align={lohi,middle}]
%
%     \vbox{\hbox{x}}
% \stopTEXpage
%
% \startTEXpage[offset=0.5ex,align={lohi,middle}]
%     \vbox{\hbox{x}}
% \stopTEXpage

% \def\pack_framed_forgetall{\forgetall}

\def\pack_framed_set_foregroundcolor
  {\edef\p_framed_foregroundcolor{\framedparameter\c!foregroundcolor}%
   \ifx\p_framed_foregroundcolor\empty\else\dousecolorparameter\p_framed_foregroundcolor\fi}

\def\pack_framed_do_setups
  {\ifx\p_framed_setups\empty \else
     \setups[\p_framed_setups]% \texsetup (or only one!)
   % \fastsetup\p_framed_setup % singular would have been better
   \fi}

\def\pack_framed_format_format_yes
  {\vbox to \d_framed_height
     \bgroup
       \let\postprocessframebox\relax
     % \pack_framed_forgetall
       \iftrialtypesetting \else
         \pack_framed_set_foregroundcolor
       \fi
       \oninterlineskip
       \hsize\d_framed_width
       \vsize\d_framed_height
       \pack_framed_do_setups
       \raggedcommand
       \pack_framed_do_top
       \bgroup
       \synchronizeinlinedirection
       \localbegstrut
       \aftergroup\localendstrut
       \aftergroup\pack_framed_do_bottom
       \aftergroup\egroup
       \doformatonelinerbox}

\def\pack_framed_format_format_nop
  {\vbox to \d_framed_height
     \bgroup
       \let\postprocessframebox\relax
     % \pack_framed_forgetall
       \iftrialtypesetting \else
         \pack_framed_set_foregroundcolor
       \fi
       \oninterlineskip
       \hsize\d_framed_width
       \vsize\d_framed_height
       \pack_framed_do_setups
       \raggedcenter
       \vss
       \bgroup
       \synchronizeinlinedirection
       \localbegstrut
       \aftergroup\localendstrut
       \aftergroup\vss
       \aftergroup\egroup
       \doformatonelinerbox}

\def\pack_framed_format_format_height
  {\vbox to \d_framed_height
     \bgroup
       \let\postprocessframebox\relax
     % \pack_framed_forgetall
       \iftrialtypesetting \else
         \pack_framed_set_foregroundcolor
       \fi
       \oninterlineskip
       \pack_framed_do_setups
       \raggedcommand
       \vss
       \bgroup
       \aftergroup\localendstrut
       \aftergroup\vss
       \aftergroup\egroup
       \synchronizeinlinedirection
       \localbegstrut
       \doformatonelinerbox}

\def\pack_framed_format_format_width
  {\vbox
     \bgroup
       \let\postprocessframebox\relax
     % \pack_framed_forgetall
       \iftrialtypesetting \else
         \pack_framed_set_foregroundcolor
       \fi
       \oninterlineskip
       \hsize\d_framed_width
       \pack_framed_do_setups
       \raggedcommand
       \pack_framed_do_top
       \bgroup
       \synchronizeinlinedirection
       \localbegstrut
       \aftergroup\localendstrut
       \aftergroup\pack_framed_do_bottom
       \aftergroup\egroup
       \doformatonelinerbox}

\def\pack_framed_format_format_vsize
  {\vbox to \d_framed_height % no vpack .. maybe grid
     \bgroup
       \let\postprocessframebox\relax
     % \pack_framed_forgetall
       \iftrialtypesetting \else
         \pack_framed_set_foregroundcolor
       \fi
       \vsize\d_framed_height
       \pack_framed_do_setups
       \vss
       \bgroup
       \aftergroup\vss
       \aftergroup\egroup
       \hbox
         \bgroup
         \aftergroup\egroup
         \synchronizeinlinedirection
         \localstrut
         \doformatonelinerbox}

\def\pack_framed_format_format_hsize
  {\hbox to \d_framed_width
     \bgroup
       \let\postprocessframebox\relax
     % \pack_framed_forgetall
       \iftrialtypesetting \else
         \pack_framed_set_foregroundcolor
       \fi
       \pack_framed_do_setups
       \hss
       \synchronizeinlinedirection
       \localstrut
       \bgroup
       \aftergroup\hss
       \aftergroup\egroup
       \doformatonelinerbox}

\def\pack_framed_format_format_no_size
  {\hbox
     \bgroup
       \iftrialtypesetting \else
         \pack_framed_set_foregroundcolor
       \fi
       \let\postprocessframebox\relax
       \pack_framed_do_setups
       \synchronizeinlinedirection
       \localstrut
       \doformatonelinerbox}

%D On the next page we show some examples of how these macros come into action. The
%D examples show us how \type {fit}, \type {broad} dimensions influence the
%D formatting. Watch the visualized struts. \footnote {Here we used \type
%D {\showstruts}.}
%D
%D \startpostponing
%D \bgroup
%D \showstruts
%D \dontcomplain
%D \starttabulate[|c|c|c|c|c|c|]
%D % \HL
%D \NC \framed[width=.2\hsize, height=.2\hsize, align=]       {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=broad,    align=]       {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=fit,      align=]       {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=.2\hsize, align=]       {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=broad,    align=]       {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=fit,      align=]       {a\endgraf b\endgraf c}
%D \NC \NR
%D % \HL
%D \NC \framed[width=.2\hsize, height=.2\hsize, align=yes]    {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=broad,    align=yes]    {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=fit,      align=yes]    {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=.2\hsize, align=yes]    {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=broad,    align=yes]    {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=fit,      align=yes]    {a\endgraf b\endgraf c}
%D \NC \NR
%D % \HL
%D \NC \framed[width=.2\hsize, height=.2\hsize, align=right]  {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=broad,    align=right]  {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=fit,      align=right]  {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=.2\hsize, align=right]  {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=broad,    align=right]  {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=fit,      align=right]  {a\endgraf b\endgraf c}
%D \NC \NR
%D % \HL
%D \NC \framed[width=.2\hsize, height=.2\hsize, align=left]   {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=broad,    align=left]   {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=fit,      align=left]   {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=.2\hsize, align=left]   {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=broad,    align=left]   {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=fit,      align=left]   {a\endgraf b\endgraf c}
%D \NC \NR
%D % \HL
%D \NC \framed[width=.2\hsize, height=.2\hsize, align=middle] {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=broad,    align=middle] {a\endgraf b\endgraf c}
%D \NC \framed[width=.2\hsize, height=fit,      align=middle] {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=.2\hsize, align=middle] {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=broad,    align=middle] {a\endgraf b\endgraf c}
%D \NC \framed[width=fit,      height=fit,      align=middle] {a\endgraf b\endgraf c}
%D \NC \NR
%D % \HL
%D \stoptabulate
%D \egroup
%D \stoppostponing

%D \macros
%D   {framednoflines, framedlastlength}
%D
%D It is possible to let the frame macro calculate the width of a centered box
%D automatically (\type {fit}). When doing so, we need to reshape the box:

\newcount\framednoflines
\newdimen\framedfirstheight
\newdimen\framedlastdepth
\newdimen\framedminwidth
\newdimen\framedmaxwidth
\newdimen\framedaveragewidth

\def\pack_framed_reshape_reset
  {\framednoflines    \zerocount
   \framedfirstheight \zeropoint
   \framedlastdepth   \zeropoint
   \framedminwidth    \zeropoint
   \framedmaxwidth    \zeropoint
   \framedaveragewidth\zeropoint}

\def\pack_framed_reshape_process{\ifvbox\b_framed_normal\clf_doreshapeframedbox\b_framed_normal\relax\fi}
\def\pack_framed_reshape_analyze{\ifvbox\b_framed_normal\clf_doanalyzeframedbox\b_framed_normal\relax\fi}

% torture test / strange case (much depth) / method 2 needed
%
% \startTEXpage[frame=on]
% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
% test outside formula
% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
% \blank[big]
% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
% test outside formula
% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
% \stopTEXpage

%D The examples on the next page show how one can give the frame as well as the
%D background an additional offset and even a bit more depth. The blue outline is
%D the frame, the red box is the background and the small black outline is the
%D visualization of the resulting box, that is, we applied \type {\ruledhbox} to
%D the result.
%D
%D \startpostponing
%D \bgroup
%D \unprotect
%D \dontcomplain
%D
%D \startbuffer
%D \unprotect
%D \vbox to \vsize
%D   \bgroup
%D     \startalignment[middle]
%D     \vss
%D     \dontleavehmode\vbox to .8\vsize
%D       \bgroup
%D         \hsize=300pt
%D         \setupframed
%D           [background=color,
%D            backgroundcolorachtergrondkleur=darkred,
%D            width=300pt,
%D            height=60pt,
%D            framecolorkaderkleur=DemoBlue,
%D            rulethickness=2pt]
%D         \def\status%
%D           {backgroundoffset=\the\dimexpr\framedparameter\c!backgroundoffset\relax\\
%D            frameoffset=\the\dimexpr\framedparameter\c!frameoffset\relax\\
%D            depth=\the\dimexpr\framedparameter\c!depth\relax}
%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=0pt]{\status}}
%D         \vss
%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=0pt]{\status}}
%D         \vss
%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=5pt]{\status}}
%D         \vss
%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=2pt,frameoffset=5pt]{\status}}
%D         \vss
%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=2pt]{\status}}
%D         \vss
%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=5pt]{\status}}
%D       \egroup
%D     \vss
%D     \stopalignment
%D     \egroup
%D \protect
%D \stopbuffer
%D
%D \getbuffer \page
%D
%D {\setupframed[depth=4pt]\getbuffer} \page
%D
%D \protect
%D \egroup
%D \stoppostponing

%D We can draw lines from left to right and top to bottom by using the normal \type
%D {\hairline} command. Both directions need a different treatment.
%D
%D \startbuffer
%D \framed[width=4cm]           {alfa\hairline beta\hairline gamma}
%D \framed[height=2cm]            {alfa\hairline beta\hairline gamma}
%D \framed[width=4cm,height=2cm]{alfa\hairline beta\hairline gamma}
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlinecorrection
%D \hbox{\getbuffer}
%D \stoplinecorrection
%D
%D These macros try to adapt their behaviour as good as possible to the circumstances
%D and act as natural as possible.

\unexpanded\def\pack_framed_vboxed_hairline % nasty overlay mess .. needed for autowidth
  {\begingroup
   \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi
   \scratchwidth \dimexpr\scratchoffset+\d_framed_linewidth\relax
   \par
   \nointerlineskip
   \kern\scratchoffset
   \dontleavehmode
     \hrule\s!height\d_framed_linewidth\s!depth\zeropoint
   \par
   \kern-\d_framed_linewidth
   \dontleavehmode
     \hpack to \zeropoint{\hss\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth}%
     \hfill
     \hpack to \zeropoint{\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth\hss}%
   \par
   \nointerlineskip
   \kern\scratchoffset
   \nointerlineskip
   \endgraf
   \nointerlineskip
   \localbegstrut
   \endgroup}

\unexpanded\def\pack_framed_hboxed_hairline % use framed dimen
  {\bgroup
   \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi
   \ifconditional\c_framed_has_height
     \dimen\scratchheight\dimexpr\localheight/\plustwo+\strutdp-\plustwo\d_framed_linewidth\relax
     \dimen\scratchdepth \dimexpr\localheight/\plustwo-\strutdp+\plustwo\d_framed_linewidth\relax
   \else
     \dimen\scratchheight\dimexpr\strutht+\scratchoffset\relax
     \dimen\scratchdepth \dimexpr\strutdp+\scratchoffset\relax
   \fi
   \unskip
   \setbox\scratchbox\hpack
     {\kern\scratchoffset
      \vrule\s!height\dimen\scratchheight\s!depth\dimen\scratchdepth\s!width\d_framed_linewidth
      \kern\scratchoffset}%
   \ht\scratchbox\strutht
   \dp\scratchbox\strutdp
   \box\scratchbox
   \ignorespaces
   \egroup}

%D The argument of the frame command accepts \type{\\} as a sort of newline signal. In
%D horizontal boxes it expands to a space.

\unexpanded\def\pack_framed_vboxed_newline
  {\endgraf\ignorespaces}

\unexpanded\def\pack_framed_hboxed_newline
  {\unskip\normalspace\ignorespaces}

%D We can set each rule on or off. The default setting is inherited from
%D \type {frame}. An earlier implementation use a bit different approach, but the new
%D one seems more natural:
%D
%D \bgroup
%D \setuptyping[margin=0pt]
%D \startlinecorrection
%D \startbuffer
%D \framed[offset=overlay,frame=on]{\darkred\blackrule}
%D \stopbuffer
%D \hbox{\getbuffer\vbox{\typebuffer}}
%D
%D \startbuffer
%D \framed[offset=overlay,frame=on,bottomframe=off]{\darkred\blackrule}
%D \stopbuffer
%D \hbox{\getbuffer\vbox{\typebuffer}}
%D
%D \startbuffer
%D \framed[offset=overlay,frame=on,bottomframe=on]{\darkred\blackrule}
%D \stopbuffer
%D \hbox{\getbuffer\vbox{\typebuffer}}
%D
%D \startbuffer
%D \framed[offset=overlay,frame=off]{\darkred\blackrule}
%D \stopbuffer
%D \hbox{\getbuffer\vbox{\typebuffer}}
%D
%D \startbuffer
%D \framed[offset=overlay,frame=off,bottomframe=off]{\darkred\blackrule}
%D \stopbuffer
%D \hbox{\getbuffer\vbox{\typebuffer}}
%D
%D \startbuffer
%D \framed[offset=overlay,frame=off,bottomframe=on]{\darkred\blackrule}
%D \stopbuffer
%D \hbox{\getbuffer\vbox{\typebuffer}}
%D \stoplinecorrection
%D \egroup

%D \macros
%D   {startframedtext, setupframedtexts, defineframedtext}
%D
%D The general framing command we discussed previously, is not entirely suited for
%D what we call framed texts, as for instance used in intermezzo's. The next
%D examples show what we have in mind.
%D
%D \startbuffer[framed-0]
%D \setupframedtexts
%D   [frame=off,
%D    width=\hsize,
%D    background=screen]
%D
%D \startframedtext
%D By default the framed text is centered \dots
%D \stopframedtext
%D
%D \startframedtext[right]
%D \dots\ but we can also align left, middle and right.
%D \stopframedtext
%D \stopbuffer
%D
%D \startbuffer[framed-1]
%D \defineframedtext
%D   [Example]
%D   [width=6cm,
%D    height=5cm]
%D
%D \startExample
%D \typebuffer[framed-1]
%D \stopExample
%D \stopbuffer
%D
%D \startbuffer[framed-2]
%D \defineframedtext
%D   [Example]
%D   [width=6cm]
%D
%D \startExample
%D \typebuffer[framed-2]
%D \stopExample
%D \stopbuffer
%D
%D \startbuffer[framed-3]
%D \defineframedtext
%D   [Example]
%D   [height=5cm]
%D
%D \startExample
%D \typebuffer[framed-3]
%D \stopExample
%D \stopbuffer
%D
%D \startbuffer[framed-4]
%D \defineframedtext
%D   [Example]
%D   [width=fit,height=broad]
%D
%D \Example{a very exciting example}
%D \stopbuffer
%D
%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-0] \egroup
%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-1] \egroup
%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-2] \egroup
%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-3] \egroup
%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-4] \egroup
%D
%D Here we can see that we have a predefined framed text class as well as the
%D tools for defining our own. So we have:
%D
%D \showsetup{setupframedtexts}
%D
%D as well as the definition command:
%D
%D \showsetup{defineframedtext}
%D
%D that generates two commands:
%D
%D \showsetup{start<<framedtext>>}
%D \showsetup{<<framedtext>>}
%D
%D The next definition shows the defaults.

\installcorenamespace{framedtext}
\installcorenamespace{framedtextlocation}

\installframedcommandhandler \??framedtext {framedtext} \??framedtext

\let\setupframedtexts\setupframedtext

\setupframedtext
  [\c!width=.75\hsize,
   \c!height=\v!fit,
   \c!align=\v!yes,
  %\c!top=,
   \c!bottom=\vfill,
   \c!offset=1em,
  %\c!bodyfont=,
  %\c!style=,
  %\c!color=,
  %\c!left=,
   \c!right=\hfill,
   \c!before=\blank,
   \c!after=\blank,
  %\c!inner=,
   \c!frame=\v!on,
  %\c!topframe=,
  %\c!bottomframe=,
  %\c!leftframe=,
  %\c!rightframe=,
   \c!radius=.5\bodyfontsize,
   \c!corner=\v!rectangular,
  %\c!orientation=,
  %\c!indenting=,
  %\c!foregroundcolor=,
  %\c!foregroundstyle=,
  %\c!background=,
  %\c!backgroundcolor=,
   \c!linecorrection=\v!on,
   \c!depthcorrection=\v!on,
   \c!margin=\v!standard]

\appendtoks
    \setuevalue{\e!start\currentframedtext}{\pack_framed_text_start {\currentframedtext}}%
    \setuevalue{\e!stop \currentframedtext}{\pack_framed_text_stop                      }%
    \setuevalue        {\currentframedtext}{\pack_framed_text_direct{\currentframedtext}}%
\to \everydefineframedtext

\setvalue{\??framedtextlocation\v!left  }{\letframedtextparameter\c!left \relax
                                          \letframedtextparameter\c!right\hfill}

\setvalue{\??framedtextlocation\v!right }{\letframedtextparameter\c!left \hfill
                                          \letframedtextparameter\c!right\relax}

\setvalue{\??framedtextlocation\v!middle}{\letframedtextparameter\c!left \hfill
                                          \letframedtextparameter\c!right\hfill}

\setvalue{\??framedtextlocation\v!none  }{\letframedtextparameter\c!left \relax
                                          \letframedtextparameter\c!right\relax
                                          \settrue\c_framed_text_location_none}

\unexpanded\def\pack_framed_text_start#1%
  {\bgroup
   \edef\currentframedtext{#1}%
   \dodoubleempty\pack_framed_text_start_indeed}

\def\pack_framed_text_start_indeed[#1][#2]%
  {\doifelseassignment{#1}
     {\pack_framed_text_start_continue\empty{#1}}
     {\pack_framed_text_start_continue{#1}{#2}}}

% todo: sort out first/lastline ht/dp

\def\pack_framed_text_start_continue#1#2%
  {\setupframedtexts[\currentframedtext][#2]%
   \doifsomething{#1}{\setframedtextparameter\c!location{#1}}% does not listen to #3
   \setfalse\c_framed_text_location_none
   \csname\??framedtextlocation\framedtextparameter\c!location\endcsname
   \resetframedtextparameter\c!location
   \pack_framed_text_check
   \setbox\b_framed_normal\vbox % \vpack
     \startboxedcontent
       \hsize\localhsize
    %  \insidefloattrue % ? better
       \usebodyfontparameter\framedtextparameter
    %  \edef\p_framed_text_strut{\letframedtextparameter\c!strut}% to be used
       \letframedtextparameter\c!strut\v!no
       \inheritedframedtextframed\bgroup
         \let\\=\endgraf
         \edef\p_framed_text_depthcorrection{\framedtextparameter\c!depthcorrection}%
         \ifx\p_framed_text_depthcorrection\v!on
            \pack_framed_text_start_depth_correction
         \else
            \bgroup
         \fi
         \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
         \doinhibitblank
         \useindentingparameter\framedtextparameter
         \useframedtextstyleandcolor\c!style\c!color
         \framedtextparameter\c!inner
         \ignorespaces}

% testcase 1:
%
% \showstruts
% \startframedtext[align={normal,tolerant},offset=0pt] \input tufte \stopframedtext
% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \input tufte \stopframedtext
% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \inframed{x} \stopframedtext
% \framed[align={normal,tolerant},offset=0pt]{\input tufte }

%D The \type {none} option is handy for nested usage, as in the presentation
%D styles, where we don't want interference.

\defineplacement[\??framedtext][\s!parent=\??framedtext\currentframedtext]

\unexpanded\def\pack_framed_text_stop % no \baselinecorrection, see faq docs
  {\endgraf
   \removelastskip
   \ifx\p_framed_text_depthcorrection\v!on
     \pack_framed_text_stop_depth_correction
   \else
     \egroup
   \fi
   \stopboxedcontent
   \ifconditional\c_framed_text_location_none
     \egroup
     \box\b_framed_normal
   \orelse\ifinsidefloat
     \egroup
     \box\b_framed_normal
   \else
     \egroup
     \placement[\??framedtext][\c!depthcorrection=\v!off]{\box\b_framed_normal}%
   \fi
   \egroup}

%D We define the general (and original) case by just saying:

\def\pack_framed_text_check % messy dependency
  {\localhsize\hsize
   \ifinsidefloat \orelse \ifdim\d_page_sides_vsize>\zeropoint % also possible: \c_page_sides_checks_done>\zeropoint
   % \strut            % rather clean way to invoke the sidefloat OTR
   % \setbox0=\lastbox % and get the widths set, so from now on we
   % \setlocalhsize    % can have framed texts alongside sidefloats
     \checksidefloat
     \setlocalhsize
   \fi}

\def\pack_framed_text_start_depth_correction
  {\bgroup
   \ifhmode
     \par
   \fi
   \ifvmode
     \verticalstrut
     % we need \nowhitespace in case of setups setting whitespace
     % nb, not safe, text vs \vbox as next
     \vskip-\struttotal
     \nowhitespace
   \fi} % na vskip ! new 20/05/2004, fails with next content being box (\scale{..})

\def\pack_framed_text_stop_depth_correction
  {\ifhmode
     \par
   \fi
   \ifvmode
     \forgetall
     \vskip-\struttotal
     \verticalstrut
     \egroup
     \forgetall % brrr too often
     \vskip-\lineheight
     \verticalstrut
   \else
     \egroup
   \fi}

%D Placement can be ignored:
%D
%D \starttyping
%D \hbox to \hsize \bgroup
%D     \startframedtext[none][width=.5\textwidth] \input tufte \stopframedtext
%D     \startframedtext[none][width=.5\textwidth] \input zapf  \stopframedtext
%D \egroup
%D
%D \hbox to \hsize \bgroup
%D     \setupframedtexts[location=none]%
%D     \startframedtext[width=.5\textwidth] \input zapf  \stopframedtext
%D     \startframedtext[width=.5\textwidth] \input tufte \stopframedtext
%D \egroup
%D \stoptyping

%D The simple brace (or group) delimited case is typeset slightly different
%D and is not aligned.

\unexpanded\def\pack_framed_text_direct#1%
  {\bgroup
   \edef\currentframedtext{#1}%
   \dosingleempty\pack_framed_text_start_direct}

\def\pack_framed_text_start_direct[#1]%
  {\usebodyfontparameter\framedtextparameter
   \iffirstargument
     \setupcurrentframedtext[#1]%
   \fi
   \edef\p_framed_text_strut{\framedtextparameter\c!strut}%
   \letframedtextparameter\c!strut\v!no
   \inheritedframedtextframed\bgroup
     \blank[\v!disable]%
     \let\\=\endgraf
     \useframedtextstyleandcolor\c!style\c!color
     \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
     \framedtextparameter\c!inner
     \ifx\p_framed_text_strut\v!no
        \let\pack_framed_strut\relax
     \else
        \let\pack_framed_strut\strut
     \fi
     \bgroup
     \aftergroup\pack_framed_text_stop_direct
     \afterassignment\ignorespaces
     \afterassignment\pack_framed_strut
     \let\next=}

\def\pack_framed_text_stop_direct
  {\removelastskip
   \egroup
   \egroup}

\defineframedtext
  [\v!framedtext]

%D \macros
%D   {defineframed}
%D
%D One can also define simple framed texts, using:
%D
%D \showsetup{defineframed}
%D
%D As suggested by Wolfgang we can now use the new \MKIV\ inheritance model instead
%D of passing a combination of arguments. This also also simplified the \type
%D {\setupframed} command. There are certainly more places where such improvements
%D can be made.

\appendtoks
    \ifcsname\??regularframedlevel\currentframed\endcsname
      % already defined, keeps settings
    \else
      \expandafter\newcount\csname\??regularframedlevel\currentframed\endcsname
    \fi
\to \everypresetframed

\appendtoks
   \setuevalue\currentframed{\pack_framed_defined_process[\currentframed]}%
\to \everydefineframed

\newcount\c_temp_framed_crap

\unexpanded\def\pack_framed_defined_process[#1]% official (not much checking, todo: parent)
  {\bgroup
   \ifcsname\??regularframedlevel#1\endcsname
    %\expandafter\let\expandafter\c_pack_framed_temp\csname\??regularframedlevel#1\endcsname
     \expandafter\let\expandafter\c_pack_framed_temp\lastnamedcs
   \else
     \let\c_pack_framed_temp\c_temp_framed_crap
   \fi
   \advance\c_pack_framed_temp\plusone
   \expandafter\def\csname\??framed#1>\the\c_pack_framed_temp:\s!parent\endcsname{\??framed#1}% \inheritlocalframed
   \bgroup
   \edef\currentframed{#1>\the\c_pack_framed_temp}%
   \pack_framed_initialize
   \dosingleempty\pack_framed_defined_process_indeed}

\def\pack_framed_defined_process_indeed[#1]%
  {\iffirstargument % faster
     \setupcurrentframed[#1]% here !
   \fi
   \pack_framed_process_indeed}

\let\placeframed\pack_framed_defined_process % new per 2012/04/23

%D We can do:
%D
%D \starttyping
%D \defineframed[\v!framed]
%D \stoptyping
%D
%D but the existing one is ok as well (less csname messy too).

%D New, for the moment private; let's see when GB finds out about this one and its
%D obscure usage. It's used in:
%D
%D \startbuffer
%D \defineframedtext
%D   [tabulateframe]
%D   [offset=overlay,
%D    backgroundoffset=3pt,
%D    background=color,
%D    backgroundcolor=green]
%D
%D \setuptabulate
%D   [tabulate]
%D   [frame=tabulateframe]
%D
%D \setuptables
%D   [frame=tabulateframe]
%D
%D \input tufte
%D
%D \starttabulate[|l|l|]
%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
%D \stoptabulate
%D
%D \input tufte
%D
%D \starttable[|l|l|]
%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
%D \stoptable
%D \stopbuffer
%D
%D \typebuffer

\installcorenamespace{framedcontent}

\installframedcommandhandler \??framedcontent {framedcontent} \??framedcontent

\setupframedcontent
  [\c!leftoffset=\zeropoint,
  %\c!rightoffset=\framedcontentparameter\c!leftoffset,
   \c!rightoffset=\scratchleftoffset,
   \c!topoffset=\zeropoint,
  %\c!bottomoffset=\framedcontentparameter\c!topoffset,
   \c!bottomoffset=\scratchtopoffset,
   \c!strut=\v!no,
  %\c!linecorrection=\v!no,
  %\c!left=,
  %\c!right=,
  %\c!width=\v!fit,
   \c!offset=\v!overlay]

\unexpanded\def\startframedcontent
  {\dosingleempty\pack_framed_start_content}

\def\pack_framed_start_content[#1]%
  {\bgroup
   \edef\currentframedcontent{#1}%
   \ifx\currentframedcontent\v!off
     \let\stopframedcontent\egroup
   \else
     \checkframedcontentparent
     \let\stopframedcontent\pack_framed_stop_content_indeed
     \expandafter\pack_framed_start_content_indeed
   \fi}

\def\pack_framed_start_content_indeed
  {\setbox\b_framed_normal\hpack\bgroup
     \setlocalhsize
     \hsize\localhsize
     \scratchleftoffset  \framedcontentparameter\c!leftoffset  \relax
     \scratchrightoffset \framedcontentparameter\c!rightoffset \relax
     \scratchtopoffset   \framedcontentparameter\c!topoffset   \relax
     \scratchbottomoffset\framedcontentparameter\c!bottomoffset\relax
     \advance\hsize\dimexpr-\scratchleftoffset-\scratchrightoffset \relax
     \advance\vsize\dimexpr-\scratchtopoffset -\scratchbottomoffset\relax
     \kern\scratchleftoffset
     \vpack\bgroup
       \vskip\scratchtopoffset
       \vbox\bgroup
         \forgetall
         \blank[\v!disable]}

\def\pack_framed_stop_content_indeed
         {\removelastskip
       \egroup
       \vskip\scratchbottomoffset
     \egroup
     \kern\scratchrightoffset
   \egroup
   \doif{\framedcontentparameter\c!width}\v!fit
     {\letframedcontentparameter\c!width\v!fixed}% no shapebox
   \ifinsidefloat
     \donefalse
   \else
     \doifelse{\framedcontentparameter\c!linecorrection}\v!yes\donetrue\donefalse
   \fi
   % plaats ?
   \ifdone\startlinecorrection\fi
   \framedcontentparameter\c!left % new
   \inheritedframedcontentframed{\box\b_framed_normal}% hm
   \framedcontentparameter\c!right % new
   \ifdone\stoplinecorrection\fi
   \egroup}

% A shared setting.

\setuplinewidth
  [\v!medium]

%D A Goodie:

\def\v!unframed{unframed}

\defineframed
  [\v!unframed]
  [\c!frame=\v!off,
   \c!rulethickness=\zeropoint,
   \c!foregroundstyle=\framedparameter\c!style,
   \c!foregroundcolor=\framedparameter\c!color]

%D Bonus (as defined in \type {pack-rul.lua}):
%D
%D \starttyping
%D \setbox\scratchbox\vbox{a\par aa\par aaa\par}
%D \the\dimexpr\themaxboxwidth\scratchbox\relax
%D \stoptyping

\let\themaxboxwidth\clf_themaxboxwidth

%D New: slow but ok for most cases:

\unexpanded\def\doifelseframed#1%
  {\ifcase\numexpr\zerocount
     \immediateassignment\edef\tempstring{#1\c!frame      }\ifx\tempstring\v!on      +\plusone\fi
     \immediateassignment\edef\tempstring{#1\c!topframe   }\ifx\tempstring\v!on      +\plusone\fi
     \immediateassignment\edef\tempstring{#1\c!bottomframe}\ifx\tempstring\v!on      +\plusone\fi
     \immediateassignment\edef\tempstring{#1\c!leftframe  }\ifx\tempstring\v!on      +\plusone\fi
     \immediateassignment\edef\tempstring{#1\c!rightframe }\ifx\tempstring\v!on      +\plusone\fi
     \immediateassignment\edef\tempstring{#1\c!background }\ifx\tempstring\empty\else+\plusone\fi
   \relax\expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments\fi}

\protect \endinput
