diff --git a/README.md b/README.md index d0ba527..576dfeb 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,39 @@ Tex文件的开头,是基本信息部分,可以根据需要添加`\title`{ ![块](/figs/fig07.png) ![标题框和文本框](/figs/fig08.png) +### 要点框自动排布(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~12 个)](/figs/fig14.png) + +几点说明: + +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`即可。 diff --git a/figs/fig14.png b/figs/fig14.png new file mode 100644 index 0000000..3cbe4d8 Binary files /dev/null and b/figs/fig14.png differ diff --git a/slides.pdf b/slides.pdf index f4bc76f..4dcbbb7 100644 Binary files a/slides.pdf and b/slides.pdf differ diff --git a/theme/beamerinnerthemeOUCSlide.sty b/theme/beamerinnerthemeOUCSlide.sty index b9d3369..3f3ee11 100644 --- a/theme/beamerinnerthemeOUCSlide.sty +++ b/theme/beamerinnerthemeOUCSlide.sty @@ -125,6 +125,180 @@ 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 \newtcolorbox{textbox}[1]{ colback=#1!5!white,