%
% file: nvverttab.sty
%
% Nova de Hi, 2021-04-01, 2022-09-24, 2024-05-16 (renamed)
% KTUG. http://www.ktug.org
%
% public domain.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% \Vtab
%%		move to the next vertical tab position
%%		or top of next page/column.
%% \VtabPositions
%%		define tabs positions, e.g.
%%		\VtabPositions{6cm, 12cm, 18cm}
%%		especially, `ht' = \textheight, e.g.
%%		\VtabPositions{.3ht,.6ht}
%%			= \VtabPositions{.3\textheight,.6\textheight}
%% \numVtabs
%%		preset <n> tabs to the \textheight;
%%		\numVtabs{3} will set tabs at the positions of
%%		1/3\textheight, 2/3\textheight, and \textheight
%%		(strictly speaking, the last one line will not be counted).
%%		<n> should be <= 10.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\ProvidesExplPackage{nvverttab}
	{ 2025-04-04 }
	{ v1.4 }
	{ vertical tab implemented by nova }

\RequirePackage{l3keys2e}

\keys_define:nn { nvverttab }
{
	ignorelastline	.bool_set_inverse:N = \opt_lastline_bool,
	numvtabs		.int_set:N = \opt_numvtabs_int
}

\keys_set:nn { nvverttab }
{
	ignorelastline	= false,
	numvtabs	 	= 2
}

\ProcessKeysOptions { nvverttab }

\dim_new:N \g_resplastline_dim
\dim_new:N \g_tottarget_dim
\dim_new:N \l_curtobot_dim
\dim_new:N \l_targtobot_dim

\clist_new:N \g_vtabpos_clist
\clist_new:N \l_lvtabs_clist

\bool_if:NTF \opt_lastline_bool
{
	\cs_if_exist:NTF \onelineskip
	{
		\dim_gset_eq:NN \g_resplastline_dim \onelineskip
	}
	{
		\dim_gset:Nn \g_resplastline_dim { \f@size pt * 1.2 }
	}
}
{
	\dim_gzero:N \g_resplastline_dim
}

\dim_gset:Nn \g_tottarget_dim { \textheight - \g_resplastline_dim }

\cs_new_nopar:Nn \calculate_vdist:
{
	\dim_compare:nTF { \pagegoal == \c_max_dim }
	{
		\dim_set_eq:NN \l_tmpa_dim \vsize
	}
	{
		\dim_set_eq:NN \l_tmpa_dim \pagegoal
	}
	
	\dim_set:Nn \l_curtobot_dim { \l_tmpa_dim - \pagetotal - \g_resplastline_dim }
}

\NewDocumentCommand \VtabPositions { m }
{
	\tl_set:Nn \l_tmpa_tl { #1 }
	\regex_replace_all:nnN { ([\d]) ht } { \1 \c{textheight} } \l_tmpa_tl
	\clist_gset:Nx \g_vtabpos_clist { \l_tmpa_tl }
}

\NewDocumentCommand \Vtab {}
{
	\if_mode_horizontal: \par \fi:
	\clist_set_eq:NN \l_lvtabs_clist \g_vtabpos_clist
	
	\move_to_next_vtab:
}

\cs_new:Nn \move_to_next_vtab:
{
	\int_compare:nTF { \clist_count:N \l_lvtabs_clist < 1 }
	{
		\newpage
	}
	{
		\calc_and_move_to_vtab:
	}
}

\cs_new:Nn \calc_and_move_to_vtab:
{
	\clist_pop:NN \l_lvtabs_clist \l_tmpa_tl
	\dim_set:Nn \l_targtobot_dim { \g_tottarget_dim - \l_tmpa_tl }
	
	\calculate_vdist:
	
	\dim_compare:nTF { \l_targtobot_dim < \c_zero_dim }
	{
		\newpage
	}
	{
		\dim_set:Nn \l_tmpa_dim { \l_curtobot_dim - \l_targtobot_dim }

		\dim_compare:nTF { \l_tmpa_dim > \c_zero_dim }
		{
			\vskip \l_tmpa_dim 
		}
		{
			\move_to_next_vtab:
		}
	}
}

\NewDocumentCommand \numVtabs { m }
{
	\int_compare:nTF { #1 > 10 }
	{
		number~too~large.
	}
	{
		\tl_clear:N \l_tmpb_tl
		\dim_set_eq:NN \l_tmpa_dim \g_tottarget_dim 
		\dim_sub:Nn \l_tmpa_dim { \baselineskip }
		\int_step_inline:nn { #1 - 1 }
		{
			\tl_put_right:Nx \l_tmpb_tl { 
				\dim_eval:n { \l_tmpa_dim * ##1 / #1 }
			}
			\int_compare:nT { ##1 < #1 - 1 }
			{
				\tl_put_right:Nn \l_tmpb_tl { , }
			}
		}

		\exp_args:No \VtabPositions { \l_tmpb_tl }
	}
}

%%% command for debugging
\NewDocumentCommand \showthevtabs {}
{
	<<
	\clist_map_inline:Nn \g_vtabpos_clist
	{
		\dim_to_decimal_in_unit:nn { \dim_eval:n { ##1 } } { 1mm } mm,~
	}
	>>
}

%%% default setting
\exp_args:Nx \numVtabs {\int_use:N \opt_numvtabs_int}

\endinput
