@@ -24,7 +24,13 @@ const |
| 24 |
NumRows = 64; |
24 |
NumRows = 64; |
| 25 |
|
25 |
|
| 26 |
type |
26 |
type |
| 27 |
TCellPart = (cpNote = 0, cpInstrument = 1, cpVolume = 2, cpEffect = 3); |
27 |
TCellPart = ( |
|
|
28 |
cpNote = 0, |
|
|
29 |
cpInstrument = 1, |
|
|
30 |
cpVolume = 2, |
|
|
31 |
cpEffectCode = 3, |
|
|
32 |
cpEffectParams = 4 |
|
|
33 |
); |
| 28 |
|
34 |
|
| 29 |
TSelectionPos = record |
35 |
TSelectionPos = record |
| 30 |
X, Y: Integer; |
36 |
X, Y: Integer; |
@@ -50,6 +56,12 @@ type |
| 50 |
procedure RenderSelectedArea; |
56 |
procedure RenderSelectedArea; |
| 51 |
procedure ClampCursors; |
57 |
procedure ClampCursors; |
| 52 |
|
58 |
|
|
|
59 |
procedure InputNote(Key: Word); |
|
|
60 |
procedure InputInstrument(Key: Word); |
|
|
61 |
procedure InputVolume(Key: Word); |
|
|
62 |
procedure InputEffectCode(Key: Word); |
|
|
63 |
procedure InputEffectParams(Key: Word); |
|
|
64 |
|
| 53 |
private |
65 |
private |
| 54 |
Cells: array[0..3, 0..63] of TCell; |
66 |
Cells: array[0..3, 0..63] of TCell; |
| 55 |
|
67 |
|
@@ -61,6 +73,8 @@ type |
| 61 |
MouseButtonDown: Boolean; |
73 |
MouseButtonDown: Boolean; |
| 62 |
Selecting: Boolean; |
74 |
Selecting: Boolean; |
| 63 |
|
75 |
|
|
|
76 |
DigitInputting: Boolean; |
|
|
77 |
|
| 64 |
procedure RenderRow(Row: Integer); |
78 |
procedure RenderRow(Row: Integer); |
| 65 |
procedure RenderCell(Cell: TCell); |
79 |
procedure RenderCell(Cell: TCell); |
| 66 |
|
80 |
|
@@ -68,7 +82,8 @@ type |
| 68 |
function SelectionsToRect(S1, S2: TSelectionPos): TRect; |
82 |
function SelectionsToRect(S1, S2: TSelectionPos): TRect; |
| 69 |
function SelectionToRect(Selection: TSelectionPos): TRect; |
83 |
function SelectionToRect(Selection: TSelectionPos): TRect; |
| 70 |
function MousePosToSelection(X, Y: Integer): TSelectionPos; |
84 |
function MousePosToSelection(X, Y: Integer): TSelectionPos; |
| 71 |
|
85 |
function KeycodeToHexNumber(Key: Word; out Num: Byte): Boolean; overload; |
|
|
86 |
function KeycodeToHexNumber(Key: Word; out Num: Integer): Boolean; overload; |
| 72 |
public |
87 |
public |
| 73 |
Cursor, Other: TSelectionPos; |
88 |
Cursor, Other: TSelectionPos; |
| 74 |
end; |
89 |
end; |
@@ -135,6 +150,7 @@ begin |
| 135 |
end; |
150 |
end; |
| 136 |
end; |
151 |
end; |
| 137 |
|
152 |
|
|
|
153 |
// Draw borders between columns |
| 138 |
Canvas.Pen.Color := TColor($ABB7BC); |
154 |
Canvas.Pen.Color := TColor($ABB7BC); |
| 139 |
Canvas.Pen.Width := 2; |
155 |
Canvas.Pen.Width := 2; |
| 140 |
R := TRect.Create(0, 0, ColumnWidth+1, Height); |
156 |
R := TRect.Create(0, 0, ColumnWidth+1, Height); |
@@ -156,16 +172,17 @@ procedure TTrackerGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, |
| 156 |
begin |
172 |
begin |
| 157 |
inherited MouseDown(Button, Shift, X, Y); |
173 |
inherited MouseDown(Button, Shift, X, Y); |
| 158 |
|
174 |
|
| 159 |
MouseButtonDown := True; |
175 |
if Button = mbLeft then |
|
|
176 |
MouseButtonDown := True; |
| 160 |
Selecting := False; |
177 |
Selecting := False; |
|
|
178 |
DigitInputting := False; |
| 161 |
|
179 |
|
| 162 |
if not (csDesigning in ComponentState) and CanFocus then |
180 |
if not (csDesigning in ComponentState) and CanFocus then |
| 163 |
SetFocus; |
181 |
SetFocus; |
| 164 |
|
182 |
|
| 165 |
Cursor := MousePosToSelection(X, Y); |
183 |
Cursor := MousePosToSelection(X, Y); |
| 166 |
|
|
|
| 167 |
ClampCursors; |
|
|
| 168 |
Other := Cursor; |
184 |
Other := Cursor; |
|
|
185 |
ClampCursors; |
| 169 |
|
186 |
|
| 170 |
Invalidate; |
187 |
Invalidate; |
| 171 |
end; |
188 |
end; |
@@ -190,22 +207,29 @@ begin |
| 190 |
inherited MouseUp(Button, Shift, X, Y); |
207 |
inherited MouseUp(Button, Shift, X, Y); |
| 191 |
|
208 |
|
| 192 |
MouseButtonDown := False; |
209 |
MouseButtonDown := False; |
|
|
210 |
DigitInputting := False; |
| 193 |
end; |
211 |
end; |
| 194 |
|
212 |
|
| 195 |
procedure TTrackerGrid.KeyDown(var Key: Word; Shift: TShiftState); |
213 |
procedure TTrackerGrid.KeyDown(var Key: Word; Shift: TShiftState); |
| 196 |
begin |
214 |
begin |
| 197 |
inherited KeyDown(Key, Shift); |
215 |
inherited KeyDown(Key, Shift); |
| 198 |
|
216 |
|
| 199 |
Writeln(Cursor.SelectedPart, ' ', High(TCellPart), ' ', Low(TCellPart)); |
|
|
| 200 |
case Key of |
217 |
case Key of |
| 201 |
VK_UP: Cursor.Y -= 1; |
218 |
VK_UP: begin |
| 202 |
VK_DOWN: Cursor.Y += 1; |
219 |
Cursor.Y -= 1; |
|
|
220 |
DigitInputting := False; |
|
|
221 |
end; |
|
|
222 |
VK_DOWN: begin |
|
|
223 |
Cursor.Y += 1; |
|
|
224 |
DigitInputting := False; |
|
|
225 |
end; |
| 203 |
VK_LEFT: begin |
226 |
VK_LEFT: begin |
| 204 |
if ssCtrl in Shift then |
227 |
if ssCtrl in Shift then |
| 205 |
Cursor.X -= 1 |
228 |
Cursor.X -= 1 |
| 206 |
else if Cursor.SelectedPart > Low(TCellPart) then begin |
229 |
else if Cursor.SelectedPart > Low(TCellPart) then begin |
| 207 |
Cursor.SelectedPart := Pred(Cursor.SelectedPart); |
230 |
Cursor.SelectedPart := Pred(Cursor.SelectedPart); |
| 208 |
end; |
231 |
end; |
|
|
232 |
DigitInputting := False; |
| 209 |
end; |
233 |
end; |
| 210 |
VK_RIGHT: begin |
234 |
VK_RIGHT: begin |
| 211 |
if ssCtrl in Shift then |
235 |
if ssCtrl in Shift then |
@@ -213,13 +237,15 @@ begin |
| 213 |
else if Cursor.SelectedPart < High(TCellPart) then begin |
237 |
else if Cursor.SelectedPart < High(TCellPart) then begin |
| 214 |
Cursor.SelectedPart := Succ(Cursor.SelectedPart); |
238 |
Cursor.SelectedPart := Succ(Cursor.SelectedPart); |
| 215 |
end; |
239 |
end; |
|
|
240 |
DigitInputting := False; |
| 216 |
end; |
241 |
end; |
| 217 |
else begin |
242 |
else begin |
| 218 |
with Cells[Cursor.X, Cursor.Y] do begin |
243 |
case Cursor.SelectedPart of |
| 219 |
Instrument := Random(20); |
244 |
cpNote: InputNote(Key); |
| 220 |
EffectCode := Random($F); |
245 |
cpInstrument: InputInstrument(Key); |
| 221 |
EffectParams := Random($FF); |
246 |
cpVolume: InputVolume(Key); |
| 222 |
Note := NoteMap.Keys[Random(NoteMap.Count)]; |
247 |
cpEffectCode: InputEffectCode(Key); |
|
|
248 |
cpEffectParams: InputEffectParams(Key); |
| 223 |
end; |
249 |
end; |
| 224 |
end; |
250 |
end; |
| 225 |
end; |
251 |
end; |
@@ -251,7 +277,7 @@ var |
| 251 |
begin |
277 |
begin |
| 252 |
R := SelectionsToRect(Cursor, Other); |
278 |
R := SelectionsToRect(Cursor, Other); |
| 253 |
|
279 |
|
| 254 |
with Cursor do begin; |
280 |
with Cursor do |
| 255 |
BitBlt( |
281 |
BitBlt( |
| 256 |
Canvas.Handle, |
282 |
Canvas.Handle, |
| 257 |
R.Left, |
283 |
R.Left, |
@@ -262,7 +288,6 @@ begin |
| 262 |
R.Left, |
288 |
R.Left, |
| 263 |
R.Top, |
289 |
R.Top, |
| 264 |
DSTINVERT); |
290 |
DSTINVERT); |
| 265 |
end; |
|
|
| 266 |
end; |
291 |
end; |
| 267 |
|
292 |
|
| 268 |
procedure TTrackerGrid.ClampCursors; |
293 |
procedure TTrackerGrid.ClampCursors; |
@@ -273,6 +298,65 @@ begin |
| 273 |
Other.X := Min(3, Max(0, Other.X)); |
298 |
Other.X := Min(3, Max(0, Other.X)); |
| 274 |
end; |
299 |
end; |
| 275 |
|
300 |
|
|
|
301 |
procedure TTrackerGrid.InputNote(Key: Word); |
|
|
302 |
var |
|
|
303 |
Temp: Integer; |
|
|
304 |
begin |
|
|
305 |
with Cells[Cursor.X, Cursor.Y] do |
|
|
306 |
if Key = VK_DELETE then |
|
|
307 |
Note := NO_NOTE |
|
|
308 |
else begin |
|
|
309 |
Keybindings.TryGetData(Key, Temp); |
|
|
310 |
if Temp <> 0 then Note := Temp; |
|
|
311 |
end; |
|
|
312 |
end; |
|
|
313 |
|
|
|
314 |
procedure TTrackerGrid.InputInstrument(Key: Word); |
|
|
315 |
var |
|
|
316 |
Temp: Byte; |
|
|
317 |
begin |
|
|
318 |
with Cells[Cursor.X, Cursor.Y] do |
|
|
319 |
if Key = VK_DELETE then Instrument := 0 |
|
|
320 |
else if KeycodeToHexNumber(Key, Temp) and (Temp < 9) then |
|
|
321 |
Instrument := ((Instrument mod 10) * 10) + Temp; |
|
|
322 |
end; |
|
|
323 |
|
|
|
324 |
procedure TTrackerGrid.InputVolume(Key: Word); |
|
|
325 |
begin |
|
|
326 |
|
|
|
327 |
end; |
|
|
328 |
|
|
|
329 |
procedure TTrackerGrid.InputEffectCode(Key: Word); |
|
|
330 |
begin |
|
|
331 |
with Cells[Cursor.X, Cursor.Y] do |
|
|
332 |
if Key = VK_DELETE then begin |
|
|
333 |
EffectCode := 0; |
|
|
334 |
EffectParams.Value := 0; |
|
|
335 |
end |
|
|
336 |
else KeycodeToHexNumber(Key, EffectCode); |
|
|
337 |
end; |
|
|
338 |
|
|
|
339 |
procedure TTrackerGrid.InputEffectParams(Key: Word); |
|
|
340 |
var |
|
|
341 |
Temp: Byte; |
|
|
342 |
begin |
|
|
343 |
with Cells[Cursor.X, Cursor.Y] do |
|
|
344 |
if Key = VK_DELETE then begin |
|
|
345 |
EffectCode := 0; |
|
|
346 |
EffectParams.Value := 0; |
|
|
347 |
end |
|
|
348 |
else if not DigitInputting then begin |
|
|
349 |
if KeycodeToHexNumber(Key, Temp) then begin |
|
|
350 |
EffectParams.Param2 := EffectParams.Param1; |
|
|
351 |
EffectParams.Param1 := Temp; |
|
|
352 |
DigitInputting := True; |
|
|
353 |
end; |
|
|
354 |
end |
|
|
355 |
else |
|
|
356 |
if KeycodeToHexNumber(Key, EffectParams.Param2) then |
|
|
357 |
DigitInputting := False; |
|
|
358 |
end; |
|
|
359 |
|
| 276 |
procedure TTrackerGrid.RenderRow(Row: Integer); |
360 |
procedure TTrackerGrid.RenderRow(Row: Integer); |
| 277 |
var |
361 |
var |
| 278 |
I: Integer; |
362 |
I: Integer; |
@@ -315,12 +399,14 @@ begin |
| 315 |
Font.Color := clGray; |
399 |
Font.Color := clGray; |
| 316 |
TextOut(PenPos.X, PenPos.Y, '...'); |
400 |
TextOut(PenPos.X, PenPos.Y, '...'); |
| 317 |
|
401 |
|
| 318 |
if (Cell.EffectCode <> 0) or (Cell.EffectParams <> 0) then begin |
402 |
if (Cell.EffectCode <> 0) or (Cell.EffectParams.Value <> 0) then begin |
| 319 |
Font.Color := GetEffectColor(Cell.EffectCode); |
403 |
Font.Color := GetEffectColor(Cell.EffectCode); |
| 320 |
TextOut( |
404 |
TextOut( |
| 321 |
PenPos.X, |
405 |
PenPos.X, |
| 322 |
PenPos.Y, |
406 |
PenPos.Y, |
| 323 |
IntToHex(Cell.EffectCode, 1) + IntToHex(Cell.EffectParams, 2) |
407 |
IntToHex(Cell.EffectCode, 1) |
|
|
408 |
+ IntToHex(Cell.EffectParams.Param1, 1) |
|
|
409 |
+ IntToHex(Cell.EffectParams.Param2, 1) |
| 324 |
); |
410 |
); |
| 325 |
end |
411 |
end |
| 326 |
else begin |
412 |
else begin |
@@ -378,8 +464,12 @@ begin |
| 378 |
CharLeft := 6; |
464 |
CharLeft := 6; |
| 379 |
CharRight := 9; |
465 |
CharRight := 9; |
| 380 |
end; |
466 |
end; |
| 381 |
cpEffect: begin |
467 |
cpEffectCode: begin |
| 382 |
CharLeft := 9; |
468 |
CharLeft := 9; |
|
|
469 |
CharRight := 10; |
|
|
470 |
end; |
|
|
471 |
cpEffectParams: begin |
|
|
472 |
CharLeft := 10; |
| 383 |
CharRight := 12; |
473 |
CharRight := 12; |
| 384 |
end; |
474 |
end; |
| 385 |
end; |
475 |
end; |
@@ -399,11 +489,45 @@ begin |
| 399 |
X := Trunc((X/ColumnWidth)*13); |
489 |
X := Trunc((X/ColumnWidth)*13); |
| 400 |
case X of |
490 |
case X of |
| 401 |
0..3: Result.SelectedPart := cpNote; |
491 |
0..3: Result.SelectedPart := cpNote; |
| 402 |
4..6: Result.SelectedPart := cpInstrument; |
492 |
4..5: Result.SelectedPart := cpInstrument; |
| 403 |
7..9: Result.SelectedPart := cpVolume; |
493 |
6..8: Result.SelectedPart := cpVolume; |
| 404 |
10..12: Result.SelectedPart := cpEffect; |
494 |
9: Result.SelectedPart := cpEffectCode; |
|
|
495 |
10..12: Result.SelectedPart := cpEffectParams; |
| 405 |
end; |
496 |
end; |
| 406 |
end; |
497 |
end; |
| 407 |
|
498 |
|
|
|
499 |
function TTrackerGrid.KeycodeToHexNumber(Key: Word; out Num: Byte): Boolean; |
|
|
500 |
begin |
|
|
501 |
Result := True; |
|
|
502 |
|
|
|
503 |
case Key of |
|
|
504 |
VK_0: Num := $0; |
|
|
505 |
VK_1: Num := $1; |
|
|
506 |
VK_2: Num := $2; |
|
|
507 |
VK_3: Num := $3; |
|
|
508 |
VK_4: Num := $4; |
|
|
509 |
VK_5: Num := $5; |
|
|
510 |
VK_6: Num := $6; |
|
|
511 |
VK_7: Num := $7; |
|
|
512 |
VK_8: Num := $8; |
|
|
513 |
VK_9: Num := $9; |
|
|
514 |
VK_A: Num := $A; |
|
|
515 |
VK_B: Num := $B; |
|
|
516 |
VK_C: Num := $C; |
|
|
517 |
VK_D: Num := $D; |
|
|
518 |
VK_E: Num := $E; |
|
|
519 |
VK_F: Num := $F; |
|
|
520 |
else Result := False; |
|
|
521 |
end; |
|
|
522 |
end; |
|
|
523 |
|
|
|
524 |
function TTrackerGrid.KeycodeToHexNumber(Key: Word; out Num: Integer): Boolean; |
|
|
525 |
var |
|
|
526 |
X: Byte; |
|
|
527 |
begin |
|
|
528 |
Result := KeycodeToHexNumber(Key, X); |
|
|
529 |
Num := X; |
|
|
530 |
end; |
|
|
531 |
|
| 408 |
end. |
532 |
end. |
| 409 |
|
533 |
|