strc-flt.mkvi / last modification: 2020-01-30 14:16
%D \module
%D   [       file=strc-flt,
%D        version=2008.10.20,
%D          title=\CONTEXT\ Structure Macros,
%D       subtitle=Float Numbering,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D This module will be redone with conditionals and everythings

\writestatus{loading}{ConTeXt Structure Macros / Float Numbering}

\registerctxluafile{strc-flt}{}

\unprotect

% todo: a keyword for this (and then a settings->hash for speed)
%
% \setuplayout[width=middle,backspace=3cm]
%
% \appendtoks
%     \settrue\inhibitmargindata
% \to \everyinsidefloat
%
% \starttext
%     \dorecurse{20}{
%         \par \inleft{\red\infofont<#1>} \par
%         \placefigure[leftmargin]{}{\framed[height=1cm,width=2cm]{}}
%       % \placefigure{#1}{\framed[height=1cm,width=2cm]{}}
%         \par line #1.1 \par line #1.2 \par
%     }
% \stoptext

% todo: delay caption creation and make setups for each method instead
%       so that we can have a list of methods and redo them as we can
%       keep the list or even better: recreate it
%
% todo: strc_floats_analyze_variables_two could trigger a setup
%       and we could have nofmethods of them
%
% todo: move variables from page-flt to strc-flt
%
% todo: p_name etc
%
% todo: less globals!
%
% todo: do all options in lua

%D This module is being converted into a mkvi one.
%D
%D - rename macros
%D - get rid of dead code
%D - less gobal mess
%D - more mkiv-ish

\installcorenamespace{float}
\installcorenamespace{floatbuilder}
\installcorenamespace{floatcaption}
\installcorenamespace{floatframed}

\installframedcommandhandler \??float        {float}        \??float
\installframedcommandhandler \??floatcaption {floatcaption} \??floatcaption
\installframedcommandhandler \??floatframed  {floatframed}  \??floatframed

\let\setupfloats  \setupfloat
\let\setupcaption \setupfloatcaption
\let\setupcaptions\setupfloatcaption

\unexpanded\def\dohandlenextfloatindent
  {\useindentnextparameter\floatparameter
   \dorechecknextindentation}

\setupcaptions
  [\c!location=\v!bottom,
   \c!grid=,
   \c!before=, % not used (yet)
   \c!inbetween={\blank[\v!medium]},
   \c!after=, % not used (yet)
   \c!spacebefore=,
   \c!spaceinbetween=, % replaces fuzzy inbetween dual usage
   \c!spaceafter=,
   \c!width=\v!fit,
   \c!minwidth=\v!fit, % id est: the width of the floatbox in some cases
   \c!headstyle=\v!bold,
   \c!headcolor=,
   \c!leftmargin=\zeropoint,
   \c!rightmargin=\zeropoint,
   \c!outermargin=\zeropoint,
   \c!innermargin=\zeropoint,
   \c!setups=,
   \c!style=\v!normal,
   \c!color=,
   \c!textstyle=,
   \c!textcolor=,
   \c!align=,
   \c!number=\v!yes,
   \c!offset=\v!overlay,
   \c!frame=\v!off,
 % \c!expansion=,
 % \c!prefix=,
 % \c!prefixconnector=,
 % \c!way=,
 % \c!prefixsegments=,
 % \c!way=,
 % \c!blockway=,
 % \c!sectionnumber=,
 % \c!separator=,
 % \c!starter=,
 % \c!stopper=,
   \c!suffixseparator=, % currently rather hard coded
   \c!suffix=\floatcaptionsuffix,
   \c!distance=\emwidth, % plus .5\emwidth minus .25\emwidth
   \c!conversion=\v!numbers,
   \c!maxwidth=\hsize,
   \c!command=]

% we can comment some of these

\setupfloats
  [\c!location=\v!middle,
   \c!width=8\lineheight,
   \c!height=6\lineheight,
   \c!offset=\v!overlay,
   \c!frame=\v!off,
   \c!strut=\v!no,
   \c!radius=.5\bodyfontsize,
   \c!corner=\v!rectangular,
   \c!grid=,
  %\c!background=,
  %\c!backgroundcolor=,
   \c!backgroundoffset=\!!zeropoint,
  %\c!topframe=,
  %\c!bottomframe=,
  %\c!leftframe=,
  %\c!rightframe=,
   \c!frameoffset=\!!zeropoint,
  %\c!before=,
  %\c!after=,
   \c!spacebefore=\v!big,
   \c!spaceafter=\v!big,
   \c!sidespacebefore=\rootfloatparameter\c!spacebefore,
   \c!sidespaceafter=\rootfloatparameter\c!spaceafter,
   \c!sidespaceinbetween=\rootfloatparameter\c!spacebefore,
   \c!spacebeforeside=, % extra, not part of, can be used to add whitespace before text
   \c!spaceafterside=,  % idem
   \c!sidealign=\v!normal,
   \c!textmethod=\ifgridsnapping2\else0\fi, % 0=raw 1=safe (.99pg) 2=tight (-1pt) % THIS WILL CHANGE
   \c!sidemethod=\ifgridsnapping2\else1\fi, % 0=raw 1=safe (.99pg) 2=tight (-1pt) % THIS WILL CHANGE
   \c!indentnext=\v!no,
   \c!margin=\emwidth,
   \c!method=1,
   \c!cache=\v!yes, % when no, then intermediate flush
   \c!leftmargin=\zeropoint,  % displacement in 'normal floats'
   \c!rightmargin=\zeropoint, % idem
   \c!innermargin=\zeropoint, % idem
   \c!outermargin=\zeropoint, % idem
   \c!leftmargindistance=\zeropoint,
   \c!rightmargindistance=\floatparameter\c!leftmargindistance,
   \c!step=\v!small, % the flush side float step (big, medium, small : always depth)
   \c!ntop=2,
   \c!nbottom=0,
   \c!nlines=4, % used?
   \c!topoffset=\zeropoint,
   \c!bottomoffset=\zeropoint,
   \c!freeregion=\v!yes,
  %\c!local=,
  %\c!bottombefore=, % e.g. \vfill
  %\c!bottomafter=,
  %\c!default=, % default location
   \c!sidethreshold=.5\strutdp, % set to "old" to check with old method
   \c!numbering=\v!yes,
   \c!compress=\v!yes, % when possible pack floats when flushing
   \c!compressdistance=\emwidth]

\setupfloatframed
  [\c!frame=\v!off,
   \c!offset=\v!overlay,
   \c!strut=\v!no]

\appendtoks
    \doifelse{\floatparameter\c!compress}\v!yes\settrue\setfalse\c_page_floats_pack_flushed
    \d_page_floats_compress_distance\floatparameter\c!compressdistance\relax
\to \everysetupfloat

%D We need to do it again here:

\setupfloat
  [\c!compress=\v!yes, % when possible pack floats when flushing
   \c!compressdistance=\emwidth]

%D Individial settings:

\installcounterassociation{floatcaption}

\appendtoks
    \let\currentfloat\currentfloatcaption % ?
    \synchronizefloatcaptioncounters
\to \everysetupfloatcaption

\appendtoks
    \let\currentfloat\currentfloatcaption % ?
    \synchronizefloatcaptioncounters
\to \everydefinefloatcaption

%D Definitions:

\let\strc_floats_define_saved\definefloat

\unexpanded\def\definefloat
  {\dotripleempty\strc_floats_define}

\def\strc_floats_define[#1][#2][#3]% name+plural+parent | name+parent+settings
  {\ifthirdargument
     \doifassignmentelse{#3}
       {\strc_floats_define_b[#1][#2][#3]}%
       {\strc_floats_define_a[#1][#2][#3]}%
   \else\ifsecondargument
     \doifelsecommandhandler\??float{#2}%
       {\strc_floats_define_a[#1][#1][#2]}%
       {\strc_floats_define_c[#1][#2]}%
   \else
     \strc_floats_define_c[#1][#1]%
   \fi\fi}

\def\strc_floats_define_a[#1][#2][#3]% name names parent
  {\definefloatcaption[#1][#3]%
   \definefloatframed[#1][#3]%
   \definecounter[#1][#3]%
   \definelist[#1][#3]%
   \copylabeltext[#1=#3]%
   \strc_floats_define_saved[#1][#3]%
   \strc_floats_define_commands{#1}{#2}}

\def\strc_floats_define_b[#1][#2][#3]% name parent settings
  {\definefloatcaption[#1][#2]%
   \definefloatframed[#1][#2]%
   \definecounter[#1][#2]%
   \definelist[#1][#2]%
   \copylabeltext[#1=#2]%
   \strc_floats_define_saved[#1][#2][#3]%
   \strc_floats_define_commands{#1}{#1}}

\def\strc_floats_define_c[#1][#2]% name names
  {\registerfloatcaptioncounter{#1}%
   \definefloatcaption[#1]%
   \definefloatframed[#1]%
   \definecounter[#1]%
   \definelist[#1]%
   \presetlabeltext[#1=\Word{#1}~]%
   \presetheadtext[#2=\Word{#2}]%
   \strc_floats_define_saved[#1]%
   \strc_floats_define_commands{#1}{#2}}

\def\strc_floats_define_commands#1#2%
  {\setuvalue         {\e!place\e!listof#2}{\dodoubleempty\strc_lists_place[#1]}% call will change
   \setuvalue      {\e!complete\e!listof#2}{\dotripleempty\strc_lists_complete_indeed[#1][#2]}% call will change
   \setuevalue                 {\e!place#1}{\strc_floats_place{#1}}%
   \setuevalue         {\e!start\e!place#1}{\strc_floats_start_place{#1}}%
   \setuevalue          {\e!stop\e!place#1}{\strc_floats_stop_place}%
   \setuevalue          {\e!start#1\e!text}{\strc_floats_start_text{#1}}%
   \setuevalue           {\e!stop#1\e!text}{\strc_floats_stop_text}%
   % these will become obsolete:
   \setuevalue               {\e!reserve#1}{\strc_floats_reserve{#1}}%
   \setuevalue{\e!start\e!reserve#1\e!text}{\strc_floats_start_reserve_text{#1}}%
   \setuevalue {\e!stop\e!reserve#1\e!text}{\strc_floats_stop_reserve_text}}

%D Fallback float body:

\unexpanded\def\strc_floats_place_empty_box % \inheritedfloatframed
  {\framed
     [\c!frame=\v!on,
      \c!width=\rootfloatparameter\c!width,
      \c!height=\rootfloatparameter\c!height,
      \c!location=\v!normal,
      \c!offset=\rootfloatparameter\c!offset]%
     {\getmessage\m!floatblocks{12}\empty}}

%D Data. We can generalize this to lists.

\newif\ifnofloatcaption
\newif\ifnofloatnumber
\newif\ifemptyfloatcaption

\installstructurelistprocessor\s!float{\usestructurelistprocessor{number+title}}

\unexpanded\def\thecurrentfloatnumbersuffix
  {\doifsomething{\floatcaptionparameter\c!suffix}
     {\floatcaptionparameter\c!suffixseparator
      \floatcaptionparameter\c!suffix
      \floatcaptionparameter\c!suffixstopper}}

\unexpanded\def\thecurrentfloatnumber
  {\ifnofloatcaption \else \ifnofloatnumber \else
     \ifx\currentfloatnumber\relax\else
       \namedtaggedlabeltexts
         \t!floatlabel \currentfloat
         \t!floatnumber\currentfloat
         {\begstrut
          \floatcaptionparameter\c!numbercommand
            {\clf_savedlistprefixednumber{\currentfloat}\currentfloatnumber\relax
             \thecurrentfloatnumbersuffix}%
          \endstrut}%
     \fi
   \fi \fi}

\unexpanded\def\thecurrentfloatcaption
  {\ifnofloatcaption \else \ifemptyfloatcaption \else
     \ifx\currentfloatnumber\relax\else
       \dostarttagged\t!floattext\empty
       \begstrut
       \floatcaptionparameter\c!textcommand
         {\clf_savedlisttitle{\currentfloat}\numexpr\currentfloatnumber\relax}%
       \endstrut
       \dostoptagged
     \fi
   \fi \fi}

%D Captions.

\let\floatcaptionsuffix\empty % an optional suffix
\let\floatcaptionnumber\empty % a logical counter

% For a while these were placeholders:
%
%D \starttyping
%D \unexpanded\def\placefloatcaption{\dodoubleempty\strc_floats_place_caption}
%D \unexpanded\def\setfloatcaption  {\dodoubleempty\strc_floats_set_caption}
%D
%D \def\strc_floats_place_caption[#tag][#reference]#caption{[not supported]}
%D \def\strc_floats_set_caption  [#tag][#reference]#caption{[not supported]}
%D
%D \unexpanded\def\placefloatcaptiontext     [#tag]{[not suported yet]}
%D \unexpanded\def\placefloatcaptionnumber   [#tag]{[not suported yet]}
%D \unexpanded\def\placefloatcaptionreference[#tag]{[not suported yet]}
%D \stoptyping
%D
%D because in \MKII\ we had:
%D
%D \starttyping
%D \let\placefloatlabel         \placefloatcaption
%D \let\placefloatlabeltext     \placefloatcaptiontext
%D \let\placefloatlabelreference\placefloatcaptionreference
%D \stoptyping
%D
%D But as it was never advertised we don't provide it in \MKIV. However, at some
%D point HvdM wanted this:
%D
%D \starttyping
%D \placefigure                     {labeltext-1}  {\externalfigure[figure-1]}
%D \placefloatcaption[figure][title={labeltext-2}]  \externalfigure[figure-2]
%D \placefigure                     {labeltext-3}  {\externalfigure[figure-3]}
%D \stoptyping
%D
%D So there you have it:

\unexpanded\def\placefloatcaption
  {\dotripleempty\strc_floats_place_caption}

\def\strc_floats_place_caption[#category][#settings][#userdata]%
  {\ifsecondargument
     % we need at least a category and title
     \dontleavehmode
     \bgroup
     \edef\currentfloat{#category}%
     \let\currentfloatcaption\currentfloat
     \resetfloatcaptionparameter\c!reference
     \resetfloatcaptionparameter\c!title
     \resetfloatcaptionparameter\c!marking
     \resetfloatcaptionparameter\c!list
     \resetfloatcaptionparameter\c!bookmark
     \setupcurrentfloatcaption[#settings]%
     \edef\currentfloatcounter{\namedcounterparameter\currentfloat\s!name}%
     \iftrialtypesetting\strc_counters_save\currentfloatcounter\fi
     \strc_counters_increment\currentfloatcounter
     \strc_counters_register_component
       \s!float
       \setupcurrentfloatcaption
       \floatcaptionparameter
       \detokenizedfloatcaptionparameter
       \relax
       \relax
       \relax
       [\s!name=\currentfloat,
        \s!counter=\currentfloatcounter,%
        \s!hascaption=\v!yes,%
        \s!hasnumber=\v!yes,%
        \s!hastitle=\v!yes]%
       [#userdata]%
     \glet\previousfloatnumber    \m_strc_counters_last_registered_index
     \glet\currentfloatnumber     \m_strc_counters_last_registered_index
     \glet\currentfloatattribute  \m_strc_counters_last_registered_attribute
     \glet\currentfloatsynchronize\m_strc_counters_last_registered_synchronize
     %
   % \iflocation
   %    \attribute\destinationattribute\currentfloatattribute\relax
   % \fi
     \currentfloatsynchronize
     \strc_floats_make_complete_caption
     %
     \iftrialtypesetting\strc_counters_restore\currentfloatcounter\fi
     \egroup
   \fi}

\newbox  \b_strc_floats_caption
\newbox  \b_strc_floats_content
\newdimen\d_strc_floats_caption_height
\newdimen\d_strc_floats_caption_depth

\def\strc_floats_make_complete_caption
  {\doifsomething{\floatcaptionparameter\c!spacebefore}{\blank[\floatcaptionparameter\c!spacebefore]}%
   \strc_floats_make_complete_caption_before
   \synchronizedisplaydirection % temp hack, till we have a proper model
   \noindent
   \gdef\lastcaptiontag{\strut\thecurrentfloatnumber}% was xdef ... needs checking
   \begingroup
     \ifnofloatcaption
       \global\d_strc_floats_caption_height\zeropoint
       \global\d_strc_floats_caption_depth \zeropoint
     \else
       \usefloatcaptionstyleandcolor\c!style\c!color
       \clf_doifelselisthastitle{\currentfloat}\numexpr\currentfloatnumber\relax
         \donothing
         \emptyfloatcaptiontrue
       \ifnofloatnumber \else \ifnofloatcaption \else
         \ifemptyfloatcaption
           \hbox{\usefloatcaptionstyleandcolor\c!headstyle\c!headcolor\thecurrentfloatnumber}%
         \else
           \doifelsenothing{\floatcaptionparameter\c!spaceinbetween}
             {\scratchskip\floatcaptionparameter\c!distance\relax
              \setbox\scratchbox\hbox
                {\usefloatcaptionstyleandcolor\c!headstyle\c!headcolor
                 \thecurrentfloatnumber
                 \floatcaptionparameter\c!headseparator
                 \dotfskip\scratchskip}%
              \doifelse{\floatcaptionparameter\c!hang}\v!yes
                 {\leftskip\wd\scratchbox
                  \llap{\box\scratchbox}}
                 {\unhbox\scratchbox}%
               \emergencystretch.5\scratchskip}
             {\hbox{\usefloatcaptionstyleandcolor\c!headstyle\c!headcolor\thecurrentfloatnumber}%
              \blank[\floatcaptionparameter\c!spaceinbetween]}%
         \fi
       \fi \fi
       \usefloatcaptionstyleandcolor\c!textstyle\c!textcolor
       \global\d_strc_floats_caption_height\strutheight
       \global\d_strc_floats_caption_depth \strutdepth
       \thecurrentfloatcaption\endgraf
     \fi
   \endgroup
   \strc_floats_make_complete_caption_after
   \doifsomething{\floatcaptionparameter\c!spaceafter}{\blank[\floatcaptionparameter\c!spaceafter]}}

%let\strc_floats_make_complete_caption_before\relax
\let\strc_floats_make_complete_caption_after \relax

\def\strc_floats_make_complete_caption_before
  {\doifelseframed\floatcaptionparameter\strc_floats_make_complete_caption_before_indeed\relax}

\def\strc_floats_make_complete_caption_before_indeed
  {\edef\m_strc_align{\floatcaptionparameter\c!align}%
   \edef\m_strc_strut{\floatcaptionparameter\c!strut}%
   \letfloatcaptionparameter\c!align\v!normal
   \letfloatcaptionparameter\c!strut\v!no
   \inheritedfloatcaptionframed
   \bgroup
   \letfloatcaptionparameter\c!align\m_strc_align
   \letfloatcaptionparameter\c!strut\m_strc_strut
   \let\strc_floats_make_complete_caption_after\egroup}

% \definefloat  [figure-1] [figure]
% \definefloat  [figure-2] [figure]
% \setupfloat   [figure-1] [location=left,leftmargin=10mm]
% \setupfloat   [figure-2] [location=left,leftmargin=-5mm]
% \setupcaption [figure-1] [align=flushleft]
% \setupcaption [figure-2] [align=flushleft,leftmargin=15mm]
%
% \startsetups somefigure
%     \ifdim\wd\nextbox>\textwidth
%         \placefloat[figure-2][][]{}{\box\nextbox}
%     \else
%         \placefloat[figure-1][][]{}{\box\nextbox}
%     \fi
% \stopsetups
%
% \unexpanded\def\setupswithbox[#1]{\dowithnextbox{\setups[#1]}\vbox}
%
% test \setupswithbox[somefigure]{\framed[width=3cm]                         {}} test
% test \setupswithbox[somefigure]{\framed[width=\dimexpr\textwidth+3cm\relax]{}} test

% temporary removed ... was not applied systematically
%
% \def\dosetcaptionthings
%   {\usesetupsparameter\floatcaptionparameter}

\def\strc_floats_check_caption_content
  {\ifnofloatcaption
   \else
     \setbox\b_strc_floats_caption\hbox
       {\settrialtypesetting
        \notesenabledfalse
        \strc_floats_make_complete_caption}%
     % new, \placefigure{\xmlfirst{#1}{somecaption}}{} passes earlier empty check
     % so here we misuse the scratch box; actually this means that the previous
     % test can go away (some day, when i redo this module)
     \ifzeropt\wd\b_strc_floats_caption
       \global\emptyfloatcaptiontrue
       \ifnofloatnumber
         \global\nofloatcaptiontrue
       \fi
     \else
       \global\emptyfloatcaptionfalse
       \setbox\b_strc_floats_caption\hpack{\hskip\leftskip\box\b_strc_floats_caption}%
     \fi
   \fi}

%D We can do this ...
%D
%D \starttyping
%D \newcount\c_strc_floats_n
%D
%D \definedataset[\s!float][\c!delay=\v!yes]
%D
%D \let\strc_float_realpage\realpageno
%D
%D \def\strc_float_save_data
%D   {\setdataset[\s!float][\number\c_strc_floats_n][]}
%D
%D \def\strc_float_load_data % precedes save !
%D   {\global\advance\c_strc_floats_n\plusone
%D    \xdef\strc_float_realpage{\datasetvariable\s!float{\number\c_strc_floats_n}\s!page}%
%D    \ifx\strc_float_realpage\empty
%D      \glet\strc_float_realpage\realpageno % \realfolio
%D    \fi}
%D \stoptyping
%D
%D ... but this is more efficient:

\definepagestate[\s!float][\c!delay=\v!yes]

\newcount\c_strc_floats_n

\let\strc_float_realpage\realpageno

\def\strc_float_save_data
  {\setpagestate[\s!float][\number\c_strc_floats_n]}

\def\strc_float_load_data % precedes save !
  {\global\advance\c_strc_floats_n\plusone
   \xdef\strc_float_realpage{\pagestaterealpage\s!float{\number\c_strc_floats_n}}%
   \ifx\strc_float_realpage\empty
    \glet\strc_float_realpage\realpageno % \realfolio
   \fi}

%D test case:
%D
%D \starttyping
%D \setupfloat[figure][criterium=\marginwidth,fallback=bottom]
%D \dorecurse{3}{
%D     \chapter{test}
%D     \placefigure[bottom]{1}{\framed{bottom}}
%D     test
%D     \placetable[bottom]{1}{\framed{table}}
%D     test
%D     \placetable{2}{\framed{table}}
%D     test
%D     \placefigure[left]{2}{\framed{left but way too wide}}
%D     \input tufte
%D     \placefigure[left]{3}{\framed{left but ok}}
%D     \input tufte }
%D \stoptyping

% A complication is that we may have to handle a pagebreak
% first, which in turn may issue a (postponed) float.
% Therefore we may not trust on variable assignments before
% we're really dealing with the float. Some day I'll root out
% the global settings.

\let\lastplacedfloat\empty

\def\strc_floats_set_current_tag#tag%
  {\edef\currentfloat{#tag}%
   \ifx\currentfloat\empty
     \let\currentfloat\v!figure % a bit of a hack
   \fi
   \doifelsecommandhandler\??float\currentfloat
     \donothing
     {\writestatus\m!floatblocks{unknown float type '\currentfloat'}%
      \let\currentfloat\v!figure}% also a hack
   \glet\lastplacedfloat\currentfloat
   \let\m_strc_floats_saved_userdata\empty
   \let\currentfloatcaption\currentfloat}

\let\askedfloatmethod \empty
\let\askedfloatoptions\empty

\def\strc_floats_reset_variables
  {\global\emptyfloatcaptionfalse
   \global\nofloatcaptionfalse
   \global\nofloatnumberfalse
   \glet\askedfloatmethod \empty
   \glet\askedfloatoptions\empty}

% place

\let\floatlabel         \empty
\let\floatcolumn        \empty
\let\floatrow           \empty
\let\floatlocation      \empty
\let\floatlocationmethod\empty

\def\strc_floats_analyze_location
  {% more will be moved here
   \let\floatlabel \empty
   \let\floatcolumn\empty
   \let\floatrow   \empty
   %
   \edef\floatcaptionlocation{\floatcaptionparameter\c!location}%
   %
   \setfloatmethodvariables\floatlocation}

\unexpanded\def\strc_floats_place#tag%
  {\flushnotes
   \page_otr_command_flush_side_floats % here !
   \strc_floats_begin_group
   \strc_floats_set_current_tag{#tag}%
   \dodoubleempty\strc_floats_place_indeed}

\newtoks\c_floats_every_table_float

\appendtoks
    \edef\floatlocation{\v!force,\v!always,\floatlocation}%
    \setupfloat[\c!spacebefore=\v!none,\c!spaceafter=\v!none]%
\to \c_floats_every_table_float

\ifdefined\dotagregisterfloat \else \let\dotagregisterfloat\gobbletwoarguments \fi

\def\strc_floats_place_indeed[#location][#reference]#caption%
  {\strc_floats_reset_variables
   \xdef\askedfloatoptions{#location}%
   \edef\floatlocation{#location}%
   \ifx\floatlocation\empty
     \edef\floatlocation{\floatparameter\c!default}% beware of a clash between alignment locations
   \fi
   \ifintable
     \the\c_floats_every_table_float
   \fi
   \strc_floats_analyze_location
   % todo: use \lets
   \setupcurrentfloatcaption[\c!reference={#reference},\c!title={#caption},\c!marking=,\c!list=,\c!bookmark=]%
   \doifelseinset\v!split\floatlocation\strc_floats_place_next_box_split\strc_floats_place_next_box_normal}

\unexpanded\def\placefloat
  {\flushnotes
   \page_otr_command_flush_side_floats % here !
   \strc_floats_begin_group
   \dotripleempty\strc_floats_place_float}

\def\strc_floats_place_float[#tag]%
  {\strc_floats_set_current_tag{#tag}%
   \strc_floats_place_indeed}

% start-stop

% \startplacefigure[title=oeps][subtitle=whatever]
%     \framed[width=10cm,height=5cm]{\floatuserdataparameter{subtitle}}
% \stopplacefigure

\installcorenamespace{floatuserdata}

\installsetuponlycommandhandler \??floatuserdata {floatuserdata}

\let\m_strc_floats_saved_userdata\empty % todo: reset this in non start|stop cases

\unexpanded\def\strc_floats_start_place#tag%
  {\flushnotes
   \page_otr_command_flush_side_floats % here !
   \strc_floats_begin_group
   \strc_floats_set_current_tag{#tag}%
   \dodoubleempty\strc_floats_start_place_indeed}

%D We abuse the settings to pick up some float parameters too which makes it
%D messy.

\def\strc_floats_start_place_indeed[#settings][#userdata]%
  {\strc_floats_reset_variables
   % save
   \edef\m_location    {\floatcaptionparameter\c!location}%
   \edef\m_topoffset   {\floatcaptionparameter\c!topoffset}%
   \edef\m_bottomoffset{\floatcaptionparameter\c!bottomoffset}%
   \edef\m_freeregion  {\floatcaptionparameter\c!freeregion}%
   % preset
   \letfloatcaptionparameter        \c!location     \empty
   \setexpandedfloatcaptionparameter\c!topoffset   {\floatparameter\c!topoffset}%
   \setexpandedfloatcaptionparameter\c!bottomoffset{\floatparameter\c!bottomoffset}%
   \setexpandedfloatcaptionparameter\c!freeregion  {\floatparameter\c!freeregion}%
   \letfloatcaptionparameter        \c!reference    \empty
   \letfloatcaptionparameter        \c!title        \empty
   \letfloatcaptionparameter        \c!marking      \empty
   \letfloatcaptionparameter        \c!list         \empty
   \letfloatcaptionparameter        \c!bookmark     \empty
   % pickup
   \setupcurrentfloatcaption[#settings]%
   \ifsecondargument
     \setupcurrentfloatuserdata[#userdata]%
     \def\m_strc_floats_saved_userdata{#userdata}%
   \else
     \let\m_strc_floats_saved_userdata\empty
   \fi
   % check
   \edef\floatlocation{\floatcaptionparameter\c!location}%
   \ifx\floatlocation\empty
      \edef\floatlocation{\floatparameter\c!default}%
   \fi
   % inherit
   \setexpandedfloatparameter\c!topoffset   {\floatcaptionparameter\c!topoffset}%
   \setexpandedfloatparameter\c!bottomoffset{\floatcaptionparameter\c!bottomoffset}%
   \setexpandedfloatparameter\c!freeregion  {\floatcaptionparameter\c!freeregion}%
   % restore
   \letfloatcaptionparameter\c!location    \m_location
   \letfloatcaptionparameter\c!topoffset   \m_topoffset
   \letfloatcaptionparameter\c!bottomoffset\m_bottomoffset
   \letfloatcaptionparameter\c!freeregion  \m_freeregion
   %
   \strc_floats_analyze_location
   \doifelseinset\v!split\floatlocation\strc_floats_place_next_box_split\strc_floats_place_next_box_normal
   \bgroup
   \ignorespaces}

\unexpanded\def\strc_floats_stop_place
  {\removeunwantedspaces
   \egroup}

\unexpanded\def\startplacefloat
  {\flushnotes
   \page_otr_command_flush_side_floats % here !
   \strc_floats_begin_group
   \dotripleempty\strc_floats_start_place_float}

\def\strc_floats_start_place_float[#tag]%
  {\strc_floats_set_current_tag{#tag}%
   \strc_floats_start_place_indeed}

\let\stopplacefloat\strc_floats_stop_place

% reserve

\unexpanded\def\strc_floats_reserve#tag%
  {\flushnotes
   \page_otr_command_flush_side_floats % here !
   \strc_floats_begin_group
   \strc_floats_set_current_tag{#tag}%
   \dotripleempty\strc_floats_reserve_indeed}

\def\strc_floats_reserve_indeed[#settings][#location][#reference]#caption% maybe check for #settings
  {\strc_floats_place_indeed[#location][#reference]{#caption}{\strc_floats_reserve_box{#settings}}}

\def\strc_floats_reserve_box#settings%
  {\begingroup
   \setupcurrentfloat[\c!frame=\v!on,#settings]%
   \inheritedfloatframed{}%
   \endgroup}

% text

\unexpanded\def\strc_floats_start_text#tag%
  {\flushnotes      % Here indeed?
   \page_otr_command_flush_side_floats % Here indeed?
   \strc_floats_begin_text_group
   \strc_floats_set_current_tag{#tag}%
   \dodoubleempty\strc_floats_start_text_indeed}

\def\strc_floats_start_text_indeed[#location][#reference]%
  {\strc_floats_place_indeed[\v!text,#location,\v!left][#reference]}

\unexpanded\def\strc_floats_stop_text
  {\strc_floats_stop_text_indeed}

% reserved text

\unexpanded\def\strc_floats_start_reserve_text#tag%
  {\flushnotes
   \page_otr_command_flush_side_floats
   \strc_floats_begin_text_group
   \strc_floats_set_current_tag{#tag}%
   \dotripleempty\strc_floats_start_reserve_text_indeed}

\def\strc_floats_start_reserve_text_indeed[#settings][#location][#reference]#caption%
  {\strc_floats_place_indeed[\v!text,#location,\v!left][#reference]{#caption}{\strc_floats_reserve_box{#settings}}}

\unexpanded\def\strc_floats_stop_reserve_text
  {\strc_floats_stop_text_indeed}

% special hack

\def\strc_floats_begin_group     {\begingroup}
\def\strc_floats_end_group       {\carryoverpar\endgroup}
\def\strc_floats_end_split_group {\endgroup}
\def\strc_floats_begin_text_group{\begingroup\let\strc_floats_end_group\relax}
\def\strc_floats_end_text_group  {\endgroup}

% implementation

%setnewconstant\c_page_one_float_method  \zerocount % 0=raw 1=safe (.99) 2=tight (-1pt) / belongs in page-one
\setnewconstant\c_strc_floats_rotation   \zerocount % 0 90 180 270
\newconditional\c_strc_floats_par_float

\ifdefined\page_margin_strc_floats_before    \else \let\page_margin_strc_floats_before   \relax \fi
\ifdefined\page_margin_strc_floats_set_hsize \else \let\page_margin_strc_floats_set_hsize\relax \fi

\def\flushfloatslist
  {\v!left,\v!right,\v!inner,\v!outer,%
   \v!backspace,\v!cutspace,%
   \v!inleft,\v!inright,\v!inmargin,%
   \v!leftmargin,\v!rightmargin,\v!leftedge,\v!rightedge,%
   \v!innermargin,\v!outermargin,\v!inneredge,\v!outeredge,%
   \v!text,\v!opposite}% \v!page

\unexpanded\def\strc_floats_place_next_box_split
  {\let\splitfloatfinalizer\strc_floats_end_split_group
   \let\strc_floats_end_group\relax
   \splitfloat{\strc_floats_place_next_box_normal}}

\unexpanded\def\strc_floats_place_next_box_normal
  {\ifconditional\c_page_floats_some_waiting
     % this was \checkwaitingfloats spread all over
     \doifelseinset\v!always\floatlocation
       {\showmessage\m!floatblocks5\empty}
       {\doifelsecommon\floatlocation\flushfloatslist\page_otr_command_flush_floats\donothing}%
     % but which should be done before using box \floatbox
   \fi
   \page_margin_strc_floats_before % todo: each float handler gets a before
   \global\insidefloattrue
   \dostarttaggedchained\t!float\currentfloat\??float
   \page_margin_strc_floats_set_hsize % todo: each float handler gets a set_hsize
   \the\everyinsidefloat
   \strc_floats_analyze_variables_one
   \dostarttagged\t!floatcontent\empty
   \dowithnextboxcontent
     {\strc_floats_set_local_hsize
      \floatparameter\c!inner
      \postponenotes} % new
     {\dostoptagged
      \strc_floats_finish_placement}
     \vbox}

%D \starttyping
%D \definefloat
%D   [one] [figure]
%D   [default=right,
%D    rightmargindistance=-20cm,
%D    criterium=129pt,
%D    fallback=rightmargin]
%D
%D \definefloat
%D   [two] [figure]
%D   [default=right,
%D    rightmargindistance=-20cm,
%D    criterium=129pt,
%D    fallback=three]
%D
%D \definefloat
%D   [three] [figure]
%D   [default=rightmargin,
%D    rightmargindistance=0cm]
%D
%D \placefloat[one]{}{\blackrule[width=30pt]}  \samplefile{tufte}
%D \placefloat[one]{}{\blackrule[width=60pt]}  \samplefile{tufte}
%D \placefloat[one]{}{\blackrule[width=90pt]}  \samplefile{tufte}
%D \placefloat[one]{}{\blackrule[width=130pt]} \samplefile{tufte}
%D \placefloat[two]{}{\blackrule[width=130pt]} \samplefile{tufte}
%D \stoptyping

\def\strc_floats_finish_placement
  {\doifsomething{\floatparameter\c!criterium}
     {\ifdim\wd\nextbox>\floatparameter\c!criterium\relax
        \edef\forcedfloatmethod{\floatparameter\c!fallback}%
        \ifx\forcedfloatmethod\empty \else
          \doifelsecommandhandler\??float\forcedfloatmethod
            {\let\currentfloat\forcedfloatmethod
             \edef\floatlocation{\floatparameter\c!default}%
             \let\forcedfloatmethod\floatlocation}
            \donothing
        \fi
        \ifx\forcedfloatmethod\empty
          \let\forcedfloatmethod\v!here
        \fi
      \fi}%
   \strc_floats_check_extra_actions
   \strc_floats_analyze_variables_two
   \strc_floats_place_packaged_boxes
   \dotagregisterfloat\askedfloatoptions\askedfloatmethod
   \dostoptagged % tricky .... needs checking
   % we need to carry over the par because of side floats
   \global\d_page_sides_downshift \zeropoint
   \global\d_page_sides_extrashift\zeropoint
   \ifconditional\c_strc_floats_par_float
     \doifinset\v!reset\floatlocation\page_sides_forget_floats
     \doinhibitblank
   \fi
   \strc_floats_end_group}

% nicer is a bunch of states and one loop that sets those states

\newdimen\d_strc_floats_top
\newdimen\d_strc_floats_bottom
\newdimen\d_strc_floats_overflow

% \def\strc_floats_calculate_skip#target#skip%
%   {\begingroup
%    \edef\askedfloatskip{\rootfloatparameter#skip}%
%    \ifx\askedfloatskip\empty
%      \global#target\zeropoint
%    \else\ifx\askedfloatskip\v!none
%      \global#target\zeropoint
%    \else
%      \setbox\scratchbox\vbox{\whitespace\blank[\askedfloatskip]}% todo: move whitespace inside blank
%      \global#target\ht\scratchbox
%    \fi\fi
%    \endgroup}

\def\strc_floats_calculate_skip#target#skip%
  {\begingroup
   \edef\p_blank{\rootfloatparameter#skip}%
   \ifx\p_blank\v!nowhite
     \edef\p_blank{-\v!white}%
   \fi
   \prerollblank[\p_blank]%
   \global#target\prerolledblank
   \endgroup}

\def\strc_floats_analyze_variables_two
  {\ifinsidecolumns
     \global\setfalse\c_strc_floats_par_float
   \else
     \doifelsecommon\floatlocation\flushfloatslist
       {\global\settrue \c_strc_floats_par_float}%
       {\global\setfalse\c_strc_floats_par_float}%
   \fi
   % variable initializations
   \global\d_page_sides_shift       \zeropoint
   \global\d_page_sides_maximum     \zeropoint
   \global\c_page_sides_align       \zerocount
   \global\c_page_sides_tolerance   \zerocount
   \global\c_page_sides_skipmode    \zerocount
   \global\c_strc_floats_rotation   \zerocount
   \global\d_page_sides_margin      \floatparameter\c!margin
   \global\d_page_sides_leftshift   \floatparameter\c!leftmargindistance
   \global\d_page_sides_rightshift  \floatparameter\c!rightmargindistance
   \global\d_page_sides_topoffset   \floatparameter\c!topoffset
   \global\d_page_sides_bottomoffset\floatparameter\c!bottomoffset
   \global\c_page_sides_method      \floatparameter\c!sidemethod
   \global\c_page_one_float_method  \floatparameter\c!textmethod
   \global\c_page_floats_n_of_top   \rootfloatparameter\c!ntop
   \global\c_page_floats_n_of_bottom\rootfloatparameter\c!nbottom
   \global\d_strc_floats_overflow   \zeropoint
   \ifconditional\c_strc_floats_par_float
     \global\d_strc_floats_top        \zeropoint
     \global\d_strc_floats_bottom     \zeropoint
     \strc_floats_calculate_skip\d_page_sides_topskip   \c!sidespacebefore
     \strc_floats_calculate_skip\d_page_sides_bottomskip\c!sidespaceafter
     \strc_floats_calculate_skip\d_page_sides_midskip   \c!sidespaceinbetween
     \strc_floats_calculate_skip\d_strc_floats_top      \c!spacebeforeside
     \strc_floats_calculate_skip\d_strc_floats_bottom   \c!spaceafterside
   \else
     \global\d_page_sides_topskip     \zeropoint
     \global\d_page_sides_bottomskip  \zeropoint
     \strc_floats_calculate_skip\d_strc_floats_top   \c!spacebefore
     \strc_floats_calculate_skip\d_strc_floats_bottom\c!spaceafter
   \fi
   % keyword handling
   \ifconditional\c_strc_floats_par_float
     \processaction
       [\floatparameter\c!sidealign]
       [\v!height=>\global\c_page_sides_align\plusone  ,%
          \v!line=>\global\c_page_sides_align\plustwo  ,% (***)
         \v!depth=>\global\c_page_sides_align\plusthree,%
          \v!grid=>\global\c_page_sides_align\plusfour ,%
      \v!halfline=>\global\c_page_sides_align\plusfive ]%
     \ifcase\c_page_sides_align\relax % todo: optie v!lokaal => \else
       \doifinset\v!height  \floatlocation{\global\c_page_sides_align\plusone  }%
       \doifinset\v!line    \floatlocation{\global\c_page_sides_align\plustwo  }%
       \doifinset\v!depth   \floatlocation{\global\c_page_sides_align\plusthree}%
       \doifinset\v!grid    \floatlocation{\global\c_page_sides_align\plusfour }%
       \doifinset\v!halfline\floatlocation{\global\c_page_sides_align\plusfive }% meant for 'none'
     \fi
     \doifinset\v!high        \floatlocation{\global\c_page_sides_skipmode \plusone  }%
     \doifinset\v!low         \floatlocation{\global\c_page_sides_skipmode \plustwo  }%
     \doifinset\v!fit         \floatlocation{\global\c_page_sides_skipmode \plusthree}%
     \doifinset\v!tolerant    \floatlocation{\global\c_page_sides_tolerance\plusone  }%
     \doifinset\v!verytolerant\floatlocation{\global\c_page_sides_tolerance\plustwo  }%
   \else
     \processallactionsinset
       [\floatlocation]%
       [ 90=>\global\c_strc_floats_rotation\commalistelement\relax,%
        180=>\global\c_strc_floats_rotation\commalistelement\relax,%
        270=>\global\c_strc_floats_rotation\commalistelement\relax]%
   \fi
   \doifelseinset\v!nonumber\floatlocation
     {\global\nofloatnumbertrue}%
     {\doifelse{\floatcaptionparameter\c!number}\v!yes
        {\global\nofloatnumberfalse}%
        {\global\nofloatnumbertrue}}%
   \doifelseinset\v!none\floatlocation
     {\global\nofloatcaptiontrue}%
     {\global\nofloatcaptionfalse}%
   \doif{\floatcaptionparameter\c!number}\v!none % new
     {\global\nofloatcaptiontrue}%
   \doifinset\v!effective\floatlocation
     {\letfloatparameter       \c!leftmargin \effectiveleftskip
      \letfloatparameter       \c!rightmargin\effectiverightskip
      \letfloatcaptionparameter\c!leftmargin \effectiveleftskip
      \letfloatcaptionparameter\c!rightmargin\effectiverightskip}%
   \ifemptyfloatcaption \ifnofloatnumber
     \global\nofloatcaptiontrue
   \fi \fi}

% documenteren in details

\def\strc_floats_analyze_variables_one
  {\doifelse{\floatparameter\c!local}\v!yes\settrue\setfalse\c_page_floats_center_box_global % fout keyword
   \ifconditional\c_page_floats_center_box_global
     \settrue\c_page_floats_center_box_local
   \else
     \doifelseinset\v!local\floatlocation\settrue\setfalse\c_page_floats_center_box_local
   \fi
   \doifelse{\floatparameter\c!freeregion}\v!yes
     \settrue\setfalse\c_strc_floats_mark_as_free
   \doifnotcommon{\v!always,\v!here,\v!force}\floatlocation % ! ! ! ! ! !
     {\setfalse\c_page_floats_center_box_global
      \setfalse\c_page_floats_center_box_local}}

\def\naturalfloatheight{\the\naturalfloatwd}
\def\naturalfloatwidth {\the\naturalfloatht}
\def\naturalfloatdepth {\the\naturalfloatdp}

\def\floatcaptionheight{\the\floatcaptionwd}
\def\floatcaptionwidth {\the\floatcaptionht}
\def\floatcaptiondepth {\the\floatcaptiondp}

\newdimen\naturalfloatwd
\newdimen\naturalfloatht
\newdimen\naturalfloatdp

\newdimen\floatcaptionwd
\newdimen\floatcaptionht
\newdimen\floatcaptiondp

\def\strc_floats_set_natural_dimensions#box%
  {\global\naturalfloatwd\wd#box\relax
   \global\naturalfloatht\ht#box\relax
   \global\naturalfloatdp\dp#box\relax}

\def\strc_floats_set_caption_dimensions#box%
  {\global\floatcaptionwd\wd#box\relax
   \global\floatcaptionht\ht#box\relax
   \global\floatcaptiondp\dp#box\relax}

\def\doifelsemainfloatbody
  {\ifinsidesplitfloat
     \ifconditional\splitfloatfirstdone
       \doubleexpandafter\secondoftwoarguments
     \else
       \doubleexpandafter\firstoftwoarguments
     \fi
   \else
     \expandafter\firstoftwoarguments
   \fi}

\let\doifmainfloatbodyelse\doifelsemainfloatbody

% todo: optional user pars

\let\currentfloatattribute\empty % to be checked

\def\floatcaptionattribute
  {\iflocation
      \ifx\currentfloatattribute\empty
        % safeguard, can be samepage too
      \else
       \ifnofloatcaption
       \else
         \ifinsidesplitfloat
            \ifconditional\splitfloatfirstdone
            \else
              attr \destinationattribute \currentfloatattribute
            \fi
         \else
           attr \destinationattribute \currentfloatattribute
         \fi
       \fi
     \fi
   \fi}

\newconditional\usesamefloatnumber

% \startplacefigure[location=here,reference=first, title=first, group=alpha,groupsuffix=.a]
%     \externalfigure[dummy][height=2cm]
% \stopplacefigure
% \startplacefigure[location=here,reference=second,title=second,group=alpha,groupsuffix=.b]
%     \externalfigure[dummy][height=2cm]
% \stopplacefigure
%
% uses:

\def\strc_floats_group_index
  {\numexpr\clf_listgroupindex{\currentfloat}{\currentfloatgroup}\relax}

\def\strc_floats_place_packaged_boxes
  {\expandafter\strc_floats_place_packaged_boxes_indeed\expandafter{\m_strc_floats_saved_userdata}}

\def\strc_floats_place_packaged_boxes_indeed#userdata%
  {\bgroup
   \ifconditional\usesamefloatnumber
     \glet\currentfloatnumber     \previousfloatnumber
     \glet\currentfloatattribute  \empty
     \glet\currentfloatsynchronize\relax
   \else
     \edef\currentfloatcounter{\namedcounterparameter\currentfloat\s!name}%
     \edef\currentfloatgroup  {\floatcaptionparameter\c!group}%
     \ifnofloatnumber \else \ifnofloatcaption \else
       \ifx\currentfloatgroup\empty
         % independent
         \iftrialtypesetting\strc_counters_save\currentfloatcounter\fi
         \strc_counters_increment\currentfloatcounter
       \else\ifcase\strc_floats_group_index
         % first in group
         \iftrialtypesetting\strc_counters_save\currentfloatcounter\fi
         \strc_counters_increment\currentfloatcounter
       \else
         % next in group
       \fi \fi
     \fi \fi
     % *1* as an alternative we could set counter parameters here if needed
     \strc_counters_register_component
       \s!float
       \setupcurrentfloatcaption
       \floatcaptionparameter
       \detokenizedfloatcaptionparameter
       \relax
       \relax
       \relax
       [\s!name=\currentfloat,% was c!name
        \s!counter=\currentfloatcounter,%
        \s!hascaption=\ifnofloatcaption \v!no\else\v!yes\fi,%
        \s!hasnumber=\ifnofloatnumber   \v!no\else\v!yes\fi,%
        \s!hastitle=\ifemptyfloatcaption\v!no\else\v!yes\fi]%
       [#userdata]%
     \glet\previousfloatnumber    \m_strc_counters_last_registered_index
     \glet\currentfloatnumber     \m_strc_counters_last_registered_index
     \glet\currentfloatattribute  \m_strc_counters_last_registered_attribute
     \glet\currentfloatsynchronize\m_strc_counters_last_registered_synchronize
   \fi
   %
   \iftrialtypesetting\else\global\setfalse\usesamefloatnumber\fi % one shot
   % check float box
   \strc_floats_set_natural_dimensions\nextbox
   \global\setbox\floatbox\vbox{\floatparameter\c!command{\box\nextbox}}% can be anything so no pack
   \strc_floats_set_natural_dimensions\floatbox
   \ifzeropt\htdp\floatbox
     \showmessage\m!floatblocks{11}\empty
     \global\setbox\floatbox\vpack
       {\dostarttagged\t!floatcontent\empty
        \strc_floats_place_empty_box
        \dostoptagged}%
   \fi
   % deal with lack of caption
   \global\setbox\floatbox\vpack \floatcaptionattribute
     {\doifelsemainfloatbody\currentfloatsynchronize\donothing
      \unvbox\floatbox
      \ifnofloatcaption
        \vss
      \fi}% gets rid of the depth (unless tabulate)
   \iftrialtypesetting\strc_counters_restore\currentfloatcounter\fi
   \egroup
   % place the float
   \strc_floats_set_box
   \strc_floats_get_box
   \global\insidefloatfalse}


\newdimen\availablefloatwidth
\newdimen\availablefloatheight

\def\strc_floats_set_local_hsize
  {\ifconditional\c_page_floats_center_box_local
     % also available check here?
     \seteffectivehsize
     \hsize\localhsize
   \else
     \doifinset\v!margin\floatlocation % brr, really needed! see wm will be redone
       {\hsize\namedmarginblockparameter\empty\c!width}%
   \fi
   \edef\p_availablewidth {\floatparameter\c!availablewidth }%
   \edef\p_availableheight{\floatparameter\c!availableheight}%
   \availablefloatwidth \ifx\p_availablewidth \empty\hsize\else\p_availablewidth \relax\fi
   \availablefloatheight\ifx\p_availableheight\empty\vsize\else\p_availableheight\relax\fi}

\ifdefined\everyinsidefloat \else \newevery \everyinsidefloat \relax \fi

\appendtoks
    \everyinsidefloat\emptytoks % in case it's called earlier
    \strc_float_load_data
\to \everyinsidefloat

\def\doifelserightpagefloat
  {\ifdoublesided
     \ifsinglesided
       \doubleexpandafter\firstoftwoarguments
     \else
       \doubleexpandafter\doifelseoddpagefloat
     \fi
   \else
     \expandafter\firstoftwoarguments
   \fi}

\def\doifelseoddpagefloat
  {\ifodd\purenumber\strc_float_realpage\space
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\let\doifrightpagefloatelse\doifelserightpagefloat
\let\doifoddpagefloatelse  \doifelseoddpagefloat

\appendtoks
    \let\rightorleftpageaction\doifelserightpagefloat
\to \everyinsidefloat

% \let\movesidefloat\gobbleoneargument

% new : \place...[leftmargin,-2*line]; we need to catch fxtb:2*3
% watch out: line alone aligns on the line ! ! !

\unexpanded\def\movesidefloat[#settings]% (-)n*line|x=,y=
  {\global\d_page_sides_downshift \zeropoint
   \global\d_page_sides_extrashift\zeropoint
   \doifelseassignment{#settings}%
     {\begingroup
      \setupcurrentfloat[\c!x=\zeropoint,\c!y=\zeropoint,#settings]%
      \ifgridsnapping
        \getnoflines{\floatparameter\c!y}%
        \global\d_page_sides_downshift\noflines\lineheight
      \else
        \global\d_page_sides_downshift\floatparameter\c!y
      \fi
      \global\d_page_sides_extrashift\floatparameter\c!x
      \endgroup}
     {\movedownsidefloat[#settings]}}

\installcorenamespace{floatmovement}

\setvalue{\??floatmovement \v!line}{\strc_floats_move_down_line+}
\setvalue{\??floatmovement+\v!line}{\strc_floats_move_down_line+}
\setvalue{\??floatmovement-\v!line}{\strc_floats_move_down_line-}
\setvalue{\??floatmovement \v!hang}{\strc_floats_move_down_hang\plusone}
\setvalue{\??floatmovement+\v!hang}{\strc_floats_move_down_hang\plusone}
\setvalue{\??floatmovement-\v!hang}{\strc_floats_move_down_hang\minusone}

\setvalue{\??floatmovement-2*\v!line}{\strc_floats_move_down_line{-2}}
\setvalue{\??floatmovement+2*\v!line}{\strc_floats_move_down_line{2}}
\setvalue{\??floatmovement 2*\v!line}{\strc_floats_move_down_line{2}}

\unexpanded\def\installfloatmovement#1#2{\setvalue{\??floatmovement#1}{#2}}

\def\strc_floats_move_down#setting%
  {\begincsname\??floatmovement#setting\endcsname}

\def\strc_floats_move_down_line#sign%
  {\if!!donea \else
     \global\d_page_sides_downshift\zeropoint
     \!!doneatrue
   \fi
   \global\advance\d_page_sides_downshift#sign\lineheight}

\def\strc_floats_move_down_hang#lines%
  {\if!!doneb \else
     \global\c_page_sides_n_of_lines\zerocount
     \!!donebtrue
   \fi
   \global\advance\c_page_sides_n_of_lines#lines\relax}

\unexpanded\def\movedownsidefloat[#settings]% already in core
  {\doifnotinstring{:}{#settings}
     {\begingroup
      \!!doneafalse
      \!!donebfalse
      \normalexpanded{\dorepeatwithcommand[#settings]}\strc_floats_move_down
      \endgroup}}

\unexpanded\def\hangsidefloat[#number]%
  {\global\c_page_sides_n_of_lines#number\relax}

\def\strc_floats_set_extra_action#rightpagelocation#leftpagelocation%
  {\rightorleftpageaction
     {\let\extrafloatlocation#rightpagelocation}%
     {\let\extrafloatlocation#leftpagelocation}}

\let\extrafloatlocation\empty

\installcorenamespace{extrafloataction}

\setvalue{\??extrafloataction      \v!inner}#1{\strc_floats_set_extra_action\v!left       \v!right}
\setvalue{\??extrafloataction      \v!outer}#1{\strc_floats_set_extra_action\v!right      \v!left}
\setvalue{\??extrafloataction\v!innermargin}#1{\strc_floats_set_extra_action\v!leftmargin \v!rightmargin}
\setvalue{\??extrafloataction\v!outermargin}#1{\strc_floats_set_extra_action\v!rightmargin\v!leftmargin}
\setvalue{\??extrafloataction  \v!inneredge}#1{\strc_floats_set_extra_action\v!leftedge   \v!rightedge}
\setvalue{\??extrafloataction  \v!outeredge}#1{\strc_floats_set_extra_action\v!rightedge  \v!leftedge}
\setvalue{\??extrafloataction  \v!backspace}#1{\strc_floats_set_extra_action\v!backspace  \v!cutspace}
\setvalue{\??extrafloataction   \v!cutspace}#1{\strc_floats_set_extra_action\v!cutspace   \v!backspace}
%setvalue{\??extrafloataction     \v!margin}#1{\strc_floats_set_extra_action\v!cutspace   \v!backspace}
\setvalue{\??extrafloataction       \v!left}#1{\strc_floats_set_extra_action\v!left       \v!left}
\setvalue{\??extrafloataction      \v!right}#1{\strc_floats_set_extra_action\v!right      \v!right}
\setvalue{\??extrafloataction       \v!line}#1{} % only -n*line is handled (see ***)
\setvalue{\??extrafloataction    \s!unknown}#1{\movedownsidefloat[#1]}

\def\strc_floats_check_extra_actions % less tracingthis way ....
  {\doifnotinset\v!text\floatlocation % fuzzy, text overloads left, since then it's a directive
     {\let\extrafloatlocation\empty
      % \d_page_sides_downshift will be reset afterwards, and can
      % already be set at this point
      \processcommacommand[\floatlocation]\strc_floats_check_extra_actions_step
      \ifx\extrafloatlocation\empty \else
        \edef\floatlocation{\extrafloatlocation,\floatlocation}%
        \setfloatmethodvariables\floatlocation
      \fi}}

\def\strc_floats_check_extra_actions_step#step%
  {\csname\??extrafloataction
     \ifcsname\??extrafloataction#step\endcsname#step\else\s!unknown\fi
   \endcsname{#step}}

% pas op, maxbreedte niet instellen als plaats=links/rechts

\def\strc_floats_set_local_dimensions
  {\global\d_page_sides_shift  \zeropoint       % duplicate
   \global\d_page_sides_maximum\zeropoint\relax % duplicate
   \ifzeropt\d_page_sides_downshift\else
     \global\setbox\floatbox\vpack
       {\vskip\d_page_sides_downshift
        \nointerlineskip
        \box\floatbox}%
   \fi
   \edef\p_minwidth{\floatparameter\c!minwidth}%
   \ifx\p_minwidth\empty
     % nothing
   \else
     \scratchwidth\p_minwidth\relax
     \ifdim\wd\floatbox<\scratchwidth
       \strc_floats_realign_floatbox_horizontal_two
     \fi
   \fi
   % we can also support edges .. in that case no common but a fast loop
   \doifelseinset\v!hanging\floatlocation
     {\doifelsecommon{\v!inleft,\v!leftmargin}\floatlocation
        {\let\p_maxwidth\leftmarginwidth}%
        {\doifelsecommon{\v!inright,\v!rightmargin}\floatlocation
           {\let\p_maxwidth\rightmarginwidth}%
           {\edef\p_maxwidth{\floatparameter\c!maxwidth}}}}%
     {\edef\p_maxwidth{\floatparameter\c!maxwidth}}%
   \ifx\p_maxwidth\empty
     % nothing
   \else
     \scratchwidth\p_maxwidth\relax
     \ifdim\wd\floatbox>\scratchwidth
       \doifelsecommon{\v!inright,\v!rightmargin,\v!rightedge,\v!inleft,\v!leftmargin,\v!leftedge}\floatlocation
         {\global\d_page_sides_maximum\scratchwidth}
         {\doifelsecommon{\v!right,\v!left}\floatlocation
            \strc_floats_realign_floatbox_horizontal_one
            \strc_floats_realign_floatbox_horizontal_two}%
     \fi
   \fi}

\def\strc_floats_realign_floatbox_horizontal_one
  {\global\setbox\floatbox\hpack to \scratchwidth
     {\doifnotinset\v!right\floatlocation\hss
      \box\floatbox
      \doifnotinset\v!left\floatlocation\hss}}

\def\strc_floats_realign_floatbox_horizontal_two % why is this
  {\global\setbox\floatbox\hpack to \scratchwidth
     {\doifnot{\floatparameter\c!location}\v!left\hss
      \box\floatbox
      \doifnot{\floatparameter\c!location}\v!right\hss}}

\unexpanded\def\placefloats
  {\page_otr_command_flush_floats}

\unexpanded\def\betweenfloatblanko % assumes that spaceafter is present
  {\blank[\rootfloatparameter\c!spacebefore]} % or v!back,....

% keep as old 1
%
% \unexpanded\def\doplacefloatbox % used elsewhere
%   {%\forgetall % NO
%    \whitespace
%    \blank[\rootfloatparameter\c!spacebefore]
%    \page_otr_command_flush_float_box
%    \blank[\rootfloatparameter\c!spaceafter]}
%
% keep as old 2
%
% \unexpanded\def\doplacefloatbox % used elsewhere
%   {%\forgetall % NO
%    \whitespace
%    \blank[\rootfloatparameter\c!spacebefore]
%    \nointerlineskip
%    \flushnotes % new per 2014-05-29 : todo: move them up in the mvl
%    \nointerlineskip
%    \page_otr_command_flush_float_box
%    \nointerlineskip
%    \blank[\rootfloatparameter\c!spaceafter]}

\def\strc_floats_apply_skip#1%
  {\edef\m_space{\rootfloatparameter#1}%
   \ifx\m_space\empty \else\ifx\m_space\v!none \else
      \directvspacing\m_space
   \fi\fi}

\unexpanded\def\doplacefloatbox % used elsewhere
  {%\forgetall % NO
   \whitespace
   \strc_floats_apply_skip\c!spacebefore
   \nointerlineskip
   \flushnotes % new per 2014-05-29 : todo: move them up in the mvl
   \nointerlineskip
   \page_otr_command_flush_float_box
 % \nointerlineskip % interferes with depth of caption
   \strc_floats_apply_skip\c!spaceafter}

% test case:
%
% \placefigure[page,none]{}{\blackrule[width=\textwidth,height=0.9\textheight,color=green]}
% \placefigure[page,none]{}{\blackrule[width=\textwidth,height=1.0\textheight,color=green]}
% \placefigure[page,none]{}{\blackrule[width=\textwidth,height=1.1\textheight,color=green]}

% the [#1] will go away

\def\page_one_place_float_text % this macro should be defined elsewhere
  {%\checkwaitingfloats\floatlocationmethod
   % todo: check if #1 is indeed \floatlocation or maybe more
   \global\floatwidth    \wd\floatbox
   \global\floatheight   \ht\floatbox % forget about the depth
   \global\floattextwidth\dimexpr\hsize-\floatwidth-\rootfloatparameter\c!margin\relax
   \edef\floatlocation{\floatlocationmethod}% to be sure .. why
   \doifelseinset\v!tall\floatlocationmethod
     {\floattextheight\dimexpr\pagegoal-\pagetotal-\bigskipamount\relax % ugly, this bigskip
      \ifdim\floattextheight>\textheight
        \floattextheight\textheight
      \fi
      \boxmaxdepth\zeropoint\relax            % toegevoegd
      \ifdim\floattextheight<\floatheight
        \floattextheight\floatheight
      \fi
      \setbox\floattext\vbox to \floattextheight}
     {\setbox\floattext\vbox}%
   \bgroup
   \forgetall
   \setupblank
   \setupwhitespace % new, also needed for footnotes
   \blank[\v!disable]
   \hsize\floattextwidth
   \ignorespaces}

\def\strc_floats_stop_text_indeed % todo
  {\egroup
   \doifnotinset\v!tall\floatlocation
     {\floattextheight\ifdim\ht\floattext<\floatheight\floatheight\else\ht\floattext\fi}%
   \setbox\floatbox\vpack to \floattextheight
     {\hsize\floatwidth
      \doifelseinset\v!both\floatlocation
        {\doifelseinset\v!low\floatlocation
           {\vfill\box\floatbox}
           {\doifelseinset\v!middle\floatlocation
              {\vfill\box\floatbox\vfill}
              {\box\floatbox\vfill}}}
        {\box\floatbox\vfill}}%
    \setbox\floattext\vpack to \floattextheight
     {\hsize\floattextwidth
      \doifelseinset\v!low\floatlocation
        {\vfill
         \box\floattext
         \doifinset\c!offset\floatlocation{\whitespace\blank}}
        {\doifelseinset\v!middle\floatlocation
           {\vfill
            \box\floattext
            \vfill}
           {\doifinset\v!offset\floatlocation{\whitespace\blank}%
            \box\floattext
            \vfill}}}%
   \doifelseinset\v!right\floatlocation
     {\setbox\floatbox\hpack to \hsize
        {\box\floattext
         \hfill
         \box\floatbox}}
     {\setbox\floatbox\hpack to \hsize
        {\box\floatbox
         \hfill
         \box\floattext}}%
   \baselinecorrection
   \whitespace
   \blank[\rootfloatparameter\c!spacebefore]%
   \doifnotinset\v!tall\floatlocation
     {\dp\floatbox\openstrutdepth}% dp\strutbox}%      % toegevoegd
   \box\floatbox
   \dostoptagged
   \blank[\rootfloatparameter\c!spaceafter]%
   \strc_floats_end_text_group
   \page_floats_report_total}

\def\borderedfloatbox
  {\begingroup
   \setupcurrentfloat[\c!location=\v!normal,\c!width=\v!fit,\c!height=\v!fit]%
   \inheritedfloatframed{\box\floatbox}%
   \endgroup}

% minwidth=fit,width=max : no overshoot, as wide as graphic

% keep these as reference:
%
% \def\strc_floats_align_content_indeed
%   {\alignstrutmode\zerocount
%    \doifnotcommon\floatcaptionlocation{\v!outermargin,\v!innermargin,\v!leftmargin,\v!rightmargin}
%      {\shiftalignedline
%         {\floatparameter\c!leftmargin }{\floatparameter\c!rightmargin}%
%         {\floatparameter\c!innermargin}{\floatparameter\c!outermargin}}%
%    \alignedline{\floatparameter\c!location}\v!middle}
%
% \def\strc_floats_align_caption_indeed
%   {\alignstrutmode\zerocount
%    \shiftalignedline
%      {\floatcaptionparameter\c!leftmargin }{\floatcaptionparameter\c!rightmargin}%
%      {\floatcaptionparameter\c!innermargin}{\floatcaptionparameter\c!outermargin}%
%    \alignedline{\floatparameter\c!location}\v!middle}
%
% Test case:
%
% \setupfloats[location=left]
% \setupfloatcaption[width=max]
%
% \startfloatcombination
%     \placefigure{}{}
%     \placefigure{}{}
% \stopfloatcombination

%D In a floatcombination we ignore the margins .. if that is ever needed we need another
%D state (instead of local).

\def\strc_floats_align_indeed
  {\alignedline{\floatparameter\c!location}\v!middle}

\def\strc_floats_shift_indeed#1%
  {\shiftalignedline{#1\c!leftmargin}{#1\c!rightmargin}{#1\c!innermargin}{#1\c!outermargin}}

\def\strc_floats_align_content_indeed
  {\alignstrutmode\zerocount
   \ifx\forcedfloatmethod\v!local \else
     \doifnotcommon\floatcaptionlocation{\v!outermargin,\v!innermargin,\v!leftmargin,\v!rightmargin}
       {\strc_floats_shift_indeed\floatparameter}%
     \expandafter\strc_floats_align_indeed
   \fi}

\def\strc_floats_align_caption_indeed
  {\alignstrutmode\zerocount
   \ifx\forcedfloatmethod\v!local
     \expandafter\strc_floats_align_indeed_local
   \else
     \strc_floats_shift_indeed\floatcaptionparameter
     \expandafter\strc_floats_align_indeed
   \fi}

% \def\strc_floats_align_indeed_local#1%
%   {\begingroup
%    \hsize\wd\floatbox
%    \strc_floats_align_indeed{#1}%
%    \endgroup}

\let\strc_floats_align_indeed_local\firstofoneargument

\newdimen\d_strc_floats_content
\newdimen\d_strc_float_temp_height
\newdimen\d_strc_float_temp_width

\newconditional\c_floats_adapt_to_caption_width
\newconditional\c_floats_store_minimal_package

\def\captionminwidth {15\bodyfontsize} % can become parameter (but what name)
\def\captionovershoot{2\emwidth}       % can become parameter (but what name)

\let\strc_floats_mark_pag_as_free\relax

\def\strc_floats_set_page_variant
  {\bgroup
   \strc_floats_set_local_hsize
   \ifcase\c_strc_floats_rotation\else
     \swapdimens\hsize\vsize
   \fi
   \forgetall
   \postponenotes
   \dontcomplain
   \setbox\b_strc_floats_content\vpack{\borderedfloatbox}%
   \let\strc_floats_align_content\strc_floats_align_content_indeed
   \let\strc_floats_align_caption\strc_floats_align_caption_indeed
   \strc_floats_check_caption_content
   \d_strc_floats_content\wd\b_strc_floats_content
   \ifcase\floatparameter\c!method
     % nothing
   \or
     % automatic
     \ifnofloatcaption
       \strc_floats_prepare_no_caption
       \strc_floats_set_caption_dimensions\voidbox
      %\page_backgrounds_add_local_to_box\floatbox % was \doglobal but not needed
     \else
       % todo: installable maken, variant/method=auto vs macro
       \strc_floats_prepare_page_caption
      %\page_backgrounds_add_local_to_box\b_strc_floats_content
       \setbox\b_strc_floats_caption\hbox % text
         {\floatcaptionparameter\c!command{\box\b_strc_floats_caption}}%
       \strc_floats_set_caption_dimensions\b_strc_floats_caption
       \moveboxontogrid\b_strc_floats_caption{\floatcaptionparameter\c!grid}\d_strc_floats_caption_height
      %\page_backgrounds_add_local_to_box\b_strc_floats_caption
       \strc_floats_build_box
     \fi
   \or
     % semi automatic
   \or
     % manual
   \fi
   \ifconditional\c_floats_store_minimal_package
      % nothing
   \else\ifcase\c_strc_floats_rotation
     \doifnotinset\v!margin\floatlocation % brr, really needed! see wm
       {\postcenterfloatbox\d_strc_floats_content
        \strc_floats_mark_pag_as_free}%
       % mark as free not done here
   \else
     \global\setbox\floatbox\vpack
       {\rotate[\c!rotation=\number\c_strc_floats_rotation]{\box\floatbox}}%
     \strc_floats_mark_pag_as_free
   \fi\fi
   \egroup}

\def\strc_floats_prepare_no_caption
  {\global\setbox\floatbox\vpack % pas op als wd groter dan hsize
     {\ifinsidecolumns\ifdim\wd\b_strc_floats_content>\hsize
        \let\strc_floats_align_content\relax
      \fi\fi
      \strc_floats_align_content{\copy\b_strc_floats_content}}}

\def\strc_floats_prepare_page_caption
  {\edef\p_strc_floats_caption_width   {\floatcaptionparameter\c!width}%
   \edef\p_strc_floats_caption_minwidth{\floatcaptionparameter\c!minwidth}%
   \edef\p_strc_floats_caption_align   {\floatcaptionparameter\c!align}%
   \dostarttagged\t!floatcaption\empty
   \doifcommonelse\floatcaptionlocation{\v!top,\v!bottom}
      {\strc_floats_prepare_page_caption_top_bottom}
      {\ifx\p_strc_floats_caption_width\v!fit
         \strc_floats_prepare_side_auto_caption
       \else\ifx\p_strc_floats_caption_width\v!max
         \strc_floats_prepare_side_auto_caption
       \else
         \strc_floats_prepare_side_width_caption
      \fi\fi}%
   \dostoptagged}

\def\strc_floats_prepare_page_caption_top_bottom
  {\ifx\p_strc_floats_caption_width\v!fit
     \strc_floats_prepare_page_caption_top_bottom_fit_max
   \else\ifx\p_strc_floats_caption_width\v!max
     \strc_floats_prepare_page_caption_top_bottom_fit_max
   \else
     \strc_floats_prepare_side_width_caption % new, special effects (see icare)
   \fi\fi}

\def\strc_floats_prepare_page_caption_top_bottom_fit_max
  {\ifx\p_strc_floats_caption_minwidth\v!fit
     \ifx\p_strc_floats_caption_width\v!max
       \strc_floats_prepare_stack_caption_max
     \else\ifdim\wd\b_strc_floats_caption>\wd\b_strc_floats_content % wider caption
       \ifx\p_strc_floats_caption_width\v!fit
         \strc_floats_prepare_stack_caption_auto
       \else
         \strc_floats_prepare_stack_caption_width
       \fi
     \else
       \strc_floats_prepare_stack_caption_min
     \fi\fi
  \else
    \strc_floats_prepare_stack_caption_fixed
  \fi}

\def\strc_floats_caption_set_align
  {\edef\m_align{\v!reset\ifx\p_strc_floats_caption_align\empty\else,\fi\p_strc_floats_caption_align}%
   \doifinset\v!tolerant    \floatcaptionlocation{\edef\m_align{\m_align,\v!tolerant}}%
   \doifinset\v!verytolerant\floatcaptionlocation{\edef\m_align{\m_align,\v!verytolerant}}%
   \doifinset\v!stretch     \floatcaptionlocation{\edef\m_align{\m_align,\v!stretch}}%
   \setupalign[\m_align]}

\def\strc_floats_prepare_side_auto_caption
  {\scratchdimen\dimexpr\hsize-\wd\b_strc_floats_content-\floatparameter\c!margin\relax
   \ifdim\wd\b_strc_floats_caption>\scratchdimen
     \ifdim\wd\b_strc_floats_caption<1.3\scratchdimen
       \scratchdimen0.8\scratchdimen
     \fi
   \fi
   \setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\scratchdimen
      \strc_floats_make_complete_caption}}

\def\strc_floats_prepare_side_width_caption
  {\setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\floatcaptionparameter\c!width
      \strc_floats_make_complete_caption}}

\def\strc_floats_prepare_stack_caption_fixed
  {\setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\floatcaptionparameter\c!minwidth % special effects
      \strc_floats_make_complete_caption}}

\def\strc_floats_prepare_stack_caption_max
  {\setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\wd\b_strc_floats_content
      \strc_floats_make_complete_caption}}

\def\strc_floats_prepare_stack_caption_width
  {\setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\floatcaptionparameter\c!width
      \strc_floats_make_complete_caption}}

\def\strc_floats_prepare_stack_caption_min
  {\setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\wd\b_strc_floats_content
      \ifx\p_strc_floats_caption_align\empty
        \raggedcenter % on purpose overloads align !
      \fi
      \strc_floats_make_complete_caption}}

\def\strc_floats_prepare_stack_caption_auto
  {\ifx\p_strc_floats_caption_align\empty \else
     \doifnotinset\v!middle\p_strc_floats_caption_align{\let\captionovershoot\!!zeropoint}%
   \fi
   \edef\captionhsize{\the\wd\b_strc_floats_content}%
   \scratchwidth\floatcaptionparameter\c!maxwidth\relax
   \ifconditional\c_floats_adapt_to_caption_width
     \let\captionminwidth \!!zeropoint
     \let\captionovershoot\!!zeropoint
   \fi
   \ifdim\captionhsize>\scratchwidth
     % float is wider than \hsize
     \setbox\b_strc_floats_caption\vbox
       {\settrialtypesetting
        \strc_floats_caption_set_align
        \hsize\scratchwidth
        \notesenabledfalse
        \strc_floats_make_complete_caption}%
     \ifdim\ht\scratchbox>\lineheight % more lines
       \setbox\b_strc_floats_caption\vbox
         {\strc_floats_caption_set_align
          \hsize\dimexpr\captionhsize-\captionovershoot\relax
          \ifdim\hsize<\captionminwidth\relax
            \hsize\scratchwidth
          \fi
          \strc_floats_make_complete_caption}%
     \else
       \setbox\b_strc_floats_caption\vbox
         {\strc_floats_caption_set_align
          \hsize\scratchwidth
          \strc_floats_make_complete_caption}%
     \fi
   \else
     % float is smaller of equal to \hsize
     \ifdim\captionhsize<\captionminwidth\relax
       \scratchdimen\captionminwidth % float smaller than min width
       \edef\captionhsize{\the\scratchdimen}%
% \ifconditional\c_floats_adapt_to_caption_width
%   \setbox\b_strc_floats_content\hpack to \captionhsize{\hss\box\b_strc_floats_content\hss}%
% \fi
     \fi
     \setbox\scratchbox\vbox     % test with overshoot
       {\settrialtypesetting
        \scratchdimen\dimexpr\captionhsize+\captionovershoot+3\emwidth\relax % 3em is an average word length
        \ifdim\scratchdimen<\hsize
          \hsize\scratchdimen
        \fi
        \notesenabledfalse
        \strc_floats_make_complete_caption}%
     \ifdim\ht\scratchbox>\lineheight
       % at least an average word longer than a line
       \setbox\b_strc_floats_caption\vbox
         {\strc_floats_caption_set_align
          \scratchdimen\dimexpr\captionhsize+\captionovershoot\relax
          \ifdim\scratchdimen<\hsize
            \hsize\scratchdimen
          \fi
          \strc_floats_make_complete_caption}%
     \else\ifx\p_strc_floats_caption_align\empty
       \setbox\b_strc_floats_caption\vbox
         {\strc_floats_caption_set_align
          \hsize\captionhsize
          \raggedcenter % overloads
          \strc_floats_make_complete_caption}%
     \else
       \setbox\b_strc_floats_caption\vbox
         {\strc_floats_caption_set_align
          \hsize\captionhsize
          \strc_floats_make_complete_caption}%
     \fi\fi
   \fi}

\def\strc_floats_between_stack
  {\endgraf
   \nointerlineskip
   \floatcaptionparameter\c!inbetween
   \endgraf}

\def\strc_floats_build_box_default % done
  {\strc_floats_align_content{\box\b_strc_floats_content}}

\def\strc_floats_build_box_next_right#1%
  {\ifconditional\c_strc_floats_par_float \hpack \else \expandafter \strc_floats_align_content \fi % skip, no pack
     {\d_strc_float_temp_height\ht\b_strc_floats_content
      \box\b_strc_floats_content
      \doifnotinset\v!hang\floatcaptionlocation
        {\dotfskip{\floatcaptionparameter\c!distance}}%
      \vbox to\d_strc_float_temp_height{#1}}}

\def\strc_floats_build_box_next_left#1%
  {\ifconditional\c_strc_floats_par_float \hpack \else \expandafter \strc_floats_align_content \fi % skip, no pack
     {\d_strc_float_temp_height\ht\b_strc_floats_content
      \vbox to\d_strc_float_temp_height{#1}%
      \doifnotinset\v!hang\floatcaptionlocation
        {\dotfskip{\floatcaptionparameter\c!distance}}%
      \box\b_strc_floats_content}}

\def\strc_floats_build_box_next_outer
  {\doifelserightpagefloat\strc_floats_build_box_next_right\strc_floats_build_box_next_left}

\def\strc_floats_build_box_next_inner
  {\doifelserightpagefloat\strc_floats_build_box_next_left\strc_floats_build_box_next_right}

\def\strc_floats_build_box_next_right_hang#1%
  {\ifconditional\c_strc_floats_par_float \hpack \else \expandafter \strc_floats_align_content \fi
     {\d_strc_float_temp_height\ht\b_strc_floats_content
      \box\b_strc_floats_content
      \vbox to\d_strc_float_temp_height{#1}}}

\def\strc_floats_build_box_next_left_hang#1%
  {\ifconditional\c_strc_floats_par_float \hpack \else \expandafter \strc_floats_align_content \fi
     {\d_strc_float_temp_height\ht\b_strc_floats_content
      \vbox to\d_strc_float_temp_height{#1}%
      \box\b_strc_floats_content}}

% \def\strc_floats_build_box_next_right_margin_indeed#1#2%
%   {\ifconditional\c_strc_floats_par_float
%      \hpack\bgroup
%        \d_strc_float_temp_height\ht\b_strc_floats_content
%        \box\b_strc_floats_content
%        \hsmash{\hskip#1\vbox to\d_strc_float_temp_height{#2}}%
%      \egroup
%    \else
%      \begingroup
%      \d_strc_float_temp_height\ht\b_strc_floats_content
%      \everyrightofalignedline{\hsmash{\hskip#1\vbox to\d_strc_float_temp_height{#2}}}%
%      \strc_floats_align_content{\box\b_strc_floats_content}%
%      \endgroup
%     \fi}
%
% \def\strc_floats_build_box_next_left_margin_indeed#1#2%
%   {\ifconditional\c_strc_floats_par_float
%      \hpack\bgroup
%        \d_strc_float_temp_height\ht\b_strc_floats_content
%        \hsmash{\hskip-\dimexpr#1+\wd\b_strc_floats_caption\relax\vbox to\d_strc_float_temp_height{#2}}%
%        \box\b_strc_floats_content
%      \egroup
%    \else
%      \begingroup
%      \d_strc_float_temp_height\ht\b_strc_floats_content
%      \everyleftofalignedline{\hsmash{\hskip-\dimexpr#1+\wd\b_strc_floats_caption\relax\vbox to\d_strc_float_temp_height{#2}}}%
%      \strc_floats_align_content{\box\b_strc_floats_content}%
%      \endgroup
%    \fi}

\def\strc_floats_build_box_next_right_margin_indeed#1#2%
  {\ifconditional\c_strc_floats_par_float
     \hpack\bgroup
       \d_strc_float_temp_height\ht\b_strc_floats_content
       \box\b_strc_floats_content
       \hsmash{\hskip#1\vbox to\d_strc_float_temp_height{#2}}%
     \egroup
   \else
     \begingroup
     \d_strc_float_temp_height\ht\b_strc_floats_content
     \setbox\scratchboxone\vbox{#2}%
     \ifdim\htdp\scratchboxone>\htdp\b_strc_floats_content
       \global\d_strc_floats_overflow\dimexpr\htdp\scratchboxone-\htdp\b_strc_floats_content\relax
     \fi
     \ht\scratchboxone\d_strc_float_temp_height
     \everyrightofalignedline{\hsmash{\hskip#1\box\scratchboxone}}%
     \strc_floats_align_content{\box\b_strc_floats_content}%
     \endgroup
    \fi}

\def\strc_floats_build_box_next_left_margin_indeed#1#2%
  {\ifconditional\c_strc_floats_par_float
     \hpack\bgroup
       \d_strc_float_temp_height\ht\b_strc_floats_content
       \hsmash{\hskip-\dimexpr#1+\wd\b_strc_floats_caption\relax\vbox to\d_strc_float_temp_height{#2}}%
       \box\b_strc_floats_content
     \egroup
   \else
     \begingroup
     \d_strc_float_temp_height\ht\b_strc_floats_content
     \setbox\scratchboxone\vbox{#2}%
     \ifdim\htdp\scratchboxone>\htdp\b_strc_floats_content
       \global\d_strc_floats_overflow\dimexpr\htdp\scratchboxone-\htdp\b_strc_floats_content\relax
     \fi
     \ht\scratchboxone\d_strc_float_temp_height
     \everyleftofalignedline{\hsmash{\hskip-\dimexpr#1+\wd\scratchboxone\relax\box\scratchboxone}}%
     \strc_floats_align_content{\box\b_strc_floats_content}%
     \endgroup
   \fi}

\def\strc_floats_build_box_next_right_margin
  {\strc_floats_build_box_next_right_margin_indeed\rightmargindistance}

\def\strc_floats_build_box_next_left_margin
  {\strc_floats_build_box_next_left_margin_indeed \leftmargindistance}

\def\strc_floats_build_box_next_outer_margin
  {\doifelserightpagefloat
     {\strc_floats_build_box_next_right_margin_indeed\rightmargindistance}
     {\strc_floats_build_box_next_left_margin_indeed \rightmargindistance}}

\def\strc_floats_build_box_next_inner_margin
  {\doifelserightpagefloat
     {\strc_floats_build_box_next_left_margin_indeed \leftmargindistance}
     {\strc_floats_build_box_next_right_margin_indeed\leftmargindistance}}

\def\strc_floats_build_box_next % beware, we first check on left/rightmargin because there can be left/right also
  {\let\next\strc_floats_build_box_next_left
   \processallactionsinset[\floatcaptionlocation]
     [ \v!outermargin=>\let\next\strc_floats_build_box_next_outer_margin,
       \v!innermargin=>\let\next\strc_floats_build_box_next_inner_margin,
        \v!leftmargin=>\let\next\strc_floats_build_box_next_left_margin,
       \v!rightmargin=>\let\next\strc_floats_build_box_next_right_margin,
       \v!lefthanging=>\let\next\strc_floats_build_box_next_left_hang,
      \v!righthanging=>\let\next\strc_floats_build_box_next_right_hang,
             \v!outer=>\let\next\strc_floats_build_box_next_outer,
             \v!inner=>\let\next\strc_floats_build_box_next_inner,
              \v!left=>\let\next\strc_floats_build_box_next_left,
             \v!right=>\let\next\strc_floats_build_box_next_right]%
   \next}

\def\strc_floats_build_box_side
  {\ifconditional\c_strc_floats_par_float
     \let\next\strc_floats_build_box_high
   \else
     \let\next\strc_floats_build_box_middle
     \processallactionsinset[\floatcaptionlocation]
       [   \v!low=>\let\next\strc_floats_build_box_low,
        \v!middle=>\let\next\strc_floats_build_box_middle,
          \v!high=>\let\next\strc_floats_build_box_high]%
   \fi
   \next}

\def\strc_floats_flush_right_caption_hang
  {\hsmash{\rlap{\dotfskip{\floatcaptionparameter\c!distance}\box\b_strc_floats_caption}}}

\def\strc_floats_flush_left_caption_hang
  {\hsmash{\llap{\box\b_strc_floats_caption\dotfskip{\floatcaptionparameter\c!distance}}}}

\def\strc_floats_flush_caption_hang
  {\doifelseinset\v!righthanging\floatcaptionlocation
     {\strc_floats_flush_right_caption_hang}
     {\doifelseinset\v!lefthanging\floatcaptionlocation
        {\strc_floats_flush_left_caption_hang}
        {\doifelseinset\v!hang\floatcaptionlocation
           {\doifelseinset\v!outer\floatcaptionlocation
              {\doifelserightpagefloat{\strc_floats_flush_right_caption_hang}{\strc_floats_flush_left_caption_hang}}
              {\doifelseinset\v!right\floatcaptiondirectives
                 {\strc_floats_flush_right_caption_hang}
                 {\strc_floats_flush_left_caption_hang}}}
        {\box\b_strc_floats_caption}}}}

\def\strc_floats_build_box_high
  {\strc_floats_build_box_next{\strc_floats_between_stack\strc_floats_flush_caption_hang\vfill}}

\def\strc_floats_build_box_low
  {\strc_floats_build_box_next{\vfill\strc_floats_flush_caption_hang\strc_floats_between_stack}}

\def\strc_floats_build_box_middle
  {\strc_floats_build_box_next{\vfill\box\b_strc_floats_caption\vfill}}

% \definefloat
%   [lefty][lefties][figure]
% \setupfloat
%   [lefty]
%   [default=left,
%    rightmargindistance=-2cm,
%    leftmargindistance=-2cm]
% \setupcaption
%   [lefty]
%   [location={bottom,overlay}]
%
% \starttext
%     \placelefty{}{} \input tufte \input tufte
%     \placelefty{}{} \input tufte \input tufte
% \stoptext

\def\strc_floats_build_box_top_stack_normal_overlay
  {\vbox to \ht\b_strc_floats_content{\vss\strc_floats_build_box_top_stack_normal_content}}

\def\strc_floats_build_box_top_stack_normal_content
  {\d_strc_float_temp_width\wd\b_strc_floats_content
   \ifconditional\c_strc_floats_par_float
     \hpack{\strc_floats_locate_side_float{\box\b_strc_floats_caption}}%
     \strc_floats_between_stack
     \hpack{\hbox{\box\b_strc_floats_content}}%
   \else
     \page_otr_command_set_float_hsize
     \hpack{\strc_floats_locate_text_float{\box\b_strc_floats_caption}}
     \strc_floats_between_stack
     \hpack{\strc_floats_align_content{\box\b_strc_floats_content}}%
   \fi}

\def\strc_floats_build_box_bottom_stack_normal_overlay
  {\vbox to \ht\b_strc_floats_content{\strc_floats_build_box_bottom_stack_normal_content\vss}}

\def\strc_floats_build_box_bottom_stack_normal_content
  {\d_strc_float_temp_width\wd\b_strc_floats_content
   \ifconditional\c_strc_floats_par_float
     \hpack{\hpack{\box\b_strc_floats_content}}%
     \strc_floats_between_stack
     \hpack{\strc_floats_locate_side_float{\box\b_strc_floats_caption}}%
   \else
     \page_otr_command_set_float_hsize
     \hpack{\strc_floats_align_content{\box\b_strc_floats_content}}%
     \strc_floats_between_stack
     \hpack{\strc_floats_locate_text_float{\box\b_strc_floats_caption}}%
   \fi}

\def\strc_floats_build_box_top_stack_normal
  {\doifelseinset\v!overlay{\floatcaptionparameter\c!location}
      \strc_floats_build_box_top_stack_normal_overlay
      \strc_floats_build_box_top_stack_normal_content}

\def\strc_floats_build_box_bottom_stack_normal
  {\doifinset\v!overlay{\floatcaptionparameter\c!location}
    \strc_floats_build_box_bottom_stack_normal_overlay
    \strc_floats_build_box_bottom_stack_normal_content}

\def\strc_floats_build_box_top_stack_grid
  {\dp\b_strc_floats_caption\strutdepth
   \setbox\scratchbox\vbox
     {\d_strc_float_temp_width\wd\b_strc_floats_content
      \hsize\d_strc_float_temp_width
      \ifconditional\c_strc_floats_par_float
        \strc_floats_locate_side_float{\box\b_strc_floats_caption}%
        \vss\strc_floats_between_stack
        \hpack{\box\b_strc_floats_content}%
      \else
        \page_otr_command_set_float_hsize
        \strc_floats_locate_text_float{\box\b_strc_floats_caption}%
        \vss\strc_floats_between_stack
        \strc_floats_align_content{\box\b_strc_floats_content}%
      \fi}%
   \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
   \vpack to \noflines\lineheight{\unvbox\scratchbox}}

\def\strc_floats_build_box_bottom_stack_grid
  {\dp\b_strc_floats_caption\strutdepth
   \setbox\scratchbox\vbox
     {\d_strc_float_temp_width\wd\b_strc_floats_content
      \hsize\d_strc_float_temp_width
      \ifconditional\c_strc_floats_par_float
        \hpack{\box\b_strc_floats_content}%
        \vss\strc_floats_between_stack
        \strc_floats_locate_side_float{\box\b_strc_floats_caption}%
      \else
        \page_otr_command_set_float_hsize
        \strc_floats_align_content{\box\b_strc_floats_content}%
        \vss\strc_floats_between_stack
        \strc_floats_locate_text_float{\box\b_strc_floats_caption}%
      \fi}%
   \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
   \vpack to \noflines\lineheight{\unvbox\scratchbox}}

\def\strc_floats_build_box_top_stack_stretch
  {\dp\b_strc_floats_caption\strutdepth
   \setbox\scratchbox\vpack
     {\strc_floats_align_caption{\copy\b_strc_floats_caption}%
      \strc_floats_align_content{\copy\b_strc_floats_content}}%
   \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
   \vbox to \noflines\lineheight % pack ?
     {\d_strc_float_temp_width\wd\b_strc_floats_content
      \hsize\d_strc_float_temp_width
      \ifconditional\c_strc_floats_par_float
        \strc_floats_locate_side_float{\box\b_strc_floats_caption}%
        \vss\strc_floats_between_stack\vss
        \hpack{\box\b_strc_floats_content}%
      \else
        \page_otr_command_set_float_hsize
        \strc_floats_locate_text_float{\box\b_strc_floats_caption}%
        \vss\strc_floats_between_stack\vss
        \strc_floats_align_content{\box\b_strc_floats_content}%
      \fi}}

\def\strc_floats_build_box_bottom_stack_stretch
  {\dp\b_strc_floats_caption\strutdepth
   \setbox\scratchbox\vpack
     {\strc_floats_align_content{\copy\b_strc_floats_content}%
      \strc_floats_align_caption{\copy\b_strc_floats_caption}}%
   \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
   \vbox to \noflines\lineheight
     {\d_strc_float_temp_width\wd\b_strc_floats_content
      \hsize\d_strc_float_temp_width
      \ifconditional\c_strc_floats_par_float
        \hpack{\box\b_strc_floats_content}%
        \vss\strc_floats_between_stack\vss
        \strc_floats_locate_side_float{\box\b_strc_floats_caption}%
      \else
        \page_otr_command_set_float_hsize
        \strc_floats_align_content{\box\b_strc_floats_content}%
        \vss\strc_floats_between_stack\vss
        \strc_floats_locate_text_float{\box\b_strc_floats_caption}%
      \fi}}

\def\strc_floats_build_box_top
  {\let\next\strc_floats_build_box_top_stack_normal
   \processfirstactioninset[\floatcaptionparameter\c!location]
     [   \v!grid=>\let\next\strc_floats_build_box_top_stack_grid,
        \v!lines=>\let\next\strc_floats_build_box_top_stack_stretch]% was \v!grid but interfered
   \next}

\def\strc_floats_build_box_bottom
  {\let\next\strc_floats_build_box_bottom_stack_normal
   \processfirstactioninset[\floatcaptionparameter\c!location]
     [   \v!grid=>\let\next\strc_floats_build_box_bottom_stack_grid,
        \v!lines=>\let\next\strc_floats_build_box_bottom_stack_stretch]% was \v!grid but interfered
   \next}

\def\strc_floats_relocate_caption_right#1{\strc_floats_align_caption{\hbox to \d_strc_float_temp_width{\hss#1}}}
\def\strc_floats_relocate_caption_left #1{\strc_floats_align_caption{\hbox to \d_strc_float_temp_width{#1\hss}}}

\unexpanded\def\installfloatboxbuilder#1#2{\setvalue{\??floatbuilder#1}{#2}}

\def\strc_floats_build_box
  {\strc_floats_build_box_before
   \global\setbox\floatbox\vbox % pack ? probably not
     {\strc_floats_set_local_hsize
      \forgetall
      \ifconditional\c_floats_store_minimal_package
        \strc_floats_build_box_separate_make
      \else
      % \let\floatcaptionarrangement\s!default
        \let\floatcaptionarrangement\v!bottom % for Alan
        \processcommacommand[\floatcaptionparameter\c!location]\strc_floats_build_box_step
        \ifcsname\??floatbuilder\floatcaptionarrangement\endcsname
          \lastnamedcs
        \else
          \strc_floats_build_box_default
        \fi
      \fi}%
   \strc_floats_build_box_after}

% \let\strc_floats_build_box_before\relax
% \let\strc_floats_build_box_after \relax

\def\strc_floats_build_box_before
  {\let\currentfloatframed\currentfloat
   \floatwidth\wd
     \ifdim\wd\b_strc_floats_content>\wd\b_strc_floats_caption
       \b_strc_floats_content\else\b_strc_floats_caption
     \fi}

\def\strc_floats_build_box_after
  {\doifelseframed\floatframedparameter\strc_floats_build_box_after_indeed\relax}

\def\strc_floats_build_box_after_indeed
  {\global\setbox\floatbox\hpack
     {\edef\m_width{\floatframedparameter\c!width}%
      \ifx\m_width\v!fit
        \let\m_width\floatwidth
      \else\ifx\m_width\v!broad
        \let\m_width\v!fit
      \fi\fi
      \letfloatframedparameter\c!strut\v!no
      \letfloatframedparameter\c!width\m_width
      \inheritedfloatframedframed
        {\box\floatbox}}}

% special purpose: used in floatcombinations

\newbox\b_strc_floats_separate_content
\newbox\b_strc_floats_separate_caption

\def\strc_floats_build_box_separate_set
  {\settrue\c_floats_adapt_to_caption_width
   \settrue\c_floats_store_minimal_package}

\def\strc_floats_build_box_separate_make
  {\offinterlineskip
   \vpack to \onepoint{\box\b_strc_floats_content}\break
   \vpack to \onepoint{\box\b_strc_floats_caption}}

\def\strc_floats_build_box_separate_split#1%
  {\setbox\scratchbox\vbox\bgroup
     \setbox\scratchbox\vpack{#1}%
     \unvbox\scratchbox\relax
     \setbox\scratchbox\lastbox
    %\doloop{%
        \unvbox\scratchbox
        \setbox\scratchbox\lastbox
    %   \ifdim\ht\scratchbox=2\onepoint
          \unvbox\scratchbox
          \setbox\scratchbox\lastbox
    %     \exitloop
    %   \fi
    %}%
     \splittopskip\zeropoint
     \global\setbox\b_strc_floats_separate_content\vsplit\scratchbox to \onepoint
     \global\setbox\b_strc_floats_separate_caption\vsplit\scratchbox to \onepoint
   \egroup
   \global\setbox\b_strc_floats_separate_content\vpack
     {\unvbox\b_strc_floats_separate_content
      \setbox\scratchbox\lastbox
      \unvbox\scratchbox}%
   \global\setbox\b_strc_floats_separate_caption\tpack
     {\unvbox\b_strc_floats_separate_caption
      \setbox\scratchbox\lastbox
      \unvbox\scratchbox}}

% \def\strc_floats_build_box_step#1%
%   {\doifdefined{\??floatbuilder#1}{\def\floatcaptionarrangement{#1}\quitcommalist}}

\def\strc_floats_build_box_step#1%
  {\ifcsname\??floatbuilder#1\endcsname
     \def\floatcaptionarrangement{#1}% \let\floatcaptionarrangement\commalistelement
     \quitcommalist
   \fi}

\def\strc_floats_locate_text_float
  {\let\next\strc_floats_align_caption
   \processallactionsinset[\floatcaptionparameter\c!location]
     [ \v!left=>\let\next\strc_floats_relocate_caption_left,
      \v!right=>\let\next\strc_floats_relocate_caption_right,
      \v!inner=>\doifelserightpagefloat{\let\next\strc_floats_relocate_caption_left }{\let\next\strc_floats_relocate_caption_right},
      \v!outer=>\doifelserightpagefloat{\let\next\strc_floats_relocate_caption_right}{\let\next\strc_floats_relocate_caption_left }]%
   \next}

\installfloatboxbuilder \v!none         \strc_floats_build_box_default
\installfloatboxbuilder \s!default      \strc_floats_build_box_default
\installfloatboxbuilder \v!high         \strc_floats_build_box_high
\installfloatboxbuilder \v!low          \strc_floats_build_box_low
\installfloatboxbuilder \v!middle       \strc_floats_build_box_middle

\installfloatboxbuilder \v!rightmargin  \strc_floats_build_box_side % added 2016-08-23
\installfloatboxbuilder \v!leftmargin   \strc_floats_build_box_side % added 2016-08-23
\installfloatboxbuilder \v!innermargin  \strc_floats_build_box_side % added 2016-08-23
\installfloatboxbuilder \v!outermargin  \strc_floats_build_box_side % added 2016-08-23

\installfloatboxbuilder \v!left         \strc_floats_build_box_side
\installfloatboxbuilder \v!right        \strc_floats_build_box_side
\installfloatboxbuilder \v!inner        \strc_floats_build_box_side % added 2016-08-23
\installfloatboxbuilder \v!outer        \strc_floats_build_box_side % added 2016-08-23

\installfloatboxbuilder \v!lefthanging  \strc_floats_build_box_side % added 2016-08-23
\installfloatboxbuilder \v!righthanging \strc_floats_build_box_side % added 2016-08-23
\installfloatboxbuilder \v!hang         \strc_floats_build_box_side % added 2016-08-23

\installfloatboxbuilder \v!top          \strc_floats_build_box_top
\installfloatboxbuilder \v!bottom       \strc_floats_build_box_bottom

% \setuplayout[grid=yes] \showgrid \setupcaptions[style=smallbodyfont,location=grid,inbetween=]
%
% \starttext
%     test \placefigure{}                 {\externalfigure[cow.pdf][frame=on,grid=yes]}   test \page
%     test \placefigure{\input zapf\relax}{\externalfigure[cow.pdf][frame=on,grid=yes]}   test \page
%     test \placefigure{}                 {\externalfigure[cow.pdf][frame=on,grid=depth]} test \page
%     test \placefigure{\input zapf\relax}{\externalfigure[cow.pdf][frame=on,grid=depth]} test \page
% \stoptext

% This might move to page-flt:

\newif\ifpostponecolumnfloats \postponecolumnfloatsfalse % don't change

\setnewconstant\postcenterfloatmethod\plusone

\def\postcenterfloatbox#1%
  {\scratchdimen
     \ifcase\postcenterfloatmethod
       #1% \wd\floatbox
     \or\ifinsidecolumns
       \ifpostponecolumnfloats\makeupwidth\else#1\fi
     \else\ifdim#1>\hsize
       \hsize
     \else
       \wd\floatbox
     \fi\fi\fi
   \global\setbox\floatbox\hbox to \scratchdimen
   % {\hfill\box\floatbox\hfill}} % geen \hss, gaat mis in kolommen !
   % {\hss  \box\floatbox\hss  }} % wel \hss, anders mis in colset
     {\ifconditional\c_page_floats_center_box_global
        \donetrue
      \else\ifconditional\c_page_floats_center_box_local
        \donetrue
      \else
        \donefalse
      \fi\fi
      \ifdim\scratchdimen>\effectivehsize
        \donefalse
      \fi
      \hss\ifdone\hskip\effectiveleftskip\fi
      \box\floatbox
      \ifdone\hskip\effectiverightskip\fi\hss}}

\def\strc_floats_set_paragraph_variant
  {\bgroup
   \forgetall
   \postponenotes
   \dontcomplain
   \setbox\b_strc_floats_content\vbox{\borderedfloatbox}% \vpack >?
  %\page_backgrounds_add_local_to_box\b_strc_floats_content
   \ifnofloatcaption
     \global\setbox\floatbox\vpack{\box\b_strc_floats_content}%
   \else
     \strc_floats_check_caption_content
     \strc_floats_prepare_side_caption
     \setbox\b_strc_floats_caption\hbox{\floatcaptionparameter\c!command{\box\b_strc_floats_caption}}% \hpack ?
     \moveboxontogrid\b_strc_floats_caption{\floatcaptionparameter\c!grid}\d_strc_floats_caption_height
    %\page_backgrounds_add_local_to_box\b_strc_floats_caption
     \strc_floats_build_side_box
   \fi
   \egroup}

\def\strc_floats_prepare_side_caption
  {\dostarttagged\t!floatcaption\empty
   \edef\p_strc_floats_caption_width{\floatcaptionparameter\c!width}%
   \edef\p_strc_floats_caption_align{\floatcaptionparameter\c!align}%
   \ifx\p_strc_floats_caption_width\v!max
     \strc_floats_prepare_side_caption_max
   \else\ifx\p_strc_floats_caption_width\v!fit
     \strc_floats_prepare_side_caption_fit
   \else
     \strc_floats_prepare_side_caption_width
   \fi\fi
   \dostoptagged}

% these could be \??floatpreparesidecaption

% \setupfloat[figure][location=left]
% \setupcaption[figure][width=max]
%
% \placefigure{my figure caption my figure caption}{\framed[width=4cm,height=1cm]{}} \input tufte
% \placefigure{my figure caption}                  {\framed[width=4cm,height=1cm]{}} \input tufte

\def\strc_floats_prepare_side_caption_max
  {\setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\wd\b_strc_floats_content
      \strc_floats_make_complete_caption}}

\def\strc_floats_prepare_side_caption_fit % or center when smaller
  {\ifdim\wd\b_strc_floats_caption>\wd\b_strc_floats_content\relax
     \setbox\b_strc_floats_caption\vbox
       {\forgetall % needed?
        \strc_floats_caption_set_align
        \hsize\wd\b_strc_floats_content
        \strc_floats_make_complete_caption}%
   \else
     % maybe we should listen to the align option here (now side floats need the max option
     \setbox\b_strc_floats_caption\hpack to \wd\b_strc_floats_content
       {\hss\hbox{\strc_floats_make_complete_caption}\hss}%
   \fi}

\def\strc_floats_prepare_side_caption_width
  {\setbox\b_strc_floats_caption\vbox
     {\strc_floats_caption_set_align
      \hsize\p_strc_floats_caption_width % \wd\b_strc_floats_content
      \strc_floats_make_complete_caption}}

% % maybe (but then also prepare_page that way):
%
% \installcorenamespace{floatpreparesidecaption}
%
% \def\strc_floats_prepare_side_caption
%   {\dostarttagged\t!floatcaption\empty
%    \edef\p_strc_floats_caption_width{\floatcaptionparameter\c!width}%
%    \edef\p_strc_floats_caption_align{\floatcaptionparameter\c!align}%
%    \expandnamespacemacro\??floatpreparesidecaption\p_strc_floats_caption_width\s!unknown
%    \dostoptagged}
%
% \setvalue{\??floatpreparesidecaption\v!max}%
%   {\setbox\b_strc_floats_caption\vbox
%      {\strc_floats_caption_set_align
%       \hsize\wd\b_strc_floats_content
%       \strc_floats_make_complete_caption}}
%
% \setvalue{\??floatpreparesidecaption\v!fit}%
%   {\ifdim\wd\b_strc_floats_caption>\wd\b_strc_floats_content\relax
%      \setbox\b_strc_floats_caption\vbox
%        {\forgetall % needed?
%         \hsize\wd\b_strc_floats_content
%         \strc_floats_make_complete_caption}%
%    \else
%      \setbox\b_strc_floats_caption\hbox to \wd\b_strc_floats_content
%        {\hss\hbox{\strc_floats_make_complete_caption}\hss}%
%    \fi}
%
% \setvalue{\??floatpreparesidecaption\s!unknown}%
%   {\setbox\b_strc_floats_caption\vbox
%      {\strc_floats_caption_set_align
%       \hsize\p_strc_floats_caption_width % \wd\b_strc_floats_content
%       \strc_floats_make_complete_caption}}

\def\strc_floats_locate_side_float#1%
  {\begingroup
   \alignstrutmode\zerocount
   \hsize\d_strc_float_temp_width \forgetall
   \alignedline{\floatparameter\c!location}\v!middle{#1}%
   \endgroup}

\def\strc_floats_build_side_box
  {\let\strc_floats_align_content\relax
   \let\strc_floats_align_caption\relax
   \strc_floats_build_box}

\def\strc_floats_set_box % todo : \global\setbox, currently messy
  {\ifvisible
     \par
     \edef\floatcaptiondirectives{\floatparameter\c!location,\floatcaptionparameter\c!location}%
     \ifconditional\c_strc_floats_par_float
       \strc_floats_set_paragraph_variant
     \else
       \strc_floats_set_page_variant
     \fi
     \strc_floats_set_local_dimensions
     \global\advance\totalnoffloats\plusone
     \ifconditional\c_floats_store_minimal_package \else
       \setbox\floatbox\hpack{\strc_float_save_data\box\floatbox}% still needed? we will do renumbering differently
     \fi
     \global\floatheight\htdp\floatbox
     \global\floatwidth\wd\floatbox
     \ifconditional\c_floats_store_minimal_package \else
       \doifnotinset\v!margin\floatlocation % gaat namelijk nog fout
         {\setbox\floatbox\vpack
            {\parindent\zeropoint
             \box\floatbox}}%
     \fi
     \wd\floatbox\floatwidth
     \ifdim\dimexpr\floatheight+\lineheight\relax<\textheight \else
       \global\floatheight\dimexpr\textheight-\lineheight\relax
       \ht\floatbox\floatheight
       \dp\floatbox\zeropoint
       \showmessage\m!floatblocks{10}{\the\totalnoffloats}%
     \fi
   \fi}

% \def\dooutput{\sidefloatoutput} % redefinition of \dooutput

\definefloat
  [\v!figure]
  [\v!figures]

\definefloat
  [\v!table]
  [\v!tables]

\setupfloat
  [\v!table]
  [\c!frame=\v!off]

\definefloat
  [\v!intermezzo]
  [\v!intermezzi]

\definefloat
  [\v!graphic]
  [\v!graphics]

% float strategy, replaces some of the above macros

\installcorenamespace{floatmethods}

\let\floatmethod      \empty % set by lua
\let\floatlabel       \empty % set by lua
\let\floatcolumn      \empty % set by lua
\let\floatrow         \empty % set by lua
\let\forcedfloatmethod\empty % set by lua and floatcombinations

\def\setfloatmethodvariables#1% \floatmethod \floatlabel \floatrow \floatcolumn
  {\clf_analysefloatmethod{#1}}

\def\somesomewherefloat[#1]%
  {\page_floats_save_somewhere_float\s!somewhere{#1}}

\def\strc_floats_get_box
  {\ifvisible
%      \let\floatlabel \empty
%      \let\floatcolumn\empty
%      \let\floatrow   \empty
%      \setfloatmethodvariables\floatlocation
     % todo: nog algemeen otr
%      \ifdefined\OTRSETsetpreferedcolumnslot
%        \OTRSETsetpreferedcolumnslot\floatcolumn\floatrow
%      \fi
     \ifcsname\??floatmethods\currentoutputroutine:\floatmethod\endcsname \else
        \let\floatmethod\v!here
     \fi
     \ifx\forcedfloatmethod\empty \else
       \let\floatmethod\forcedfloatmethod
     \fi
\let\askedfloatmethod\floatmethod
\ifexporting \ifx\askedfloatmethod\v!here \else
  \showmessage\m!floatblocks{15}{\askedfloatmethod,\v!here}%
  \let\floatlocation\v!here
\fi \fi
     % [] will go
     \edef\floatlocationmethod{\floatmethod,\floatlocation}%
     \csname\??floatmethods\currentoutputroutine:\floatmethod\endcsname
   \fi}

\installcorenamespace{floatsettings}

\unexpanded\def\installfloatmethod#1#2#3% routine keyword handler
  {\setvalue{\??floatmethods#1:#2}{#3}}

\unexpanded\def\handlefloatmethod#1%
  {\csname\??floatmethods\currentoutputroutine:#1\endcsname}

% \unexpanded\def\installfloatmethod#1#2#3% routine keyword handler
%   {\ifcsname\??floatsettings#1:#2\endcsname \else
%      \expandafter\newtoks\csname\??floatsettings#1:#2\endcsname
%    \fi
%    \setvalue{\??floatmethods#1:#2}{#3}}
%
% \unexpanded\def\startfloatmethodsettings#1#2 #3\stopfloatmethodsettings
%   {\csname\??floatsettings#1:#2\endcsname\expandafter{\the\csname\??floatsettings#1:#2\endcsname#3}}
%
% \let\stopfloatmethodsettings\relax
%
% \unexpanded\def\applyfloatmethodsettings#1#2{\the\??floatsettings#1:#2\endcsname}

\definesystemconstant{tblr}
\definesystemconstant{lrtb}
\definesystemconstant{tbrl}
\definesystemconstant{rltb}
\definesystemconstant{btlr}
\definesystemconstant{lrbt}
\definesystemconstant{btrl}
\definesystemconstant{rlbt}
\definesystemconstant{fxtb}
\definesystemconstant{fxbt}
\definesystemconstant{fixd}

% can move to page-one:

\installfloatmethod \s!singlecolumn \v!here        \page_one_place_float_here
\installfloatmethod \s!singlecolumn \v!force       \page_one_place_float_force
\installfloatmethod \s!singlecolumn \v!left        \page_one_place_float_left
\installfloatmethod \s!singlecolumn \v!right       \page_one_place_float_right
\installfloatmethod \s!singlecolumn \v!text        \page_one_place_float_text
\installfloatmethod \s!singlecolumn \v!top         \page_one_place_float_top
\installfloatmethod \s!singlecolumn \v!bottom      \page_one_place_float_bottom
\installfloatmethod \s!singlecolumn \v!auto        \page_one_place_float_auto
\installfloatmethod \s!singlecolumn \v!margin      \page_one_place_float_margin
\installfloatmethod \s!singlecolumn \v!opposite    \page_one_place_float_face
\installfloatmethod \s!singlecolumn \v!page        \page_one_place_float_page
\installfloatmethod \s!singlecolumn \v!leftpage    \page_one_place_float_leftpage
\installfloatmethod \s!singlecolumn \v!rightpage   \page_one_place_float_rightpage
\installfloatmethod \s!singlecolumn \v!inmargin    \page_one_place_float_inmargin
\installfloatmethod \s!singlecolumn \v!inleft      \page_one_place_float_leftmargin
\installfloatmethod \s!singlecolumn \v!inright     \page_one_place_float_rightmargin
\installfloatmethod \s!singlecolumn \v!leftmargin  \page_one_place_float_leftmargin
\installfloatmethod \s!singlecolumn \v!rightmargin \page_one_place_float_rightmargin
\installfloatmethod \s!singlecolumn \v!leftedge    \page_one_place_float_leftedge
\installfloatmethod \s!singlecolumn \v!rightedge   \page_one_place_float_rightedge
\installfloatmethod \s!singlecolumn \v!somewhere   \page_one_place_float_somewhere
\installfloatmethod \s!singlecolumn \v!backspace   \page_one_place_float_backspace
\installfloatmethod \s!singlecolumn \v!cutspace    \page_one_place_float_cutspace
\installfloatmethod \s!singlecolumn \s!tblr        \page_one_place_float_top
\installfloatmethod \s!singlecolumn \s!lrtb        \page_one_place_float_top
\installfloatmethod \s!singlecolumn \s!tbrl        \page_one_place_float_top
\installfloatmethod \s!singlecolumn \s!fxtb        \page_one_place_float_top
\installfloatmethod \s!singlecolumn \s!rltb        \page_one_place_float_top
\installfloatmethod \s!singlecolumn \s!btlr        \page_one_place_float_bottom
\installfloatmethod \s!singlecolumn \s!lrbt        \page_one_place_float_bottom
\installfloatmethod \s!singlecolumn \s!btrl        \page_one_place_float_bottom
\installfloatmethod \s!singlecolumn \s!rlbt        \page_one_place_float_bottom
\installfloatmethod \s!singlecolumn \s!fxbt        \page_one_place_float_bottom
\installfloatmethod \s!singlecolumn \s!fixd        \page_one_place_float_force

%D Local floats:

\installcorenamespace{localfloats}
\installcorenamespace{localfloatstack}

\installsetuponlycommandhandler \??localfloats {localfloats}

\setuplocalfloats
  [%\c!before=\blank,
   %\c!after=\blank,
   \c!inbetween=\blank]

\initializeboxstack\??localfloatstack

\newcount\c_strc_localfloats_n  \let\noflocalfloats\c_strc_localfloats_n

\unexpanded\def\resetlocalfloats
  {\global\c_strc_localfloats_n\zerocount
   \initializeboxstack\??localfloatstack}

\unexpanded\def\somelocalfloat
  {\global\advance\c_strc_localfloats_n\plusone
   \savebox\??localfloatstack{\number\c_strc_localfloats_n}{\box\floatbox}}

\unexpanded\def\getlocalfloats
  {\dorecurse\c_strc_localfloats_n
     {\ifnum\recurselevel=\plusone % 1\relax
        \directlocalfloatsparameter\c!before
      \else
        \directlocalfloatsparameter\c!inbetween
      \fi
      \dontleavehmode\hpack{\foundbox\??localfloatstack\recurselevel}% \restorebox...
      \ifnum\recurselevel=\c_strc_localfloats_n\relax
        \directlocalfloatsparameter\c!after
      \fi}}

\unexpanded\def\flushlocalfloats
  {\getlocalfloats
   \resetlocalfloats}

% \unexpanded\def\getlocalfloat#1%
%   {\normalexpanded{\foundbox{\??localfloatstack}{\number#1}}}% \vbox{\restorebox...}

\unexpanded\def\getlocalfloat#1%
  {\foundbox\??localfloatstack{\number#1}} % \vbox{\restorebox...}

\unexpanded\def\forcelocalfloats
  {\let\forcedfloatmethod\v!local}

\installfloatmethod \s!singlecolumn \v!local \somelocalfloat
\installfloatmethod \s!multicolumn  \v!local \somelocalfloat
\installfloatmethod \s!mixedcolumn  \v!local \somelocalfloat
\installfloatmethod \s!columnset    \v!local \somelocalfloat

\protect \endinput