VScode住人の探検記

Visual Studio Codeでなんでもこなすのがポリシー。LaTeX(2020/7/19~), C(2021/1/25~), C#(2/4~), HTML&CSS(2/14~), Python(2/16~), JavaScript(2/28~), jQuery(3/18~), Sass(Scss)(3/20~),シェルスクリプト(3/21~), jCanvas(5/21~), WordPress(5/23~), PHP(5/31~)

ページまたぎ可能なリングノート枠【tcolorboxの可能性】

f:id:nix_campane:20210110131300j:plain

ありそうでなかなかない、LaTeXで使えるリングノート枠。
下のブログを見つけてfancyparに惚れこんだものの、ページまたぎができないと察して頭を抱えていた。

konoyonohana.blog.fc2.com

ならば自分で作ればいいじゃないか!という持ち前の勢いの良さで、tcolorboxのマニュアル(※530ページ、全文英語)を読み始める。
その他にも海外ブログやら類似パッケージのstyファイルやらいろいろなものを読み漁って、なんとか丸1日で実装にこぎ着けたので、コード全文とその解説をまとめておく。

なお、以下ではすべてpLaTeX(ptex2pdf)でコンパイルしている。

手順0,制作の方向性

fancyparは『個々の段落を装飾する』マクロ集であり、複数の段落をまとめて囲むことは想定されていない。実際、fancyparパッケージで定義されているものはコマンドであり、環境ではないので、(\parboxで囲んで無理やり1行と認識させない限り)内部で改行などをすればエラーが吐き出されるはずである。

そこで今回実装したいのは、fancyparの\NotebookParというコマンドで出力されるリングノート枠の改良版だ。
具体的には、次のような機能をもつものを作りたい。

  • 枠内で改行可能
  • ページまたぎ可能
  • 枠内であらゆるコマンドや環境が使える

なお、個人的に罫線は無い方が読みやすい気がするので、本家のような罫線はつけない方向で行く。

手順1,fancyparのstyファイルからリング部分のコードを抜き出す

