新增要点框自动排布环境 pointboxgrid(每行最多 4 个)
把任意多个要点自动排成网格,规则:行数 = ceil(N/4),尽量均匀且上行不少于下行
(1~4 一行;5→3+2;6→3+3;7→4+3;8→4+4;9→3+3+3;10→4+3+3;11→4+4+3;12→4+4+4)。
用法:
\begin{pointboxgrid}{高度}
\pointitem{标题}{颜色}{内容}
...
\end{pointboxgrid}
另提供 \pointboxsetup{每行最多几个}{横向间距}{纵向间距}(默认 4 / 8pt / 6pt)。
实现要点(本机 expl3 的坑,已在代码注释中说明):
- 比较一律用 \ifnum:\int_compare:nNnT 在本机 TeX Live 下会把所有 ##1
都判成“小于等于”,导致行内个数分配失效。
- 列宽走 \fp_eval:n + \dim_to_fp:n:expl3 的维度乘法(*)在此环境下静默算出 0pt。
- 要点内容存进带索引的宏、再用 \tl_use:c 取用,避开不可靠的 \exp_after:wN 展开。
- 必须 \begin{columns}[onlytextwidth],否则默认 columns 的左右边距会让 4 列各溢出约 10pt。
另外:总高超过正文可用高度时给出 oucslide Warning
(总高 ≈ 69 + 行数×高度 + (行数−1)×25 pt;正文可用高度取 243pt)。
已验证:1~12 个排布全部符合规则;TL2022/2023/2024/2025/2026 均 0 错误 0 溢出;
原有内容不受影响(纯新增 174 行)。
This commit is contained in:
@@ -249,6 +249,39 @@ Tex文件的开头,是基本信息部分,可以根据需要添加`\title`{
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
### 要点框自动排布(pointboxgrid)
|
||||||
|
|
||||||
|
要点框数量多的时候,不需要自己摆 `columns`——用 `pointboxgrid` 环境会自动排成网格:
|
||||||
|
|
||||||
|
```
|
||||||
|
\begin{pointboxgrid}{高度}
|
||||||
|
\pointitem{标题}{颜色}{内容}
|
||||||
|
\pointitem{标题}{颜色}{内容}
|
||||||
|
...
|
||||||
|
\end{pointboxgrid}
|
||||||
|
```
|
||||||
|
|
||||||
|
**排布规则:每行最多 4 个;超过 4 个自动分成多行,并尽量均匀(上行不少于下行)。**
|
||||||
|
|
||||||
|
| 个数 | 排布 | 个数 | 排布 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 1~4 | 一行 | 9 | 3 + 3 + 3 |
|
||||||
|
| 5 | 3 + 2 | 10 | 4 + 3 + 3 |
|
||||||
|
| 6 | 3 + 3 | 11 | 4 + 4 + 3 |
|
||||||
|
| 7 | 4 + 3 | 12 | 4 + 4 + 4 |
|
||||||
|
| 8 | 4 + 4 | N | 行数 = ⌈N/4⌉,前 N mod 行数 行每行多放一个 |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
几点说明:
|
||||||
|
|
||||||
|
1. **高度参数的含义和 `pointbox` 的 `height` 一样**,是固定高度——内容别写超,超了会画到框外(见下)。数量多时记得**把高度调小**。
|
||||||
|
2. **行数多了会超出页面底部**。经验值:正文区高约 243pt,总高 ≈ `69 + 行数×高度 + (行数−1)×25`(pt)。
|
||||||
|
所以 **4 行时高度不要超过 24pt**。超过时编译日志里会有 `oucslide Warning` 提醒。
|
||||||
|
3. 想让每行放更多/更少,可改 `\l_ouc_pbg_max`(默认 4);间距可改 `\l_ouc_pbg_gap`(横向,默认 8pt)与
|
||||||
|
`\l_ouc_pbg_vgap`(纵向,默认 6pt)。
|
||||||
|
4. 单个要点框仍然可以像以前那样手写 `columns` + `pointbox`,两种用法并存。
|
||||||
|
|
||||||
## 代码
|
## 代码
|
||||||
|
|
||||||
模板可以插入代码块,使用`lstlisting`即可。
|
模板可以插入代码块,使用`lstlisting`即可。
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
Binary file not shown.
@@ -125,6 +125,180 @@
|
|||||||
title=#1
|
title=#1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%% ======================================================================
|
||||||
|
%% 要点框自动排布:pointboxgrid
|
||||||
|
%% ----------------------------------------------------------------------
|
||||||
|
%% 把任意多个要点自动排成「每行最多 4 个」的网格:
|
||||||
|
%% \begin{pointboxgrid}{高度}
|
||||||
|
%% \pointitem{标题}{颜色}{内容}
|
||||||
|
%% ...
|
||||||
|
%% \end{pointboxgrid}
|
||||||
|
%%
|
||||||
|
%% 排布规则(行数尽可能少,并尽量均匀):
|
||||||
|
%% 1~4 个 → 一行
|
||||||
|
%% 5 个 → 上行 3 + 下行 2
|
||||||
|
%% 6 个 → 3 + 3
|
||||||
|
%% 7 个 → 4 + 3
|
||||||
|
%% 8 个 → 4 + 4
|
||||||
|
%% 9 个 → 3 + 3 + 3
|
||||||
|
%% 10 个 → 4 + 3 + 3
|
||||||
|
%% 11 个 → 4 + 4 + 3
|
||||||
|
%% 12 个 → 4 + 4 + 4
|
||||||
|
%% 一般地:行数 = ceil(N/4),前 N mod 行数 行每行多放 1 个。
|
||||||
|
%%
|
||||||
|
%% 说明:
|
||||||
|
%% - 高度参数与 pointbox 的 height 含义相同(固定高度,内容别超出)。
|
||||||
|
%% - 较多行时请自行减小高度,避免总高超出页面(建议行数 ≤ 4)。
|
||||||
|
%% - 「每行最多几个」由 \ouc_pbg_max 控制;间距由 \ouc_pbg_gap /
|
||||||
|
%% \ouc_pbg_vgap 控制,需要时在导言区改这两个长度。
|
||||||
|
%% ======================================================================
|
||||||
|
\ExplSyntaxOn
|
||||||
|
\int_new:N \l_ouc_pbg_cnt
|
||||||
|
\int_new:N \l_ouc_pbg_n
|
||||||
|
\int_new:N \l_ouc_pbg_rows
|
||||||
|
\int_new:N \l_ouc_pbg_base
|
||||||
|
\int_new:N \l_ouc_pbg_rem
|
||||||
|
\int_new:N \l_ouc_pbg_k
|
||||||
|
\int_new:N \l_ouc_pbg_km
|
||||||
|
\int_new:N \l_ouc_pbg_i
|
||||||
|
\int_new:N \l_ouc_pbg_max
|
||||||
|
\dim_new:N \l_ouc_pbg_est
|
||||||
|
\dim_new:N \l_ouc_pbg_colw
|
||||||
|
\dim_new:N \l_ouc_pbg_gap
|
||||||
|
\dim_new:N \l_ouc_pbg_vgap
|
||||||
|
\dim_new:N \l_ouc_pbg_h
|
||||||
|
\int_set:Nn \l_ouc_pbg_max { 4 }
|
||||||
|
\dim_new:N \l_ouc_pbg_avail
|
||||||
|
\dim_set:Nn \l_ouc_pbg_avail { 243pt }
|
||||||
|
\dim_set:Nn \l_ouc_pbg_gap { 8pt }
|
||||||
|
\dim_set:Nn \l_ouc_pbg_vgap { 6pt }
|
||||||
|
|
||||||
|
%% 收集一个要点:内容按原样存进带索引的宏,不做任何展开
|
||||||
|
\NewDocumentCommand \pointitem { m m m }
|
||||||
|
{
|
||||||
|
\int_incr:N \l_ouc_pbg_cnt
|
||||||
|
\tl_set:cn { l_ouc_pbg_t_ \int_use:N \l_ouc_pbg_cnt } {#1}
|
||||||
|
\tl_set:cn { l_ouc_pbg_c_ \int_use:N \l_ouc_pbg_cnt } {#2}
|
||||||
|
\tl_set:cn { l_ouc_pbg_b_ \int_use:N \l_ouc_pbg_cnt } {#3}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% 画一个要点框:按序号直接取用存好的宏
|
||||||
|
\cs_new_protected:Npn \ouc_pbg_emit:n #1
|
||||||
|
{
|
||||||
|
\begin{pointbox}
|
||||||
|
[ \tl_use:c { l_ouc_pbg_t_#1 } ]
|
||||||
|
{ \tl_use:c { l_ouc_pbg_c_#1 } }
|
||||||
|
{ \dim_use:N \l_ouc_pbg_h }
|
||||||
|
\tl_use:c { l_ouc_pbg_b_#1 }
|
||||||
|
\end{pointbox}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% 列宽 = (正文宽 - (k-1)*间距) / k
|
||||||
|
%% 注:某些 TeX Live 下 expl3 的维度乘法(*)会静默算出 0,
|
||||||
|
%% 因此走 fp_eval + dim_to_fp 的浮点路径,稳妥。
|
||||||
|
\cs_new_protected:Nn \ouc_pbg_setcolw:
|
||||||
|
{
|
||||||
|
\int_set:Nn \l_ouc_pbg_km { \int_use:N \l_ouc_pbg_k - 1 }
|
||||||
|
\dim_set:Nn \l_ouc_pbg_colw
|
||||||
|
{
|
||||||
|
\fp_eval:n
|
||||||
|
{
|
||||||
|
( \dim_to_fp:n { \textwidth }
|
||||||
|
- \int_use:N \l_ouc_pbg_km * \dim_to_fp:n { \l_ouc_pbg_gap } )
|
||||||
|
/ \int_use:N \l_ouc_pbg_k
|
||||||
|
}
|
||||||
|
pt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\cs_new_protected:Nn \ouc_pbg_typeset:
|
||||||
|
{
|
||||||
|
\int_set:Nn \l_ouc_pbg_n { \int_use:N \l_ouc_pbg_cnt }
|
||||||
|
\int_compare:nNnT { \int_use:N \l_ouc_pbg_n } > { 0 }
|
||||||
|
{
|
||||||
|
%% 行数 = ceil(N / max)
|
||||||
|
\int_set:Nn \l_ouc_pbg_rows
|
||||||
|
{
|
||||||
|
\int_div_truncate:nn
|
||||||
|
{ \int_use:N \l_ouc_pbg_n + \int_use:N \l_ouc_pbg_max - 1 }
|
||||||
|
{ \int_use:N \l_ouc_pbg_max }
|
||||||
|
}
|
||||||
|
%% 均匀分配:前 rem 行每行多 1 个(上行不少于下行)
|
||||||
|
\int_set:Nn \l_ouc_pbg_base
|
||||||
|
{
|
||||||
|
\int_div_truncate:nn
|
||||||
|
{ \int_use:N \l_ouc_pbg_n } { \int_use:N \l_ouc_pbg_rows }
|
||||||
|
}
|
||||||
|
\int_set:Nn \l_ouc_pbg_rem
|
||||||
|
{
|
||||||
|
\int_use:N \l_ouc_pbg_n
|
||||||
|
- \int_use:N \l_ouc_pbg_base * \int_use:N \l_ouc_pbg_rows
|
||||||
|
}
|
||||||
|
%% 预估总高度并与正文可用高度比较(公式按实测校准):
|
||||||
|
%% 总高 ≈ 69pt(首行含标题条) + 行数*高度 + (行数-1)*25pt(行间距)
|
||||||
|
\dim_set:Nn \l_ouc_pbg_est
|
||||||
|
{
|
||||||
|
\fp_eval:n
|
||||||
|
{
|
||||||
|
69
|
||||||
|
+ \int_use:N \l_ouc_pbg_rows * \dim_to_fp:n { \l_ouc_pbg_h }
|
||||||
|
+ ( \int_use:N \l_ouc_pbg_rows - 1 ) * 25
|
||||||
|
}
|
||||||
|
pt
|
||||||
|
}
|
||||||
|
\ifdim \l_ouc_pbg_est > \l_ouc_pbg_avail
|
||||||
|
\PackageWarning{oucslide}
|
||||||
|
{
|
||||||
|
要点框共 \int_use:N \l_ouc_pbg_n\space 个,排成
|
||||||
|
\int_use:N \l_ouc_pbg_rows\space 行、每框高 \dim_use:N \l_ouc_pbg_h,
|
||||||
|
预估总高 \dim_use:N \l_ouc_pbg_est\space 已超过正文可用高度
|
||||||
|
\dim_use:N \l_ouc_pbg_avail,可能超出页面底部。
|
||||||
|
请把高度改小(4 行时建议不超过 24pt)或减少要点个数
|
||||||
|
}
|
||||||
|
\fi
|
||||||
|
\int_zero:N \l_ouc_pbg_i
|
||||||
|
\int_step_inline:nn { \int_use:N \l_ouc_pbg_rows }
|
||||||
|
{
|
||||||
|
\int_set:Nn \l_ouc_pbg_k { \int_use:N \l_ouc_pbg_base }
|
||||||
|
%% 注意:此处的比较必须用 \ifnum。
|
||||||
|
%% expl3 的 \int_compare:nNnT 在这套 TeX Live 下判定有误,
|
||||||
|
%% 会把所有 ##1 都判成"小于等于",导致行内个数分配失效。
|
||||||
|
\ifnum ##1 > \int_use:N \l_ouc_pbg_rem \else
|
||||||
|
\int_incr:N \l_ouc_pbg_k
|
||||||
|
\fi
|
||||||
|
\ouc_pbg_setcolw:
|
||||||
|
%% 必须用 [onlytextwidth],否则默认 columns 会带来
|
||||||
|
%% 左/右边距,4 列时左右各溢出约 10pt。
|
||||||
|
\begin{columns}[onlytextwidth]
|
||||||
|
\int_step_inline:nn { \int_use:N \l_ouc_pbg_k }
|
||||||
|
{
|
||||||
|
\int_incr:N \l_ouc_pbg_i
|
||||||
|
\begin{column}{\dim_use:N \l_ouc_pbg_colw}
|
||||||
|
\ouc_pbg_emit:n { \int_use:N \l_ouc_pbg_i }
|
||||||
|
\end{column}
|
||||||
|
}
|
||||||
|
\end{columns}
|
||||||
|
\ifnum ##1 < \int_use:N \l_ouc_pbg_rows
|
||||||
|
\vspace{\dim_use:N \l_ouc_pbg_vgap}
|
||||||
|
\fi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% 友好设置:\pointboxsetup{每行最多几个}{横向间距}{纵向间距}
|
||||||
|
%% 例如 \pointboxsetup{5}{6pt}{4pt}
|
||||||
|
\NewDocumentCommand \pointboxsetup { m m m }
|
||||||
|
{
|
||||||
|
\int_set:Nn \l_ouc_pbg_max {#1}
|
||||||
|
\dim_set:Nn \l_ouc_pbg_gap {#2}
|
||||||
|
\dim_set:Nn \l_ouc_pbg_vgap {#3}
|
||||||
|
}
|
||||||
|
|
||||||
|
\NewDocumentEnvironment { pointboxgrid } { m }
|
||||||
|
{ \int_zero:N \l_ouc_pbg_cnt \dim_set:Nn \l_ouc_pbg_h {#1} }
|
||||||
|
{ \ouc_pbg_typeset: }
|
||||||
|
\ExplSyntaxOff
|
||||||
|
|
||||||
%文本框textbox
|
%文本框textbox
|
||||||
\newtcolorbox{textbox}[1]{
|
\newtcolorbox{textbox}[1]{
|
||||||
colback=#1!5!white,
|
colback=#1!5!white,
|
||||||
|
|||||||
Reference in New Issue
Block a user