Создание внешнего вида блокнота в tcolorbox; проблемы с рисованием правильного количества строк

Создание внешнего вида блокнота в tcolorbox; проблемы с рисованием правильного количества строк

Я пытаюсь создать что-то похожее на фрагмент блокнотной бумаги в tcolorboxсреде, рисуя горизонтальные линии и вертикальную линию. Проблема, с которой я сталкиваюсь, заключается в том, что я не знаю, как определить верхний предел количества линий, если я не закодирую их жестко. Это вызывает проблему, когда цветной блок разрывается на странице, а блоки имеют разную высоту. Линии рисуются снизу блока. Если блок имеет две разные длины, то сложно сделать так, чтобы линии выглядели так, будто они были равномерно распределены сверху.

Как мне получить высоту tcolorbox? Я пробовал\tcbвысотатекстано использование этого для вертикальной линии даже не работает. Кроме того, я не знаю, как написать цикл с разделением событий. Предпочтительно, чтобы линии были размером с межстрочный интервал документа, но это не обязательно. После получения высоты мне нужно, чтобы рисование линии начиналось с верха поля, а не с низа.

\documentclass[letterpaper, 10pt]{article}

\usepackage[skins, raster, breakable]{tcolorbox}
\usepackage{tikz}
\usetikzlibrary{decorations,decorations.markings,optics}
\usepackage[english]{babel}
\usepackage{blindtext}

\begin{document}
\pagestyle{empty}

\tikzset{normal lines/.style={gray, very thin}} 

\tcbset{paper/.style={enhanced,colback=green!10,colframe=green!65!black,width=\textwidth,breakable,left=1.3in,
        overlay={
            \begin{tcbclipframe}
              \foreach \y in {0.25, 0.5,...,10.25}
                  \draw[style=normal lines](0,\y in) -- (8.5in, \y in);
              \draw[style=normal lines] (1.25in,0)--(1.25in, 3in);
            \end{tcbclipframe}
        }   
    }   
}
\blindtext[5]
\begin{tcolorbox}[paper]
\blindtext[2]
\end{tcolorbox}

\end{document}

введите описание изображения здесь

решение1

Я предлагаю сделать это с помощью tcolorboxподскина enhanced(который подходит для бьющихся коробок). В коде, приведенном ниже, мы определяем скин с именем, paperкоторый является производным от enhanced, и заставляем tcolorboxстиль paperвыполняться skin=paper(среди прочего, например, устанавливать желаемые цвета рамки и фона). Мы также определяем три подскина paperfirst, papermiddleи paperlastсоответственно производные от enhancedfirst, enhancedmiddleи enhancedlast; они позволяют нам придать желаемый вид коробке во всех случаях (неразбитый, сломанный сверху и не сломанный снизу, сломанный снизу и не сломанный сверху, сломанный и сверху, и снизу).

Так как enhancedскин задает /tcb/geometry nodes=true, он определяет узлы с именами frame, interior, segmentation, и title, которые позволяют нам получить доступ к интересным точкам tcolorbox. Здесь можно использовать или frameдля interiorвычисления высоты блока (они не дают точно такого же результата, как /tcb/leftrule, /tcb/toprule, /tcb/rightruleи /tcb/bottomruleпринадлежат , frameно не interior). В paperскине, определенном ниже, мы используем interiorузел для вычисления количества горизонтальных линий для рисования и подходящих комбинаций frameи interiorдля протяженности вертикальной линии в зависимости от того, разорван ли блок сверху и разорван ли он снизу. Расчет количества горизонтальных линий для рисования можно выполнить с помощью \pgfmathtruncatemacro, например (это также можно сделать с помощью int()внутри \pgfmathsetmacroвызова).

Примечание: Я внес небольшое изменение в ваш normal linesстиль. Он line widthбольше, но правила нарисованы с помощью opacity=..., как определено в /tcb/paper/rule opacity. Этот рисунок сделан внутри , transparency groupцель которого — убедиться, что пересечения правил не темнее других мест в правилах.

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{breakable, skins}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{lipsum}

\makeatletter

\tikzset{normal lines/.style={gray, thin}}
\tcbset{paper/left margin/.initial=1.25in,
        paper/line spacing/.initial=1cm,
        paper/rule opacity/.initial=0.4,
        paper/.style={
          skin=paper, colback=green!10, colframe=green!65!black,
          breakable, left=1.3in,
        }
}

\newif\if@paper@broken@top
\newif\if@paper@broken@bottom
\pgfkeys{/tcb/paper/broken top/.is if=@paper@broken@top,
         /tcb/paper/broken bottom/.is if=@paper@broken@bottom
}

% The various parts don't have the same skin when a box is broken. This also
% influences where we want the vertical rule to extend to.
\tcbsubskin{paperfirst}{enhancedfirst}{
  paper/broken top=false, paper/broken bottom=true
}
\tcbsubskin{papermiddle}{enhancedmiddle}{
  paper/broken top=true, paper/broken bottom=true
}
\tcbsubskin{paperlast}{enhancedlast}{
  paper/broken top=true, paper/broken bottom=false
}