結論から言うと、fancypar.styの116~124行目がリング部分を記述するコードである。

    \tikz{%
      \draw[draw=black,fill=white] (-1,-0.3) circle (3pt);%リング穴を描画
      \ifFP@fancypar@spiral%spiral=trueというオプションをつけた場合は以下の処理(リングを描画)
        \draw[very thin,rotate=4,double=\FancyNSColor,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%
      \else\relax%spiral=falseというオプションをつけた場合は何もしない
      \fi
    }

今回はspiral=trueとしてリングノート風の出力を得たいので、リング穴とリングを描画するコードだけ抜き出す。

 \tikz{%
      \draw[draw=black,fill=white] (-1,-0.3) circle (3pt);%リング穴を描画
      \draw[very thin,rotate=4,double=\FancyNSColor,%この行以下でリングを描画
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%
 }

\FancyNSColorという色は、43行目で次のように定義されている。

\DeclareOptionX[FP]<fancypar>{spiralcolor}{\def\FancyNSColor{#1}}

これは、spiralcolor=…というオプションで指定した色が\FancyNSColorであるという意味だが、今回はそのようなオプションはつけずにデフォルトの色を指定することにする。
fancyparパッケージのドキュメント(fancypar.pdf)の6ページを見ると、デフォルトの色はLightYellow3であるらしい。
インターネットでRGB値を調べ、次のように定義しておく。

\definecolor{lightyellowiii}{RGB}{205,205,180}

先ほどの\FancyNSColorをlightyellowiiiに置き換えて、次のようにするとコンパイルが可能になる。

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}
\usepackage[dvipdfmx]{graphicx,color}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
\definecolor{lightyellowiii}{RGB}{205,205,180}

\begin{document}

 \tikz{%
      \draw[draw=black,fill=white] (-1,-0.3) circle (3pt);%リング穴を描画
      \draw[very thin,rotate=4,double=lightyellowiii,%この行以下でリングを描画
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%
 }
 
\end{document}

コンパイル結果は、次のようになる。

f:id:nix_campane:20210110131158j:plain

手順2,リングを新たなデコレーション単位として定義する

さて、問題はこのリングをどうやって枠の左上から左下までに渡って等間隔に配置するか?なのだが、散々ネットを徘徊した末に、次の方法で実装できそうな予感がしてきた。

TikZにはdecoration.shapesというライブラリがある。
このライブラリを読み込むと、予め定義した図形(猫の足跡とか)を何度もスタンプを押すように並べることができるようになる。
そこで、先ほど描画したリング1つを新たなスタンプとして定義して、枠の左上から左下まで並べていけば、目的のレイアウトは実現できそうだ。

その前に、先ほど描いたリングを90°回転させておく。

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}
\usepackage[dvipdfmx]{graphicx,color}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
\definecolor{lightyellowiii}{RGB}{205,205,180}

\begin{document}

 \tikz{%
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%rotate=90で90°回転、回転させるとリングと穴がズレるので、穴となる円の中心をちょっとずらした
      \draw[very thin,rotate=90,double=lightyellowiii,%rotate=90で90°回転
          double distance=1.5pt]
          (-1,-0.2) arc (40:-250:10pt and 2pt);
 }
 
\end{document}

コンパイル結果は

f:id:nix_campane:20210110131214j:plain

どうやらスタンプとして並べられるときに図形が-90°回転されるようなので、予め90°回転させておかないと目的の出力が得られない。

自分で新たなスタンプを定義するには、\pgfdeclaredecorationコマンドを用いるらしい。
上の画像のリングをspiralスタンプとして、次のように定義する。

\pgfdeclaredecoration{spiral}{initial}
{
 \state{initial}
[width=\pgfdecoratedpathlength/floor(\pgfdecoratedpathlength/13pt] %13がリングの間隔を決める
  {
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%ここからがさっきのコード
      \draw[very thin,rotate=90,double=lightyellowiii,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%ここまでがさっきのコード
  }
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }
}

コードの意味についてはとりあえず省略(実はまだあんまりよくわかっていない)
とりあえず、
13より大きな値にするとリングの間隔はより広くなる。小さな値にするとより狭くなる。ここは好みで調整

実際にこのスタンプを使ってみよう。

 \tikz{
         \draw[decorate,decoration={spiral}]  %spiralスタンプを使う宣言
          (0,0)--(0,-10);% (0,0)と(0,-10)を結ぶ直線状にスタンプを並べる
 }

のようにしてスタンプを並べることができる。
コンパイル用の完全版は、

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}
\usepackage[dvipdfmx]{graphicx,color}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc,%座標を使って図形を描くために必要
                   decorations.shapes}%スタンプを並べるために必要
\definecolor{lightyellowiii}{RGB}{205,205,180}

\pgfdeclaredecoration{spiral}{initial}%ここからがさっきのspiralスタンプの定義
{
 \state{initial}[width=\pgfdecoratedpathlength/floor(\pgfdecoratedpathlength/13pt)] 
  {
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%
      \draw[very thin,rotate=90,double=lightyellowiii,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);
  }
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }
}%ここまでがさっきのspiralスタンプの定義

\begin{document}

 \tikz{
         \draw[decorate,decoration={spiral}]  %spiralスタンプを使う宣言
          (0,0)--(0,-10);% (0,0)と(0,-10)を結ぶ直線状にスタンプを並べる
 }

\end{document}

コンパイル結果は、

f:id:nix_campane:20210110131234j:plain

手順3,デコレーション機能をtcolorboxのデザインで使う

tcolorboxでは、『左上』などの位置情報を方角で表現する。

  • 枠の左上の角…frame.north west
  • 枠内部の左上端…interior.north west

よって、枠の左上から左下にわたってspiralスタンプを並べる命令は次のようにかける。

\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);

(※いい感じにリングノートに見えるように、左端から少しずらしている)

ringnote環境のコード全文

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}%オプションは一例
\usepackage[dvipdfmx]{graphicx,color}%オプションは一例
\usepackage{xcolor}

