OSDN Git Service

184fa656d248178133cd2455a62bb1cc9035fb43
[strokestylet/CsWin10Desktop3.git] / StrokeStyleT / ステージ / 選曲 / 曲パネルビュー.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Linq;
5 using FDK.メディア;
6
7 namespace SST.ステージ.選曲
8 {
9         /// <summary>
10         /// 曲パネルリスト(9列3行)を表示する。
11         /// </summary>
12         /// <remarks>
13         /// 静止時の可視範囲は、左右両端の1列を除いた7列3行。
14         /// 左右両端の列は、静止時は画面外に位置しており、左右スクロール中にのみ画面内に一部が表示される。
15         /// 「カーソル」は、常に、曲パネル内のいずれか1枚の曲を選択している。
16         /// カーソルは、初期状態では中央の曲を選択しており、本クラスのメソッドを使って上下左右に移動することができる。
17         /// カーソルが選択している曲は強調表示(視覚効果として少し拡大して表示)される。
18         /// </remarks>
19         class 曲パネルビュー : FDK.Activity
20         {
21                 public 曲パネルビュー()
22                 {
23                         this.子リスト.Add( this.Nullパネルの画像 = new テクスチャ( @"$(Static)\images\選曲パネル.png" ) );
24                 }
25                 public void カーソルを上に移動する()
26                 {
27                         if( 0 < this.カーソル位置.Y )
28                         {
29                                 this.カーソル位置.Y--;
30                         }
31                         else
32                         {
33                                 this.カーソル位置.X--;
34                                 this.カーソル位置.Y = 2;
35                         }
36
37                         // カーソルと一緒に、選択曲も移動する。
38                         StrokeStyleT.曲ツリー管理.前のノードを選択する();
39                 }
40                 public void カーソルを下に移動する()
41                 {
42                         if( 2 > this.カーソル位置.Y )
43                         {
44                                 this.カーソル位置.Y++;
45                         }
46                         else
47                         {
48                                 this.カーソル位置.X++;
49                                 this.カーソル位置.Y = 0;
50                         }
51
52                         // カーソルと一緒に、選択曲も移動する。
53                         StrokeStyleT.曲ツリー管理.次のノードを選択する();
54                 }
55                 public void カーソルを左に移動する()
56                 {
57                         this.カーソル位置.X--;    // 制限なし
58
59                         // カーソルと一緒に、選択曲も移動する。
60                         StrokeStyleT.曲ツリー管理.前のノードを選択する();
61                         StrokeStyleT.曲ツリー管理.前のノードを選択する();
62                         StrokeStyleT.曲ツリー管理.前のノードを選択する();
63                 }
64                 public void カーソルを右に移動する()
65                 {
66                         this.カーソル位置.X++;    // 制限なし
67
68                         // カーソルと一緒に、選択曲も移動する。
69                         StrokeStyleT.曲ツリー管理.次のノードを選択する();
70                         StrokeStyleT.曲ツリー管理.次のノードを選択する();
71                         StrokeStyleT.曲ツリー管理.次のノードを選択する();
72                 }
73                 protected override void On活性化( デバイスリソース dr )
74                 {
75                         this.活性化した直後である = true;
76                 }
77                 protected override void On非活性化( デバイスリソース dr )
78                 {
79                 }
80                 public void 進行描画する( デバイスリソース dr )
81                 {
82                         // 進行。
83
84                         if( this.活性化した直後である )
85                         {
86                                 this.活性化した直後である = false;
87                                 this.横スクロール用カウンタ = new FDK.カウンタ.定間隔進行();
88                         }
89                         else
90                         {
91                                 #region " カーソルの移動に伴う全パネルの横方向スクロール進行。"
92                                 //----------------
93                                 this.横スクロール用カウンタ.経過時間の分だけ進行する( 8, () => {
94
95                                         int オフセットの加減算速度 = 1;
96
97                                         #region " カーソルが中央から遠いほど速くなるよう、オフセットの加減算速度(絶対値)を計算する。"
98                                         //------------------
99                                         int 距離 = Math.Abs( 4 - this.カーソル位置.X );
100                                         if( 1 >= 距離 )
101                                                 オフセットの加減算速度 = 2;
102                                         else if( 4 >= 距離 )
103                                                 オフセットの加減算速度 = 4;
104                                         else if( 6 >= 距離 )
105                                                 オフセットの加減算速度 = 6;
106                                         else
107                                                 オフセットの加減算速度 = 8;
108                                         //------------------
109                                         #endregion
110
111                                         // オフセット と カーソル位置.X を更新する。
112                                         if( ( 4 > this.カーソル位置.X ) ||
113                                                 ( ( 4 == this.カーソル位置.X ) && ( 0 > this.パネル全体のY軸回転オフセット ) ) )
114                                         {
115                                                 #region " (A) パネルは、左から右へ、移動する。"
116                                                 //-----------------
117                                                 this.パネル全体のY軸回転オフセット += オフセットの加減算速度;
118
119                                                 // 1列分移動した
120                                                 if( 64 <= this.パネル全体のY軸回転オフセット )
121                                                 {
122                                                         this.パネル全体のY軸回転オフセット -= 64;  // 0 付近に戻る
123                                                         this.カーソル位置.X++;
124                                                 }
125                                                 //-----------------
126                                                 #endregion
127                                         }
128                                         else if( ( 4 < this.カーソル位置.X ) ||
129                                                 ( ( 4 == this.カーソル位置.X ) && ( 0 < this.パネル全体のY軸回転オフセット ) ) )
130                                         {
131                                                 #region " (B) パネルは、右から左へ、移動する。"
132                                                 //-----------------
133                                                 this.パネル全体のY軸回転オフセット -= オフセットの加減算速度;
134
135                                                 // 1列分移動した
136                                                 if( -64 >= this.パネル全体のY軸回転オフセット )
137                                                 {
138                                                         this.パネル全体のY軸回転オフセット += 64;  // 0 付近に戻る
139                                                         this.カーソル位置.X--;
140                                                 }
141                                                 //-----------------
142                                                 #endregion
143                                         }
144
145                                 } );
146                                 //----------------
147                                 #endregion
148                         }
149
150                         // 描画。
151
152                         Debug.Assert( null != StrokeStyleT.ユーザ管理?.現在選択されているユーザ?.曲ツリーのルートノード );
153
154                         var 曲リスト管理 = StrokeStyleT.曲ツリー管理;
155                         var 曲リスト = 曲リスト管理.現在選択されているノード?.親ノード.子ノードリスト ?? 曲リスト管理.現在の管理対象ツリー.子ノードリスト;
156                         var 描画する曲 = 曲リスト管理.現在選択されているノード;    // null 可
157                         var カーソル位置の曲 = (曲.Node) null;   // null 可
158
159                         #region " 左上隅パネルに対応する曲リストノードを検索する。"
160                         //-----------------
161                         int 現在のカーソルから左上隅までの差 = 0 - ( this.カーソル位置.X * 3 + this.カーソル位置.Y );   // 現在のカーソルの位置に、現在選択されている曲が対応するものとする。
162
163                         if( 0 < 現在のカーソルから左上隅までの差 )
164                         {
165                                 // 曲リストを前方へたどる。
166                                 for( int i = 0; i < 現在のカーソルから左上隅までの差; i++ )
167                                         描画する曲 = 描画する曲?.次のノード;
168                         }
169                         else
170                         {
171                                 // 曲リストを後方へたどる。
172                                 for( int i = 現在のカーソルから左上隅までの差; i < 0; i++ )
173                                         描画する曲 = 描画する曲?.前のノード;
174                         }
175                         //-----------------
176                         #endregion
177                         #region " 9×3枚の曲パネルを描画する。"
178                         //-----------------
179                         for( int i = 0; i < ( 9 * 3 ); i++ )
180                         {
181                                 var パネル位置 = new SharpDX.Point( i / 3, i % 3 );
182
183                                 if( パネル位置 == this.カーソル位置 )
184                                 {
185                                         // カーソル位置にあるパネルは後で描画するので、覚えておく。
186                                         カーソル位置の曲 = 描画する曲;
187                                 }
188                                 else
189                                 {
190                                         this.パネルを一枚描画する( dr, 描画する曲, パネル位置, これはカーソル位置のパネルである: false );
191                                 }
192
193                                 // 次のノードへ移動。(選択ノードは移動しない。)
194                                 描画する曲 = 描画する曲?.次のノード;
195                         }
196                         //-----------------
197                         #endregion
198                         #region " カーソル位置のパネルを描画する。"
199                         //-----------------
200                         if( ( 0 <= this.カーソル位置.X ) && ( 9 > this.カーソル位置.X ) &&
201                                 ( 0 <= this.カーソル位置.Y ) && ( 3 > this.カーソル位置.Y ) )
202                         {
203                                 this.パネルを一枚描画する(
204                                         dr,
205                                         カーソル位置の曲,   // 先の for ループ内で取得済み。
206                                         this.カーソル位置,
207                                         これはカーソル位置のパネルである: true );
208                         }
209                         //-----------------
210                         #endregion
211                 }
212
213                 protected const float カーソル位置のパネルの拡大率 = 1.25f;
214                 protected bool 活性化した直後である = false;
215                 protected readonly FDK.メディア.テクスチャ Nullパネルの画像;
216                 protected FDK.カウンタ.定間隔進行 横スクロール用カウンタ = null;
217                 /// <summary>
218                 /// 左上隅のパネルを (0,0) とした時の、カーソル位置の座標。
219                 /// 負数も可。
220                 /// </summary>
221                 protected SharpDX.Point カーソル位置 = new SharpDX.Point( 4, 1 );
222                 /// <summary>
223                 /// -63~63。パネル全体の表示位置を、負数は 左 へ、正数は 右 へずらす 。(正負と左右の対応に注意。)
224                 /// </summary>
225                 /// <remarks>
226                 /// ±64 は、パネル1列分を表すサイズ。
227                 /// </remarks>
228                 protected int パネル全体のY軸回転オフセット = 0;
229
230                 /// <summary>
231                 /// パネルを一枚(ノード画像とタイトル画像)を、指定したパネル位置に描画する。
232                 /// </summary>
233                 /// <param name="パネルノード">null 可。</param>
234                 protected void パネルを一枚描画する( デバイスリソース dr, 曲.Node パネルノード, SharpDX.Point パネル位置, bool これはカーソル位置のパネルである = false )
235                 {
236                         // 画面を見ながら直観的に調整した固定パラメータたち。
237                         const float 見かけの倍率 = 3.0f;
238                         const float パネル全体のY方向移動量dpx = +250f;    // パネル全体を少しだけ上にシフトする。
239                         const float パネル全体のZ方向移動量dpx = +3000f;
240                         const float 行間 = 1.1f;
241                         const float パネル間X方向角度deg = 19f;
242
243                         // Nullパネル画像を表示する。
244                         {
245                                 var 拡大縮小 = SharpDX.Matrix.Scaling( パネルノード.ノードの全体サイズdpx.Width, パネルノード.ノードの全体サイズdpx.Height, 1f )
246                                         * SharpDX.Matrix.Scaling( 見かけの倍率 );
247
248                                 var 平行移動 = SharpDX.Matrix.Translation(
249                                         0f,
250                                         パネル全体のY方向移動量dpx + ( 1 - パネル位置.Y ) * ( パネルノード.ノードの全体サイズdpx.Height * 見かけの倍率 * 行間 ),
251                                         パネル全体のZ方向移動量dpx );
252
253                                 var Y軸回転 = SharpDX.Matrix.RotationY( SharpDX.MathUtil.DegreesToRadians( ( パネル位置.X - 4 ) * パネル間X方向角度deg ) );
254
255                                 this.Nullパネルの画像.進行描画する( dr, ( 拡大縮小 * 平行移動 * Y軸回転 ) );
256                         }
257                         if( null != パネルノード )
258                         {
259                                 // ノード画像を表示する。
260                                 {
261                                         var 拡大縮小 = SharpDX.Matrix.Scaling( パネルノード.ノードの画像領域のサイズdpx.Width, パネルノード.ノードの画像領域のサイズdpx.Height, 1f )
262                                                         * SharpDX.Matrix.Scaling( 見かけの倍率 );
263
264                                         var 平行移動 = SharpDX.Matrix.Translation(
265                                                 0f,
266                                                 パネル全体のY方向移動量dpx
267                                                         + ( 1 - パネル位置.Y ) * ( パネルノード.ノードの全体サイズdpx.Height * 見かけの倍率 * 行間 )
268                                                         + ( パネルノード.ノードのタイトル領域のサイズdpx.Height / 2f ) * 見かけの倍率,
269                                                 パネル全体のZ方向移動量dpx + 1f );
270
271                                         var Y軸回転 = SharpDX.Matrix.RotationY( SharpDX.MathUtil.DegreesToRadians( ( パネル位置.X - 4 ) * パネル間X方向角度deg ) );
272
273                                         パネルノード.ノード画像を描画する( dr, ( 拡大縮小 * 平行移動 * Y軸回転 ) );
274                                 }
275
276                                 // タイトル文字列画像を表示する。
277                                 {
278                                         float 幅dpx = Math.Min( パネルノード.タイトル画像サイズdpx.Width, パネルノード.ノードのタイトル領域のサイズdpx.Width );     // 左右にはみ出さないよう圧縮
279                                         var 拡大縮小 = SharpDX.Matrix.Scaling( 幅dpx, パネルノード.タイトル画像サイズdpx.Height, 1f )
280                                                 * SharpDX.Matrix.Scaling( 見かけの倍率 );
281
282                                         var 平行移動 = SharpDX.Matrix.Translation(
283                                                 0f,
284                                                 パネル全体のY方向移動量dpx
285                                                         + ( 1 - パネル位置.Y ) * ( パネルノード.ノードの全体サイズdpx.Height * 見かけの倍率 * 行間 )
286                                                         - ( パネルノード.ノードの画像領域のサイズdpx.Height / 2f ) * 見かけの倍率,
287                                                 パネル全体のZ方向移動量dpx + 2f );
288
289                                         var Y軸回転 = SharpDX.Matrix.RotationY( SharpDX.MathUtil.DegreesToRadians( ( パネル位置.X - 4 ) * パネル間X方向角度deg ) );
290
291                                         パネルノード.タイトル画像を描画する( dr, ( 拡大縮小 * 平行移動 * Y軸回転 ) );
292                                 }
293                         }
294                 }
295         }
296 }