\tcbsubskin{paper}{enhanced}{
  skin first=paperfirst, skin middle=papermiddle, skin last=paperlast,
  paper/broken top=false, paper/broken bottom=false,
  overlay={
    \begin{tcbclipinterior}
    \begin{scope}[opacity=\pgfkeysvalueof{/tcb/paper/rule opacity},
                  transparency group]
    % Make sure the vertical rule extends exactly as far as we want, depending
    % on where the box is broken.
    \if@paper@broken@top
      \coordinate (top for vert rule) at (frame.north west);
    \else
      \coordinate (top for vert rule) at (interior.north west);
    \fi
    %
    \if@paper@broken@bottom
      \coordinate (bottom for vert rule) at (frame.south west);
    \else
      \coordinate (bottom for vert rule) at (interior.south west);
    \fi
    %
    \draw[transform canvas={xshift=\pgfkeysvalueof{/tcb/paper/left margin}},
          style=normal lines] (top for vert rule) -- (bottom for vert rule);
    %
    \path let \p1=($(interior.north)-(interior.south)$) in
      \pgfextra{%
        \pgfmathtruncatemacro{\tmp}{veclen(\p1) /
                                    \pgfkeysvalueof{/tcb/paper/line spacing}}%
        \xdef\paperskin@nblines{\tmp}};
    \foreach \i in {1,..., \paperskin@nblines} {
       \pgfmathsetlengthmacro{\paperskin@shift}{
         -\i*\pgfkeysvalueof{/tcb/paper/line spacing}}
       \draw[style=normal lines]
         ([yshift=\paperskin@shift]interior.north west) --
         ([yshift=\paperskin@shift]interior.north east);
    }
    \end{scope}
    \end{tcbclipinterior}
  },
}

\makeatother

\pagestyle{empty}

\begin{document}

\lipsum[1]
\begin{tcolorbox}[paper]
\lipsum[2]
\end{tcolorbox}

\lipsum[3]
\begin{tcolorbox}[paper]
\lipsum[4-5]
\end{tcolorbox}

\end{document}

Скриншот

Неразбитая коробка:

Крупный план неразбитой коробки

firstчасть сломанной коробки:

Крупный план сломанной коробки, первая часть

lastчасть сломанной коробки:

Крупный план сломанной коробки, последняя часть

Часть middle(сломанная сверху)и(внизу) также будет нарисовано правильно, с вертикальной линейкой, простирающейся как раз настолько, насколько это необходимо:

Коробка сломана сверху и снизу

Примечание: следующая часть моего кода:

\tcbsubskin{paper}{enhanced}{
  ...
  overlay={
    ...
    % Make sure the vertical rule extends exactly as far as we want, depending
    % on where the box is broken.
    \if@paper@broken@top
      \coordinate (top for vert rule) at (frame.north west);
    \else
      \coordinate (top for vert rule) at (interior.north west);
    \fi
    %
    \if@paper@broken@bottom
      \coordinate (bottom for vert rule) at (frame.south west);
    \else
      \coordinate (bottom for vert rule) at (interior.south west);
    \fi

можно записать и так:

\newcommand*{\paper@defcoord}[3]{
  \coordinate (#2 for vert rule) at (#1.#3 west);
}

\tcbsubskin{paper}{enhanced}{
  ...
  overlay={
    ...
    % Make sure the vertical rule extends exactly as far as we want, depending
    % on where the box is broken.
    \edef\tmp{\if@paper@broken@top frame\else interior\fi}
    \expandafter\paper@defcoord\expandafter{\tmp}{top}{north}
    \edef\tmp{\if@paper@broken@bottom frame\else interior\fi}
    \expandafter\paper@defcoord\expandafter{\tmp}{bottom}{south}

но первый способ кажется гораздо более простым для чтения, поэтому я решил оставить его в полном примере.

решение2

Вместо сетки, нарисованной от руки, можно использовать TikZсетку с большим xstep. Следующий код показывает возможное решение (вдохновленное примером в tcolorboxдокументации, стр. 131). Это не решает проблему с разбитыми ящиками и корректировкой вертикального положения.

\documentclass{article}
\usepackage[most]{tcolorbox}
\usepackage{lmodern}
\usepackage{blindtext}

\newtcolorbox{notebook}{
    enhanced,
    breakable,
    colback=green!10,
    colframe=green!65!black,
    left=1.3in,
    underlay={%
        \begin{tcbclipinterior}
        \draw[help lines, ystep=\baselineskip, xstep=\linewidth, 
            shift={(interior.north west)}](interior.south west) grid (interior.north east);
        \draw[help lines] ([xshift=1.25in]interior.north west)--
            ([xshift=1.25in]interior.south west);
        \end{tcbclipinterior}}
    }

\begin{document}
\blindtext[1]
\begin{notebook}
\blindtext[3]
\end{notebook}
\end{document}

введите описание изображения здесь

Связанный контент