KLWPで日曜始まりのカレンダーを作る

KLWPで日曜始まりの月間カレンダーを作る。
ZooperWidgetだとモジュールが増えすぎると動作が重くなりがちだけど、KLWPは100程度ならオブジェクトが増えても重くならないのがステキ。

作り方の基本としては、orefolder.netさんのKLWPでカレンダーその2:月間カレンダーを作ってみる(当日印つき)を参考に作るんだけど、個人的には日曜始まりのカレンダーの方が使いやすいので、少し改造します。
(上記リンクの説明は月曜始まりのカレンダー)

なお、自分の理解力が低すぎて書いてあることを噛み砕いて理解するまでに丸3日ほどかかったので、躓いたポイントをメモしていきます。

枠組みを作る

カレンダーを作る前の基本的な操作を知っておきます。オブジェクトをタイル状に並べてみます。
大きさを揃えた図形を作り、その上にテキストを重ねます。
そしてこれをタイル状に並べてみます。

コンポーネントで包む

今回はカレンダーを作るので、カレンダーのオブジェクトを全てコンポーネントという箱に入れてしまいます。
更にその中にグループ化(並べる)→グループ化(並べる)として、その中に図形を入れます。
図形にテキストを重ねるので、グループ化(重ねる)の中に図形とテキストを入れます。

入れ子のイメージ (2)
※3日が当日の場合、背景色を変更する

入れ子のイメージ (1)

階層順にするとこんな感じ。
(低い方から順に記述)

  1. ベース
    1. コンポーネント
      1. グループ化(並べる)
        1. グループ化(並べる)
          1. グループ化(重ねる)
            1. 図形(長方形)
            2. テキスト(1)
          2. グループ化(重ねる)
            1. 図形(長方形)
            2. テキスト(2)
          3. グループ化(重ねる)
            1. 図形(長方形)
            2. テキスト(3)
          4. グループ化(重ねる)
            1. 図形(長方形)
            2. テキスト(4)
          5. グループ化(重ねる)
            1. 図形(長方形)
            2. テキスト(5)
          6. グループ化(重ねる)
            1. 図形(長方形)
            2. テキスト(6)
          7. グループ化(重ねる)
            1. 図形(長方形)
            2. テキスト(7)
        2. グループ化(並べる)
          1. 2週目
        3. グループ化(並べる)
          1. 3週目

グループを横に並べるには、レイヤーの "並べ方" を変更します。
(縦方向)と(横方向)があり、括弧外にあるのは揃える位置です。左なら"aligin: left"、右なら"align: right;"です。
同様に上なら"vertical-align: top;"で、下なら"vertical-align: bottom;"という意味です。
イメージ画像を参考に、グループ化(並べる)を包んでいるグループ化(並べる)では縦方向に。
グループ化(重ねる)を包んでいるグループ化(並べる)では横方向を指定します。

カレンダーを作る

肩慣らしが終わったところで本題。
の前に、グローバル変数を設定しておきます。
グローバル変数はコンポーネント毎に設定できるので、コンポーネントを選択してからグローバル変数を作成していきます。
名前は適当に付けています。分かりやすいものに変えて下さい。
なお以下の本文中ではここで設定した変数名で記述しているので、変数名を変更した場合は適宜読みかえて下さい。

変数名 備考
fntclr1 #FFFFFFFF 平日の文字色(当月)
fntclr2 #FF4343CA 土曜の文字色(当月)
fntclr3 #FFCA4343 日曜の文字色(当月)
fntclr6 #95CCCCCC 平日の文字色(当月外)
fntclr7 #954343CA 土曜の文字色(当月外)
fntclr8 #95CA4343 日曜の文字色(当月外)
capt LogotypeJp Mp B 1.1 曜日用フォント。コーポレート・ロゴ (太字)
fntnum Verdana 日付用フォント
tdybg #2BD6D6D6 当日用の背景色
pmld 前月の最終日。欄外参照
rmld 当月の最終日。欄外参照
day 2週目最初の日。欄外参照

fntclr3の次がfntclr6になっているのは、いずれ祝祭日フラグを設定する時の予備番号として空けてあります。
pmldrmldはorefolder.netさんのものをそのまま使え(い)ます。
dayについては次で説明。

