page-sid.mkxl /size: 38 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=page-sid,
3%D        version=2000.10.20,
4%D          title=\CONTEXT\ Page Macros,
5%D       subtitle=Side Floats,
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 Page Macros / Side Floats}
15
16\unprotect
17
18%D These macro deal with side floats. We started with Daniel Comenetz macros as
19%D published in TUGBoat Volume 14 (1993), No.\ 1: Anchored Figures at Either Margin.
20%D I extended and patched the macros to suite our needs which results in a messy
21%D module.
22%D
23%D A complication is that we need to deal with spacing differently before and after
24%D the float. Also, whitespace can interfere as does the prevdepth. There is no real
25%D universal solution. So, by now not much is left of that code, if only because we
26%D need to match \CONTEXT\ spacing module, because we have more placement options
27%D and control and because the math hackery is not suitable for \CONTEXT\ anyway.
28%D
29%D This code had been redone many times because we kept running into spacing issues
30%D and it's not that much fun (or rewarding). It's probably the module that made
31%D me go into distraciton mode most often (like watching amusing Walk of The
32%D Earth, sophisticated Massive Attack video clips, impressive Davie504 movies
33%D and so on).
34
35\newdimension   \d_page_sides_margin
36\newdimension   \d_page_sides_height       % includes the topskip
37\newdimension   \d_page_sides_width
38\newdimension   \d_page_sides_hsize
39\newdimension   \d_page_sides_vsize
40\newdimension   \d_page_sides_vsize_reset
41\newdimension   \d_page_sides_progress
42\newdimension   \d_page_sides_page_total
43\newdimension   \d_page_sides_shape_down_shift
44
45\newdimension   \d_page_sides_leftoffset
46\newdimension   \d_page_sides_rightoffset
47
48%newbox         \b_page_sides_bottom
49\newbox         \b_page_sides_spill_over
50
51\newinteger     \c_page_sides_lines_done
52\newinteger     \c_page_sides_checks_done
53\newinteger     \c_page_sides_n_of_lines
54\newinteger     \c_page_sides_n_of_hang
55\newconstant    \c_page_sides_float_type
56\newinteger     \c_page_sides_hangafter
57
58\newconditional \c_page_sides_short
59\newconditional \c_page_sides_flag
60\newconditional \c_page_sides_shape_down
61\newconditional \c_page_sides_keep_together
62\newconditional \c_page_sides_force_shape    % not default now
63
64\newdimension   \d_page_sides_shift
65\newdimension   \d_page_sides_extrashift
66\newdimension   \d_page_sides_leftshift
67\newdimension   \d_page_sides_rightshift
68\newdimension   \d_page_sides_leftskip
69\newdimension   \d_page_sides_rightskip
70\newdimension   \d_page_sides_maximum
71\newdimension   \d_page_sides_topskip
72\newdimension   \d_page_sides_bottomskip
73\newdimension   \d_page_sides_midskip
74\newdimension   \d_page_sides_downshift
75\newdimension   \d_page_sides_pagetotal
76\newdimension   \d_page_sides_topoffset
77\newdimension   \d_page_sides_bottomoffset
78\newdimension   \d_page_sides_toptotal
79\newdimension   \d_page_sides_bottomtotal
80
81\newconstant    \c_page_sides_align
82\newconstant    \c_page_sides_skipmode
83\newconstant    \c_page_sides_tolerance
84
85\newconstant    \c_page_sides_method % sort of obsolete
86
87\newdimension   \d_page_sides_progression
88
89\newinteger     \c_page_sides_m_of_lines
90\newconditional \c_page_sides_delayed
91
92%newconditional \c_page_sides_check_same_page
93
94\newif          \iftracesidefloats % public (might change)
95
96%D Defaults:
97
98\d_page_sides_vsize_reset -\onepoint
99%d_page_sides_vsize_reset  \zeropoint % could be an option, needs testing
100
101%D We have some basic (and colorful) tracing:
102
103\def\page_sides_floats_legend
104  {\showmessage\m!floatblocks{16}\empty
105   \glet\page_sides_floats_legend\relax}
106
107\installtextracker{floats.anchoring}
108  {\page_sides_floats_legend
109   \tracesidefloatstrue}
110  {\tracesidefloatsfalse}
111
112%D The horizontal shifts depend on the location: left or right in the text, margin
113%D or edge. These shifts are rather stable and don't interfere with the page flow
114%D as much as the vertical ones do.
115
116\def\page_sides_process_float_backspace  {\global\c_page_sides_float_type\plusone  \page_sides_handle_float}
117\def\page_sides_process_float_leftedge   {\global\c_page_sides_float_type\plustwo  \page_sides_handle_float}
118\def\page_sides_process_float_leftmargin {\global\c_page_sides_float_type\plusthree\page_sides_handle_float}
119\def\page_sides_process_float_left       {\global\c_page_sides_float_type\plusfour \page_sides_handle_float}
120\def\page_sides_process_float_right      {\global\c_page_sides_float_type\plusfive \page_sides_handle_float}
121\def\page_sides_process_float_rightmargin{\global\c_page_sides_float_type\plussix  \page_sides_handle_float}
122\def\page_sides_process_float_rightedge  {\global\c_page_sides_float_type\plusseven\page_sides_handle_float}
123\def\page_sides_process_float_cutspace   {\global\c_page_sides_float_type\pluseight\page_sides_handle_float}
124\def\page_sides_process_float_margin     {\global\c_page_sides_float_type\pluseight\page_sides_handle_float}
125
126\def\page_sides_check_horizontal_skips
127  {\ifcase\c_page_sides_skipmode
128   \or % high
129   \or % low
130   \or % fit
131     \global\d_page_sides_margin\zeropoint
132   \fi}
133
134\def\page_sides_apply_horizontal_shift
135  {\ifdim\d_page_sides_maximum>\zeropoint
136     \ifcase\c_page_sides_float_type
137       % invalid
138     \or
139       % backspace
140     \or
141       \global\d_page_sides_shift{%
142         -\d_page_sides_maximum
143         -\rightorleftpageaction \leftedgedistance   \rightedgedistance
144         -\rightorleftpageaction \leftmarginwidth    \rightmarginwidth
145         -\rightorleftpageaction \leftmargindistance \rightmargindistance
146         -\compensatedinnermakeupmargin
147       }%
148     \or
149       \global\d_page_sides_shift{%
150         -\d_page_sides_maximum
151         -\rightorleftpageaction \leftmargindistance \rightmargindistance
152         -\compensatedinnermakeupmargin
153       }%
154     \or
155       % left
156     \or
157       % right
158     \or
159       \global\d_page_sides_shift{%
160         -\d_page_sides_maximum
161         -\rightorleftpageaction \leftmargindistance \rightmargindistance
162         -\compensatedinnermakeupmargin
163       }%
164     \or
165       \global\d_page_sides_shift{%
166         -\d_page_sides_maximum
167         -\rightorleftpageaction \leftedgedistance   \rightedgedistance
168         -\rightorleftpageaction \leftmarginwidth    \rightmarginwidth
169         -\rightorleftpageaction \leftmargindistance \rightmargindistance
170         -\compensatedinnermakeupmargin
171       }%
172     \or
173       % cutspace
174     \fi
175   \fi
176   \ifzeropt\d_page_sides_shift
177     \ifnum\c_page_sides_float_type=\plusfour
178       \global\advanceby\d_page_sides_shift\d_page_sides_extrashift
179       \global\d_page_sides_extrashift\zeropoint
180     \orelse\ifnum\c_page_sides_float_type=\plusfive
181       \global\advanceby\d_page_sides_shift\d_page_sides_extrashift
182       \global\d_page_sides_extrashift\zeropoint
183     \fi
184   \else
185     \ifnum\c_page_sides_float_type<\plusfour
186       \global\c_page_sides_float_type\plusfour
187     \orelse\ifnum\c_page_sides_float_type>\plusfive
188       \global\c_page_sides_float_type\plusfive
189     \fi
190   \fi}
191
192\def\page_sides_set_skips
193  {\global\d_page_sides_rightskip\zeropoint
194   \global\d_page_sides_leftskip \zeropoint
195   \ifcase\c_page_sides_float_type
196   \or % backspace
197     \global\d_page_sides_leftskip{%
198       +\rightorleftpageaction \backspace           \cutspace
199       +\compensatedinnermakeupmargin
200     }%
201   \or % leftedge
202     \global\d_page_sides_leftskip{%
203       +\rightorleftpageaction \leftmargindistance  \rightmargindistance
204       +\rightorleftpageaction \leftmarginwidth     \rightmarginwidth
205       +\rightorleftpageaction \leftedgedistance    \rightedgedistance
206       +\compensatedinnermakeupmargin
207     }%
208   \or % leftmargin
209     \global\d_page_sides_leftskip{%
210       +\rightorleftpageaction \leftmargindistance  \rightmargindistance
211       +\compensatedinnermakeupmargin
212     }%
213   \or % leftside
214   \or % rightside
215   \or % rightmargin
216     \global\d_page_sides_rightskip{%
217       +\rightorleftpageaction \rightmargindistance \leftmargindistance
218       +\compensatedinnermakeupmargin
219     }%
220   \or % rightedge
221     \global\d_page_sides_rightskip{%
222       +\rightorleftpageaction \rightmargindistance \leftmargindistance
223       +\rightorleftpageaction \rightmarginwidth    \leftmarginwidth
224       +\rightorleftpageaction \rightedgedistance   \leftedgedistance
225       +\compensatedinnermakeupmargin
226     }%
227   \or % cutspace
228     \global\d_page_sides_rightskip{%
229       +\rightorleftpageaction \cutspace            \backspace
230       +\compensatedinnermakeupmargin
231     }%
232   \fi
233   \global\d_page_sides_leftoffset \d_page_sides_rightskip
234   \global\d_page_sides_rightoffset\d_page_sides_leftskip
235   \ifdim\d_page_sides_rightskip>\zeropoint
236     \global\advanceby\d_page_sides_rightskip\rightskip
237   \fi
238   \ifdim\d_page_sides_leftskip >\zeropoint
239     \global\advanceby\d_page_sides_leftskip \leftskip
240   \fi}
241
242%D Shifts get applied to the float box:
243
244\def\page_sides_relocate_float#1%
245  {\global\setbox\floatbox\hpack
246     {\ifnum\c_page_sides_float_type=\plusfour
247        \kern\d_page_sides_leftshift
248      \orelse\ifnum\c_page_sides_float_type=\plusone
249        \kern\d_page_sides_leftshift
250      \fi
251      \ifnum\c_page_sides_float_type>\plusfour
252        \kern-\d_page_sides_extrashift
253      \else
254        \kern\d_page_sides_shift
255      \fi
256      \vbox{#1\ifnum\c_page_sides_align=\plusfour \removedepth \fi}%
257      \ifnum\c_page_sides_float_type>\plusfour
258        \kern\d_page_sides_shift
259      \else
260        \kern-\d_page_sides_extrashift
261      \fi
262      \ifnum\c_page_sides_float_type=\pluseight
263        \kern\d_page_sides_rightshift
264      \orelse\ifnum\c_page_sides_float_type=\plusfive
265        \kern\d_page_sides_rightshift
266      \fi}}
267
268%D The vertical skips are a nightmare and this mechanism is about as complex
269%D as one can get it.
270
271\def\page_sides_check_vertical_skips
272  {\ifdim\d_page_sides_topskip   <\zeropoint\d_page_sides_topskip   \zeropoint\fi
273   \ifdim\d_page_sides_bottomskip<\zeropoint\d_page_sides_bottomskip\zeropoint\fi
274   \ifdim\d_page_sides_midskip   <\zeropoint\d_page_sides_midskip   \zeropoint\fi
275   %
276   \global\d_page_sides_toptotal   {\d_page_sides_topskip   +\d_page_sides_topoffset   }%
277   \global\d_page_sides_bottomtotal{\d_page_sides_bottomskip+\d_page_sides_bottomoffset}%
278   \ifcase\c_page_sides_skipmode
279   \or % high
280     \global\d_page_sides_toptotal   \d_page_sides_topoffset
281   \or % low
282     \global\d_page_sides_bottomtotal\d_page_sides_bottomoffset
283   \or % fit
284     \global\d_page_sides_toptotal   \d_page_sides_topoffset
285     \global\d_page_sides_bottomtotal\d_page_sides_bottomoffset
286   \fi}
287
288%D These shifts get (selectively) applied with a bit of optional tracing.
289
290\def\page_sides_apply_vertical_shift_normal
291  {\global\setbox\floatbox\hpack % why extra box
292     {\vpack
293        {\forgetall
294         \hsize\wd\floatbox
295         \vskip\privatescratchdimen
296         \offinterlineskip
297         \box\floatbox
298         % somehow we need this \scratchbox magic, but at least it's the same as the
299         % tracer now
300         \setbox\scratchbox\emptyhbox
301         \wd\scratchbox\hsize
302         \ht\scratchbox\d_page_sides_bottomtotal
303         \box\scratchbox
304         \vskip-\d_page_sides_bottomtotal
305         \ifnum\c_page_sides_align=\plusfive
306           \vskip-\lineheight
307         \fi}}}
308
309\def\page_sides_apply_vertical_shift_traced
310  {\global\setbox\floatbox\hpack % why extra box
311     {\backgroundline[trace:r]{\ruledhpack{\vpack
312        {\forgetall
313         \hsize\wd\floatbox
314         \vskip\privatescratchdimen
315         \offinterlineskip
316         \backgroundline
317           [trace:g]%
318           {\ruledhpack{\box\floatbox}}%
319         \par
320         \blackrule
321           [\c!color=trace:s,%
322            \c!height=\d_page_sides_bottomtotal,%
323            \c!depth=\zeropoint,%
324            \c!width=\hsize]%
325         \vskip-\d_page_sides_bottomtotal
326         \ifnum\c_page_sides_align=\plusfive
327           \vskip-\lineheight
328         \fi}}}}}
329
330\def\page_sides_apply_vertical_shift
331  {\ifnum\c_page_sides_align=\plusfour
332     \getnoflines{\ht\floatbox}%
333     \privatescratchdimen{\noflines\lineheight-\strutdp}%
334     \getrawnoflines\d_page_sides_toptotal
335     \advanceby\privatescratchdimen\noflines\lineheight
336     \page_sides_force_depth
337     \ht\floatbox\privatescratchdimen
338     \dp\floatbox\zeropoint
339   \else
340   \fi
341   \ifcase\c_page_sides_align \else
342     \global\d_page_sides_toptotal\zeropoint
343   \fi
344   \privatescratchdimen
345     \ifnum\c_page_sides_float_type<\plusfour
346       \d_page_sides_toptotal
347     \orelse\ifnum\c_page_sides_float_type>\plusfive
348       \d_page_sides_toptotal
349     \else
350       \zeropoint
351     \fi
352   % the top of the box is at the previous baseline
353   \ifcase\c_page_sides_align
354       % 0 normal
355     \advanceby\privatescratchdimen\strutdp % or \openstrutdepth
356   \or % 1 height
357     \advanceby\privatescratchdimen\strutdp % or \openstrutdepth
358   \or % 2 line
359   \or % 3 depth
360     \advanceby\privatescratchdimen\lineheight % or \openlineheight
361     \advanceby\privatescratchdimen\strutdp    % or \openstrutdepth
362   \or % 4 grid
363     \privatescratchdimen\zeropoint
364   \or
365     \advanceby\privatescratchdimen\strutht % or \openstrutheight
366   \fi
367   % new
368   \global\c_page_sides_lines_done\zerocount
369   \ifconditional\c_page_sides_shape_down
370     \global\d_page_sides_shape_down_shift{%
371        \privatescratchdimen
372       +\htdp\floatbox
373     }%
374     \advanceby\privatescratchdimen\c_page_sides_n_of_lines\lineheight
375\advanceby\privatescratchdimen2\lineheight
376   \else
377     \global\d_page_sides_shape_down_shift\zeropoint
378     \advanceby\privatescratchdimen\c_page_sides_n_of_lines\lineheight
379   \fi
380   \iftracesidefloats
381     \page_sides_apply_vertical_shift_traced % uses \privatescratchdimen
382   \else
383     \page_sides_apply_vertical_shift_normal % uses \privatescratchdimen
384   \fi
385   \ifnum\c_page_sides_float_type<\plusfour
386     \global\d_page_sides_toptotal\zeropoint
387   \orelse\ifnum\c_page_sides_float_type>\plusfive
388     \global\d_page_sides_toptotal\zeropoint
389   \fi
390   \global\d_page_sides_downshift\zeropoint}
391
392%D We have a few virtual dimensions. I'm not sure what to do with \type
393%D {\pagedepth} and \type {\pageshrink} in the next two. If we ever need
394%D that it will become options.
395
396\permanent\def\d_page_sides_flush_criterium
397  {\dimexpr
398      \d_page_sides_vsize
399     -\d_page_sides_bottomtotal
400     -\pagetotal
401   \relax}
402
403\permanent\def\d_page_sides_room_criterium
404  {\dimexpr
405      \d_page_sides_vsize
406     -\d_page_sides_bottomtotal % added here too
407     -\pagetotal
408   \relax}
409
410%D In order to get a consistent spacing we force a strutdepth unless the
411%D preceding material has more depth than that already. This way anchoring
412%D becomes predictable.
413
414% \protected\def\page_sides_force_depth
415%   {\iftracesidefloats
416%     \begingroup
417%      \c_page_force_strut_depth_trace_mode\plusone
418%      \ifconditional\c_page_sides_check_same_page
419%        \forcestrutdepthplus
420%      \else
421%        \forcestrutdepth
422%     \fi
423%     \endgroup
424%    \else
425%      \ifconditional\c_page_sides_check_same_page
426%        \forcestrutdepthplus
427%      \else
428%        \forcestrutdepth
429%      \fi
430%    \fi
431%    \page_otr_command_set_vsize} % new
432
433% test case:
434%
435% \starttext
436%     \strut\vskip180mm \input ward
437%     \subject{Test}
438%     \placefigure[right,none]{none}{\blackrule[width=4cm,height=3cm]} test
439% \stoptext
440
441\protected\def\page_sides_force_depth
442  {\iftracesidefloats
443     \enabletrackers[otr.forcestrutdepth]% \c_page_force_strut_depth_trace_mode\plusone
444   \fi
445 % \unless\ifvmode
446 %   \writestatus{side floats}{confusion}
447 % \fi
448   % flush what we have and check
449   \forcestrutdepth
450   % trigger pagebuilder, \pageboundary gives nicer tracing
451   \iffalse
452     \penalty\zerocount % works too
453   \else
454    %\tracingpages\plusone \tracingonline\plustwo
455     \pageboundary\plustenthousand % becomes a penalty (after triggering the callback) (experimental!)
456    %\tracingpages\zerocount
457   \fi
458   \page_otr_command_set_vsize} % new, no longer really needed
459
460\def\page_sides_flush_floats
461  {\ifconditional\c_page_sides_shape_down\else
462     \par
463   \fi
464   \ifdim\d_page_sides_flush_criterium>\zeropoint
465     \page_sides_flush_floats_progress
466     \page_sides_flush_floats_after_next
467   \fi
468   \page_sides_flush_floats_reset}
469
470\def\page_sides_flush_floats_text
471  {\par
472   % what with \c_anch_backgrounds_text_level>\plusone
473   \ifdim\d_page_sides_flush_criterium>\zeropoint
474     \page_sides_flush_floats_progress
475     \page_sides_flush_floats_after_none
476   \fi
477   \page_sides_flush_floats_reset}
478
479\def\page_sides_flush_floats_reset
480  {\global\d_page_sides_vsize\d_page_sides_vsize_reset
481   % also here if used at all \global\holdinginserts\zerocount
482   \global\c_page_sides_short\conditionalfalse
483   \global\c_page_sides_flag\conditionalfalse
484   \global\c_page_sides_checks_done\zerocount}
485
486\def\page_sides_flush_floats_after_none % we force a flush
487  {\ifdim\d_page_sides_midskip>\zeropoint
488      \blank[\the\d_page_sides_midskip]
489   \fi
490   \ignoreparskip
491   \blank[\v!disable]}
492
493\def\page_sides_flush_floats_after_next % we have two successive ones
494  {\ifdim\d_page_sides_bottomskip>\zeropoint
495      \blank[\the\d_page_sides_bottomskip]
496   \fi
497   \ignoreparskip
498   \blank[\v!disable]}
499
500%D A rudimentary checker:
501
502\permanent\protected\def\doifelsesidefloat
503  {\par
504   \ifdim\d_page_sides_room_criterium>\zeropoint % -\pagedepth
505     \expandafter\firstoftwoarguments
506   \else
507     \expandafter\secondoftwoarguments
508   \fi}
509
510\aliased\let\doifsidefloatelse\doifelsesidefloat
511
512%D Sometimes we need to fill up the space alongside a side float and this
513%D is where we define the helpers. A user can enforce a smaller step. We use
514%D large steps when possible.
515
516\installcorenamespace{sidefloatsteps}
517
518\defcsname\??sidefloatsteps\v!line  \endcsname{\strut}
519\defcsname\??sidefloatsteps\v!big   \endcsname{\strut}
520\defcsname\??sidefloatsteps\v!medium\endcsname{\halflinestrut} % was \halfstrut
521\defcsname\??sidefloatsteps\v!small \endcsname{\noheightstrut} % was \quarterstrut
522
523\def\page_sides_flush_floats_tracer
524  {\dontleavehmode
525   \ruledhpack\bgroup\backgroundline[trace:b]{%
526     \llap{\smash{\vrule\s!width4\points\s!height.4\points\s!depth.4\points}}%
527     \ifnum\recurselevel=\plusone
528       \llap{\smash{\smallinfofont\the\scratchdimen}\hskip.5\leftmargindistance}%
529     \orelse\ifodd\recurselevel
530       \llap{\smash{\smallinfofont\recurselevel}\hskip.5\leftmargindistance}%
531     \fi
532     \page_sides_flush_floats_normal
533     \kern\hsize
534   \egroup}}
535
536\def\page_sides_flush_floats_normal
537  {\ifdim\scratchdimen>\struthtdp
538     \strut
539   \else
540     \m_pages_strut
541   \fi}
542
543\def\page_sides_flush_floats_progress
544  {\begingroup
545   \page_sides_force_depth
546   \parskip\zeroskip
547   \let\page_sides_flush_floats\relax
548   \edef\m_pages_strut
549     {\ifcsname\??sidefloatsteps\rootfloatparameter\c!step\endcsname
550        \lastnamedcs
551      \else
552        \noheightstrut
553      \fi}%
554   \forgetall
555   \offinterlineskip
556   \localcontrolledrepeating
557     {\scratchdimen\d_page_sides_flush_criterium
558      \ifdim\scratchdimen>\onepoint      % good enough, can become configurable
559        \ifnum\currentloopiterator>\plushundred % safeguard, sort of deadcycles
560          \quitloop
561        \orelse\iftracesidefloats
562          \page_sides_flush_floats_tracer\par
563        \else
564          \page_sides_flush_floats_normal\par
565        \fi
566      \else
567        \page_sides_force_depth
568        \quitloop
569      \fi}%
570   \endgroup}
571
572%D We force a parskip and ignore it afterwards. We can nil it by setting the
573%D \type {spacebeforeside} parameter. We can have a leading blank so we need
574%D to make sure that we use blank to inject the parskip and then ignore
575%D the one injected by the engine.
576
577\def\page_sides_inject_before
578  {\page_sides_force_depth
579   \ifdim\parskip>\zeropoint
580     \ifdim\parskip>\d_strc_floats_top
581       \ifdim\d_strc_floats_top>\zeropoint
582         \ignoreparskip
583         \blank[\v!white]%
584       \else
585         \checkedblank[\rootfloatparameter\c!spacebeforeside]%
586       \fi
587     \else
588       \checkedblank[\rootfloatparameter\c!spacebeforeside]%
589     \fi
590   \else
591     \checkedblank[\rootfloatparameter\c!spacebeforeside]%
592   \fi}
593
594%D We are now done with \type {spacebefore} and the parskip is already
595%D injected. The dummy line makes sure that we anchor properly and it
596%D also can serve as tracer.
597
598\def\page_sides_inject_dummy_line_normal
599  {\hpack to \availablehsize{\strut\hss}}
600
601\def\page_sides_inject_dummy_line_traced
602  {\ruledhpack to \availablehsize{\backgroundline[trace:c]{\page_sides_inject_dummy_line_normal}}}
603
604\def\page_sides_inject_dummy_lines
605  {\par
606   \nointerlineskip
607 % \ifnum\lastpenalty>\zerocount
608 %   \penalty\plustenthousand
609 % \fi
610   \dontleavehmode
611   \iftracesidefloats
612     \page_sides_inject_dummy_line_traced
613   \else
614     \page_sides_inject_dummy_line_normal
615   \fi
616   \par
617   % on an empty page we have topskip, say 12pt
618   \ignoreparskip
619   % this can be 18.5pt
620   \kern-{\lineheight+\strutdp}%
621   % so we can actually have a -2.5pt skip on top
622   \ignoreparskip
623   \blank[\v!samepage]
624   \blank[\v!disable]
625   % now say we are negative now
626   \ifdim\pagetotal<\zeropoint
627      % then we're at the top of the page ... quite messy .. i really need to
628      % make the page builder a bit more flexible .. should we do something now?
629   \fi}
630
631%D Checkers:
632
633\def\page_sides_check_floats_after_par
634  {\page_sides_check_floats_indeed
635   \ifdim\d_page_sides_pagetotal=\pagetotal \else
636     \glet\page_sides_check_floats\page_sides_check_floats_indeed
637     \page_sides_flush_floats
638     \global\c_page_sides_n_of_lines\zerocount % here !
639   \fi}
640
641\protected\def\page_sides_flush_floats_after_par
642  {\global\d_page_sides_pagetotal\pagetotal
643   \glet\page_sides_check_floats\page_sides_check_floats_after_par}
644
645\protected\def\page_sides_forget_floats
646  {\global\d_page_sides_vsize\d_page_sides_vsize_reset
647   \global\c_page_sides_n_of_lines\zerocount
648   % also here if used at all \global\holdinginserts\zerocount
649   \global\c_page_sides_short\conditionalfalse
650   \global\c_page_sides_flag\conditionalfalse}
651
652%D Here comes the output routine. We either go the fast route or we use the
653%D normal one (stored in \type {\page_otr_command_side_float_output}. We no
654%D longer have this fuzzy code around with penalties and indentation and
655%D such.
656
657\def\page_sides_output_routine
658  {\page_otr_command_side_float_output
659   \ifconditional\c_page_sides_short
660     \global\c_page_sides_short\conditionalfalse
661   \else
662     \global\d_page_sides_vsize\d_page_sides_vsize_reset
663     \global\c_page_sides_n_of_lines\zerocount
664   \fi}
665
666\def\page_sides_place_float
667  {\ifnum\c_page_sides_float_type=\plusfour \kern\d_page_sides_toptotal \fi
668   \ifnum\c_page_sides_float_type=\plusfive \kern\d_page_sides_toptotal \fi
669   \ifconditional\c_page_sides_shape_down
670     \page_sides_place_float_normal
671   \else
672     \ifgridsnapping
673       \page_sides_place_float_grid
674     \else
675       \page_sides_place_float_normal
676     \fi
677     \par
678     \kern-\d_page_sides_height
679     \penalty10001 % oeps, this will change
680     \normalbaselines
681   \fi}
682
683\def\page_sides_place_float_normal
684  {\page_sides_push_float_inline\firstofoneargument}
685
686%D The following needs some more work .. consider this a quick hack. We probably
687%D need an mkiv hanging grid option.
688
689\def\page_sides_place_snap_to_grid#1%
690  {\edef\p_grid{\floatparameter\c!grid}%
691   \ifempty\p_grid\else
692     \snaptogrid[\p_grid]%
693   \fi
694   \hpack{#1}}
695
696\def\page_sides_place_float_grid
697  {\getrawnoflines\d_page_sides_height % raw ?
698   \d_page_sides_height\noflines\lineheight
699   \page_sides_push_float_inline\page_sides_place_snap_to_grid}
700
701\let\strc_floats_mark_par_as_free\relax
702
703% \def\page_sides_push_float_inline#1%
704%   {\begingroup
705%    \reseteverypar % needed !
706%    \parskip\zeroskip  % needed !
707%    \nointerlineskip
708%    \page_sides_set_skips
709%    \page_floats_report_total
710%    \relax
711%   %\lefttoright % not needed in lmtx
712%    \strc_floats_mark_par_as_free
713%    \ifcase\c_page_sides_float_type
714%      % invalid
715%    \or % backspace
716%      \noindent#1{\llap{\rlap{\box\floatbox}\kern\d_page_sides_leftskip}}\hfill
717%    \or % leftedge
718%      \noindent#1{\llap{\box\floatbox\kern\d_page_sides_leftskip}}\hfill
719%    \or % leftmargin
720%      \noindent#1{\llap{\box\floatbox\kern\d_page_sides_leftskip}}\hfill
721%    \or % leftside
722%      \noindent#1{\box\floatbox}\hfill
723%    \or % rightside
724%      \hfill#1{\box\floatbox}%
725%    \or % rightmargin
726%      \hfill#1{\rlap{\kern\d_page_sides_rightskip\box\floatbox}}%
727%    \or % rightedge
728%      \hfill#1{\rlap{\kern\d_page_sides_rightskip\box\floatbox}}%
729%    \or % cutspace
730%      \hfill#1{\rlap{\kern\d_page_sides_rightskip\llap{\box\floatbox}}}%
731%    \fi
732%    \endgroup}
733
734\def\page_sides_push_float_inline_indeed#1%
735  {\ifcase\c_page_sides_float_type
736     % invalid
737   \or % backspace
738     \noindent#1{\llap{\rlap{\box\floatbox}\kern\d_page_sides_leftskip}}\hfill
739   \or % leftedge
740     \noindent#1{\llap{\box\floatbox\kern\d_page_sides_leftskip}}\hfill
741   \or % leftmargin
742     \noindent#1{\llap{\box\floatbox\kern\d_page_sides_leftskip}}\hfill
743   \or % leftside
744     \noindent#1{\box\floatbox}\hfill
745   \or % rightside
746     \hfill#1{\box\floatbox}%
747   \or % rightmargin
748     \hfill#1{\rlap{\kern\d_page_sides_rightskip\box\floatbox}}%
749   \or % rightedge
750     \hfill#1{\rlap{\kern\d_page_sides_rightskip\box\floatbox}}%
751   \or % cutspace
752     \hfill#1{\rlap{\kern\d_page_sides_rightskip\llap{\box\floatbox}}}%
753   \fi}
754
755\def\page_sides_push_float_inline#1%
756  {\ifconditional\c_page_sides_shape_down
757     \page_sides_set_skips
758     \page_floats_report_total
759     \global\setbox\floatbox\hbox to \hsize\bgroup
760       \page_sides_push_float_inline_indeed#1%
761     \egroup
762   \else
763     \begingroup
764     \reseteverypar    % needed !
765     \parskip\zeroskip % needed !
766     \nointerlineskip
767     \page_sides_set_skips
768     \page_floats_report_total
769     \relax
770    %\lefttoright % not needed in lmtx
771     \strc_floats_mark_par_as_free
772     \page_sides_push_float_inline_indeed#1%
773     \endgroup
774   \fi}
775
776% \def\page_sides_analyse_progress
777%   {\d_page_sides_progress\d_page_sides_vsize
778%    \ifconditional\c_page_sides_flag
779%      \advanceby\d_page_sides_progress-\d_page_sides_page_total
780%      \global\c_page_sides_flag\conditionalfalse
781%    \else
782%      \advanceby\d_page_sides_progress-\pagetotal
783%    \fi}
784
785% test case
786%
787% \usemodule[art-01]
788% \starttext
789%     \dorecurse{40}{\line{#1}}
790%     \placefigure[left]{}{}
791%     \input ward
792%     \startitemize
793%         \item word \item word \item word \item word
794%     \stopitemize
795%     \input ward
796%     \page
797% \stoptext
798
799\def\page_sides_analyse_progress
800  {%\page_otr_command_set_vsize % this is new, otherwise topfloats are not taken into account
801   \d_page_sides_progress\d_page_sides_vsize
802   \ifconditional\c_page_sides_flag
803     \advanceby\d_page_sides_progress-\d_page_sides_page_total
804     \global\c_page_sides_flag\conditionalfalse
805   \else
806     \ifdim{\d_page_sides_progress+\d_page_sides_bottomtotal}>\pagegoal
807       % we adapt pagegoal because we can already have placed something with
808       % everypar and we hope that it triggers a flush, see test above
809       \pagegoal{\pagegoal-\d_page_sides_bottomtotal}%
810     \fi
811     \advanceby\d_page_sides_progress-\pagetotal
812   \fi}
813
814\def\page_sides_analyse_space_stage_one
815  {\global\c_page_sides_flag\conditionaltrue
816% \ifdim\pagegoal=\maxdimen
817%     \pagegoal\textheight % maybe
818% \fi
819   \global\d_page_sides_page_total\pagetotal % global
820   \ifnum\c_page_sides_float_type<\plusfour
821     \global\d_page_sides_width \zeropoint
822   \orelse\ifnum\c_page_sides_float_type>\plusfive
823     \global\d_page_sides_width\zeropoint
824   \else
825     \global\d_page_sides_width{\wd\floatbox+\d_page_sides_margin}%
826   \fi
827   \ifdim\d_page_sides_width<\zeropoint
828     \global\d_page_sides_width\zeropoint
829   \fi
830   \global\d_page_sides_hsize {\hsize-\d_page_sides_width}%
831   \global\d_page_sides_height{\htdp\floatbox+\d_page_sides_toptotal}%
832   \global\d_page_sides_vsize {\d_page_sides_height+\d_page_sides_page_total}%
833   \scratchdimenone\d_page_sides_vsize
834   \scratchdimentwo\pagegoal
835   \ifcase\c_page_sides_tolerance
836     \ifcase\c_page_sides_method
837       % method 0 : raw
838     \or
839       % method 1 : safe (default)
840       \advanceby\scratchdimentwo -\strutdp
841     \or
842       % method 2 : tight (grid default)
843       \advanceby\scratchdimenone -\onepoint
844     \fi
845   \or
846     % tolerant
847     \advanceby\scratchdimentwo -.5\strutdp
848   \or
849     % verytolerant
850   % \advanceby\scratchdimenone -\onepoint (maybe)
851   \else
852     \advanceby\scratchdimentwo -\strutdp
853   \fi}
854
855\def\page_sides_analyse_space_stage_two
856  {% how about \pagedepth
857   \ifdim\scratchdimenone>\scratchdimentwo
858     \global\c_page_floats_room\conditionalfalse
859   \else
860     \ifdim{\pagegoal-\d_page_sides_vsize}<\d_page_sides_bottomtotal
861      % just weird: \global\advanceby\d_page_sides_vsize \scratchdimenone
862       \global\c_page_sides_short\conditionaltrue
863       % why was this \global\holdinginserts\plusone
864     \else
865       \global\advanceby\d_page_sides_vsize \d_page_sides_bottomtotal % wins over inbetween
866       \global\c_page_sides_short\conditionalfalse
867     \fi
868     \global\c_page_floats_room\conditionaltrue
869   \fi}
870
871\def\page_sides_analyse_space
872  {\page_sides_analyse_space_stage_one
873%    \ifconditional\c_page_sides_check_same_page
874%      \ifdim\d_spac_prevcontent>\zeropoint
875%        \ifdim{\scratchdimenone+\d_spac_prevcontent}>\scratchdimentwo
876%          \clf_pushatsame
877%          \setbox\scratchbox\vpack{\clf_popatsame}%
878%          \page
879%          \box\scratchbox
880%          \vskip-\lineskip
881%          \page_sides_analyse_space_stage_one
882%        \fi
883%      \fi
884%    \fi
885   \page_sides_analyse_space_stage_two
886   \ifconditional\c_page_sides_shape_down
887     \global\c_page_floats_room\conditionaltrue
888   \fi}
889
890%D As we have no clear end of one or more paragraphs we only have pre float
891%D skips.
892
893\newconstant\c_page_sides_page_method % will be: \c_page_sides_page_method\plusone
894
895\def\page_otr_force_new_page_one
896  {\vskip\d_page_sides_height
897   \penalty\outputpenalty
898   \vskip{\strutdp-\d_page_sides_height}%
899   \prevdepth\strutdp}
900  %\ignoreparskip}
901
902% \def\page_sides_handle_float#1%
903%   {\page_sides_initialize_checker
904%    \page_sides_check_horizontal_skips
905%    \page_sides_check_vertical_skips
906%    \page_sides_apply_horizontal_shift
907%    \page_sides_check_previous_float
908%    \page_sides_inject_before
909%    \page_sides_inject_dummy_lines
910%    \page_sides_relocate_float{#1}%
911%    \page_sides_apply_vertical_shift
912%    \page_sides_analyse_space
913%    \ifconditional\c_page_floats_room
914%      \global\c_page_sides_delayed\conditionalfalse
915%      % we're ok
916%    \else
917%      \global\c_page_sides_delayed\conditionaltrue
918%      \global\c_page_sides_m_of_lines\c_page_sides_n_of_lines
919%      \ifcase\c_page_sides_page_method
920%        \page_otr_fill_and_eject_page
921%      \or
922%        \page_otr_force_new_page_one
923%      \else
924%        \page_otr_fill_and_eject_page
925%      \fi
926%      \global\c_page_sides_n_of_lines\c_page_sides_m_of_lines
927%      \page_sides_analyse_space
928%     %\page_sides_inject_before
929%      \page_sides_inject_dummy_lines
930%    \fi
931%    \page_sides_place_float
932%    \global\c_page_sides_delayed\conditionalfalse
933%    \page_sides_check_floats_reset
934%    \page_sides_wrapup}
935
936\def\page_sides_handle_float#1%
937  {\page_sides_initialize_checker
938   \page_sides_check_horizontal_skips
939   \page_sides_check_vertical_skips
940   \page_sides_apply_horizontal_shift
941   \page_sides_check_previous_float
942   \page_sides_inject_before
943   \page_sides_inject_dummy_lines
944   \page_sides_relocate_float{#1}%
945   \page_sides_apply_vertical_shift
946   \page_sides_analyse_space
947   \ifconditional\c_page_floats_room
948     \global\c_page_sides_delayed\conditionalfalse
949     % we're ok
950   \else
951     \ifconditional\c_page_sides_keep_together
952       \clf_interceptsamepagecontent\b_page_sides_spill_over
953     \fi
954     \global\c_page_sides_delayed\conditionaltrue
955     \global\c_page_sides_m_of_lines\c_page_sides_n_of_lines
956     \ifcase\c_page_sides_page_method
957       \page_otr_fill_and_eject_page
958     \or
959       \page_otr_force_new_page_one
960     \else
961       \page_otr_fill_and_eject_page
962     \fi
963     \ifvoid\b_page_sides_spill_over\else
964       \box\b_page_sides_spill_over
965     \fi
966     \page_sides_analyse_space
967    %\page_sides_inject_before
968     \page_sides_inject_dummy_lines
969   \fi
970   \page_sides_place_float
971   \global\c_page_sides_delayed\conditionalfalse
972   \page_sides_check_floats_reset
973   \page_sides_wrapup}
974
975\def\page_sides_wrapup
976  {% we need to do this aftergroup
977   \aftergroup\par
978   \aftergroup\ignoreparskip
979   \aftergroup\ignorespaces
980   \aftergroup\page_sizes_delay_float}%
981
982\def\page_sides_local_float_flush
983  {\ifconditional\c_page_sides_shape_down
984     \ifnum\localboxlinenumber=\c_page_sides_n_of_lines\relax
985       \hpack to \localboxlinewidth
986         xoffset -\the\localboxlinewidth
987         yoffset -\d_page_sides_shape_down_shift
988       {\box\floatbox}%
989     \fi
990   \fi}
991
992%D Experimental and tricky:
993%D
994%D \starttext
995%D     \samplefile{lorem} \blank[20*line]
996%D     \startplacefigure[location={right,15*hang,force}]
997%D    %\startplacefigure[location={right,15*hang}]
998%D         \framed[width=30mm,height=20mm]{!!}
999%D     \stopplacefigure
1000%D     \dorecurse{10}{\samplefile{lorem}}
1001%D \stoptext
1002
1003\definelocalboxes
1004  [\v!left:\v!float]
1005  [\c!command=\page_sides_local_float_flush,
1006   \c!location=\v!middle]
1007
1008\def\page_sizes_delay_float
1009  {\ifconditional\c_page_sides_shape_down
1010     \localbox[\v!left:\v!float]{}%
1011   \fi}%
1012
1013\def\page_sides_check_floats_indeed
1014  {\page_sides_analyse_progress
1015   \ifdim\d_page_sides_progress>\zeropoint
1016     \page_sides_check_floats_set
1017   \else
1018     \page_sides_check_floats_reset
1019   \fi
1020   \parskip\s_spac_whitespace_parskip} % not needed
1021
1022% \let\page_sides_check_floats\page_sides_check_floats_indeed
1023
1024\let\page_sides_check_floats\relax
1025
1026\def\page_sides_initialize_checker
1027  {\ifrelax\page_sides_check_floats
1028     \glet\page_sides_check_floats\page_sides_check_floats_indeed
1029     \clf_enablesidefloatchecker
1030     \glet\page_sides_initialize_checker\relax
1031   \fi}
1032
1033\protected\def\page_sides_check_floats_tracer
1034  {\begingroup
1035   \dontleavehmode
1036   \ifnum\c_page_sides_float_type>\plusfour
1037     \rlap
1038       {\hskip\availablehsize % d_page_sides_width % kern
1039        \color[trace:o]%
1040          {\rlap{\kern.25\bodyfontsize\showstruts\strut}%
1041           \vrule\s!height.5\points\s!depth.5\points\s!width\d_page_sides_width}}%
1042   \else
1043     \hskip-\d_page_sides_width % kern
1044     \color[trace:o]%
1045       {\vrule\s!height.5\points\s!depth.5\points\s!width\d_page_sides_width
1046        \llap{\showstruts\strut\kern.25\bodyfontsize}}%
1047   \fi
1048   \endgroup}
1049
1050% tricky test:
1051
1052% \starttext
1053%     \dorecurse{33}{\line{#1}}
1054%     \placefigure[left]{}{}
1055%     \input ward
1056%     \startitemize
1057%         \item word \item word \item word \item word
1058%     \stopitemize
1059%     \input ward
1060%     \page
1061%     \placefigure[left]{}{}
1062%     \dontleavehmode \begingroup \input ward \par \endgroup
1063%     \dontleavehmode \begingroup \input ward \par \endgroup
1064%     \dontleavehmode \begingroup \input ward \par \endgroup
1065%     \input ward
1066% \stoptext
1067
1068\protected\def\page_sides_check_floats_set_shape
1069  {\privatescratchtoks\emptytoks
1070   \privatescratchcounter\c_page_sides_n_of_lines
1071   \privatescratchdimen{\hsize-\d_page_sides_width}%
1072   \dorecurse\c_page_sides_n_of_lines
1073     {\toksapp\privatescratchtoks{\zeropoint\hsize}}%
1074   \ifnum\c_page_sides_n_of_hang>\c_page_sides_n_of_lines
1075     \advanceby\c_page_sides_n_of_hang -\c_page_sides_n_of_lines\relax
1076     \advanceby\privatescratchcounter\c_page_sides_n_of_hang
1077     \dorecurse\c_page_sides_n_of_hang % weird, shouldn't that be scratchcounter
1078       {\ifnum\c_page_sides_float_type>\plusfour
1079          \toksapp\privatescratchtoks{\zeropoint\privatescratchdimen}%
1080        \else
1081          \toksapp\privatescratchtoks{\d_page_sides_width\privatescratchdimen}%
1082        \fi}%
1083   \fi
1084   \parshape
1085     \numexpr\privatescratchcounter+\plusone\relax
1086     \the\privatescratchtoks
1087     \zeropoint \hsize
1088   \relax}
1089
1090\protected\def\page_sides_check_floats_set_hang
1091  {\hangindent \ifnum\c_page_sides_float_type>\plusfour -\fi\d_page_sides_width
1092   \hangafter-\c_page_sides_n_of_hang
1093   \global\c_page_sides_hangafter\hangafter}
1094
1095\protected\def\page_sides_check_floats_set
1096  {\edef\p_sidethreshold{\floatparameter\c!sidethreshold}%
1097   \ifconditional\c_page_sides_delayed
1098     % For Alan's hanging right float that moved to the next page.
1099     \d_page_sides_progress\zeropoint
1100   \fi
1101   \ifx\p_sidethreshold\v!old
1102     \d_page_sides_progression{\d_page_sides_progress+\strutht-\roundingeps}%
1103     \c_page_sides_n_of_hang\d_page_sides_progression
1104     \divideby\c_page_sides_n_of_hang \baselineskip\relax
1105   \else
1106     \d_page_sides_progression
1107       \ifempty\p_sidethreshold
1108         \d_page_sides_progress
1109       \else
1110         {\d_page_sides_progress-\p_sidethreshold}%
1111       \fi
1112     \getnoflines\d_page_sides_progression
1113     % this can be an option
1114     \ifdim{\noflines\lineheight}>{\pagegoal-\pagetotal}%
1115       \getrawnoflines\d_page_sides_progression
1116     \fi
1117     %
1118     \c_page_sides_n_of_hang\noflines
1119   \fi
1120   \global\c_page_sides_hangafter\zerocount
1121   \ifnum\c_page_sides_n_of_hang>\zerocount
1122     \ifcase\c_page_sides_n_of_lines
1123     \else
1124       \ifcase\c_page_sides_lines_done
1125         \global\c_page_sides_lines_done\c_page_sides_n_of_hang
1126       \else
1127         \privatescratchcounter\c_page_sides_lines_done
1128         \advanceby\privatescratchcounter-\c_page_sides_n_of_hang
1129         \global\advanceby\c_page_sides_n_of_lines-\privatescratchcounter
1130       \fi
1131     \fi
1132     \ifnum\c_page_sides_n_of_lines>\zerocount
1133       \page_sides_check_floats_set_shape
1134     \orelse\ifconditional\c_page_sides_force_shape
1135       \page_sides_check_floats_set_shape
1136     \else
1137       \page_sides_check_floats_set_hang
1138     \fi
1139   \fi
1140   \global\advanceby\c_page_sides_checks_done \plusone
1141   \iftracesidefloats
1142     \page_sides_check_floats_tracer
1143   \fi}
1144
1145\protected\def\page_sides_check_floats_reset
1146  {\ifcase\c_page_sides_checks_done\else
1147     \ifcase\c_page_sides_hangafter\else
1148       % we need to deal with par's ending in a group which would restore
1149       % hang parameters
1150       \global\c_page_sides_hangafter\zerocount
1151       \hangindent\zeropoint
1152     \fi
1153   % \global % no, otherwise a next hangindent won't work
1154     \c_page_sides_checks_done\zerocount
1155   \fi}
1156
1157\protected\def\page_sides_synchronize_floats
1158  {\ifinner \else
1159     \page_sides_check_floats
1160   \fi}
1161
1162\protected\def\page_sides_check_previous_float
1163  {\page_sides_analyse_progress
1164   \ifdim\d_page_sides_progress>\zeropoint \relax
1165     \ifconditional\c_page_sides_short
1166       \global\c_page_sides_short\conditionalfalse
1167       \page_otr_fill_and_eject_page
1168     \else
1169       \kern\d_page_sides_progress
1170     \fi
1171   \fi}
1172
1173% \def\adjustsidefloatdisplaylines % public, will change
1174%   {\aftergroup\page_sides_adjust_display_lines}
1175%
1176% \def\page_sides_adjust_display_lines
1177%   {\par
1178%    \noindent
1179%    \ignorespaces}
1180
1181%D We need to hook it into the other otr's. This code will be adapted once we rename
1182%D the callers. We use \type {\def} as they can be redefined! Some will become obsolete
1183
1184\permanent\protected\def\checksidefloat         {\page_sides_check_floats}
1185\permanent\protected\def\flushsidefloats        {\page_sides_flush_floats_text}
1186\permanent\protected\def\flushsidefloatsafterpar{\page_sides_flush_floats_after_par}
1187\permanent\protected\def\forgetsidefloats       {\page_sides_forget_floats}
1188%permanent\protected\def\synchronizesidefloats  {\page_sides_synchronize_floats}
1189
1190\protect \endinput
1191