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