$gv(day)$ = 2週目最初の日

orefolder.netさんで紹介されているカレンダーは月曜始まりです。
今回は日曜始まりにするので、一部修正する必要があります。

元のコード

$if(df(f,1d)=7,2,df(f,1d)=6,3,df(f,1d)=5,4,df(f,1d)=4,5,df(f,1d)=3,6,df(f,1d)=2,7,8)$

説明にも書かれている通り、$df(f,1d)$は当月の1日の曜日です。
1から7までの数値で曜日を示しています。

  • 1 = Mon
  • 2 = Tue
  • 3 = Wed
  • 4 = Thu
  • 5 = Fri
  • 6 = Sat
  • 7 = Sun

コードをバラすとこんな内容になっています。
※月曜始まりのカレンダーの場合

  • $df(f,1d)=7,2$ = 当月1日の曜日が7[日曜]なら2を返す
  • $df(f,1d)=6,3$ = 当月1日の曜日が6[土曜]なら3を返す
  • $df(f,1d)=5,4$ = 当月1日の曜日が5[金曜]なら4を返す
  • $df(f,1d)=4,5$ = 当月1日の曜日が4[木曜]なら5を返す
  • $df(f,1d)=3,6$ = 当月1日の曜日が3[水曜]なら6を返す
  • $df(f,1d)=2,7$ = 当月1日の曜日が2[火曜]なら7を返す
  • 上記のどれでもないなら8を返す

先にも書いた通り、これは月曜スタートのカレンダーの内容です。
分かりやすいように$df(f,1d)=7,2$を視覚化してみます。
その月の1日の曜日が日曜なら、(2週目最初の日は)2という意味なので……。

Mo, Tu, We, Th, Fr, Sa, Su
                         1
 2,  3,  4,  5,  6,  7,  8

合ってますね。
これを日曜始まりにすると、こんな感じになります。

Su, Mo, Tu, We, Th, Fr, Sa
 1,  2,  3,  4,  5,  6,  7
 8,  9, 10, 11, 12, 13, 14

ズレました。
コードにすると$df(f,1d)=7,8$になります。
(当月1日の曜日が7[日曜]なら8を返す)
同様に、これを修正していくと……

Su, Mo, Tu, We, Th, Fr, Sa
                         1
 2,  3,  4,  5,  6,  7,  8

当月1日の曜日が6[土曜]なら2を返す = $if(df(f,1d)=6, 2)$


Su, Mo, Tu, We, Th, Fr, Sa
                     1,  2
 3,  4,  5,  6,  7,  8,  9

当月1日の曜日が5[金曜]なら3を返す = $if(df(f,1d)=5, 3)$


Su, Mo, Tu, We, Th, Fr, Sa
                 1,  2,  3
 4,  5,  6,  7,  8,  9, 10

当月1日の曜日が4[木曜]なら4を返す = $if(df(f,1d)=4, 4)$


Su, Mo, Tu, We, Th, Fr, Sa
             1,  2,  3,  4
 5,  6,  7,  8,  9, 10, 11

当月1日の曜日が3[水曜]なら5を返す = $if(df(f,1d)=3, 5)$


Su, Mo, Tu, We, Th, Fr, Sa
         1,  2,  3,  4,  5
 6,  7,  8,  9, 10, 11, 12

当月1日の曜日が2[火曜]なら6を返す = $if(df(f,1d)=2, 6)$


Su, Mo, Tu, We, Th, Fr, Sa
     1,  2,  3,  4,  5,  6
 7,  8,  9, 10, 11, 12, 13

当月1日の曜日が7から2[日・土・金・木・水・火]のどれでもないなら7を返す = $if(hogehoge)$の例外(false)設定


まとめると、以下のような並びになります。
※日曜始まりのカレンダーの場合

  • $df(f,1d)=7,8$ = 当月1日の曜日が7[日曜]なら8を返す
  • $df(f,1d)=6,2$ = 当月1日の曜日が6[土曜]なら2を返す
  • $df(f,1d)=5,3$ = 当月1日の曜日が5[金曜]なら3を返す
  • $df(f,1d)=4,4$ = 当月1日の曜日が4[木曜]なら4を返す
  • $df(f,1d)=3,5$ = 当月1日の曜日が3[水曜]なら5を返す
  • $df(f,1d)=2,6$ = 当月1日の曜日が2[火曜]なら6を返す
  • 上記のどれでもないなら7を返す