\usepackage{tikz}
\usetikzlibrary{calc,%座標を使って図形を描くために必要
                   decorations.shapes}%スタンプを並べるために必要

\usepackage{xparse}%オプション(省略可能引数)をもつコマンド作成

\usepackage{tcolorbox}
\tcbuselibrary{listings,breakable,xparse,skins,hooks}
 %listings…私の環境ではbreakableを使う際に必要
 %breakable…ページまたぎ可能な枠を作成できる
 %xparse…オプションをもつ枠を作成できる
 %skins…TikZで枠のデザインを描き足せる
 %hooks…多種多様な機能が含まれるため、とりあえず読み込んでおくと安全
 %           たとえばunderlay unbrokenに必要
 
%リング色の定義
\definecolor{lightyellowiii}{RGB}{205,205,180}

%spiralスタンプの定義
\pgfdeclaredecoration{spiral}{initial}
{
 \state{initial}[width=\pgfdecoratedpathlength/floor(\pgfdecoratedpathlength/13pt)] 
  {
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%
      \draw[very thin,rotate=90,double=lightyellowiii,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);
  }
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }
}

%リングノート枠の定義(tcolorbox)
\DeclareTColorBox{ringnote} 
                                    { O{} O{white} O{} }%Oはオプション引数(省略可能)であることを表す。#1,#3は省略したら何もしない、#2は省略したらwhiteになる
{ enhanced,%必須
  colback=#2,%枠内の背景色を#2にする
  breakable,%ページまたぎ可能にする
  sharp corners,%枠の角を尖らせる
  left*=10mm,%枠の左辺から枠内のテキストまでの余白を調整
  boxrule=0.4pt,%枠の囲み線の太さを0.4ptにする
  %ここまでで枠を描く↑↑↑
  %ここから枠にリングを書き足す↓↓↓(underlay…枠の上にTikZで描画する)
  underlay unbroken={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたがないときの枠のデザイン
  underlay first={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたぐときの最初のページの枠のデザイン
  underlay middle={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたぐときの途中のページの枠のデザイン
  underlay last={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたぐときの最後のページの枠のデザイン
  %ここからはオプションの定義↓↓↓
  IfValueTF={#1}%#1があるかないかによって次のように処理が異なる
                {title=#1}%#1があるときは、#1をtitleとする(title枠が描かれる)
                {},%#1がないときは、title枠なし
  #3%#3があるときは、#3を枠のデザインとして追加する
}

ringnote環境の使い方

\begin{ringnote}[タイトル][テキスト背景色][さらなるtcolorboxオプション]
テキスト
\end{ringnote} 

使用例ギャラリー(ページをまたがない例)

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}%タイトル枠なし
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131300j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title]%タイトル枠あり
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131310j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title][green!7]%タイトル枠あり、枠内テキスト背景色green!7
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131330j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[][green!7]%タイトル枠なし、枠内テキスト背景色green!7
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131343j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title][green!7][colbacktitle=blue!5,%タイトル枠背景色blue!5
                                       colframe=white,%枠の色white
                                       coltitle=blue!50!black]%タイトルの文字色blue!50!black
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131352j:plain

\usepackage{lipsum}%ダミーテキスト
\definecolor{powderblue}{RGB}{230,230,255}%色パウダーブルーの定義
\usepackage{frcursive}%フランス語筆記体フォント(タイトルに使用)
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[\bfseries\textcursive{title}][powderblue!50!white][colframe=white,%枠の色white
                                                                    title style={fill,left color=red!20!white,right color=blue!20!white},%タイトル枠背景を左側red!20!white・右側blue!20!whiteのグラデーションに
                                                                    coltitle=cyan!50!white]%タイトルの文字色cyan!50!white
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131403j:plain

使用例ギャラリー(ページをまたぐ例)

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title]
\lipsum[1-9]
\end{ringnote}


f:id:nix_campane:20210110131426j:plain
f:id:nix_campane:20210110131430j:plain
f:id:nix_campane:20210110131422j:plain