pack-rul.mkxl /size: 108 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=pack-rul, % was core-rul,
3%D        version=1998.10.16,
4%D          title=\CONTEXT\ Packaging Macros,
5%D       subtitle=Ruled Content,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Packaging Macros / Ruled Content}
15
16%D The code here is expanded lots of time as framed is used in many places. This is
17%D why the code here is (and gets) optimized as much as possible. Also, by avoiding
18%D packaging and expansion we also keep tracing reasonable. For instance, multiple
19%D stacked backgrounds can slow down a run if not optimized this way.
20
21\newinteger  \framednoflines
22\newdimension\framedfirstheight
23\newdimension\framedlastdepth
24\newdimension\framedminwidth
25\newdimension\framedmaxwidth
26\newdimension\framedaveragewidth
27
28\registerctxluafile{pack-rul}{autosuffix}
29
30\unprotect
31
32% \definesystemvariable {ol}   % OmLijnd -> check scrn-fld too
33
34%D \macros
35%D   {linewidth, setuplinewidth}
36%D
37%D This module deals with rules (lines) in several ways. First we introduce two
38%D macros that can be used to set some common characteristics.
39%D
40%D \showsetup{setuplinewidth}
41%D
42%D The linewidth is available in \type{\linewidth}. The preset value of .4pt equals
43%D the default hard coded \TEX\ rule width.
44
45\newdimension\linewidth
46
47\permanent\tolerant\protected\def\setuplinewidth[#1]%
48  {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}
49
50%D The parameter handler:
51
52\installcorenamespace{framed}
53\installcorenamespace{framedtop}
54\installcorenamespace{framedbottom}
55\installcorenamespace{framedleft}
56\installcorenamespace{framedright}
57
58\installcorenamespace{regularframed}
59\installcorenamespace{simplifiedframed}
60
61\installcommandhandler \??framed {framed} \??framed
62
63\aliased\let\pack_framed_framedparameter    \framedparameter
64\aliased\let\pack_framed_framedparameterhash\framedparameterhash
65\aliased\let\pack_framed_setupcurrentframed \setupcurrentframed
66
67\def\pack_framed_initialize
68  {\enforced\let\framedparameter    \pack_framed_framedparameter
69   \enforced\let\framedparameterhash\pack_framed_framedparameterhash
70   \enforced\let\setupcurrentframed \pack_framed_setupcurrentframed
71   \inframedtrue}
72
73%D A helper:
74
75\permanent\def\frameddimension#1{\todimension{\framedparameter{#1}}}
76
77%D Inheritance:
78
79\permanent\protected\def\installinheritedframed#1%
80  {\normalexpanded{\mult_interfaces_install_inherited_framed
81     \expandafter\noexpand\csname current#1\endcsname
82     \expandafter\noexpand\csname #1parameter\endcsname
83     \expandafter\noexpand\csname #1parameterhash\endcsname
84     \expandafter\noexpand\csname do#1parameter\endcsname
85     \expandafter\noexpand\csname do#1parentparameter\endcsname
86     \expandafter\noexpand\csname do#1rootparameter\endcsname
87     \expandafter\noexpand\csname setupcurrent#1\endcsname
88     \expandafter\noexpand\csname inherited#1framed\endcsname
89     \expandafter\noexpand\csname inherited#1framedbox\endcsname}} % new
90
91\protected\def\mult_interfaces_install_inherited_framed#1#2#3#4#5#6#7#8#9%
92  {\enforced\frozen\def#5##1##2{\ifrelax##1#6{##2}\else#4{##1}{##2}\fi}%
93%    \enforced\frozen\def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\??empty\fi}% root
94\enforced\frozen\def#6##1{\ifcsname\??framed:##1\endcsname\csnamestring\else\??empty\fi}% root
95   \frozen\instance\protected\def#8%
96     {\bgroup
97      \bgroup
98      \inframedtrue
99      \enforced\let\currentframed      #1%
100      \enforced\let\framedparameter    #2%
101      \enforced\let\framedparameterhash#3%
102      \enforced\let\setupcurrentframed #7%
103      \pack_framed_process_indeed}%
104   \frozen\instance\protected\def#9%
105     {\bgroup
106      \inframedtrue
107      \enforced\let\currentframed      #1%
108      \enforced\let\framedparameter    #2%
109      \enforced\let\framedparameterhash#3%
110      \enforced\let\setupcurrentframed #7%
111      \pack_framed_process_box_indeed}}
112
113\permanent\protected\def\installframedcommandhandler#1#2#3%
114  {\installcommandhandler{#1}{#2}{#3}%
115   \installinheritedframed{#2}}
116
117\permanent\protected\def\installframedautocommandhandler#1#2#3%
118  {\installautocommandhandler{#1}{#2}{#3}%
119   \installinheritedframed{#2}}
120
121\permanent\protected\def\installsimpleframedcommandhandler#1#2#3%
122  {\installsimplecommandhandler{#1}{#2}{#3}%
123   \installinheritedframed{#2}}
124
125% corner options (with radius=0pt rectangular):
126%
127%  0 round ltrb trbl rblt bltr
128%  1 2 3 4 5 6 7 8 ltrb
129%  9 lbr rbl / 10 tlb blt / 11 ltr rtl / 12 lbr rbl
130% 13 rt tr / 14 rb br / 15 bl lb / 16 tl lt
131% 32 lr rl / 33 tb bt
132% 28 l / 29 r / 30 b / 31 t
133
134%D \starttyping
135%D \dostepwiserecurse{0}{33}{1}{
136%D     \startTEXpage[offset=1dk]
137%D         \dontleavehmode\ruledhbox{\framed
138%D           [framecolor=red,
139%D            framecorner=#1,
140%D            frameradius=\zeropoint]
141%D           {TEST #1}}
142%D         \ruledhbox{\framed
143%D           [framecolor=red,
144%D            framecorner=#1,
145%D            frameradius=10pt]
146%D           {TEST #1}}
147%D     \stopTEXpage
148%D }
149%D \stoptyping
150
151% for regular framed
152
153\setupframed
154  [\c!width=\v!fit,
155   \c!height=\v!broad,
156  %\c!minheight=\zeropoint,
157  %\c!lines=,
158   \c!offset=.25\exheight,  % \defaultframeoffset
159   \c!empty=\v!no,
160   \c!frame=\v!on,
161  %\c!topframe=,
162  %\c!bottomframe=,
163  %\c!leftframe=,
164  %\c!rightframe=,
165   \c!radius=.5\bodyfontsize, % not used directly, see below
166   \c!rulethickness=\linewidth,
167   \c!dashstep=.1\emwidth,
168   \c!corner=\v!rectangular,
169   \c!depth=\zeropoint, % not used directly, see below
170  %\c!foregroundcolor=,
171  %\c!foregroundstyle=,
172  %\c!background=,
173  %\c!backgroundcolor=,
174   \c!backgroundoffset=\zeropoint,
175  %\c!framecolor=,
176   \c!frameoffset=\zeropoint,
177   \c!backgroundcorner=\framedparameter\c!corner, % use \p_ here
178   \c!backgroundradius=\framedparameter\c!radius,
179   \c!backgrounddepth=\framedparameter\c!depth,
180   \c!framecorner=\framedparameter\c!corner,
181   \c!frameradius=\framedparameter\c!radius,
182   \c!framedepth=\framedparameter\c!depth,
183  %\c!component=,
184  %\c!region=,
185  %\c!align=,
186   \c!bottom=\vss,
187  %\c!top=,
188   \c!strut=\v!yes,
189   \c!autostrut=\v!yes,
190   \c!location=\v!normal,
191  %\c!orientation=,
192  %\c!anchoring=,
193   \c!autowidth=\v!yes,
194  %\c!setups=,
195   \c!synchronize=,
196   \c!loffset=\zeropoint,
197   \c!roffset=\zeropoint,
198   \c!toffset=\zeropoint,
199   \c!boffset=\zeropoint]
200
201%D For backgrounds and such:
202
203\defineframed
204  [\??simplifiedframed]
205  [\c!frame=\v!off,
206   \c!depth=\zeropoint,
207   \c!offset=\v!overlay,
208   \c!component=,
209   \c!region=,
210   \c!radius=.5\bodyfontsize,
211   \c!rulethickness=\linewidth,
212   \c!corner=\v!rectangular,
213   \c!backgroundoffset=\zeropoint,
214   \c!frameoffset=\zeropoint,
215   \c!backgroundcorner=\framedparameter\c!corner,  % use \p_ here
216   \c!backgroundradius=\framedparameter\c!radius,
217   \c!backgrounddepth=\framedparameter\c!depth,
218   \c!framecorner=\framedparameter\c!corner,
219   \c!frameradius=\framedparameter\c!radius,
220   \c!framedepth=\framedparameter\c!depth,
221   \c!location=\v!normal,
222   \c!loffset=\zeropoint,
223   \c!roffset=\zeropoint,
224   \c!toffset=\zeropoint,
225   \c!boffset=\zeropoint]
226
227\permanent\protected\def\definesimplifiedframed[#1]% no settings
228  {\defineframed[#1][\??simplifiedframed]%
229   \enforced\letcsname#1\endcsname\undefined}
230
231\letcsname\??simplifiedframed\endcsname\undefined
232
233%D We will communicate through module specific variables, current framed
234%D parameters and some reserved dimension registers.
235
236\newdimension\d_framed_target_wd
237\newdimension\d_framed_target_ht
238\newdimension\d_framed_target_dp
239%newdimen    \d_framed_linewidth  \aliased\let   \ruledlinewidth\d_framed_linewidth % needed at lua end
240\newdimension\d_framed_linewidth  \aliasdimension\ruledlinewidth\d_framed_linewidth % needed at lua end
241
242\lettonothing\p_frame
243\lettonothing\p_framed_adaptive
244\lettonothing\p_framed_anchoring
245\lettonothing\p_framed_autostrut
246\lettonothing\p_framed_autowidth
247\lettonothing\p_framed_background
248\lettonothing\p_framed_backgroundcolor
249\lettonothing\p_framed_backgroundcorner
250\lettonothing\p_framed_backgroundoffset
251\lettonothing\p_framed_backgroundradius
252\lettonothing\p_framed_component
253\lettonothing\p_framed_empty
254\lettonothing\p_framed_foregroundcolor
255\lettonothing\p_framed_foregroundstyle
256\lettonothing\p_framed_frame            % \framedparameter\c!frame
257\lettonothing\p_framed_framecolor
258\lettonothing\p_framed_framecorner
259%lettonothing\p_framed_frameradius
260\lettonothing\p_framed_franalyze
261\lettonothing\p_framed_lines
262\lettonothing\p_framed_location
263\lettonothing\p_framed_minheight
264\lettonothing\p_framed_orientation
265%lettonothing\p_framed_rulethickness
266\lettonothing\p_framed_setups
267\lettonothing\p_framed_synchronize
268\lettonothing\p_framed_text_depthcorrection
269\lettonothing\p_framed_text_strut
270
271%D We don't have to stick to a \TEX\ drawn rule, but also can use rounded
272%D or even fancier shapes, as we will see later on.
273
274\def\pack_framed_filled_box
275  {\edef\p_framed_backgroundcorner{\framedparameter\c!backgroundcorner}%
276   \ifx\p_framed_backgroundcorner\v!rectangular
277     \pack_framed_filled_box_normal
278   \else
279     \pack_framed_filled_box_radius
280   \fi}
281
282\def\pack_framed_filled_box_normal
283  {\vrule
284     \s!width \d_framed_target_wd
285     \s!height\d_framed_target_ht
286     \s!depth \d_framed_target_dp
287   \relax}
288
289\def\pack_framed_filled_box_radius
290  {\edef\p_framed_backgroundradius{\framedparameter\c!backgroundradius}%
291   \ifzeropt{\p_framed_backgroundradius}% just in case of .x\bodyfontsize
292     \pack_framed_filled_box_normal
293   \else
294     \pack_framed_filled_box_round
295   \fi}
296
297% \def\pack_framed_filled_box_round
298%   {\raise\d_framed_target_dp\hpack{\frule
299%      type   fill
300%      width  \d_framed_target_wd
301%      height \d_framed_target_ht
302%      depth  \d_framed_target_dp
303%      line   \d_framed_linewidth
304%      radius \dimexpr\p_framed_backgroundradius\relax
305%      corner {\p_framed_backgroundcorner}
306%    \relax}}
307
308\def\pack_framed_filled_box_round
309  {\raise\d_framed_target_dp
310   \hpack{\clf_roundedfill
311     \d_framed_target_wd
312     \d_framed_target_ht
313     \d_framed_target_dp
314     \d_framed_linewidth
315     {\p_framed_backgroundradius}%
316     {\p_framed_backgroundcorner}
317   \relax}}
318
319% we keep this as reference (should still work when uncommented)
320%
321% \def\pack_framed_stroked_box
322%   {\edef\p_framed_framecorner{\framedparameter\c!framecorner}%
323%    \ifx\p_framed_framecorner\v!rectangular
324%      \pack_framed_stroked_box_normal
325%    \else
326%      \pack_framed_stroked_box_radius
327%    \fi}
328%
329% \def\pack_framed_stroked_box_radius
330%   {\edef\p_framed_frameradius{\framedparameter\c!frameradius}%
331%    \ifzeropt\dimexpr\p_framed_frameradius\relax % just in case of .x\bodyfontsize
332%      \pack_framed_stroked_box_normal
333%    \orelse\ifx\p_framed_frame\v!on
334%      \pack_framed_stroked_box_round
335%    \fi}
336%
337% % \pack_framed_stroked_box_normal % later
338%
339% \def\pack_framed_stroked_box_round
340%   {\raise\d_framed_target_dp\hpack{\frule
341%      width  \d_framed_target_wd
342%      height \d_framed_target_ht
343%      depth  \d_framed_target_dp
344%      line   \d_framed_linewidth
345%      radius \p_framed_frameradius\relaxedspace
346%      corner {\p_framed_framecorner}
347%    \relax}}
348%
349% corner is the parent of framecorner and backgroundcorner (round value never checked)
350% when 'round' is passed it is not a number and therefore we get four sides
351
352\def\pack_framed_stroked_box
353  {\edef\p_framed_framecorner{\framedparameter\c!framecorner}%
354   \ifx\p_framed_framecorner\v!rectangular
355     \pack_framed_stroked_box_normal
356   \orelse\ifx\p_framed_frame\v!on
357     \pack_framed_stroked_box_round
358   \fi}
359
360\def\pack_framed_stroked_box_round % todo: variant without keywords
361  {\raise\d_framed_target_dp
362   \hpack{\clf_roundedoutline % we could access these at the lua end!
363     \d_framed_target_wd
364     \d_framed_target_ht
365     \d_framed_target_dp
366     \d_framed_linewidth
367     {\framedparameter\c!frameradius}%
368     {\p_framed_framecorner}
369   \relax}}
370
371% a lot of weird corners
372%
373% \startTEXpage
374%     \dontleavehmode\framed
375%         [corner=0,frame=on,framecolor=green,
376%          background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
377%     \vskip1em
378%     \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
379%         [corner=\recurselevel,frame=on,framecolor=green,
380%          background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
381%         \quad}
382%     \vskip1em
383%     \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
384%         [corner=\recurselevel,frame=on,framecolor=green,
385%          background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
386%         \quad}
387%     \vskip1em
388%     \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
389%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
390%         \quad}
391%     \vskip1em
392%     \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
393%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
394%         \quad}
395%     \vskip1em
396%     \dontleavehmode\dostepwiserecurse {9}{12}{1}{\framed
397%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
398%         \quad}
399%     \vskip1em
400%     \dontleavehmode\dostepwiserecurse{13}{16}{1}{\framed
401%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
402%         \quad}
403%     \vskip1em
404%     \dontleavehmode\dostepwiserecurse{17}{20}{1}{\framed
405%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
406%         \quad}
407%     \vskip1em
408%     \dontleavehmode\dostepwiserecurse{21}{24}{1}{\framed
409%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
410%         \quad}
411%     \vskip1em
412%     \dontleavehmode\dostepwiserecurse{25}{28}{1}{\framed
413%         [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
414%         \quad}
415% \stopTEXpage
416
417%D It won't be a surprise that we not only provide gray boxes, but also colored
418%D ones. Here it is:
419
420\def\pack_framed_background_box_color
421  {\edef\p_framed_backgroundcolor{\framedparameter\c!backgroundcolor}%
422   \ifempty\p_framed_backgroundcolor \else
423     \doifcolor\p_framed_backgroundcolor\pack_framed_background_box_color_indeed
424   \fi}
425
426\def\pack_framed_background_box_color_indeed
427  {\hpack{\dousecolorparameter\p_framed_backgroundcolor\pack_framed_filled_box}}
428
429%D \macros
430%D   {defineoverlay, doifoverlayelse, overlayoffset,
431%D    overlaywidth, overlayheight, overlaydepth,
432%D    overlaycolor, overlaylinecolor, overlaylinewidth}
433%D
434%D Before we define the macro that actually takes card of the backgrounds, we
435%D introduce overlays. An overlay is something that contrary to its name lays {\em
436%D under} the text. An example of an overlay definition is:
437%D
438%D \startbuffer[tmp-1]
439%D \defineoverlay
440%D   [fancy]
441%D   [{\externalfigure
442%D       [mp-cont.502]
443%D       [width=\overlaywidth,
444%D        height=\overlayheight]}]
445%D \stopbuffer
446%D
447%D \typebuffer[tmp-1]
448%D
449%D  That for instance can be uses in:
450%D
451%D  \startbuffer[tmp-2]
452%D  \framed[backgroundachtergrond=fancy]{How Fancy!}
453%D  \framed[backgroundachtergrond=fancy,frame=off]{Even More Fancy!}
454%D  \stopbuffer
455%D
456%D  and looks like:
457%D
458%D  \startlinecorrection
459%D  \vbox{\baselineskip24pt\getbuffer[tmp-1]\getbuffer[tmp-2]}
460%D  \stoplinecorrection
461%D
462%D The formal definition is:
463%D
464%D \showsetup{defineoverlay}
465%D
466%D This macro's definition is a bit obscure, due the many non||used arguments and
467%D the two step call that enable the setting of the width, height and depth
468%D variables. Multiple backgrounds are possible and are specified as:
469%D
470%D \starttyping
471%D \framed[background={one,two,three}]{Three backgrounds!}
472%D \stoptyping
473%D
474%D Most drawing packages only know width and height. Therefore the dimensions have a
475%D slightly different meaning here:
476%D
477%D \startitemize[packed]
478%D \item \type{\overlaywidth }: width of the overlay
479%D \item \type{\overlayheight}: height plus depth of the overlay
480%D \item \type{\overlaydepth }: depth of the overlay
481%D \stopitemize
482%D
483%D The resulting box is lowered to the right depth.
484
485\newdimension\d_overlay_width
486\newdimension\d_overlay_height
487\newdimension\d_overlay_depth
488\newdimension\d_overlay_offset
489\newdimension\d_overlay_linewidth
490\newdimension\d_overlay_mathaxis
491\newdimension\d_overlay_mathexheight
492\newdimension\d_overlay_mathemwidth
493
494\lettonothing\m_overlay_region
495
496% expandable ... in a future version the space will go (in mp one can use Overlay*)
497
498\mutable  \def\overlaywidth        {\the\d_overlay_width       \space} % We preset the variables
499\mutable  \def\overlayheight       {\the\d_overlay_height      \space} % to some reasonable default
500\mutable  \def\overlaydepth        {\the\d_overlay_depth       \space} % values.
501\mutable  \def\overlayoffset       {\the\d_overlay_offset      \space} % of the frame can be (are)
502\mutable  \def\overlaylinewidth    {\the\d_overlay_linewidth   \space} % set somewhere else.
503\mutable  \def\overlaymathaxis     {\the\d_overlay_mathaxis    \space} % set somewhere else.
504\mutable  \def\overlaymathexheight {\the\d_overlay_mathexheight\space} % set somewhere else.
505\mutable  \def\overlaymathemwidth  {\the\d_overlay_mathemwidth \space} % set somewhere else.
506\mutable  \def\overlayregion       {\m_overlay_region}
507
508\mutable  \def\overlayradius       {\todimension{\framedparameter\c!frameradius}}
509\mutable  \def\overlaycolor        {\framedparameter\c!backgroundcolor}
510\mutable  \def\overlaylinecolor    {\framedparameter\c!framecolor}
511%mutable  \edef\overlaycorner      {\framedparameter\c!backgroundcorner}
512%mutable  \edef\overlayradius      {\the\dimexpr\framedparameter\c!backgroundradius\relax}
513
514\aliased\let\usedoverlaywidth       \d_overlay_width
515\aliased\let\usedoverlayheight      \d_overlay_height
516\aliased\let\usedoverlaydepth       \d_overlay_depth
517\aliased\let\usedoverlayoffset      \d_overlay_offset
518\aliased\let\usedoverlaylinewidth   \d_overlay_linewidth
519\aliased\let\usedoverlaymathaxis    \d_overlay_mathaxis
520\aliased\let\usedoverlaymathexheight\d_overlay_mathexheight
521\aliased\let\usedoverlaymathemwidth \d_overlay_mathemwidth
522
523%D The next register is used to initialize overlays.
524
525\newtoks\everyoverlay
526
527%D An example of an initialization is the following (overlays can contain text
528%D and be executed under an regime where interlineskip is off).
529
530\installcorenamespace{overlay}
531\installcorenamespace{overlaybuiltin}
532
533\appendtoks
534    \oninterlineskip
535\to \everyoverlay
536
537\prependtoks
538    \hsize\d_overlay_width
539    \vsize\d_overlay_height
540\to \everyoverlay
541
542\protected\def\pack_overlay_define#1#2%
543  {\defcsname\??overlay#1\endcsname{\executedefinedoverlay{#1}{#2}}}
544
545\permanent\tolerant\protected\def\defineoverlay[#1]#*[#S#2]% wil be overloaded
546% {\def\pack_framed_define_overlay_indeed##1{\defcsname\??overlay##1\endcsname{\executedefinedoverlay{##1}{#2}}}%
547  {\def\pack_framed_define_overlay_indeed##1{\pack_overlay_define{##1}{#2}}%
548   \processcommalist[#1]\pack_framed_define_overlay_indeed}
549
550\permanent\protected\def\executedefinedoverlay#1#2% we can share the definitions
551  {\bgroup % redundant grouping
552   \setlayoutcomponentattribute{\v!overlay:#1}%
553   \setbox\scratchbox\hbox \layoutcomponentboxattribute{\expand\everyoverlay#2}%
554   \boxxoffset\scratchbox-.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \d_overlay_width
555   \boxyoffset\scratchbox-.5\dimexpr\ht\scratchbox-\d_framed_target_ht+\d_framed_target_dp\relax % not \d_overlay_height !
556   \wd\scratchbox\d_framed_target_wd
557   \ht\scratchbox\d_framed_target_ht
558   \dp\scratchbox\d_framed_target_dp
559   \box\scratchbox
560   \egroup}
561
562%D \macros
563%D   {overlayfakebox}
564
565\permanent\protected\def\overlayfakebox
566  {\hpack % redundant but needs testing
567     {\novrule
568        \s!width \d_overlay_width
569        \s!height\d_overlay_height
570        \s!depth \zeropoint}}
571
572%D For testing we provide:
573
574\permanent\def\doifelseoverlay#1% only tests external overlays
575  {\ifcsname\??overlay#1\endcsname
576     \expandafter\firstoftwoarguments
577   \else
578     \expandafter\secondoftwoarguments
579   \fi}
580
581\aliased\let\doifoverlayelse\doifelseoverlay
582
583%D The content of the box will be (temporary) saved in a box. We also have an
584%D extra box for backgrounds.
585
586\newbox\b_framed_normal
587\newbox\b_framed_extra
588
589\newtoks\everybackgroundbox
590
591\lettonothing\m_framed_background % we might need a public name
592
593\def\pack_framed_process_background
594  {\ifcsname\??overlaybuiltin\m_framed_background\endcsname
595     \expandafter\pack_framed_process_background_indeed_internal\lastnamedcs
596   \orelse\ifcsname\??overlay\m_framed_background\endcsname
597     \expandafter\pack_framed_process_background_indeed_external\lastnamedcs
598   \fi}
599
600\def\pack_framed_process_background_indeed_internal#1% % : in name
601  {\bgroup
602   \setbox\b_framed_extra\hpack\bgroup
603     \ifzeropt\framedbackgroundoffset\else
604       \kern-\framedbackgroundoffset
605     \fi
606     \hbox\bgroup#1\egroup
607   \egroup
608   \wd\b_framed_extra\zeropoint
609   \ht\b_framed_extra\framedbackgroundheight
610   \dp\b_framed_extra\framedbackgrounddepth
611   \box\b_framed_extra
612   \egroup}
613
614\let\pack_framed_overlay_initialize\relax
615
616\def\pack_framed_process_background_indeed_external
617  {\pack_framed_overlay_initialize
618   \pack_framed_process_background_indeed_internal}
619
620\def\pack_framed_process_backgrounds#1,#2% #2 gobbles spaces (we could avoid one catch if we have nextbackground)
621  {\edef\m_framed_background{#1}%
622   \ifx\m_framed_background\s!unknown\else
623     \pack_framed_process_background
624     \expandafter\pack_framed_process_backgrounds
625   \fi#2}
626
627%D Beware, a backgroundbox can be empty which is another reason why we set the
628%D width to zero instead of back-skipping.
629
630\newdimension\framedbackgroundwidth
631\newdimension\framedbackgroundheight
632\newdimension\framedbackgrounddepth
633\newdimension\framedbackgroundoffset
634
635\aliased\let\foregroundbox\relax
636
637\def\pack_framed_background_box_content% fuzzy but needed hack, this \vss, otherwise
638  {\vpack to \framedbackgroundheight{\vss\box\b_framed_normal\vss}} % vertical shift \backgroundheight
639
640\def\pack_framed_set_region % experiment
641  {\ifx\m_overlay_region\v!yes
642     \edef\m_overlay_region{\reservedautoregiontag}%
643   \fi}
644
645\def\pack_framed_add_region % experiment, zerocount forces the given region
646  {\anch_mark_tagged_box\b_framed_normal\m_overlay_region\zerocount}
647
648\def\pack_framed_add_background
649  {\ifconditional\c_pack_reanchor
650      \analyzelocalanchors\b_framed_normal
651   \fi
652   \setbox\b_framed_normal\hpack % was vbox % see also *1*
653     {%\pack_framed_forgetall % can be relaxed
654      \boxmaxdepth\maxdimen
655      \framedbackgroundoffset\d_framed_backgroundoffset
656      \framedbackgroundwidth \wd\b_framed_normal
657      \framedbackgroundheight\ht\b_framed_normal
658      \framedbackgrounddepth \dp\b_framed_normal
659      \d_framed_target_wd{\framedbackgroundwidth +2\framedbackgroundoffset}%
660      \d_framed_target_ht{\framedbackgroundheight+ \framedbackgroundoffset}%
661      \d_framed_target_dp{\framedbackgrounddepth + \framedbackgroundoffset+\framedparameter\c!backgrounddepth}%
662      \let\pack_framed_overlay_initialize\pack_framed_overlay_initialize_indeed
663      \ifempty\p_framed_component
664        \resetlayoutcomponentattribute
665      \else
666        \setlayoutcomponentattribute{\v!background:\p_framed_component}%
667      \fi
668      \enforced\let\foregroundbox\pack_framed_background_box_content
669      \hpack \layoutcomponentboxattribute to \framedbackgroundwidth\bgroup % width in case 'foreground' is used as overlay
670         \expand\everybackgroundbox % moved
671         \expandafter\pack_framed_process_backgrounds\p_framed_background,\s!unknown,\relax % hm, messy .. look into it
672         \box\b_framed_normal
673         \hss
674      \egroup}}
675
676\def\pack_framed_overlay_initialize_indeed
677  {\d_overlay_width       \d_framed_target_wd
678   \d_overlay_height      {\d_framed_target_ht+\d_framed_target_dp}%
679   \d_overlay_depth       \d_framed_target_dp
680   \d_overlay_linewidth   \d_framed_linewidth
681 % \d_overlay_mathaxis    \zeropoint
682 % \d_overlay_mathexheight\zeropoint
683 % \d_overlay_mathemwidth \zeropoint
684   \d_overlay_offset      \framedbackgroundoffset\relax
685   % We expand these once:
686   \edef\overlaycolor    {\framedparameter\c!backgroundcolor}%
687   \edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers
688   %
689   \let\pack_framed_overlay_initialize\relax}
690
691%D One can explictly insert the foreground box. For that purpose we introduce the
692%D overlay \type {foreground}.
693%D
694%D We predefine two already familiar backgrounds:
695
696%letcsname\??overlaybuiltin\v!screen    \endcsname\pack_framed_background_box_gray
697\letcsname\??overlaybuiltin\v!color     \endcsname\pack_framed_background_box_color
698\letcsname\??overlaybuiltin\v!foreground\endcsname\pack_framed_background_box_content % replaces: \defineoverlay[\v!foreground][\foregroundbox]
699
700%D We can specify overlays as a comma separated list of overlays, a sometimes
701%D handy feature.
702%D
703%D Besides backgrounds (overlays) we also need some macros to draw outlines (ruled
704%D borders). Again we have to deal with square and round corners. The first category
705%D can be handled by \TEX\ itself, the latter one depends on the driver. This macro
706%D also support a negative offset.
707
708\def\pack_framed_add_outline
709  {\setbox\b_framed_normal\hpack % rules on top of box
710     {\d_framed_target_wd{\wd\b_framed_normal+2\d_framed_frameoffset}%
711      \d_framed_target_ht{\ht\b_framed_normal+ \d_framed_frameoffset}%
712      \d_framed_target_dp{\dp\b_framed_normal+ \d_framed_frameoffset+\framedparameter\c!framedepth}%
713      \ifdim\d_framed_target_dp<\zeropoint
714        \advanceby\d_framed_target_ht \d_framed_target_dp
715        \scratchdimen-\d_framed_target_dp
716        \d_framed_target_dp\zeropoint
717      \else
718        \scratchdimen\zeropoint
719      \fi
720      \edef\overlaylinecolor{\framedparameter\c!framecolor}% twice, also in background
721      \setbox\b_framed_extra\hpack
722        {\kern-\d_framed_frameoffset
723         \raise\scratchdimen
724         \hpack{\ifempty\overlaylinecolor\else\dousecolorparameter\overlaylinecolor\fi\pack_framed_stroked_box}}%
725      \wd\b_framed_extra\wd\b_framed_normal
726      \ht\b_framed_extra\ht\b_framed_normal
727      \dp\b_framed_extra\dp\b_framed_normal
728      \wd\b_framed_normal\zeropoint
729      \box\b_framed_normal
730      \box\b_framed_extra}}
731
732%D A probably unknown feature:
733%D
734%D \startbuffer
735%D \hpack\bgroup
736%D     \framed[framecolor=MyColor,frame=on]    {!!!!!!!!}
737%D     \framed[framecolor=MyColor,frame=closed]{!!!!!!!!}
738%D     \framed[framecolor=MyColor,frame=small] {!!!!!!!!}
739%D \egroup
740%D \stopbuffer
741%D
742%D \typebuffer \startlinecorrection[blank] \getbuffer \stoplinecorrection
743
744% \def\pack_framed_stroked_box_normal_opened
745%   {\setbox\scratchbox\vpack \bgroup
746%      \csname\??framedtop\p_framed_frame\framedparameter\c!topframe\endcsname
747%      \nointerlineskip % new (needed for fences)
748%      \hpack \bgroup
749%        \csname\??framedleft\p_framed_frame\framedparameter\c!leftframe\endcsname
750%        \novrule
751%          \s!width \d_framed_target_wd
752%          \s!height\d_framed_target_ht
753%          \s!depth \d_framed_target_dp
754%        \csname\??framedright\p_framed_frame\framedparameter\c!rightframe\endcsname
755%      \egroup
756%      \nointerlineskip % new (needed for fences)
757%      \csname\??framedbottom\p_framed_frame\framedparameter\c!bottomframe\endcsname
758%    \egroup
759%    \wd\scratchbox\d_framed_target_wd
760%    \ht\scratchbox\d_framed_target_ht
761%    \dp\scratchbox\d_framed_target_dp
762%    \box\scratchbox}
763
764% less logging:
765
766\def\pack_framed_stroked_box_normal_opened
767  {\setbox\scratchbox\vpack \bgroup
768   % \normaloffinterlineskip % sets baselineskip, lineskip and lineskiplimit
769     \baselineskip-\thousandpoint
770     \lineskip     \zeroskip
771     \lineskiplimit\maxdimen
772     \csname\??framedtop\p_framed_frame\framedparameter\c!topframe\endcsname
773   % \nointerlineskip % new (needed for fences)
774     \hpack \bgroup
775       \csname\??framedleft\p_framed_frame\framedparameter\c!leftframe\endcsname
776       \novrule
777         \s!width \d_framed_target_wd
778         \s!height\d_framed_target_ht
779         \s!depth \d_framed_target_dp
780       \csname\??framedright\p_framed_frame\framedparameter\c!rightframe\endcsname
781     \egroup
782   % \nointerlineskip % new (needed for fences)
783     \csname\??framedbottom\p_framed_frame\framedparameter\c!bottomframe\endcsname
784   \egroup
785   \wd\scratchbox\d_framed_target_wd
786   \ht\scratchbox\d_framed_target_ht
787   \dp\scratchbox\d_framed_target_dp
788   \box\scratchbox}
789
790\def\pack_framed_stroked_box_normal_closed
791  {\hpack\bgroup
792     \scratchdimen.5\d_framed_linewidth
793     \kern\scratchdimen
794     \clf_framedoutline
795       {\d_framed_target_wd-\d_framed_linewidth}%
796       {\d_framed_target_ht-\scratchdimen}%
797       {\d_framed_target_dp-\scratchdimen}%
798       \d_framed_linewidth
799     \relax
800   \egroup}
801
802\def\pack_framed_stroked_box_normal
803  {\ifx\p_framed_frame\v!closed
804     \pack_framed_stroked_box_normal_closed
805   \else
806     \pack_framed_stroked_box_normal_opened
807   \fi}
808
809\def\pack_framed_t_rule{\hrule\s!height\d_framed_linewidth\relax\kern-\d_framed_linewidth}
810\def\pack_framed_b_rule{\kern-\d_framed_linewidth\hrule\s!height\d_framed_linewidth\relax}
811\def\pack_framed_r_rule{\kern-\d_framed_linewidth\vrule\s!width \d_framed_linewidth\relax}
812\def\pack_framed_l_rule{\vrule\s!width \d_framed_linewidth\relax\kern-\d_framed_linewidth}
813
814\letcsname\??framedtop   \v!on \v!on\endcsname\pack_framed_t_rule
815\letcsname\??framedtop   \v!off\v!on\endcsname\pack_framed_t_rule
816\letcsname\??framedtop   \v!on      \endcsname\pack_framed_t_rule
817
818\letcsname\??framedbottom\v!on \v!on\endcsname\pack_framed_b_rule
819\letcsname\??framedbottom\v!off\v!on\endcsname\pack_framed_b_rule
820\letcsname\??framedbottom\v!on      \endcsname\pack_framed_b_rule
821
822\letcsname\??framedleft  \v!on \v!on\endcsname\pack_framed_l_rule
823\letcsname\??framedleft  \v!off\v!on\endcsname\pack_framed_l_rule
824\letcsname\??framedleft  \v!on      \endcsname\pack_framed_l_rule
825
826\letcsname\??framedright \v!on \v!on\endcsname\pack_framed_r_rule
827\letcsname\??framedright \v!off\v!on\endcsname\pack_framed_r_rule
828\letcsname\??framedright \v!on      \endcsname\pack_framed_r_rule
829
830% Let's see who documents this on the wiki:
831%
832% \framed
833%   [align=middle,topframe=dash,frame=off]
834%   {\samplefile{tufte}}
835% \framed
836%   [align=middle,frame=dash,dashstep=.01hs,rulethickness=1pt]
837%   {\samplefile{tufte}}
838% \framed
839%   [align=middle,frame=dash,dashstep=10pt,rulethickness=2pt,background=color,backgroundcolor=gray]
840%   {\samplefile{tufte}}
841
842\def\pack_framed_dash{on \d_framed_framedashstep off \d_framed_framedashstep}
843
844\def\pack_framed_t_rule_d{\hrule\s!height\d_framed_linewidth\pack_framed_dash\relax\kern-\d_framed_linewidth}
845\def\pack_framed_b_rule_d{\kern-\d_framed_linewidth\hrule\s!height\d_framed_linewidth\pack_framed_dash\relax}
846\def\pack_framed_r_rule_d{\kern-\d_framed_linewidth\vrule\s!width \d_framed_linewidth\pack_framed_dash\relax}
847\def\pack_framed_l_rule_d{\vrule\s!width \d_framed_linewidth\pack_framed_dash\relax\kern-\d_framed_linewidth}
848
849\letcsname\??framedtop   \v!off \v!dash\endcsname\pack_framed_t_rule_d
850\letcsname\??framedtop   \v!dash       \endcsname\pack_framed_t_rule_d
851\letcsname\??framedtop   \v!dash\v!dash\endcsname\pack_framed_t_rule_d
852
853\letcsname\??framedbottom\v!off \v!dash\endcsname\pack_framed_b_rule_d
854\letcsname\??framedbottom\v!dash       \endcsname\pack_framed_b_rule_d
855\letcsname\??framedbottom\v!dash\v!dash\endcsname\pack_framed_b_rule_d
856
857\letcsname\??framedleft  \v!off \v!dash\endcsname\pack_framed_l_rule_d
858\letcsname\??framedleft  \v!dash       \endcsname\pack_framed_l_rule_d
859\letcsname\??framedleft  \v!dash\v!dash\endcsname\pack_framed_l_rule_d
860
861\letcsname\??framedright \v!off \v!dash\endcsname\pack_framed_r_rule_d
862\letcsname\??framedright \v!dash       \endcsname\pack_framed_r_rule_d
863\letcsname\??framedright \v!dash\v!dash\endcsname\pack_framed_r_rule_d
864
865% no overlapping rules
866
867% \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}
868% \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}}
869% \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}
870% \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}
871%
872% see above, less tracing
873%
874% \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}\kern-\d_framed_linewidth}
875% \def\pack_framed_b_rules{\kern-\d_framed_linewidth\hpack{\kern\d_framed_linewidth\vrule\s!width\dimexpr\d_framed_target_wd-2\d_framed_linewidth\relax\s!height\d_framed_linewidth}}
876% \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}
877% \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}
878%
879% more modern:
880
881\def\pack_framed_rules_hrule{\hrule\s!height\d_framed_linewidth\s!left\d_framed_linewidth\s!right \d_framed_linewidth\relax}
882\def\pack_framed_rules_vrule{\vrule\s!width \d_framed_linewidth\s!top \d_framed_linewidth\s!bottom\d_framed_linewidth\relax}% \s!yoffset-\d_framed_linewidth}
883
884\def\pack_framed_t_rules{\pack_framed_rules_hrule\kern-\d_framed_linewidth}
885\def\pack_framed_b_rules{\kern-\d_framed_linewidth\pack_framed_rules_hrule}
886\def\pack_framed_r_rules{\kern-\d_framed_linewidth\pack_framed_rules_vrule}
887\def\pack_framed_l_rules{\pack_framed_rules_vrule\kern-\d_framed_linewidth}
888
889\letcsname\??framedtop   \v!small\v!small\endcsname\pack_framed_t_rules
890\letcsname\??framedtop   \v!off  \v!small\endcsname\pack_framed_t_rules
891\letcsname\??framedtop   \v!small        \endcsname\pack_framed_t_rules
892
893\letcsname\??framedbottom\v!small\v!small\endcsname\pack_framed_b_rules
894\letcsname\??framedbottom\v!off  \v!small\endcsname\pack_framed_b_rules
895\letcsname\??framedbottom\v!small        \endcsname\pack_framed_b_rules
896
897\letcsname\??framedleft  \v!small\v!small\endcsname\pack_framed_l_rules
898\letcsname\??framedleft  \v!off  \v!small\endcsname\pack_framed_l_rules
899\letcsname\??framedleft  \v!small        \endcsname\pack_framed_l_rules
900
901\letcsname\??framedright \v!small\v!small\endcsname\pack_framed_r_rules
902\letcsname\??framedright \v!off  \v!small\endcsname\pack_framed_r_rules
903\letcsname\??framedright \v!small        \endcsname\pack_framed_r_rules
904
905% \framed
906%   [width=4cm,height=3cm,rulethickness=3mm,
907%    frame=off,rightframe=on,leftframe=on,topframe=on,bottomframe=on]
908%   {}
909% \framed
910%   [width=4cm,height=3cm,rulethickness=3mm,
911%    frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=small]
912%   {}
913% \framed
914%   [width=4cm,height=3cm,rulethickness=3mm,
915%    frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=on]
916%   {}
917
918%D The next few macros are probably the most misused ones in \CONTEXT. They deal
919%D with putting rules around boxes, provide backgrounds, offer alignment features,
920%D and some more. We start with defining some booleans. These give an impression of
921%D what we are going to take into account.
922
923% todo   : \c_framed_hasoffset
924% faster : \let\c_framed_hasoffset\falseconditional
925
926\newconditional\c_framed_has_offset
927\newconditional\c_framed_has_width
928\newconditional\c_framed_has_height
929\newconditional\c_framed_has_format
930\newconditional\c_framed_is_overlaid
931\newconditional\c_framed_has_frame
932\newconditional\c_framed_has_extra_offset
933\newconditional\c_framed_text_location_none
934
935\newconstant   \c_framed_has_strut  % 0=relaxes 1=pseudostruts 2=realstruts
936
937%D \macros
938%D   {framed, setupframed}
939%D
940%D Ruled boxes are typeset using \type{\framed}. This command is quite versatile
941%D and, although some users will probably seldom use it, one cannot overlook its
942%D features.
943%D
944%D  \showsetup{setupframed}
945%D  \showsetup{framed}
946%D
947%D This general macro is a special version of an even more general case, that can
948%D easily be linked into other macros that need some kind of framing. The local
949%D version is called with an extra parameter: the variable identifier. The reason
950%D for passing this identifier between brackets lays in the mere fact that this way
951%D we can use the optional argument grabbers.
952
953\mutable\def\defaultframeoffset{.25\exheight}
954
955\installcorenamespace{regularframedlevel}
956
957\permanent\protected\def\installregularframed#1%
958  {\defineframed[#1]}
959
960\permanent\protected\def\presetlocalframed[#1]%
961  {\defineframed[#1]}
962
963% \presetlocalframed[\??framed]
964
965\newinteger\c_pack_framed_nesting
966
967\permanent\tolerant\protected\def\framed[#S#1]%
968  {\bgroup
969   \advanceby\c_pack_framed_nesting\plusone
970   \letcsname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
971   \cdef\currentframed{>\the\c_pack_framed_nesting}%
972   \pack_framed_initialize
973   \bgroup
974   \setupcurrentframed[#1]% here !, seldom no argument so no need to optimize
975   \pack_framed_process_indeed}
976
977\permanent\tolerant\protected\def\startframed[#S#1]#*[#S#2]%
978  {\bgroup
979   \ifarguments
980     \pack_framed_initialize
981     \bgroup
982   \or
983     \ifhastok={#1}%
984       \advanceby\c_pack_framed_nesting\plusone
985       \letcsname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
986       \cdef\currentframed{>\the\c_pack_framed_nesting}%
987       \pack_framed_initialize
988       \bgroup
989       \setupcurrentframed[#1]% here !
990     \else
991       \cdef\currentframed{#1}%
992       \pack_framed_initialize
993       \bgroup
994     \fi
995   \else
996     \cdef\currentframed{#1}%
997     \pack_framed_initialize
998     \bgroup
999     \setupcurrentframed[#2]% here !
1000   \fi
1001   \pack_framed_process_indeed
1002   \bgroup
1003   \ignorespaces}
1004
1005% till here
1006
1007\permanent\protected\def\stopframed
1008  {\removeunwantedspaces
1009   \egroup}
1010
1011\permanent\protected\def\normalframedwithsettings[#S#1]%
1012  {\bgroup
1013   \advanceby\c_pack_framed_nesting\plusone
1014   \letcsname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
1015   \bgroup
1016   \cdef\currentframed{>\the\c_pack_framed_nesting}%
1017   \pack_framed_initialize
1018   \setupcurrentframed[#1]%
1019   \pack_framed_process_indeed}
1020
1021%D \startbuffer
1022%D \setupframed [framecolor=yellow]          \framed{A}
1023%D \defineframed[myframed] [framecolor=blue] \myframed{B}
1024%D \setupframed [myframed] [framecolor=red]  \myframed{C}
1025%D \stopbuffer
1026%D
1027%D \typebuffer \getbuffer
1028%D
1029%D \startbuffer
1030%D \presetlocalframed[myframed]
1031%D \localframed[myframed][framecolor=green]{oeps}
1032%D \stopbuffer
1033%D
1034%D \typebuffer \getbuffer
1035
1036%D \macros
1037%D   {ifinframed}
1038%D
1039%D The normal case first presets all parameters and next starts looking for the user
1040%D supplied ones. The first step is omitted in the local case, because these are
1041%D preset at declaration time and keep their values unless explictly changed. By
1042%D presetting the variables everytime the normal command is called, we can use this
1043%D command nested, without the unwanted side effect of inheritance. The boolean is
1044%D used to speed up the color stack.
1045
1046\newif\ifinframed
1047
1048%D The next one is faster on multiple backgrounds per page. No dimensions can be
1049%D set, only frames and backgrounds.
1050
1051%% \protected\def\fastlocalframed[#1]#2[#3]#4% 3-4
1052
1053\permanent\protected\def\fastlocalframed[#1]#*[#S#2]#3%
1054  {\bgroup
1055   \cdef\currentframed{#1}%
1056   \pack_framed_initialize
1057   \setbox\b_framed_normal\hbox{#3}%
1058   \iftrialtypesetting \else
1059     \edef\m_overlay_region{\framedparameter\c!region}%
1060     \ifempty\m_overlay_region\else
1061       \pack_framed_set_region
1062     \fi
1063   \fi
1064   \setupcurrentframed[#2]%
1065   \d_framed_frameoffset  {\framedparameter\c!frameoffset}% also used in backgrounds
1066   \d_framed_framedashstep{\framedparameter\c!dashstep}%
1067   \edef\p_framed_frame{\framedparameter\c!frame}%
1068   \edef\p_framed_background{\framedparameter\c!background}%
1069   % not here, in calling macro: setups
1070   \pack_framed_remove_depth
1071   % beware, depth goes away when we have a frame, otherwise it's retained
1072   \ifx\p_framed_frame\v!overlay \orelse \ifx\p_framed_frame\v!none \else
1073     \ifchkdimexpr\framedparameter\c!rulethickness\else
1074       \d_framed_linewidth\lastchkdimension
1075     \fi
1076     \pack_framed_add_outline % real or invisible frame
1077   \fi
1078   \ifempty\p_framed_background \else
1079     \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
1080     \d_framed_backgroundoffset
1081       \ifx\p_framed_backgroundoffset\v!frame
1082         \d_framed_frameoffset
1083       \else
1084         {\p_framed_backgroundoffset}%
1085       \fi
1086     \edef\p_framed_component{\framedparameter\c!component}%
1087     \pack_framed_add_background
1088   \fi
1089   \pack_framed_restore_depth
1090   \iftrialtypesetting\orelse\ifempty\m_overlay_region\else
1091     \pack_framed_add_region
1092   \fi
1093   \box\b_framed_normal
1094   \egroup}
1095
1096%D The next macro uses a box and takes its natural width and height so these
1097%D can better be correct.
1098
1099\protected\def\pack_framed_process_box_indeed#1#2% component box (assumes parameters set and grouped usage)
1100  {%
1101  %\setbox\b_framed_normal\box#2%
1102  %\def\b_framed_normal{#2}% protected against overload
1103   \enforced\let\b_framed_normal#2%
1104   %
1105   \edef\m_overlay_region{\framedparameter\c!region}%
1106   \ifempty\m_overlay_region\else
1107     \pack_framed_set_region
1108   \fi
1109   \d_framed_frameoffset{\framedparameter\c!frameoffset}% also used in backgrounds
1110   \edef\p_framed_frame{\framedparameter\c!frame}%
1111   \edef\p_framed_background{\framedparameter\c!background}%
1112   \ifx\p_framed_frame\v!overlay \orelse \ifx\p_framed_frame\v!none \else
1113     \ifchkdimexpr\framedparameter\c!rulethickness\else
1114       \d_framed_linewidth\lastchkdimension
1115     \fi
1116     \pack_framed_add_outline % real or invisible frame
1117   \fi
1118   \ifempty\p_framed_background \else
1119     \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
1120     \d_framed_backgroundoffset
1121       \ifx\p_framed_backgroundoffset\v!frame
1122         \d_framed_frameoffset
1123       \else
1124         \p_framed_backgroundoffset
1125       \fi
1126     \edef\p_framed_component{#1}%
1127     \pack_framed_add_background
1128   \fi
1129   \ifempty\m_overlay_region\else
1130     \pack_framed_add_region
1131   \fi
1132   \box\b_framed_normal
1133   \egroup}
1134
1135\permanent\protected\def\localbackgroundframed#1% namespace component box
1136  {\bgroup
1137   \cdef\currentframed{#1}%
1138   \pack_framed_initialize
1139   \pack_framed_process_box_indeed} % group ends here
1140
1141\mutable\let\postprocessframebox\relax
1142
1143%D A nice example by Aditya:
1144%D
1145%D \starttyping
1146%D \setupframed
1147%D   [loffset=\framedparameter{hoffset},
1148%D    roffset=\framedparameter{hoffset},
1149%D    hoffset=\zeropoint]
1150%D
1151%D \defineframed[test][hoffset=1cm]
1152%D \stoptyping
1153
1154%D A byproduct of \type {\uleaders} in the 2022 math upgrade project:
1155%D
1156%D \starttyping
1157%D \startsetups adaptive:test:a
1158%D     \setbox\usedadaptivebox\vbox to \usedadaptivetotal \bgroup
1159%D         \externalfigure
1160%D           [cow.pdf]
1161%D           [width=\framedmaxwidth,
1162%D            frame=on,
1163%D            height=\usedadaptivetotal]%
1164%D    \egroup
1165%D \stopsetups
1166%D
1167%D \startsetups adaptive:test:b
1168%D     \setbox\usedadaptivebox\vbox to \usedadaptivetotal \bgroup
1169%D         \externalfigure
1170%D           [cow.pdf]
1171%D           [width=\usedadaptivewidth,
1172%D            frame=on,
1173%D            height=\usedadaptivetotal]%
1174%D    \egroup
1175%D \stopsetups
1176%D
1177%D \framed[height=18cm,align=middle,adaptive=yes,top=,bottom=] {%
1178%D     \begstrut \samplefile{tufte} \endstrut
1179%D     \par
1180%D     \adaptivevbox
1181%D       [strut=yes,setups=adaptive:test:a]
1182%D       {\showstruts\strut\hsize5cm\hss}%
1183%D     \par
1184%D     \adaptivevbox
1185%D       [strut=yes,setups=adaptive:test:b]
1186%D       {\showstruts\strut\hsize5cm\hss}%
1187%D     \par
1188%D     \begstrut \samplefile{tufte} \endstrut
1189%D }
1190%D \stoptyping
1191
1192\newdimension\d_framed_width
1193\newdimension\d_framed_height
1194\newdimension\d_framed_frameoffset
1195\newdimension\d_framed_framedashstep
1196\newdimension\d_framed_backgroundoffset
1197\newdimension\d_framed_local_offset
1198
1199% todo: protect local \framednames
1200
1201\permanent\tolerant\protected\def\localframed[#1]#*[#S#2]%
1202  {\bgroup
1203   \bgroup
1204   \cdef\currentframed{#1}%
1205   \pack_framed_initialize
1206   \setupcurrentframed[#2]% here !
1207   \pack_framed_process_indeed}
1208
1209\permanent\protected\def\directlocalframed[#1]% no optional
1210  {\bgroup
1211   \bgroup
1212   \cdef\currentframed{#1}%
1213   \pack_framed_initialize
1214   \pack_framed_process_indeed}
1215
1216\aliased\let\localframedwithsettings\localframed
1217
1218% done
1219
1220\defineinterfaceconstant {fr!analyze} {fr:analyze} % private option
1221
1222\permanent\protected\lettonothing\delayedbegstrut
1223\permanent\protected\lettonothing\delayedendstrut
1224\permanent\protected\lettonothing\delayedstrut
1225
1226\permanent\protected\lettonothing\localbegstrut
1227\permanent\protected\lettonothing\localendstrut
1228\permanent\protected\lettonothing\localstrut
1229
1230\mutable\lettonothing\localoffset
1231\mutable\lettonothing\localwidth
1232\mutable\lettonothing\localheight
1233\mutable\lettonothing\localformat
1234
1235\mutable\let\framedwidth \zeropoint
1236\mutable\let\framedheight\zeropoint
1237\mutable\let\framedoffset\zeropoint
1238
1239\pushoverloadmode
1240    \newuserunit\framedwidth  fw % checked \d_framed_width
1241    \newuserunit\framedheight fh % checked \d_framed_height
1242    \newuserunit\framedoffset fo % checked \d_framed_local_offset
1243    \newuserunit\linewidth    lw
1244\popoverloadmode
1245
1246% better a constant:
1247
1248\newconditional\c_pack_resync
1249\newconditional\c_pack_reanchor
1250
1251% \let\spac_framed_pop_local_anchors\relax
1252
1253\def\spac_framed_push_local_anchors
1254  {\ifx\p_framed_synchronize\v!yes
1255     \c_pack_resync\conditionaltrue
1256     \c_pack_reanchor\conditionaltrue
1257     \pushlocalanchors
1258   % \aftergrouped{\aftergrouped{\poplocalanchors}}%
1259     \aftergroup\poplocalanchors
1260   \orelse\ifx\p_framed_synchronize\v!text
1261     \c_pack_resync\conditionaltrue
1262     \pushlocalanchors
1263     \aftergroup\poplocalanchors
1264   \orelse\ifx\p_framed_synchronize\v!background
1265     \c_pack_reanchor\conditionaltrue
1266     \pushlocalanchors
1267     \aftergroup\poplocalanchors
1268   \else
1269     \c_pack_resync\conditionalfalse
1270     \c_pack_reanchor\conditionalfalse
1271   \fi}
1272
1273\protected\def\pack_framed_process_indeed
1274  {\d_framed_frameoffset  {\framedparameter\c!frameoffset}%
1275   \d_framed_framedashstep{\framedparameter\c!dashstep}%
1276   \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
1277   \d_framed_backgroundoffset
1278     \ifx\p_framed_backgroundoffset\v!frame
1279       \d_framed_frameoffset
1280     \else
1281       {\p_framed_backgroundoffset}%
1282     \fi
1283   % new, experimental dirty hook
1284   \framedparameter\c!extras
1285   % to get the right spacing
1286   \edef\p_framed_foregroundstyle{\framedparameter\c!foregroundstyle}%
1287   \ifempty\p_framed_foregroundstyle\else\dousestyleparameter\p_framed_foregroundstyle\fi
1288   % beware, both the frame and background offset can be overruled
1289   %
1290   \edef\p_framed_setups{\framedparameter\c!setups}%
1291   % the next macros are visible
1292   \edef\localoffset{\framedparameter\c!offset}%
1293   \edef\localwidth {\framedparameter\c!width}%
1294   \edef\localheight{\framedparameter\c!height}%
1295   \edef\localformat{\framedparameter\c!align}%
1296   %
1297   \edef\p_strut    {\framedparameter\c!strut}%
1298   % these are not
1299   \edef\p_framed_autostrut  {\framedparameter\c!autostrut}%
1300   \edef\p_framed_frame      {\framedparameter\c!frame}%
1301   \edef\p_framed_location   {\framedparameter\c!location}%
1302   \edef\p_framed_orientation{\framedparameter\c!orientation}%
1303   \edef\p_framed_anchoring  {\framedparameter\c!anchoring}%
1304   \edef\p_framed_synchronize{\framedparameter\c!synchronize}%
1305   %
1306   \edef\p_framed_autowidth  {\framedparameter\c!autowidth}%
1307   \edef\p_framed_franalyze  {\framedparameter\c!fr!analyze}% experimental option
1308   %
1309   \ifempty\p_framed_synchronize
1310     \c_pack_resync\conditionalfalse
1311     \c_pack_reanchor\conditionalfalse
1312%      \let\spac_framed_pop_local_anchors\relax
1313   \else
1314     \spac_framed_push_local_anchors
1315   \fi
1316   %
1317   \ifx\p_framed_frame\v!overlay   % no frame, no offset, no framewidth
1318     \c_framed_has_frame\conditionalfalse
1319     \let\localoffset\v!overlay
1320   \orelse\ifx\p_framed_frame\v!none % no frame, no framewidth
1321     \c_framed_has_frame\conditionalfalse
1322   \else
1323     \c_framed_has_frame\conditionaltrue
1324   \fi
1325   \ifconditional\c_framed_has_frame
1326     \ifchkdimexpr\framedparameter\c!rulethickness\else
1327       \d_framed_linewidth\lastchkdimension
1328     \fi
1329   \else
1330     \d_framed_linewidth\zeropoint
1331   \fi
1332   % 2013/03/12: a change of order (sizes before align
1333   \ifx\localwidth\v!local
1334     \setlocalhsize
1335   \fi
1336   %
1337   \forgetall % should happen after \localwidth but before align
1338   %
1339   \ifempty\localformat
1340     \c_framed_has_format\conditionalfalse
1341   \else
1342     \c_framed_has_format\conditionaltrue
1343     \dosetraggedcommand\localformat % not that fast
1344   \fi
1345   %
1346   \ifcsname\??framedoffsetalternative\localoffset\endcsname
1347     \lastnamedcs
1348   \else
1349     \framed_offset_alternative_unknown
1350   \fi
1351   \ifcsname\??framedwidthalternative\localwidth\endcsname
1352     \lastnamedcs
1353   \else
1354     \framed_width_alternative_unknown
1355   \fi
1356   \ifcsname\??framedheightalternative\localheight\endcsname
1357     \lastnamedcs
1358   \else
1359     \framed_height_alternative_unknown
1360   \fi
1361   % the next check could move to heightalternative
1362   \ifconditional\c_framed_has_height
1363     \ifcstok{\framedparameter\c!adaptive}\v!yes
1364       \let\p_framed_adaptive\s!delay
1365     \else
1366       \lettonothing\p_framed_adaptive
1367     \fi
1368   \else
1369     \lettonothing\p_framed_adaptive
1370     \edef\p_framed_lines{\framedparameter\c!lines}%
1371     \ifempty\p_framed_lines
1372     \orelse\ifcase\p_framed_lines
1373     \else
1374       \d_framed_height\p_framed_lines\lineheight
1375       \edef\localheight{\the\d_framed_height}%
1376       \c_framed_has_height\conditionaltrue
1377     \fi
1378   \fi
1379   % this is now an option: width=local
1380   %
1381   % \ifdim\d_framed_width=\hsize
1382   %   \parindent\zeropoint
1383   %   \setlocalhsize
1384   %   \d_framed_width\localhsize
1385   % \fi
1386   % i.e. disable (colsetbackgroundproblemintechniek)
1387   \advanceby\d_framed_width  -2\d_framed_local_offset
1388   \advanceby\d_framed_height -2\d_framed_local_offset
1389   \ifcsname\??framedstrutalternative\p_strut\endcsname
1390     \lastnamedcs
1391   \else
1392     \framed_offset_alternative_unknown
1393   \fi
1394   % the next check could move to strutalternative
1395   \ifcase\c_framed_has_strut % none (not even noindent)
1396     \enforced\lettonothing\localbegstrut
1397     \enforced\lettonothing\localendstrut
1398     \enforced\lettonothing\localstrut
1399   \or % no / overlay
1400     \enforced\let\localbegstrut\pseudobegstrut
1401     \enforced\let\localendstrut\pseudoendstrut
1402     \enforced\let\localstrut   \pseudostrut
1403   \else
1404     \enforced\let\localbegstrut\begstrut
1405     \enforced\let\localendstrut\endstrut
1406     \enforced\let\localstrut   \strut
1407   \fi
1408   \ifx\p_framed_autostrut\v!yes
1409     \enforced\lettonothing\delayedbegstrut
1410     \enforced\lettonothing\delayedendstrut
1411     \enforced\lettonothing\delayedstrut
1412   \else
1413     \enforced\let         \delayedbegstrut\localbegstrut
1414     \enforced\let         \delayedendstrut\localendstrut
1415     \enforced\let         \delayedstrut   \localstrut
1416     \enforced\lettonothing\localbegstrut
1417     \enforced\lettonothing\localendstrut
1418     \enforced\lettonothing\localstrut
1419   \fi
1420   \ifconditional\c_framed_has_height
1421     \enforced\let\\\pack_framed_vboxed_newline
1422     \ifconditional\c_framed_has_width
1423       \enforced\let\hairline\pack_framed_vboxed_hairline
1424       \ifconditional\c_framed_has_format
1425         \let\next\pack_framed_format_format_yes
1426       \else
1427         \let\next\pack_framed_format_format_nop
1428       \fi
1429     \else
1430       \enforced\let\hairline\pack_framed_hboxed_hairline
1431       \ifconditional\c_framed_has_format
1432         \let\next\pack_framed_format_format_height
1433       \else
1434         \let\next\pack_framed_format_format_vsize
1435       \fi
1436     \fi
1437   \orelse\ifconditional\c_framed_has_width
1438     \ifconditional\c_framed_has_format
1439       \enforced\let\\\pack_framed_vboxed_newline
1440       \enforced\let\hairline\pack_framed_vboxed_hairline
1441       \let\next\pack_framed_format_format_width
1442     \else
1443       \enforced\let\\\pack_framed_hboxed_newline
1444       \enforced\let\hairline\pack_framed_hboxed_hairline
1445       \let\next\pack_framed_format_format_hsize
1446     \fi
1447   \else
1448     \enforced\let\\\pack_framed_hboxed_newline
1449     \enforced\let\hairline\pack_framed_hboxed_hairline
1450     \let\next\pack_framed_format_format_no_size
1451   \fi
1452   \pack_framed_check_extra_offsets
1453   \edef\p_framed_background{\framedparameter\c!background}%
1454 % \ifempty\p_framed_background
1455 %   \let\pack_framed_forgetall\forgetall
1456 % \else
1457 %   \let\pack_framed_forgetall\relax
1458 %   \forgetall
1459 % \fi
1460   \edef\framedwidth {\the\ifdim\d_framed_width >\zeropoint\d_framed_width \else\zeropoint\fi}% public
1461   \edef\framedheight{\the\ifdim\d_framed_height>\zeropoint\d_framed_height\else\zeropoint\fi}% public
1462   \edef\framedoffset{\the\ifconditional\c_framed_has_offset\dimexpr\localoffset\relax\else\zeropoint\fi}% public
1463   % for now: i need to think of something better
1464 % \bitwiseflip \normalizelinemode -\clipwidthnormalizecode % now handled in analyzer
1465   % but that's for later
1466   \ifempty\p_framed_orientation
1467     \let\pack_framed_stop_orientation\relax
1468   \else
1469     \pack_framed_start_orientation
1470   \fi
1471   \afterassignment\pack_framed_restart
1472   \setbox\b_framed_normal\next}
1473
1474% alternatives for width, height, strut and offset
1475
1476\installcorenamespace{framedwidthalternative}
1477\installcorenamespace{framedheightalternative}
1478\installcorenamespace{framedstrutalternative}
1479\installcorenamespace{framedoffsetalternative}
1480
1481% widths
1482%
1483% \inframed[adaptive=0500]{Just some words}
1484% \inframed[adaptive=0]   {Just some words}
1485% \inframed[adaptive=-500]{Just some words}
1486
1487\defcsname\??framedwidthalternative\empty\endcsname
1488  {\ifconditional\c_framed_has_format
1489     \c_framed_has_width\conditionaltrue
1490     \d_framed_width\hsize
1491   \else
1492     \c_framed_has_width\conditionalfalse
1493     \d_framed_width\zeropoint
1494   \fi}
1495
1496\defcsname\??framedwidthalternative\v!fit\endcsname
1497  {\ifconditional\c_framed_has_format
1498     \c_framed_has_width\conditionaltrue
1499     \d_framed_width\hsize
1500   \else
1501     \c_framed_has_width\conditionalfalse
1502     \d_framed_width\zeropoint
1503   \fi}
1504
1505\defcsname\??framedwidthalternative\v!fixed\endcsname % equals \v!fit but no shapebox
1506  {\ifconditional\c_framed_has_format
1507     \c_framed_has_width\conditionaltrue
1508     \d_framed_width\hsize
1509   \else
1510     \c_framed_has_width\conditionalfalse
1511     \d_framed_width\zeropoint
1512   \fi}
1513
1514\defcsname\??framedwidthalternative\v!broad\endcsname
1515  {\c_framed_has_width\conditionaltrue
1516   \d_framed_width\hsize}
1517
1518\defcsname\??framedwidthalternative\v!max\endcsname % idem broad
1519  {\c_framed_has_width\conditionaltrue
1520   \d_framed_width\hsize}
1521
1522\defcsname\??framedwidthalternative\v!local\endcsname
1523  {\c_framed_has_width\conditionaltrue
1524   %\setlocalhsize
1525   \d_framed_width\localhsize}
1526
1527% \defcsname\??framedwidthalternative\s!unknown\endcsname
1528%   {\c_framed_has_width\conditionaltrue
1529%    \d_framed_width\localwidth}
1530
1531\def\framed_width_alternative_unknown
1532  {\c_framed_has_width\conditionaltrue
1533   \d_framed_width{\localwidth}}
1534
1535% heights
1536
1537\defcsname\??framedheightalternative\empty\endcsname
1538  {\c_framed_has_height\conditionalfalse
1539   \d_framed_height\zeropoint}
1540
1541\defcsname\??framedheightalternative\v!fit\endcsname
1542  {\c_framed_has_height\conditionalfalse
1543   \d_framed_height\zeropoint}
1544
1545\defcsname\??framedheightalternative\v!broad\endcsname
1546  {\c_framed_has_height\conditionalfalse
1547   \d_framed_height\zeropoint}
1548
1549\defcsname\??framedheightalternative\v!max\endcsname
1550  {\c_framed_has_height\conditionaltrue
1551   \d_framed_height\vsize}
1552
1553% \defcsname\??framedheightalternative\s!unknown\endcsname
1554%   {\c_framed_has_height\conditionaltrue
1555%    \d_framed_height\localheight}
1556
1557\def\framed_height_alternative_unknown
1558  {\c_framed_has_height\conditionaltrue
1559   \d_framed_height{\localheight}}
1560
1561% struts (use let instead?)
1562
1563\defcsname\??framedstrutalternative\v!no\endcsname
1564  {\c_framed_has_strut\plusone}
1565
1566\defcsname\??framedstrutalternative\v!global\endcsname
1567  {\setstrut}
1568
1569\defcsname\??framedstrutalternative\v!local\endcsname
1570  {\setfontstrut}
1571
1572\defcsname\??framedstrutalternative\v!yes\endcsname
1573  {\setstrut}
1574
1575\defcsname\??framedstrutalternative\s!unknown\endcsname
1576  {\setstrut}
1577
1578\def\framed_strut_alternative_unknown
1579  {\setstrut}
1580
1581\defcsname\??framedstrutalternative\v!none\endcsname % not even pseudo struts
1582  {\c_framed_has_strut\zerocount}
1583
1584% offsets
1585
1586\defcsname\??framedoffsetalternative\v!none\endcsname
1587  {\c_framed_has_offset\conditionalfalse
1588   \c_framed_has_strut\plusone
1589   \c_framed_is_overlaid\conditionalfalse
1590   \d_framed_local_offset\d_framed_linewidth}
1591
1592\defcsname\??framedoffsetalternative\v!overlay\endcsname
1593  {% \ifx\p_framed_frame\v!no \c_framed_has_frame\conditionalfalse \fi % test first
1594   \c_framed_has_offset\conditionalfalse
1595   \c_framed_has_strut\plusone
1596   \c_framed_is_overlaid\conditionaltrue
1597   \d_framed_local_offset\zeropoint}
1598
1599% \defcsname\??framedoffsetalternative\v!strut\endcsname
1600%   {\c_framed_has_offset\conditionalfalse
1601%    \c_framed_has_strut\plustwo
1602%    \c_framed_is_overlaid\conditionaltrue
1603%    \d_framed_local_offset\zeropoint}
1604
1605\defcsname\??framedoffsetalternative\v!default\endcsname % new per 2-6-2000
1606  {\c_framed_has_offset\conditionaltrue
1607   \c_framed_has_strut\plustwo
1608   \c_framed_is_overlaid\conditionalfalse
1609   \let\localoffset\defaultframeoffset
1610   \letframedparameter\c!offset\defaultframeoffset % brrr
1611   \d_framed_local_offset{\localoffset+\d_framed_linewidth}}
1612
1613\def\framed_offset_alternative_unknown
1614  {\c_framed_has_offset\conditionaltrue
1615   \c_framed_has_strut\plustwo
1616   \c_framed_is_overlaid\conditionalfalse
1617   \let\defaultframeoffset\localoffset
1618   \d_framed_local_offset{\localoffset+\d_framed_linewidth}}
1619
1620\letcsname\??framedoffsetalternative\s!unknown\endcsname\framed_offset_alternative_unknown
1621
1622% so far for alternatives
1623
1624\let\pack_framed_stop_orientation\relax
1625
1626\def\pack_framed_restart
1627  {\aftergroup\pack_framed_finish}
1628
1629\def\pack_framed_do_top
1630  {\raggedtopcommand
1631   \framedparameter\c!top
1632   \edef\p_blank{\framedparameter\c!blank}%
1633   \ifx\p_blank\v!yes\else % auto or no
1634     \doinhibitblank
1635   \fi}
1636
1637\def\pack_framed_do_bottom
1638  {\framedparameter\c!bottom
1639   \raggedbottomcommand}
1640
1641%D Careful analysis of this macro will learn us that not all branches in the last
1642%D conditionals can be encountered, that is, some assignments to \type{\next} will
1643%D never occur. Nevertheless we implement the whole scheme, if not for future
1644%D extensions.
1645
1646% %D \macros
1647% %D   {doassigncheckedframeoffset}
1648% %D
1649% %D Offset helper (see menus):
1650%
1651% \def\doassigncheckedframeoffset#1#2% could be a fast \csname .. \endcsname
1652%   {\edef\checkedframeoffset{#2}%
1653%    #1%
1654%      \ifempty\checkedframeoffset      \zeropoint\orelse
1655%      \ifx\checkedframeoffset\v!overlay\zeropoint\orelse
1656%      \ifx\checkedframeoffset\v!none   \zeropoint\orelse
1657%      \ifx\checkedframeoffset\v!frame  \zeropoint\orelse
1658%      \ifx\checkedframeoffset\v!default\zeropoint\else
1659%        #2%
1660%      \fi
1661%    \relax}
1662%
1663% \def\doassigncheckedframeoffset#1#2% could be a fast \csname .. \endcsname
1664%   {#1\ifchkdimexpr#2\or\lastchkdimension\else\zeropoint\fi}%
1665
1666%D \macros
1667%D   {ifreshapeframebox}
1668%D
1669%D The last few lines tell what to do after the content of the box is collected and
1670%D passed to the next macro. In the case of a fixed width and centered alignment,
1671%D the content is evaluated and used to determine the most natural width. The rest
1672%D of the code deals with backgrounds and frames.
1673
1674\newif\ifreshapeframebox \reshapeframeboxtrue
1675
1676%D Beware: setting \type {top} and \type {bottom} to nothing, may
1677%D result in a frame that is larger that the given height! try:
1678%D
1679%D \starttyping
1680%D \framed
1681%D   [height=3cm,top=,bottom=,offset=overlay]
1682%D   {\strut test \shapefill \strut test}
1683%D \stoptyping
1684%D
1685%D This is intended behaviour and not a bug! One can always set
1686%D
1687%D \starttyping
1688%D ...,bottom=\kern0pt,...
1689%D \stoptyping
1690
1691% experiment ... \p_framed_franalyze -> we could support 'first' as location key
1692% option but then we will always do an analysis and reimplement the location
1693% options (btw, beware of location settings of derived functionality that bleed
1694% into this
1695
1696\def\pack_framed_profile_box
1697  {\profilegivenbox\p_profile\b_framed_normal
1698   \setbox\b_framed_normal\vpack{\unvbox\b_framed_normal}}
1699
1700\def\pack_framed_reverse_box
1701  {\ifvbox\b_framed_normal
1702%      \edef\p_linedirection{\framedparameter\c!linedirection}%
1703%      \ifx\p_linedirection\v!reverse
1704     \ifcstok{\framedparameter\c!linedirection}\v!reverse
1705       \reversevboxcontent\b_framed_normal
1706       \setbox\b_framed_normal\vpack{\unvbox\b_framed_normal}%
1707     \fi
1708   \fi}
1709
1710\def\pack_framed_finish_a
1711  {\ifreshapeframebox
1712     \pack_framed_reshape_process
1713   \orelse\ifx\p_framed_franalyze\v!yes
1714     \pack_framed_reshape_analyze
1715   \else
1716     \pack_framed_reshape_reset
1717   \fi
1718   \c_framed_has_width\conditionalfalse}
1719
1720\def\pack_framed_finish_b
1721  {\ifx\p_framed_franalyze\v!yes
1722     \pack_framed_reshape_analyze
1723   \else
1724     \pack_framed_reshape_reset
1725   \fi
1726   \c_framed_has_width\conditionalfalse}
1727
1728\def\pack_framed_finish_c
1729  {\ifx\p_framed_franalyze\v!yes
1730     \pack_framed_reshape_analyze
1731   \else
1732     \pack_framed_reshape_reset
1733   \fi}
1734
1735% Musical timestamp for the adding the "freezespacing" feature: Porcupine Tree -
1736% Herd Culling (Single Edit - Official Visualiser : some old sql code scrolling by
1737% on some paper terminal font); scalefactors are in the range -1000..1000.
1738
1739\protected\def\pack_framed_finish
1740  {\ifempty{\framedparameter\c!freezespacing}\else
1741     \boxadapt\b_framed_normal\lastnamedcs\relax
1742   \fi
1743 % \ifcstok{\framedparameter\c!limit}\v!yes
1744 %   \boxlimit\b_framed_normal % maybe
1745 % \fi
1746   \pack_framed_locator_before\p_framed_location
1747   \ifconditional\c_framed_has_format
1748     \ifempty\p_framed_anchoring\else
1749       \pack_framed_reverse_box
1750     \fi
1751     \ifx\p_framed_autowidth\v!force
1752       \pack_framed_finish_a
1753     \orelse\ifx\localwidth\v!fit
1754       \ifx\p_framed_autowidth\v!yes
1755         \pack_framed_finish_a
1756       \else
1757         \pack_framed_finish_b
1758       \fi
1759     \orelse\ifx\localwidth\v!fixed
1760       \pack_framed_finish_b
1761     \else
1762       \pack_framed_finish_c
1763     \fi
1764     \ifconditional\c_framed_has_height \else
1765       \edef\p_profile{\framedparameter\c!profile}%
1766       \ifempty\p_profile\else
1767         \pack_framed_profile_box
1768       \fi
1769     \fi
1770     \ifconditional\page_postprocessors_needed_box
1771       % quite late
1772       \page_postprocessors_linenumbers_box\b_framed_normal
1773     \fi
1774   \else
1775     \pack_framed_finish_c
1776   \fi
1777   \ifconditional\c_framed_has_width
1778     \wd\b_framed_normal\d_framed_width
1779   \fi
1780   \ifconditional\c_framed_has_height
1781     \ht\b_framed_normal\d_framed_height
1782   \else
1783     \edef\p_framed_minheight{\framedparameter\c!minheight}%
1784     \ifempty\p_framed_minheight \orelse \ifdim\ht\b_framed_normal<\p_framed_minheight
1785       \ht\b_framed_normal\p_framed_minheight
1786     \fi
1787   \fi
1788   \edef\p_framed_empty{\framedparameter\c!empty}%
1789   \ifx\p_framed_empty\v!yes
1790     \pack_framed_fake_box
1791   \fi
1792   \ifempty\p_framed_anchoring\else
1793     \pack_framed_handle_anchoring
1794   \fi
1795   \pack_framed_stop_orientation % moved here at 2014-05-25
1796   \iftrialtypesetting \else
1797     \edef\m_overlay_region{\framedparameter\c!region}%
1798     \ifempty\m_overlay_region\else
1799       \pack_framed_set_region
1800     \fi
1801   \fi
1802   \d_framed_applied_offset
1803     \ifconditional\c_framed_is_overlaid
1804       \zeropoint
1805     \else
1806       \d_framed_linewidth
1807     \fi
1808   \ifconditional\c_framed_has_offset
1809     \advanceby\d_framed_applied_offset\localoffset\relax
1810   \fi
1811   \ifconditional\c_framed_has_extra_offset
1812     \pack_framed_apply_extra_offsets % includes \d_framed_applied_offset
1813   \orelse\ifzeropt\d_framed_applied_offset
1814   \else
1815     \pack_framed_widen_box
1816   \fi
1817   %
1818   \ifrelax\postprocessframebox \else
1819     % better: \pushmacro\\postprocessframebox etc
1820     \let\next\postprocessframebox
1821     \let\postprocessframebox\relax % prevent nesting
1822     \next\b_framed_normal
1823   \fi
1824   \iftrialtypesetting
1825     % new
1826   \else
1827     \ifconditional\c_framed_has_frame % real or invisible frame
1828       \pack_framed_add_outline
1829     \fi
1830     \ifempty\p_framed_background \else
1831       \edef\p_framed_component{\framedparameter\c!component}%
1832       \pack_framed_add_background
1833     \fi
1834   \fi
1835%    \pack_framed_pop_local_anchors
1836   \pack_framed_locator_after\p_framed_location
1837   \iftrialtypesetting \orelse \ifempty\m_overlay_region \else
1838     \pack_framed_add_region
1839   \fi
1840   \box\b_framed_normal
1841   \global\frameddimensionstate % global so to be used directly afterwards !
1842     \ifconditional\c_framed_has_width
1843       \ifconditional\c_framed_has_height \plusthree \else \plusone   \fi
1844     \else
1845       \ifconditional\c_framed_has_height \plustwo   \else \zerocount \fi
1846     \fi
1847   \egroup
1848   \egroup}
1849
1850%D Anchoring is experimental and was prototyped around the ctx meeting in 2018 but
1851%D never mede it into the core yet. It operates independent of the orientation
1852%D mechanism already present. It's a rather efficient feature. Best is to use
1853%D predefined orientations, like:
1854%D
1855%D \starttyping
1856%D \defineorientation[leftflushleft] [orientation=left,horizontal=flushleft]
1857%D
1858%D \framed [anchoring={leftflushleft}] {anchoring}
1859%D \stoptyping
1860%D
1861%D But this also works:
1862%D
1863%D \starttyping
1864%D \framed [anchoring={flushleft,top,up}] {anchoring}
1865%D \stoptyping
1866%D
1867%D When an anchoring is given (use \type {normal} for the default) you can also
1868%D use the \type {xanchor} and \type {yanchor} offsets.
1869
1870% because we mess with the width later on, we need double wrapping:
1871
1872\def\pack_framed_handle_anchoring
1873  {\scratchcounter\autoorientation\p_framed_anchoring\relax
1874   \edef\p_xanchor{\framedparameter\c!xanchor}%
1875   \edef\p_yanchor{\framedparameter\c!yanchor}%
1876   \setbox\b_framed_normal\hpack{\hpack % here
1877      % using the keyword approachs works ok, don't mess with orientation
1878      % directly here using \boxorientation ... it doesn't work that well
1879      \s!orientation\scratchcounter
1880      \ifempty\p_xanchor\else \s!xoffset \p_xanchor\fi
1881      \ifempty\p_yanchor\else \s!yoffset \p_yanchor\fi
1882     {\box\b_framed_normal}}}
1883
1884\installcorenamespace{framedlocatorbefore}
1885\installcorenamespace{framedlocatorafter}
1886
1887\newconstant\frameddimensionstate % global state: 0=unknown 1=width 2=height 3=both
1888
1889\def\pack_framed_fake_box
1890  {\setbox\scratchbox\emptyhbox
1891   \wd\scratchbox\wd\b_framed_normal
1892   \ht\scratchbox\ht\b_framed_normal
1893   \dp\scratchbox\dp\b_framed_normal
1894   \setbox\b_framed_normal\box\scratchbox}
1895
1896\permanent\protected\def\installframedlocator#1#2#3%
1897  {\defcsname\??framedlocatorbefore#1\endcsname{#2}%
1898   \defcsname\??framedlocatorafter #1\endcsname{#3}}
1899
1900\def\pack_framed_locator_before#1{\begincsname\??framedlocatorbefore#1\endcsname}
1901\def\pack_framed_locator_after #1{\begincsname\??framedlocatorafter #1\endcsname}
1902
1903\newdimension\d_framed_locator_ht
1904\newdimension\d_framed_locator_dp
1905\newdimension\d_framed_locator_lo
1906\newdimension\d_framed_locator_ro
1907
1908\def\pack_framed_locator_set#1%
1909  {\d_framed_locator_ht{%
1910     #1+\d_framed_linewidth
1911     \ifconditional\c_framed_has_offset
1912       +(\framedparameter\c!offset)%
1913     \fi
1914     +(\framedparameter\c!toffset)%
1915   }%
1916   \d_framed_locator_dp{\ht\b_framed_normal-\d_framed_locator_ht}}
1917
1918\def\pack_framed_locator_set_lo
1919  {\global\d_framed_locator_lo{%
1920     \d_framed_linewidth
1921     \ifconditional\c_framed_has_offset
1922       +(\framedparameter\c!offset)%
1923     \fi
1924     +(\framedparameter\c!loffset)%
1925   }}
1926
1927\def\pack_framed_locator_set_ro
1928  {\global\d_framed_locator_ro{%
1929     \d_framed_linewidth
1930     \ifconditional\c_framed_has_offset
1931       +(\framedparameter\c!offset)%
1932     \fi
1933     +(\framedparameter\c!roffset)%
1934   }}
1935
1936% \ruledhbox
1937%   {A
1938%    \framed[width=2cm,align=middle,location=hanging]{location\\equals\\hanging}
1939%    \framed[width=2cm,align=middle,location=depth]  {location\\equals\\depth}
1940%    \framed[width=2cm,align=middle,location=height] {location\\equals\\height}
1941%    B}
1942% \vskip2cm
1943% \ruledhbox
1944%   {A
1945%    \framed[width=2cm,align=middle,location=low]    {location\\equals\\low}
1946%    \framed[width=2cm,align=middle,location=line]   {location\\equals\\line}
1947%    \framed[width=2cm,align=middle,location=high]   {location\\equals\\high}
1948%    B}
1949% \vskip2cm
1950% \ruledhbox
1951%  {A
1952%   \framed[width=2cm,align=middle,location=top]    {location\\equals\\top}
1953%   \framed[width=2cm,align=middle,location=bottom] {location\\equals\\bottom}
1954%   \framed[width=2cm,align=middle,location=lohi]   {location\\equals\\lohi}
1955%   \framed[width=2cm,align=middle,location=middle] {location\\equals\\middle}
1956%   B}
1957% \vskip2cm
1958% \ruledhbox
1959%  {A
1960%   \framed[width=2cm,align=middle,location=keep]   {location\\equals\\top}
1961%   \framed[width=2cm,align=middle,location=formula {location\\equals\\bottom}
1962%   B}
1963
1964\installframedlocator \v!hanging % best with strut=no *1* / see mail to list by SB
1965  {}
1966  {\scratchdimen\ht\b_framed_normal
1967   \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
1968   \dp\b_framed_normal\scratchdimen
1969   \ht\b_framed_normal\zeropoint
1970   \box\b_framed_normal}
1971
1972\installframedlocator \v!depth % *1*
1973  {}
1974  {\setbox\b_framed_normal\hpack{\lower\strutdp\box\b_framed_normal}%
1975   \ht\b_framed_normal{\ht\b_framed_normal-\strutdp}%
1976   \dp\b_framed_normal\strutdp
1977   \box\b_framed_normal}
1978
1979\installframedlocator \v!height % *1*
1980  {}
1981  {\scratchdimen{\ht\b_framed_normal-\strutht}%
1982   \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
1983   \dp\b_framed_normal{\ht\b_framed_normal-\strutht}%
1984   \ht\b_framed_normal\strutht
1985   \box\b_framed_normal}
1986
1987\installframedlocator \v!high
1988  {}
1989  {\pack_framed_locator_set\strutht
1990   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
1991   \ht\b_framed_normal\strutht
1992   \dp\b_framed_normal\strutdp
1993   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?
1994
1995\installframedlocator \v!line
1996  {}
1997  {\setbox\b_framed_normal\hpack{\lower.5\ht\b_framed_normal\box\b_framed_normal}%
1998   \ht\b_framed_normal.5\lineheight
1999   \dp\b_framed_normal.5\lineheight
2000   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?
2001
2002\installframedlocator \v!low
2003  {}
2004  {\pack_framed_locator_set\strutdp
2005   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}%
2006   \ht\b_framed_normal\strutht
2007   \dp\b_framed_normal\strutdp
2008   \box\b_framed_normal}
2009
2010\installframedlocator \v!top
2011  {}
2012  {\pack_framed_locator_set\strutht
2013   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
2014   \ht\b_framed_normal\d_framed_locator_ht
2015   \dp\b_framed_normal\d_framed_locator_dp
2016   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?
2017
2018\installframedlocator \v!middle
2019  {}
2020  {\scratchdimen.5\ht\b_framed_normal
2021   \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
2022   \ht\b_framed_normal\scratchdimen
2023   \dp\b_framed_normal\scratchdimen
2024   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?
2025
2026\installframedlocator \v!lohi % maybe also \v!center
2027  {\pack_framed_locator_before\v!middle}
2028  {\pack_framed_locator_after \v!middle}
2029
2030\installframedlocator \v!bottom
2031  {}
2032  {\pack_framed_locator_set\strutdp
2033   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}%
2034   \ht\b_framed_normal\d_framed_locator_dp
2035   \dp\b_framed_normal\d_framed_locator_ht
2036   \hpack{\box\b_framed_normal}} %  why do we pack .. dange of loosing?
2037
2038\installframedlocator \v!keep % retains height/depth
2039  {\pack_framed_remove_depth}
2040  {\pack_framed_restore_depth}
2041
2042\newdimension\d_framed_formula
2043
2044\installframedlocator \v!formula % private, will become a more generic name
2045  {}
2046  {\pack_framed_locator_set\d_framed_formula
2047   \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
2048   \ht\b_framed_normal\d_framed_locator_ht
2049   \dp\b_framed_normal\d_framed_locator_dp
2050   \hpack{\box\b_framed_normal}} %  why do we pack .. danger of loosing?
2051
2052\installframedlocator \v!inline
2053  {}
2054  {\scratchoffset{\strutdp+\d_framed_applied_offset}%
2055   \boxyoffset\b_framed_normal{\boxyoffset\b_framed_normal-\scratchoffset}%
2056   \ht\b_framed_normal{\ht\b_framed_normal-\scratchoffset}%
2057   \dp\b_framed_normal{\strutdp+\d_framed_applied_offset}%
2058   \box\b_framed_normal}
2059
2060% also used in fastlocalframed
2061
2062\newdimension\d_framed_original_wd
2063\newdimension\d_framed_original_ht
2064\newdimension\d_framed_original_dp
2065
2066\def\pack_framed_remove_depth
2067  {\d_framed_original_wd\wd\b_framed_normal
2068   \d_framed_original_ht\ht\b_framed_normal
2069   \d_framed_original_dp\dp\b_framed_normal
2070   \ifzeropt\d_framed_original_dp\else
2071     \setbox\b_framed_normal\hpack{\raise\d_framed_original_dp\box\b_framed_normal}%
2072   \fi
2073   \wd\b_framed_normal\d_framed_original_wd
2074   \ht\b_framed_normal{\d_framed_original_ht+\d_framed_original_dp}%
2075   \dp\b_framed_normal\zeropoint}
2076
2077\def\pack_framed_restore_depth
2078  {\ifzeropt\d_framed_original_dp \else
2079     \setbox\b_framed_normal\hpack{\lower\d_framed_original_dp\box\b_framed_normal}%
2080   \fi
2081   \wd\b_framed_normal\d_framed_original_wd
2082   \ht\b_framed_normal\d_framed_original_ht
2083   \dp\b_framed_normal\d_framed_original_dp}
2084
2085% \framed[width=12cm,height=3cm,orientation=0]{\input ward\relax}
2086% \framed[width=12cm,height=3cm,orientation=90]{\input ward\relax}
2087% \framed[width=12cm,height=3cm,orientation=180]{\input ward\relax}
2088% \framed[width=12cm,height=3cm,orientation=270]{\input ward\relax}
2089% \framed[width=12cm,height=3cm,orientation=-90]{\input ward\relax}
2090% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax}
2091% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax}
2092
2093\def\pack_framed_start_orientation
2094  {\ifcase\p_framed_orientation
2095     \let\pack_framed_stop_orientation\relax
2096   \else
2097     \let\pack_framed_stop_orientation\pack_framed_stop_orientation_indeed
2098   \fi}
2099
2100\def\pack_framed_stop_orientation_indeed
2101  {\setbox\b_framed_normal\hpack{\dorotatebox\p_framed_orientation\hpack{\box\b_framed_normal}}%
2102   \d_framed_height\ht\b_framed_normal
2103   \d_framed_width \wd\b_framed_normal}
2104
2105%D The last conditional takes care of the special situation of in||line \inframed
2106%D [height=3cm] {framed} boxes. Such boxes have to be \inframed {aligned} with the
2107%D running text.
2108
2109\permanent\tolerant\protected\def\inframed[#S#1]{\framed[\c!location=\v!low,#1]}
2110
2111%D When we set \type{empty} to \type{yes}, we get ourselves a frame and/or background,
2112%D but no content, so actually we have a sort of phantom framed box.
2113
2114%D This previous framing macros needs a lot of alternatives for putting rules around
2115%D boxes, inserting offsets and aligning text. Each step is handled by separate macros.
2116
2117\newdimension\d_framed_applied_offset
2118\newdimension\d_framed_loffset
2119\newdimension\d_framed_roffset
2120\newdimension\d_framed_toffset
2121\newdimension\d_framed_boffset
2122
2123\def\pack_framed_check_extra_offsets % we could check h and v indepently
2124  {\c_framed_has_extra_offset\conditionalfalse
2125   \d_framed_loffset{\framedparameter\c!loffset}%
2126   \d_framed_roffset{\framedparameter\c!roffset}%
2127   \d_framed_toffset{\framedparameter\c!toffset}%
2128   \d_framed_boffset{\framedparameter\c!boffset}%
2129   \ifzeropt\d_framed_loffset\else \advanceby\d_framed_width -\d_framed_loffset \c_framed_has_extra_offset\conditionaltrue \fi
2130   \ifzeropt\d_framed_roffset\else \advanceby\d_framed_width -\d_framed_roffset \c_framed_has_extra_offset\conditionaltrue \fi
2131   \ifzeropt\d_framed_toffset\else \advanceby\d_framed_height-\d_framed_toffset \c_framed_has_extra_offset\conditionaltrue \fi
2132   \ifzeropt\d_framed_boffset\else \advanceby\d_framed_height-\d_framed_boffset \c_framed_has_extra_offset\conditionaltrue \fi}
2133
2134\def\pack_framed_apply_extra_offsets
2135  {\setbox\b_framed_normal\vpack\bgroup
2136     \advanceby\d_framed_toffset\d_framed_applied_offset
2137     \advanceby\d_framed_boffset\d_framed_applied_offset
2138     \advanceby\d_framed_loffset\d_framed_applied_offset
2139     \advanceby\d_framed_roffset\d_framed_applied_offset
2140     \kern\d_framed_toffset
2141     \hpack\bgroup
2142        \kern\d_framed_loffset
2143        \box\b_framed_normal
2144        \kern\d_framed_roffset
2145     \egroup
2146     \kern\d_framed_boffset
2147   \egroup}
2148
2149\def\pack_framed_widen_box
2150  {\setbox\b_framed_normal\vpack
2151     {\kern\d_framed_applied_offset
2152      \hpack{\kern\d_framed_applied_offset\box\b_framed_normal\kern\d_framed_applied_offset}%
2153      \kern\d_framed_applied_offset}}
2154
2155%D Let's hope that the next few examples show us enough of what needs to be
2156%D done by the auxiliary macros.
2157%D
2158%D \startbuffer
2159%D \framed[height=1cm,offset=.5cm]   {rule based learning}
2160%D \framed[height=1cm,offset=0cm]    {rule based learning}
2161%D \framed[height=1cm,offset=none]   {rule based learning}
2162%D \framed[height=1cm,offset=overlay]{rule based learning}
2163%D \stopbuffer
2164%D
2165%D \typebuffer
2166%D
2167%D \startlinecorrection
2168%D \hbox{\getbuffer}
2169%D \stoplinecorrection
2170%D
2171%D \startbuffer
2172%D \framed[offset=.5cm]   {rule based learning}
2173%D \framed[offset=0cm]    {rule based learning}
2174%D \framed[offset=none]   {rule based learning}
2175%D \framed[offset=overlay]{rule based learning}
2176%D \stopbuffer
2177%D
2178%D \typebuffer
2179%D
2180%D \startlinecorrection
2181%D \hbox{\getbuffer}
2182%D \stoplinecorrection
2183%D
2184%D \startbuffer
2185%D \framed[strut=no,offset=.5cm]   {rule based learning}
2186%D \framed[strut=no,offset=0cm]    {rule based learning}
2187%D \framed[strut=no,offset=none]   {rule based learning}
2188%D \framed[strut=no,offset=overlay]{rule based learning}
2189%D \stopbuffer
2190%D
2191%D \typebuffer
2192%D
2193%D \startlinecorrection
2194%D \hbox{\getbuffer}
2195%D \stoplinecorrection
2196%D
2197%D \startbuffer
2198%D \framed[width=3cm,align=left]   {rule\\based\\learning}
2199%D \framed[width=3cm,align=middle] {rule\\based\\learning}
2200%D \framed[width=3cm,align=right]  {rule\\based\\learning}
2201%D \framed[width=fit,align=middle] {rule\\based\\learning}
2202%D \stopbuffer
2203%D
2204%D \typebuffer
2205%D
2206%D \startlinecorrection
2207%D \hbox{\dontcomplain\getbuffer}
2208%D \stoplinecorrection
2209%D
2210%D So now we're ready for the complicated stuff. We distinguish between borders with
2211%D straight lines and those with round corners. When using the first alternative it
2212%D is possible to turn off one or more lines. More fancy shapes are also possible by
2213%D specifying dedicated backgrounds. Turning lines on and off is implemented as
2214%D efficient as possible and as a result is interface language dependant. This next
2215%D implementation evolved from simpler ones. It puts for instance the rules on top
2216%D of the content and provides additional offset capabilities. The lot of calls to
2217%D other macros makes this mechanism not that easy to comprehend.
2218%D
2219%D We handle left, right or middle alignment as well as fixed or free widths and
2220%D heights. Each combination gets its own macro.
2221%D
2222%D The following code handles one-liners: \type {align={line,flushright}}. Beware,
2223%D since we entered a group and either or not grab the next bgroup token, we need to
2224%D finish the group in the oneliner mode.
2225
2226\ifdefined\raggedonelinerstate \else \newconditional\raggedonelinerstate \fi
2227
2228\permanent\protected\def\doformatonelinerbox % beware: assumes explicit preceding bgroup
2229  {\ifconditional\raggedonelinerstate
2230     \expandafter\dodoformatonelinerbox
2231   \else
2232     \expandafter\nodoformatonelinerbox
2233   \fi}
2234
2235\permanent\protected\def\dodoformatonelinerbox
2236  {\afterassignment\redoformatonelinerbox
2237   \setbox\nextbox\hbox} % maybe \hpack
2238
2239\permanent\protected\def\redoformatonelinerbox
2240  {\aftergroup\dododoformatonelinerbox
2241   \ignorespaces}
2242
2243\permanent\protected\def\dododoformatonelinerbox
2244  {\hpack to \hsize % was \hbox
2245     {\ifcase\raggedstatus\or\hss\or\hss       \fi
2246      \unhbox\nextbox \removeunwantedspaces
2247      \ifcase\raggedstatus\or    \or\hss\or\hss\fi}%
2248   \egroup}
2249
2250\permanent\protected\def\nodoformatonelinerbox % grabs {
2251  {\let\next=}
2252
2253%D The handlers:
2254
2255% Beware, we have a \noindent so an empty line is indeed an empty line and
2256% the \synchronizeinlinedirection triggers a vbox instead of a line.
2257%
2258% \startTEXpage[offset=0.5ex,align={lohi,middle}]
2259%
2260%     \vbox{\hbox{x}}
2261% \stopTEXpage
2262%
2263% \startTEXpage[offset=0.5ex,align={lohi,middle}]
2264%     \vbox{\hbox{x}}
2265% \stopTEXpage
2266
2267% \def\pack_framed_forgetall{\forgetall}
2268
2269\def\pack_framed_set_foregroundcolor
2270  {\edef\p_framed_foregroundcolor{\framedparameter\c!foregroundcolor}%
2271   \ifempty\p_framed_foregroundcolor\else\dousecolorparameter\p_framed_foregroundcolor\fi}
2272
2273\def\pack_framed_do_setups
2274  {\ifempty\p_framed_setups \else
2275     \setups[\p_framed_setups]% \texsetup (or only one!)
2276   % \fastsetup\p_framed_setup % singular would have been better
2277   \fi}
2278
2279\def\pack_framed_format_format_yes
2280  {\vbox to \d_framed_height \p_framed_adaptive
2281     \bgroup
2282       \let\postprocessframebox\relax
2283     % \pack_framed_forgetall
2284       \iftrialtypesetting \else
2285         \pack_framed_set_foregroundcolor
2286       \fi
2287       \oninterlineskip
2288       \hsize\d_framed_width
2289       \vsize\d_framed_height
2290       \pack_framed_do_setups
2291       \raggedcommand
2292       \pack_framed_do_top
2293       \synchronizeinlinedirection
2294       \localbegstrut
2295       \atendofgroup\localendstrut
2296       \atendofgroup\pack_framed_do_bottom
2297       \doformatonelinerbox}
2298
2299\def\pack_framed_format_format_nop
2300  {\vbox to \d_framed_height
2301     \bgroup
2302       \let\postprocessframebox\relax
2303     % \pack_framed_forgetall
2304       \iftrialtypesetting \else
2305         \pack_framed_set_foregroundcolor
2306       \fi
2307       \oninterlineskip
2308       \hsize\d_framed_width
2309       \vsize\d_framed_height
2310       \pack_framed_do_setups
2311       \raggedcenter
2312       \vss
2313       \synchronizeinlinedirection
2314       \localbegstrut
2315       \atendofgroup\localendstrut
2316       \atendofgroup\vss
2317       \doformatonelinerbox}
2318
2319\def\pack_framed_format_format_height
2320  {\vbox to \d_framed_height
2321     \bgroup
2322       \let\postprocessframebox\relax
2323     % \pack_framed_forgetall
2324       \iftrialtypesetting \else
2325         \pack_framed_set_foregroundcolor
2326       \fi
2327       \oninterlineskip
2328       \pack_framed_do_setups
2329       \raggedcommand
2330       \vss
2331       \synchronizeinlinedirection
2332       \localbegstrut
2333       \atendofgroup\localendstrut
2334       \atendofgroup\vss
2335       \doformatonelinerbox}
2336
2337\def\pack_framed_format_format_width
2338  {\vbox
2339     \bgroup
2340       \let\postprocessframebox\relax
2341     % \pack_framed_forgetall
2342       \iftrialtypesetting \else
2343         \pack_framed_set_foregroundcolor
2344       \fi
2345       \oninterlineskip
2346       \hsize\d_framed_width
2347       \pack_framed_do_setups
2348       \raggedcommand
2349       \pack_framed_do_top
2350       \synchronizeinlinedirection
2351       \localbegstrut
2352       \atendofgroup\localendstrut
2353       \atendofgroup\pack_framed_do_bottom
2354       \doformatonelinerbox}
2355
2356\def\pack_framed_format_format_vsize
2357  {\vbox to \d_framed_height % no vpack .. maybe grid
2358     \bgroup
2359       \let\postprocessframebox\relax
2360     % \pack_framed_forgetall
2361       \iftrialtypesetting \else
2362         \pack_framed_set_foregroundcolor
2363       \fi
2364       \vsize\d_framed_height
2365       \pack_framed_do_setups
2366       \vss
2367       \atendofgroup\vss
2368       \hbox
2369         \bgroup
2370         \aftergroup\egroup
2371         \synchronizeinlinedirection
2372         \localstrut
2373         \doformatonelinerbox}
2374
2375\def\pack_framed_format_format_hsize
2376  {\hbox to \d_framed_width
2377     \bgroup
2378       \let\postprocessframebox\relax
2379     % \pack_framed_forgetall
2380       \iftrialtypesetting \else
2381         \pack_framed_set_foregroundcolor
2382       \fi
2383       \pack_framed_do_setups
2384       \hss
2385       \synchronizeinlinedirection
2386       \localstrut
2387       \atendofgroup\hss
2388       \doformatonelinerbox}
2389
2390\def\pack_framed_format_format_no_size
2391  {\hbox
2392     \bgroup
2393       \iftrialtypesetting \else
2394         \pack_framed_set_foregroundcolor
2395       \fi
2396       \let\postprocessframebox\relax
2397       \pack_framed_do_setups
2398       \synchronizeinlinedirection
2399       \localstrut
2400       \doformatonelinerbox}
2401
2402%D On the next page we show some examples of how these macros come into action. The
2403%D examples show us how \type {fit}, \type {broad} dimensions influence the
2404%D formatting. Watch the visualized struts. \footnote {Here we used \type
2405%D {\showstruts}.}
2406%D
2407%D \startpostponing
2408%D \bgroup
2409%D \showstruts
2410%D \dontcomplain
2411%D \starttabulate[|c|c|c|c|c|c|]
2412%D % \HL
2413%D \NC \framed[width=.2\hsize, height=.2\hsize, align=]       {a\endgraf b\endgraf c}
2414%D \NC \framed[width=.2\hsize, height=broad,    align=]       {a\endgraf b\endgraf c}
2415%D \NC \framed[width=.2\hsize, height=fit,      align=]       {a\endgraf b\endgraf c}
2416%D \NC \framed[width=fit,      height=.2\hsize, align=]       {a\endgraf b\endgraf c}
2417%D \NC \framed[width=fit,      height=broad,    align=]       {a\endgraf b\endgraf c}
2418%D \NC \framed[width=fit,      height=fit,      align=]       {a\endgraf b\endgraf c}
2419%D \NC \NR
2420%D % \HL
2421%D \NC \framed[width=.2\hsize, height=.2\hsize, align=yes]    {a\endgraf b\endgraf c}
2422%D \NC \framed[width=.2\hsize, height=broad,    align=yes]    {a\endgraf b\endgraf c}
2423%D \NC \framed[width=.2\hsize, height=fit,      align=yes]    {a\endgraf b\endgraf c}
2424%D \NC \framed[width=fit,      height=.2\hsize, align=yes]    {a\endgraf b\endgraf c}
2425%D \NC \framed[width=fit,      height=broad,    align=yes]    {a\endgraf b\endgraf c}
2426%D \NC \framed[width=fit,      height=fit,      align=yes]    {a\endgraf b\endgraf c}
2427%D \NC \NR
2428%D % \HL
2429%D \NC \framed[width=.2\hsize, height=.2\hsize, align=right]  {a\endgraf b\endgraf c}
2430%D \NC \framed[width=.2\hsize, height=broad,    align=right]  {a\endgraf b\endgraf c}
2431%D \NC \framed[width=.2\hsize, height=fit,      align=right]  {a\endgraf b\endgraf c}
2432%D \NC \framed[width=fit,      height=.2\hsize, align=right]  {a\endgraf b\endgraf c}
2433%D \NC \framed[width=fit,      height=broad,    align=right]  {a\endgraf b\endgraf c}
2434%D \NC \framed[width=fit,      height=fit,      align=right]  {a\endgraf b\endgraf c}
2435%D \NC \NR
2436%D % \HL
2437%D \NC \framed[width=.2\hsize, height=.2\hsize, align=left]   {a\endgraf b\endgraf c}
2438%D \NC \framed[width=.2\hsize, height=broad,    align=left]   {a\endgraf b\endgraf c}
2439%D \NC \framed[width=.2\hsize, height=fit,      align=left]   {a\endgraf b\endgraf c}
2440%D \NC \framed[width=fit,      height=.2\hsize, align=left]   {a\endgraf b\endgraf c}
2441%D \NC \framed[width=fit,      height=broad,    align=left]   {a\endgraf b\endgraf c}
2442%D \NC \framed[width=fit,      height=fit,      align=left]   {a\endgraf b\endgraf c}
2443%D \NC \NR
2444%D % \HL
2445%D \NC \framed[width=.2\hsize, height=.2\hsize, align=middle] {a\endgraf b\endgraf c}
2446%D \NC \framed[width=.2\hsize, height=broad,    align=middle] {a\endgraf b\endgraf c}
2447%D \NC \framed[width=.2\hsize, height=fit,      align=middle] {a\endgraf b\endgraf c}
2448%D \NC \framed[width=fit,      height=.2\hsize, align=middle] {a\endgraf b\endgraf c}
2449%D \NC \framed[width=fit,      height=broad,    align=middle] {a\endgraf b\endgraf c}
2450%D \NC \framed[width=fit,      height=fit,      align=middle] {a\endgraf b\endgraf c}
2451%D \NC \NR
2452%D % \HL
2453%D \stoptabulate
2454%D \egroup
2455%D \stoppostponing
2456
2457%D \macros
2458%D   {framednoflines, framedlastlength}
2459%D
2460%D It is possible to let the frame macro calculate the width of a centered box
2461%D automatically (\type {fit}). When doing so, we need to reshape the box:
2462
2463% \newinteger  \framednoflines
2464% \newdimension\framedfirstheight
2465% \newdimension\framedlastdepth
2466% \newdimension\framedminwidth
2467% \newdimension\framedmaxwidth
2468% \newdimension\framedaveragewidth
2469
2470\def\pack_framed_reshape_reset
2471  {\framednoflines    \zerocount
2472   \framedfirstheight \zeropoint
2473   \framedlastdepth   \zeropoint
2474   \framedminwidth    \zeropoint
2475   \framedmaxwidth    \zeropoint
2476   \framedaveragewidth\zeropoint}
2477
2478\def\pack_framed_reshape_process
2479  {\ifvbox\b_framed_normal
2480     \ifconditional\c_pack_resync
2481       \clf_doresyncframedbox
2482     \else
2483       \clf_doreshapeframedbox
2484     \fi\b_framed_normal\relax
2485     \ifx\p_framed_adaptive\s!delay
2486       \adaptivecheckbox\b_framed_normal
2487     \fi
2488   \fi}
2489
2490\def\pack_framed_reshape_analyze
2491  {\ifvbox\b_framed_normal
2492     \ifconditional\c_pack_resync
2493       \clf_doresyncframedbox
2494     \else
2495       \clf_doanalyzeframedbox
2496     \fi\b_framed_normal\relax
2497   \fi}
2498
2499% torture test / strange case (much depth) / method 2 needed
2500%
2501% \startTEXpage[frame=on]
2502% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
2503% test outside formula
2504% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
2505% \blank[big]
2506% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
2507% test outside formula
2508% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
2509% \stopTEXpage
2510
2511%D The examples on the next page show how one can give the frame as well as the
2512%D background an additional offset and even a bit more depth. The blue outline is
2513%D the frame, the red box is the background and the small black outline is the
2514%D visualization of the resulting box, that is, we applied \type {\ruledhbox} to
2515%D the result.
2516%D
2517%D \startpostponing
2518%D \bgroup
2519%D \unprotect
2520%D \dontcomplain
2521%D
2522%D \startbuffer
2523%D \unprotect
2524%D \vbox to \vsize
2525%D   \bgroup
2526%D     \startalignment[middle]
2527%D     \vss
2528%D     \dontleavehmode\vbox to .8\vsize
2529%D       \bgroup
2530%D         \hsize=300pt
2531%D         \setupframed
2532%D           [background=color,
2533%D            backgroundcolorachtergrondkleur=darkred,
2534%D            width=300pt,
2535%D            height=60pt,
2536%D            framecolorkaderkleur=DemoBlue,
2537%D            rulethickness=2pt]
2538%D         \def\status%
2539%D           {backgroundoffset=\the\dimexpr\framedparameter\c!backgroundoffset\relax\\
2540%D            frameoffset=\the\dimexpr\framedparameter\c!frameoffset\relax\\
2541%D            depth=\the\dimexpr\framedparameter\c!depth\relax}
2542%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=0pt]{\status}}
2543%D         \vss
2544%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=0pt]{\status}}
2545%D         \vss
2546%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=5pt]{\status}}
2547%D         \vss
2548%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=2pt,frameoffset=5pt]{\status}}
2549%D         \vss
2550%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=2pt]{\status}}
2551%D         \vss
2552%D         \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=5pt]{\status}}
2553%D       \egroup
2554%D     \vss
2555%D     \stopalignment
2556%D     \egroup
2557%D \protect
2558%D \stopbuffer
2559%D
2560%D \getbuffer \page
2561%D
2562%D {\setupframed[depth=4pt]\getbuffer} \page
2563%D
2564%D \protect
2565%D \egroup
2566%D \stoppostponing
2567
2568%D We can draw lines from left to right and top to bottom by using the normal \type
2569%D {\hairline} command. Both directions need a different treatment.
2570%D
2571%D \startbuffer
2572%D \framed[width=4cm]           {alfa\hairline beta\hairline gamma}
2573%D \framed[height=2cm]            {alfa\hairline beta\hairline gamma}
2574%D \framed[width=4cm,height=2cm]{alfa\hairline beta\hairline gamma}
2575%D \stopbuffer
2576%D
2577%D \typebuffer
2578%D
2579%D \startlinecorrection
2580%D \hbox{\getbuffer}
2581%D \stoplinecorrection
2582%D
2583%D These macros try to adapt their behaviour as good as possible to the circumstances
2584%D and act as natural as possible.
2585
2586\protected\def\pack_framed_vboxed_hairline % nasty overlay mess .. needed for autowidth
2587  {\begingroup
2588   \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi
2589   \scratchwidth{\scratchoffset+\d_framed_linewidth}%
2590   \par
2591   \nointerlineskip
2592   \kern\scratchoffset
2593   \dontleavehmode
2594     \hrule\s!height\d_framed_linewidth\s!depth\zeropoint
2595   \par
2596   \kern-\d_framed_linewidth
2597   \dontleavehmode
2598     \hpack to \zeropoint{\hss\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth}%
2599     \hfill
2600     \hpack to \zeropoint{\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth\hss}%
2601   \par
2602   \nointerlineskip
2603   \kern\scratchoffset
2604   \nointerlineskip
2605   \endgraf
2606   \nointerlineskip
2607   \localbegstrut
2608   \endgroup}
2609
2610\protected\def\pack_framed_hboxed_hairline % use framed dimen
2611  {\bgroup
2612   \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi
2613   \ifconditional\c_framed_has_height
2614     \dimen\scratchheight{\localheight/\plustwo+\strutdp-\plustwo\d_framed_linewidth}%
2615     \dimen\scratchdepth {\localheight/\plustwo-\strutdp+\plustwo\d_framed_linewidth}%
2616   \else
2617     \dimen\scratchheight{\strutht+\scratchoffset}%
2618     \dimen\scratchdepth {\strutdp+\scratchoffset}%
2619   \fi
2620   \unskip
2621   \setbox\scratchbox\hpack
2622     {\kern\scratchoffset
2623      \vrule\s!height\dimen\scratchheight\s!depth\dimen\scratchdepth\s!width\d_framed_linewidth
2624      \kern\scratchoffset}%
2625   \ht\scratchbox\strutht
2626   \dp\scratchbox\strutdp
2627   \box\scratchbox
2628   \ignorespaces
2629   \egroup}
2630
2631%D The argument of the frame command accepts \type{\\} as a sort of newline signal. In
2632%D horizontal boxes it expands to a space.
2633
2634\protected\def\pack_framed_vboxed_newline
2635  {\endgraf\ignorespaces}
2636
2637\protected\def\pack_framed_hboxed_newline
2638  {\unskip\normalspace\ignorespaces}
2639
2640%D We can set each rule on or off. The default setting is inherited from
2641%D \type {frame}. An earlier implementation use a bit different approach, but the new
2642%D one seems more natural:
2643%D
2644%D \bgroup
2645%D \setuptyping[margin=0pt]
2646%D \startlinecorrection
2647%D \startbuffer
2648%D \framed[offset=overlay,frame=on]{\darkred\blackrule}
2649%D \stopbuffer
2650%D \hbox{\getbuffer\vbox{\typebuffer}}
2651%D
2652%D \startbuffer
2653%D \framed[offset=overlay,frame=on,bottomframe=off]{\darkred\blackrule}
2654%D \stopbuffer
2655%D \hbox{\getbuffer\vbox{\typebuffer}}
2656%D
2657%D \startbuffer
2658%D \framed[offset=overlay,frame=on,bottomframe=on]{\darkred\blackrule}
2659%D \stopbuffer
2660%D \hbox{\getbuffer\vbox{\typebuffer}}
2661%D
2662%D \startbuffer
2663%D \framed[offset=overlay,frame=off]{\darkred\blackrule}
2664%D \stopbuffer
2665%D \hbox{\getbuffer\vbox{\typebuffer}}
2666%D
2667%D \startbuffer
2668%D \framed[offset=overlay,frame=off,bottomframe=off]{\darkred\blackrule}
2669%D \stopbuffer
2670%D \hbox{\getbuffer\vbox{\typebuffer}}
2671%D
2672%D \startbuffer
2673%D \framed[offset=overlay,frame=off,bottomframe=on]{\darkred\blackrule}
2674%D \stopbuffer
2675%D \hbox{\getbuffer\vbox{\typebuffer}}
2676%D \stoplinecorrection
2677%D \egroup
2678
2679%D \macros
2680%D   {startframedtext, setupframedtexts, defineframedtext}
2681%D
2682%D The general framing command we discussed previously, is not entirely suited for
2683%D what we call framed texts, as for instance used in intermezzo's. The next
2684%D examples show what we have in mind.
2685%D
2686%D \startbuffer[framed-0]
2687%D \setupframedtexts
2688%D   [frame=off,
2689%D    width=\hsize,
2690%D    background=screen]
2691%D
2692%D \startframedtext
2693%D By default the framed text is centered \dots
2694%D \stopframedtext
2695%D
2696%D \startframedtext[right]
2697%D \dots\ but we can also align left, middle and right.
2698%D \stopframedtext
2699%D \stopbuffer
2700%D
2701%D \startbuffer[framed-1]
2702%D \defineframedtext
2703%D   [Example]
2704%D   [width=6cm,
2705%D    height=5cm]
2706%D
2707%D \startExample
2708%D \typebuffer[framed-1]
2709%D \stopExample
2710%D \stopbuffer
2711%D
2712%D \startbuffer[framed-2]
2713%D \defineframedtext
2714%D   [Example]
2715%D   [width=6cm]
2716%D
2717%D \startExample
2718%D \typebuffer[framed-2]
2719%D \stopExample
2720%D \stopbuffer
2721%D
2722%D \startbuffer[framed-3]
2723%D \defineframedtext
2724%D   [Example]
2725%D   [height=5cm]
2726%D
2727%D \startExample
2728%D \typebuffer[framed-3]
2729%D \stopExample
2730%D \stopbuffer
2731%D
2732%D \startbuffer[framed-4]
2733%D \defineframedtext
2734%D   [Example]
2735%D   [width=fit,height=broad]
2736%D
2737%D \Example{a very exciting example}
2738%D \stopbuffer
2739%D
2740%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-0] \egroup
2741%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-1] \egroup
2742%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-2] \egroup
2743%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-3] \egroup
2744%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-4] \egroup
2745%D
2746%D Here we can see that we have a predefined framed text class as well as the
2747%D tools for defining our own. So we have:
2748%D
2749%D \showsetup{setupframedtexts}
2750%D
2751%D as well as the definition command:
2752%D
2753%D \showsetup{defineframedtext}
2754%D
2755%D that generates two commands:
2756%D
2757%D \showsetup{start<<framedtext>>}
2758%D \showsetup{<<framedtext>>}
2759%D
2760%D The next definition shows the defaults.
2761
2762\installcorenamespace{framedtext}
2763\installcorenamespace{framedtextlocation}
2764
2765\installframedcommandhandler \??framedtext {framedtext} \??framedtext
2766
2767\let\setupframedtexts\setupframedtext
2768
2769\setupframedtext
2770  [\c!width=.75\hsize,
2771   \c!height=\v!fit,
2772   \c!align=\v!yes,
2773  %\c!top=,
2774   \c!bottom=\vfill,
2775   \c!offset=1em,
2776  %\c!bodyfont=,
2777  %\c!style=,
2778  %\c!color=,
2779  %\c!left=,
2780   \c!right=\hfill,
2781   \c!before=\blank,
2782   \c!after=\blank,
2783  %\c!inner=,
2784   \c!frame=\v!on,
2785  %\c!topframe=,
2786  %\c!bottomframe=,
2787  %\c!leftframe=,
2788  %\c!rightframe=,
2789   \c!radius=.5\bodyfontsize,
2790   \c!corner=\v!rectangular,
2791  %\c!orientation=,
2792  %\c!indenting=,
2793  %\c!foregroundcolor=,
2794  %\c!foregroundstyle=,
2795  %\c!background=,
2796  %\c!backgroundcolor=,
2797   \c!linecorrection=\v!on,
2798   \c!depthcorrection=\v!on,
2799   \c!margin=\v!standard]
2800
2801\appendtoks
2802    \frozen\instance\protected\edefcsname\e!start\currentframedtext\endcsname{\pack_framed_text_start [\currentframedtext]}%
2803    \frozen\instance\protected\edefcsname\e!stop \currentframedtext\endcsname{\pack_framed_text_stop                      }%
2804    \frozen\instance\protected\edefcsname        \currentframedtext\endcsname{\pack_framed_text_direct[\currentframedtext]}%
2805\to \everydefineframedtext
2806
2807\defcsname\??framedtextlocation\v!left\endcsname
2808  {\letframedtextparameter\c!left \relax
2809   \letframedtextparameter\c!right\hfill}
2810
2811\defcsname\??framedtextlocation\v!right\endcsname
2812  {\letframedtextparameter\c!left \hfill
2813   \letframedtextparameter\c!right\relax}
2814
2815\defcsname\??framedtextlocation\v!middle\endcsname
2816  {\letframedtextparameter\c!left \hfill
2817   \letframedtextparameter\c!right\hfill}
2818
2819\defcsname\??framedtextlocation\v!none\endcsname
2820  {\letframedtextparameter\c!left \relax
2821   \letframedtextparameter\c!right\relax
2822   \c_framed_text_location_none\conditionaltrue}
2823
2824\tolerant\protected\def\pack_framed_text_start[#1]#*[#S#2]#*[#S#3]% or #1#*[#2]#*[#3]% and pass {#1}
2825  {\bgroup
2826   \cdef\currentframedtext{#1}%
2827   \doifelseassignment{#2}%
2828     {\pack_framed_text_start_indeed\empty{#2}}
2829     {\pack_framed_text_start_indeed{#2}{#3}}}
2830
2831% todo: sort out first/lastline ht/dp . . will be a more advanced mechanism some day (soon)
2832
2833\def\pack_framed_text_start_indeed#1#2%
2834  {\setupframedtexts[\currentframedtext][#2]%
2835   \ifempty{#1}\else
2836     \setframedtextparameter\c!location{#1}% does not listen to #3
2837   \fi
2838   \c_framed_text_location_none\conditionalfalse
2839   \begincsname\??framedtextlocation\framedtextparameter\c!location\endcsname
2840   \resetframedtextparameter\c!location
2841   \pack_framed_text_check
2842   \setbox\b_framed_normal\vbox % \vpack
2843     \startboxedcontent
2844       \hsize\localhsize
2845    %  \insidefloattrue % ? better
2846       \usebodyfontparameter\framedtextparameter
2847    %  \edef\p_framed_text_strut{\letframedtextparameter\c!strut}% to be used
2848       \letframedtextparameter\c!strut\v!no
2849       \inheritedframedtextframed\bgroup
2850         \enforced\let\\\endgraf
2851         \edef\p_framed_text_depthcorrection{\framedtextparameter\c!depthcorrection}%
2852         \ifx\p_framed_text_depthcorrection\v!on
2853            \pack_framed_text_start_depth_correction
2854         \else
2855            \bgroup
2856         \fi
2857         % no longer: \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
2858         \doinhibitblank
2859         \useindentingparameter\framedtextparameter
2860         \useframedtextstyleandcolor\c!style\c!color
2861         \framedtextparameter\c!inner
2862         \ignorespaces}
2863
2864% testcase 1:
2865%
2866% \showstruts
2867% \startframedtext[align={normal,tolerant},offset=0pt] \input tufte \stopframedtext
2868% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \input tufte \stopframedtext
2869% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \inframed{x} \stopframedtext
2870% \framed[align={normal,tolerant},offset=0pt]{\input tufte }
2871
2872%D The \type {none} option is handy for nested usage, as in the presentation
2873%D styles, where we don't want interference.
2874
2875\defineplacement[\??framedtext][\s!parent=\??framedtext\currentframedtext]
2876
2877\protected\def\pack_framed_text_stop % no \baselinecorrection, see faq docs
2878  {\endgraf
2879   \removelastskip
2880   \ifx\p_framed_text_depthcorrection\v!on
2881     \pack_framed_text_stop_depth_correction
2882   \else
2883     \egroup
2884   \fi
2885   \stopboxedcontent
2886   \ifconditional\c_framed_text_location_none
2887     \egroup
2888     \box\b_framed_normal
2889   \orelse\ifinsidefloat
2890     \egroup
2891     \box\b_framed_normal
2892   \else
2893     \egroup
2894     \placement[\??framedtext][\c!depthcorrection=\v!off]{\box\b_framed_normal}%
2895   \fi
2896   \egroup}
2897
2898%D We define the general (and original) case by just saying:
2899
2900\def\pack_framed_text_check % messy dependency
2901  {\localhsize\hsize
2902   \ifinsidefloat \orelse \ifdim\d_page_sides_vsize>\zeropoint % also possible: \c_page_sides_checks_done>\zeropoint
2903   % \strut            % rather clean way to invoke the sidefloat OTR
2904   % \setbox0=\lastbox % and get the widths set, so from now on we
2905   % \setlocalhsize    % can have framed texts alongside sidefloats
2906     \checksidefloat
2907     \setlocalhsize
2908   \fi}
2909
2910\def\pack_framed_text_start_depth_correction
2911  {\bgroup
2912   \ifhmode
2913     \par
2914   \fi
2915   \ifvmode
2916     \verticalstrut
2917     % we need \nowhitespace in case of setups setting whitespace
2918     % nb, not safe, text vs \vbox as next
2919     \vskip-\struttotal
2920     \nowhitespace
2921   \fi} % na vskip ! new 20/05/2004, fails with next content being box (\scale{..})
2922
2923\def\pack_framed_text_stop_depth_correction
2924  {\ifhmode
2925     \par
2926   \fi
2927   \ifvmode
2928     \forgetall
2929     \vskip-\struttotal
2930     \verticalstrut
2931     \egroup
2932     \forgetall % brrr too often
2933     \vskip-\lineheight
2934     \verticalstrut
2935   \else
2936     \egroup
2937   \fi}
2938
2939%D Placement can be ignored:
2940%D
2941%D \starttyping
2942%D \hbox to \hsize \bgroup
2943%D     \startframedtext[none][width=.5\textwidth] \input tufte \stopframedtext
2944%D     \startframedtext[none][width=.5\textwidth] \input zapf  \stopframedtext
2945%D \egroup
2946%D
2947%D \hbox to \hsize \bgroup
2948%D     \setupframedtexts[location=none]%
2949%D     \startframedtext[width=.5\textwidth] \input zapf  \stopframedtext
2950%D     \startframedtext[width=.5\textwidth] \input tufte \stopframedtext
2951%D \egroup
2952%D \stoptyping
2953
2954%D The simple brace (or group) delimited case is typeset slightly different
2955%D and is not aligned.
2956
2957\let\pack_framed_strut\relax
2958
2959\tolerant\protected\def\pack_framed_text_direct[#1]#*[#S#2]%
2960  {\bgroup
2961   \cdef\currentframedtext{#1}%
2962   \usebodyfontparameter\framedtextparameter
2963   \setupcurrentframedtext[#2]%
2964   \edef\p_framed_text_strut{\framedtextparameter\c!strut}%
2965   \letframedtextparameter\c!strut\v!no
2966   \inheritedframedtextframed\bgroup
2967     \blank[\v!disable]%
2968     \enforced\let\\\endgraf
2969     \useframedtextstyleandcolor\c!style\c!color
2970     % no longer: \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
2971     \framedtextparameter\c!inner
2972     \ifx\p_framed_text_strut\v!no
2973        \let\pack_framed_strut\relax
2974     \else
2975        \let\pack_framed_strut\strut
2976     \fi
2977     \bgroup
2978     \aftergroup\pack_framed_text_stop_direct
2979     \afterassignment\ignorespaces
2980     \afterassignment\pack_framed_strut
2981     \let\next=}
2982
2983\def\pack_framed_text_stop_direct
2984  {\removelastskip
2985   \egroup
2986   \egroup}
2987
2988\defineframedtext
2989  [\v!framedtext]
2990
2991%D \macros
2992%D   {defineframed}
2993%D
2994%D One can also define simple framed texts, using:
2995%D
2996%D \showsetup{defineframed}
2997%D
2998%D As suggested by Wolfgang we can now use the new \MKIV\ inheritance model instead
2999%D of passing a combination of arguments. This also also simplified the \type
3000%D {\setupframed} command. There are certainly more places where such improvements
3001%D can be made.
3002
3003\appendtoks
3004    \ifcsname\??regularframedlevel\currentframed\endcsname
3005      % already defined, keeps settings
3006    \else
3007      \expandafter\newinteger\csname\??regularframedlevel\currentframed\endcsname
3008    \fi
3009\to \everypresetframed
3010
3011\appendtoks
3012    \frozen\instance\protected\edefcsname\currentframed\endcsname{\pack_framed_defined_process[\currentframed]}%
3013\to \everydefineframed
3014
3015\newinteger\c_temp_framed_crap
3016
3017% \permanent\tolerant\protected\def\pack_framed_defined_process[#1]#*[#2]% official (not much checking, todo: parent)
3018%   {\bgroup
3019%    \ifcsname\??regularframedlevel#1\endcsname
3020%     %\expandafter\let\expandafter\c_pack_framed_temp\csname\??regularframedlevel#1\endcsname
3021%      \expandafter\let\expandafter\c_pack_framed_temp\lastnamedcs
3022%    \else
3023%      \let\c_pack_framed_temp\c_temp_framed_crap
3024%    \fi
3025%    \advanceby\c_pack_framed_temp\plusone
3026%    \defcsname\??framed#1>\the\c_pack_framed_temp:\s!parent\endcsname{\??framed#1}% \inheritlocalframed
3027%    \bgroup
3028%    \cdef\currentframed{#1>\the\c_pack_framed_temp}%
3029%    \pack_framed_initialize
3030%    \setupcurrentframed[#2]% here !
3031%    \pack_framed_process_indeed}
3032
3033\permanent\tolerant\protected\def\pack_framed_defined_process[#1]#*[#S#2]% official (not much checking, todo: parent)
3034  {\bgroup
3035   \ifcsname\??regularframedlevel#1\endcsname
3036    %\expandafter\let\expandafter\c_pack_framed_temp\csname\??regularframedlevel#1\endcsname
3037     \scratchcounter\lastnamedcs
3038   \else
3039     \scratchcounter\c_temp_framed_crap
3040   \fi
3041   \advanceby\scratchcounter\plusone
3042   \defcsname\??framed#1>\the\scratchcounter:\s!parent\endcsname{\??framed#1}% \inheritlocalframed
3043   \bgroup
3044   \cdef\currentframed{#1>\the\scratchcounter}%
3045   \pack_framed_initialize
3046   \setupcurrentframed[#2]% here !
3047   \pack_framed_process_indeed}
3048
3049\aliased\let\placeframed\pack_framed_defined_process % new per 2012/04/23
3050
3051%D We can do:
3052%D
3053%D \starttyping
3054%D \defineframed[\v!framed]
3055%D \stoptyping
3056%D
3057%D but the existing one is ok as well (less csname messy too).
3058
3059%D New, for the moment private; let's see when GB finds out about this one and its
3060%D obscure usage. It's used in:
3061%D
3062%D \startbuffer
3063%D \defineframedtext
3064%D   [tabulateframe]
3065%D   [offset=overlay,
3066%D    backgroundoffset=3pt,
3067%D    background=color,
3068%D    backgroundcolor=green]
3069%D
3070%D \setuptabulate
3071%D   [tabulate]
3072%D   [frame=tabulateframe]
3073%D
3074%D \setuptables
3075%D   [frame=tabulateframe]
3076%D
3077%D \input tufte
3078%D
3079%D \starttabulate[|l|l|]
3080%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
3081%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
3082%D \stoptabulate
3083%D
3084%D \input tufte
3085%D
3086%D \starttable[|l|l|]
3087%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
3088%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
3089%D \stoptable
3090%D \stopbuffer
3091%D
3092%D \typebuffer
3093
3094\installcorenamespace{framedcontent}
3095
3096\installframedcommandhandler \??framedcontent {framedcontent} \??framedcontent
3097
3098\setupframedcontent
3099  [\c!leftoffset=\zeropoint,
3100  %\c!rightoffset=\framedcontentparameter\c!leftoffset,
3101   \c!rightoffset=\scratchleftoffset,
3102   \c!topoffset=\zeropoint,
3103  %\c!bottomoffset=\framedcontentparameter\c!topoffset,
3104   \c!bottomoffset=\scratchtopoffset,
3105   \c!strut=\v!no,
3106  %\c!linecorrection=\v!no,
3107  %\c!left=,
3108  %\c!right=,
3109  %\c!width=\v!fit,
3110   \c!offset=\v!overlay]
3111
3112\permanent\let\stopframedcontent\relax
3113
3114\permanent\tolerant\protected\def\startframedcontent[#1]%
3115  {\bgroup
3116   \cdef\currentframedcontent{#1}%
3117   \ifx\currentframedcontent\v!off
3118     \enforced\let\stopframedcontent\egroup
3119   \else
3120     \checkframedcontentparent
3121     \enforced\let\stopframedcontent\pack_framed_stop_content_indeed
3122     \expandafter\pack_framed_start_content_indeed
3123   \fi}
3124
3125\def\pack_framed_start_content_indeed
3126  {\setbox\b_framed_normal\hpack\bgroup
3127     \setlocalhsize
3128     \hsize\localhsize
3129     \scratchleftoffset  {\framedcontentparameter\c!leftoffset}%
3130     \scratchrightoffset {\framedcontentparameter\c!rightoffset}%
3131     \scratchtopoffset   {\framedcontentparameter\c!topoffset}%
3132     \scratchbottomoffset{\framedcontentparameter\c!bottomoffset}%
3133     \advanceby\hsize{-\scratchleftoffset-\scratchrightoffset }%
3134     \advanceby\vsize{-\scratchtopoffset -\scratchbottomoffset}%
3135     \kern\scratchleftoffset
3136     \vpack\bgroup
3137       \vskip\scratchtopoffset
3138       \vbox\bgroup
3139         \forgetall
3140         \blank[\v!disable]}
3141
3142\protected\def\pack_framed_stop_content_indeed
3143         {\removelastskip
3144       \egroup
3145       \vskip\scratchbottomoffset
3146     \egroup
3147     \kern\scratchrightoffset
3148   \egroup
3149   \ifcstok{\framedcontentparameter\c!width}\v!fit
3150     \letframedcontentparameter\c!width\v!fixed% no shapebox
3151   \fi
3152   \ifinsidefloat
3153     \donefalse
3154   \orelse\ifcstok{\framedcontentparameter\c!linecorrection}\v!yes
3155     \donetrue
3156   \else
3157     \donefalse
3158   \fi
3159   % plaats ?
3160   \ifdone\startlinecorrection\fi
3161   \framedcontentparameter\c!left % new
3162   \inheritedframedcontentframed{\box\b_framed_normal}% hm
3163   \framedcontentparameter\c!right % new
3164   \ifdone\stoplinecorrection\fi
3165   \egroup}
3166
3167% A shared setting.
3168
3169\setuplinewidth
3170  [\v!medium]
3171
3172%D A Goodie:
3173
3174\defineframed
3175  [\v!unframed]
3176  [\c!frame=\v!off,
3177   \c!rulethickness=\zeropoint,
3178   \c!foregroundstyle=\framedparameter\c!style,
3179   \c!foregroundcolor=\framedparameter\c!color]
3180
3181%D Bonus (as defined in \type {pack-rul.lua}):
3182%D
3183%D \starttyping
3184%D \setbox\scratchbox\vbox{a\par aa\par aaa\par}
3185%D \the\dimexpr\themaxboxwidth\scratchbox\relax
3186%D \stoptyping
3187
3188% \let\themaxboxwidth % defined at the lua end
3189
3190%D Fast enough for most cases (we could do a massive \type {\ifhastok} instead):
3191
3192\permanent\protected\def\doifelseframed#1%
3193         {\ifcstok{#1\c!frame      }\v!on\expandafter\firstoftwoarguments
3194   \orelse\ifcstok{#1\c!topframe   }\v!on\expandafter\firstoftwoarguments
3195   \orelse\ifcstok{#1\c!bottomframe}\v!on\expandafter\firstoftwoarguments
3196   \orelse\ifcstok{#1\c!leftframe  }\v!on\expandafter\firstoftwoarguments
3197   \orelse\ifcstok{#1\c!rightframe }\v!on\expandafter\firstoftwoarguments
3198   \orelse\ifempty{#1\c!background }\expandafter\secondoftwoarguments
3199     \else                          \expandafter\firstoftwoarguments\fi}
3200
3201%D A bit out of place here:
3202
3203% \defineoverlay
3204%   [hacker]
3205%   [\overlayfigure{hacker.jpg}]
3206%
3207% \startclipframed
3208%   [background={foreground,hacker},align={middle,lohi},width=8cm]
3209%   \samplefile{ward}
3210% \stopclipframed
3211
3212\permanent\tolerant\protected\def\startclipframed[#1]%
3213  {\startgraphicgroup
3214   \framed[\c!background={\v!foreground,clipframed},#1]\bgroup\starteffect[\v!clip]}
3215
3216\permanent\protected\def\stopclipframed
3217  {\stopeffect
3218   \egroup
3219   \stopgraphicgroup}
3220
3221\defineoverlay
3222  [clipframed]
3223  [{\blackrule[\c!width=\overlaywidth,\c!height=\overlayheight,\c!color=darkred]}]
3224
3225
3226\protect \endinput
3227