$if(
  df(f,1d)=7,8,
  df(f,1d)=6,2,
  df(f,1d)=5,3,
  df(f,1d)=4,4,
  df(f,1d)=3,5,
  df(f,1d)=2,6,
  7
)$

…となります。
コードは1行で記述しなければならないというルールはないので、複数行の方が分かりやすければこのままで問題ありません。

前月の最終週が表示される可能性がある週 …の補足

X = $gv(pmld)$

$gv(day)$ = 8

Su, Mo, Tu, We, Th, Fr, Sa
 1,  2,  3,  4,  5,  6,  7
 8,

$gv(day)$ = 7

Su, Mo, Tu, We, Th, Fr, Sa
 X,  1,  2,  3,  4,  5,  6
 7,

$gv(day)$ = 6

Su, Mo, Tu, We, Th, Fr, Sa
-1,  X,  1,  2,  3,  4,  5
 6,

$gv(day)$ = 5

Su, Mo, Tu, We, Th, Fr, Sa
-2, -1,  X,  1,  2,  3,  4
 5,

$gv(day)$ = 4

Su, Mo, Tu, We, Th, Fr, Sa
-3, -2, -1,  X,  1,  2,  3
 4,

$gv(day)$ = 3

Su, Mo, Tu, We, Th, Fr, Sa
-4, -3, -2, -1,  X,  1,  2
 3,

$gv(day)$ = 2

Su, Mo, Tu, We, Th, Fr, Sa
-5, -4, -3, -2, -1,  X,  1
 2,

これらを踏まえて、日曜から金曜枠までを埋めます。
上の法則を見れば分かるとおり、土曜枠に前月最終日が入ることはありません。

日曜枠

上述の通り、$gv(day)$が7なら日曜枠は$gv(pmld)$
6なら-1, 5なら-2…と続き、2なら-5になる。2~7のどれでもないもの。つまり8なら1が入るので以下のような式になります。

$if(
  gv(day)=7, gv(pmld),
  gv(day)=6, gv(pmld)-1,
  gv(day)=5, gv(pmld)-2,
  gv(day)=4, gv(pmld)-3,
  gv(day)=3, gv(pmld)-4,
  gv(day)=2, gv(pmld)-5, 1
)$
月曜枠
$(if
  gv(day)=7, 1,
  gv(day)=6, gv(pmld),
  gv(day)=5, gv(pmld)-1,
  gv(day)=4, gv(pmld)-2,
  gv(day)=3, gv(pmld)-3,
  gv(day)=2, gv(pmld)-4, 2
)$
火曜枠
$(if
  gv(day)=7, 2,
  gv(day)=6, 1,
  gv(day)=5, gv(pmld),
  gv(day)=4, gv(pmld)-1,
  gv(day)=3, gv(pmld)-2,
  gv(day)=2, gv(pmld)-3, 3
)$
水曜枠
$(if
  gv(day)=7, 3,
  gv(day)=6, 2,
  gv(day)=5, 1,
  gv(day)=4, gv(pmld),
  gv(day)=3, gv(pmld)-1,
  gv(day)=2, gv(pmld)-2, 4
)$
木曜枠
$(if
  gv(day)=7, 4,
  gv(day)=6, 3,
  gv(day)=5, 2,
  gv(day)=4, 1,
  gv(day)=3, gv(pmld),
  gv(day)=2, gv(pmld)-1, 5
)$
金曜枠
$(if
  gv(day)=7, 5,
  gv(day)=6, 4,
  gv(day)=5, 3,
  gv(day)=4, 2,
  gv(day)=3, 1,
  gv(day)=2, gv(pmld), 6
)$
土曜枠
$gv(day)-1$

文字色の指定

前月の最終週が入り込む場合があるので、当月外の文字色のグローバル関数と使い分けます。
具体的には上記のコードを流用して…

