typo-lbx.mkxl /size: 12 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=typo-lbx,
3%D        version=2021.10.10,
4%D          title=\CONTEXT\ Typesetting Macros,
5%D       subtitle=Local Boxes,
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 Typesetting Macros / Local Boxes}
15
16% This time the usual musical timestamp is: New Scary Goldings ft. John Scofield
17% MonoNeon & Louis Cole (late October 2021) (plus the playlist in loop mode) and
18% further improved after watching Cory Wong's LIVE IN MPLS (9 FEB 2019) concert.
19
20% maybe: \iflocalbox 0/1/2
21
22\registerctxluafile{typo-lbx}{autosuffix}
23
24%D The advantage is that it's deal with in the par builder which has some advantages
25%D but when used in complex situation there can be side effects. Therefore is should
26%D be considered a somewhat low level mechanism on top of which one can write more
27%D mechanisms that provide more rendering control. Also, keep in mind that combining
28%D many instances at the same time add some complizity. Therefore, for the moment it's
29%D a playground.
30
31\unprotect
32
33% Local boxes are a real mess and although we already mnade it behave better it's
34% still a trouble maker.
35
36% \def\typo_localboxes_reset
37%   {\localleftbox  {}% no index here, works grouped
38%    \localrightbox {}%
39%    \localmiddlebox{}}
40
41\aliased\let\typo_localboxes_reset\resetlocalboxes
42
43\appendtoks
44    \typo_localboxes_reset
45\to \everyforgetall
46
47\definesystemattribute[localboxesmark][public]
48
49%D We used to pass arguments but there might be many so ...
50
51\newbox\localboxcontentbox
52
53\installcorenamespace{localboxes}
54\installcorenamespace{localboxesattribute}
55\installcorenamespace{localboxesnamespace}
56\installcorenamespace{localboxeslocations}
57\installcorenamespace{localboxesresetters}
58
59\installcommandhandler \??localboxes {localboxes} \??localboxes
60
61\setuplocalboxes
62  [\c!command=\localboxcontent,
63   \c!width=\zeropoint,
64   \c!location=\v!left,
65   \c!distance=\zeropoint]
66
67\newinteger\c_typo_localboxes
68\newinteger\c_typo_localboxes_index
69
70\appendtoks
71    \global\advanceby\c_typo_localboxes\plusone
72    \global\expandafter\integerdef\csname\??localboxesattribute\currentlocalboxes\endcsname\c_typo_localboxes
73    \gletcsname\??localboxesnamespace\the\c_typo_localboxes\endcsname\currentlocalboxes
74\to \everydefinelocalboxes
75
76%D The optional argument forces setting the \quote {whole} paragraph properties (which is needed
77%D when the assignment happens after e.g.\ \type {\everypar} but is also meant for the first
78%D line.
79
80%D Todo: reserve index 1 for this:
81
82\def\typo_paragraphs_l#1{\localleftbox  \ifcstok{#1}\v!global par\fi}
83\def\typo_paragraphs_r#1{\localrightbox \ifcstok{#1}\v!global par\fi}
84\def\typo_paragraphs_m#1{\localmiddlebox\ifcstok{#1}\v!global par\fi}
85
86\permanent\tolerant\protected\def\leftparbox  [#1]{\typo_paragraphs_l{#1}\bgroup\enforced\let\leftparbox \relax\let\next}
87\permanent\tolerant\protected\def\rightparbox [#1]{\typo_paragraphs_r{#1}\bgroup\enforced\let\rightparbox\relax\let\next}
88\permanent\tolerant\protected\def\middleparbox[#1]{\typo_paragraphs_m{#1}\bgroup\enforced\let\rightparbox\relax\let\next}
89
90% called back:
91
92\permanent\protected\def\localboxcontent
93  {\box\localboxcontentbox}
94
95\permanent\protected\def\localboxcommand
96  {\ifcsname\??localboxesnamespace\number\localboxindex\endcsname
97    %\cdef\currentlocalboxes{\lastnamedcs}%
98     \expandafter\let\expandafter\currentlocalboxes\lastnamedcs
99     \setbox\localboxcontentbox\hbox
100       {\uselocalboxesstyleandcolor\c!style\c!color % sometimes redundant
101        \localboxesparameter\c!command}%
102   \fi}
103
104%D We don't group because we set the local boxes. Also, watch out: by injecting the
105%D existing local box we create nested ones. This is handled in the callback but if
106%D really needed one can do something like (do we need a primitive?):
107
108\mutable\lettonothing\currentlocalboxeslocation
109
110\def\typo_localboxes_localbox
111  {\ifx\currentlocalboxeslocation\v!right
112     \localrightbox
113   \orelse\ifx\currentlocalboxeslocation\v!left
114     \localleftbox
115   \else
116     \localmiddlebox
117   \fi}
118
119\def\typo_localboxes_zero#1#2#3%
120  {\ifcsname\??localboxesattribute#2\endcsname
121     \c_typo_localboxes_index\lastnamedcs
122     \cdef\currentlocalboxes{#2}%
123     \edef\currentlocalboxeslocation{#1}%
124     \typo_localboxes_localbox
125        \s!index \c_typo_localboxes_index
126        \bgroup
127          \hpack
128            \ifcstok{\localboxesparameter\c!repeat}\v!no
129              \s!attr \localboxesmarkattribute \localboxmarkonce\c_typo_localboxes_index\relax
130            \fi
131            \s!to \zeropoint
132          \bgroup
133            \uselocalboxesstyleandcolor\c!style\c!color
134            \hbox{#3}%
135            \hss
136          \egroup
137        \egroup
138   \fi}
139
140\def\typo_localboxes_asis#1#2#3%
141  {\ifcsname\??localboxesattribute#2\endcsname
142     \c_typo_localboxes_index\lastnamedcs
143     \cdef\currentlocalboxes{#2}%
144     \edef\currentlocalboxeslocation{#1}%
145     \typo_localboxes_localbox
146        \s!index \c_typo_localboxes_index
147        \bgroup
148          \hpack
149            \ifcstok{\localboxesparameter\c!repeat}\v!no
150              \s!attr \localboxesmarkattribute \localboxmarkonce\c_typo_localboxes_index\relax
151            \fi
152            % todo: use width if dimension, use distance if given
153          \bgroup
154            \uselocalboxesstyleandcolor\c!style\c!color
155            \hbox{#3}% no \hss
156          \egroup
157        \egroup
158   \fi}
159
160\defcsname\??localboxeslocations\v!left     \endcsname{\typo_localboxes_zero\v!left  }
161\defcsname\??localboxeslocations\v!right    \endcsname{\typo_localboxes_zero\v!right }
162\defcsname\??localboxeslocations\v!lefttext \endcsname{\typo_localboxes_asis\v!left  }
163\defcsname\??localboxeslocations\v!righttext\endcsname{\typo_localboxes_asis\v!right }
164\defcsname\??localboxeslocations\v!middle   \endcsname{\typo_localboxes_asis\v!middle}
165
166\letcsname\??localboxesresetters\v!left     \endcsname\v!left
167\letcsname\??localboxesresetters\v!right    \endcsname\v!right
168\letcsname\??localboxesresetters\v!lefttext \endcsname\v!left
169\letcsname\??localboxesresetters\v!righttext\endcsname\v!right
170\letcsname\??localboxesresetters\v!middle   \endcsname\v!middle
171
172\permanent\tolerant\protected\def\resetlocalbox[#1]%
173  {\ifcsname\??localboxesattribute#1\endcsname
174     \c_typo_localboxes_index\lastnamedcs
175     \cdef\currentlocalboxes{#1}%
176     \ifcsname\??localboxesresetters\localboxesparameter\c!location\endcsname
177       \edef\currentlocalboxeslocation{\lastnamedcs}%
178       \typo_localboxes_localbox \s!index \c_typo_localboxes_index {}%
179     \fi
180   \fi}
181
182\def\typo_localboxes_box#1%
183  {\dowithnextboxcontent
184     {\cdef\currentlocalboxes{#1}%
185      \uselocalboxesstyleandcolor\c!style\c!color}
186     {\ifcsname\??localboxeslocations\namedlocalboxesparameter{#1}\c!location\endcsname
187        \expandafter\lastnamedcs
188      \else
189        \csname\??localboxeslocations\v!left\expandafter\endcsname
190      \fi{#1}{\unhbox\nextbox}}}
191
192
193\permanent\tolerant\protected\def\localbox[#1]%
194  {\typo_localboxes_box{#1}\hbox}
195
196\permanent\tolerant\protected\def\startlocalbox[#1]%
197  {\dowithnextbox
198     {\ifcsname\??localboxeslocations\namedlocalboxesparameter{#1}\c!location\endcsname
199         \expandafter\lastnamedcs
200       \else
201         \csname\??localboxeslocations\v!left\expandafter\endcsname
202       \fi{#1}{\unhbox\nextbox}}%
203     \hbox\bgroup
204     \cdef\currentlocalboxes{#1}%
205     \uselocalboxesstyleandcolor\c!style\c!color
206     \enforced\def\stoplocalbox{\removeunwantedspaces\egroup}%
207     \ignorespaces}
208
209\aliased\let\stoplocalbox\donothing
210
211\permanent\tolerant\protected\def\startlocalboxrange[#1]%
212  {\globalpushmacro\stoplocalboxrange
213   \ifcsname\??localboxeslocations\namedlocalboxesparameter{#1}\c!location\endcsname
214     \lastnamedcs{#1}{}%
215   \fi}
216
217\permanent\protected\def\stoplocalboxrange
218  {\globalpopmacro\stoplocalboxrange}%
219
220% using left and right with left lagging behind:
221%
222% \permanent\protected\def\localmarginlefttext#1%
223%   {\setbox\localboxcontentbox\hpack
224%      {\unhbox\localboxcontentbox
225%       \setbox\localboxcontentbox\lastbox
226%       \unhbox\localboxcontentbox}%
227%    \hpack xoffset -\dimexpr
228%       #1
229%      +\localboxprogress
230%      +\localboxleftoffset
231%      +\wd\localboxcontentbox
232%      +\localboxesparameter\c!distance
233%    \relax{\box\localboxcontentbox}}
234%
235% \permanent\protected\def\localmarginrighttext#1%
236%   {\hpack xoffset \dimexpr
237%       #1
238%      +\localboxrightoffset
239%      +\localboxlocalwidth
240%      -\localboxprogress
241%      +\localboxesparameter\c!distance
242%    \relax{\box\localboxcontentbox}}
243
244% using middle:
245
246\permanent\protected\def\localmarginlefttext#1%
247  {\ifzeropt\localboxesparameter\c!width\relax
248     % a but ugly hack ... for now
249     \setbox\localboxcontentbox\hpack
250       {\unhbox\localboxcontentbox
251        \setbox\localboxcontentbox\lastbox
252        \unhbox\localboxcontentbox}%
253   \fi
254   \hpack \s!xoffset {%
255     -#1%
256     -\localboxprogress
257     -\wd\localboxcontentbox
258     -(\localboxesparameter\c!distance)%
259   }{\box\localboxcontentbox}}
260
261\permanent\protected\def\localmarginrighttext#1%
262  {\hpack \s!xoffset {%
263      #1
264     +\localboxlinewidth
265     -\localboxprogress
266     +{\localboxesparameter\c!distance}%
267   }{\box\localboxcontentbox}}
268
269% todo: use generic one above
270
271\permanent\protected\def\localmargintext[#1]#2%
272  {\dontleavehmode
273   \ifcsname\??localboxesattribute#1\endcsname
274     \c_typo_localboxes_index\lastnamedcs
275     \cdef\currentlocalboxes{#1}%
276     \edef\currentlocalboxeslocation{\localboxesparameter\c!location}%
277     \ifx\currentlocalboxeslocation\v!right\localrightbox\orelse\ifx\currentlocalboxeslocation\v!left\localleftbox\else\localmiddlebox\fi
278        \s!index \c_typo_localboxes_index
279        \bgroup
280          \hpack
281            \ifcstok{\localboxesparameter\c!repeat}\v!no
282              \s!attr \localboxesmarkattribute \localboxmarkonce\c_typo_localboxes_index\relax
283            \fi
284            to \zeropoint
285          \bgroup
286            \uselocalboxesstyleandcolor\c!style\c!color
287            \hbox{#2}%
288            \hss
289          \egroup
290        \egroup
291   \fi}
292
293\definelocalboxes
294  [\v!leftmargin]
295  [\c!command=\localmarginlefttext\zeropoint,
296   \c!repeat=\v!no,
297   \c!distance=\leftmargindistance,
298 % \c!location=\v!left]
299   \c!location=\v!middle]
300
301\definelocalboxes
302  [\v!rightmargin]
303  [\c!command=\localmarginrighttext\zeropoint,
304   \c!repeat=\v!no,
305   \c!distance=\rightmargindistance,
306 % \c!location=\v!right]
307   \c!location=\v!middle]
308
309\definelocalboxes
310  [\v!leftedge]
311  [\c!command=\localmarginlefttext\leftmargintotal,
312   \c!repeat=\v!no,
313   \c!distance=\leftedgedistance,
314 % \c!location=\v!left]
315   \c!location=\v!middle]
316
317\definelocalboxes
318  [\v!rightedge]
319  [\c!command=\localmarginrighttext\rightmargintotal,
320   \c!repeat=\v!no,
321   \c!distance=\rightedgedistance,
322 % \c!location=\v!right]
323   \c!location=\v!middle]
324
325%D Here is an example of usage:
326
327%D \starttyping
328%D \definelocalboxes
329%D   [linenumber]
330%D   [command=\LeftNumber,location=left,width=3em,style=\bs,color=darkred]
331%D
332%D \definelocalboxes
333%D   [linenumbertwo] [linenumber]
334%D   [command=\RightNumber,location=right,width=6em,style=\bf,color=darkgreen]
335%D
336%D \definelocalboxes
337%D   [linetext]
338%D   [command=\LeftText,location=lefttext,style=\bs,color=darkblue]
339%D
340%D \definelocalboxes
341%D   [linetexttwo] [linetext]
342%D   [command=\RightText,location=righttext,style=\bf,color=darkgray]
343%D
344%D % \def\LineNumberL{\the\localboxlinenumber}
345%D % \def\LineNumberR{\the\localboxlinenumber}
346%D
347%D % \newinteger\MyLineNumberL
348%D % \newinteger\MyLineNumberR
349%D % \def\LineNumberL{\global\advanceby\MyLineNumberL\plusone\the\MyLineNumberL}
350%D % \def\LineNumberR{\global\advanceby\MyLineNumberR\plusone\the\MyLineNumberR}
351%D
352%D \definecounter[MyLineNumberL]
353%D \definecounter[MyLineNumberR]
354%D
355%D \setupcounter[MyLineNumberL][numberconversion=characters]
356%D \setupcounter[MyLineNumberR][numberconversion=romannumerals]
357%D
358%D \def\LineNumberL{\incrementcounter[MyLineNumberL]\convertedcounter[MyLineNumberL]}
359%D \def\LineNumberR{\incrementcounter[MyLineNumberR]\convertedcounter[MyLineNumberR]}
360%D
361%D \protected\def\LeftNumber {\hbox to \localboxesparameter{width}{\strut(\LineNumberL\hss)}}
362%D \protected\def\RightNumber{\hbox to \localboxesparameter{width}{\strut(\hss\LineNumberR)}}
363%D
364%D % \protected\def\LeftNumber {\hbox to \localboxesparameter{width}{\strut\box\localboxcontentbox\hss)}}
365%D % \protected\def\RightNumber{\hbox to \localboxesparameter{width}{\strut(\hss\box\localboxcontentbox)}}
366%D
367%D \protected\def\LeftText {\localboxcontentbox\quad}
368%D \protected\def\RightText{\quad\localboxcontentbox}
369%D
370%D \start
371%D     \localbox[linenumber]{}%
372%D     \localbox[linenumbertwo]{}%
373%D     \localbox[linetext]{L}%
374%D     \startlocalbox[linetexttwo]
375%D         R
376%D     \stoplocalbox
377%D     \dorecurse{100}{
378%D         \samplefile{tufte}
379%D         \par
380%D     }
381%D \stop
382%D \stoptyping
383
384\protect \endinput
385
386