日曜枠の文字色
$if(
  gv(day)=7, gv(fntclr8),
  gv(day)=6, gv(fntclr8),
  gv(day)=5, gv(fntclr8),
  gv(day)=4, gv(fntclr8),
  gv(day)=3, gv(fntclr8),
  gv(day)=2, gv(fntclr8),
  gv(fntclr3)
)$

…でもいいのだけれど、もっと単純化できるので短縮してしまった方が良いでしょう。

$if(
  gv(day)<8, gv(fntclr8),
  gv(fntclr3)
)$

$gv(day)$の値が8未満なら当月外の文字色。そうではないなら当月の文字色。と簡略化できます。

以下、同様に。

月曜枠の文字色
$if(
  gv(day)<7, gv(fntclr6),
  gv(fntclr1)
)$
火曜枠の文字色
$if(
  gv(day)<6, gv(fntclr6),
  gv(fntclr1)
)$
水曜枠の文字色
$if(
  gv(day)<5, gv(fntclr6),
  gv(fntclr1)
)$
木曜枠の文字色
$if(
  gv(day)<4, gv(fntclr6),
  gv(fntclr1)
)$
金曜枠の文字色
$if(
  gv(day)<3, gv(fntclr6),
  gv(fntclr1)
)$
土曜枠の文字色
$gv(fntclr2)$

gv(day)<2…つまり1[土曜]に前月最終日が入ることはないので、当月の土曜の文字色が確定で入ります。

2週目~4週目

orefolder.netさんの説明の通り、$gv(day)+1$という書き方で進めます。
一番カレンダーが長くなるケースと、一番カレンダーが短くなるケースの2パターンを見比べれば分かりますが……。

カレンダーが一番長くなるケース
(31日まである月で、1日が土曜の場合)

    Su, Mo, Tu, We, Th, Fr, Sa
1.                           1
2.   2,  3,  4,  5,  6,  7,  8
3.   9, 10, 11, 12, 13, 14, 15
4.  16, 17, 18, 19, 20, 21, 22
5.  23, 24, 25, 26, 27, 28, 29
6.  30, 31

カレンダーが一番コンパクトに収まるケース
(日曜が1日で、閏年の2月の場合)

    Su, Mo, Tu, We, Th, Fr, Sa
1.   1,  2,  3,  4,  5,  6,  7
2.   8,  9, 10, 11, 12, 13, 14
3.  15, 16, 17, 18, 19, 20, 21
4.  22, 23, 24, 25, 26, 27, 28
5.
6.

このように4週目に次月の1日が来るケースはありえないのです。
ちなみに月曜始まりの場合でも……。

    Mo, Tu, We, Th, Fr, Sa, Su
1.   1,  2,  3,  4,  5,  6,  7
2.   8,  9, 10, 11, 12, 13, 14
3.  15, 16, 17, 18, 19, 20, 21
4.  22, 23, 24, 25, 26, 27, 28
5.
6.

起こり得ないので安心してください。

来月の最初週が表示される可能性がある週 の補足

orefolder.netさんの説明どおり、修正なしでそのまま使えます。

今月の数字が表示されるのは最大(1日が日曜で31日までの月)でも6週の火曜日までです。なので6週水曜以降の枠は先ほどの条件式が正の場合しかありませんので、式自体も$gv(day)+30-gv(rmld)$といった部分だけで大丈夫です。

引用元: KLWPでカレンダーその2:月間カレンダーを作ってみる(当日印つき) | orefolder.net

の部分の補足説明をします。
先にも挙げた "カレンダーが一番長くなるケース" を見てみると…

    Su, Mo, Tu, We, Th, Fr, Sa
1.                           1
2.   2,  3,  4,  5,  6,  7,  8
3.   9, 10, 11, 12, 13, 14, 15
4.  16, 17, 18, 19, 20, 21, 22
5.  23, 24, 25, 26, 27, 28, 29
6.  30, 31

…となっています。
6行目の火曜日以降は確実に次月最初週が入るため、$gv(day)+30-gv(rmld)$だけで良い。ということです。
逆に5行目の日曜から、6行目の月曜までには次月1週目と2週目が入る可能性があるため、条件分岐のコード$if()$が必要です。