@@ -28,10 +28,11 @@ const |
| 28 |
UNDO_STACK_SIZE = 100; |
28 |
UNDO_STACK_SIZE = 100; |
| 29 |
|
29 |
|
| 30 |
type |
30 |
type |
|
|
31 |
TPatternGrid = array[0..3] of PPattern; |
| 31 |
|
32 |
|
| 32 |
{ TSavedPattern } |
33 |
{ TSavedPattern } |
| 33 |
|
34 |
|
| 34 |
TSavedPattern = object |
35 |
TSavedPattern = record |
| 35 |
PatternNumber: Integer; |
36 |
PatternNumber: Integer; |
| 36 |
Pattern: TPattern; |
37 |
Pattern: TPattern; |
| 37 |
end; |
38 |
end; |
@@ -40,6 +41,22 @@ type |
| 40 |
TUndoDeque = TDeque<TUndoRedoAction>; |
41 |
TUndoDeque = TDeque<TUndoRedoAction>; |
| 41 |
TRedoStack = TStack<TUndoRedoAction>; |
42 |
TRedoStack = TStack<TUndoRedoAction>; |
| 42 |
|
43 |
|
|
|
44 |
{ TSelectionEnumerator } |
|
|
45 |
|
|
|
46 |
TSelectionEnumerator = record |
|
|
47 |
private |
|
|
48 |
function GetCurrent: TSelectionRow; |
|
|
49 |
public |
|
|
50 |
Grid: TPatternGrid; |
|
|
51 |
Row: Integer; |
|
|
52 |
Cursor, Other: TSelectionPos; |
|
|
53 |
|
|
|
54 |
constructor Create(Grid: TPatternGrid; Cursor, Other: TSelectionPos); |
|
|
55 |
function MoveNext: Boolean; |
|
|
56 |
property Current: TSelectionRow read GetCurrent; |
|
|
57 |
function GetEnumerator: TSelectionEnumerator; |
|
|
58 |
end; |
|
|
59 |
|
| 43 |
{ TTrackerGrid } |
60 |
{ TTrackerGrid } |
| 44 |
|
61 |
|
| 45 |
TTrackerGrid = class(TCustomControl) |
62 |
TTrackerGrid = class(TCustomControl) |
@@ -86,7 +103,7 @@ type |
| 86 |
function KeycodeToHexNumber(Key: Word; out Num: Integer): Boolean; overload; |
103 |
function KeycodeToHexNumber(Key: Word; out Num: Integer): Boolean; overload; |
| 87 |
private |
104 |
private |
| 88 |
PatternMap: TPatternMap; |
105 |
PatternMap: TPatternMap; |
| 89 |
Patterns: array[0..3] of PPattern; |
106 |
Patterns: TPatternGrid; |
| 90 |
PatternNumbers: array[0..3] of Integer; |
107 |
PatternNumbers: array[0..3] of Integer; |
| 91 |
|
108 |
|
| 92 |
CharHeight: Integer; |
109 |
CharHeight: Integer; |
@@ -118,11 +135,59 @@ type |
| 118 |
Parent: TWinControl; |
135 |
Parent: TWinControl; |
| 119 |
PatternMap: TPatternMap); reintroduce; |
136 |
PatternMap: TPatternMap); reintroduce; |
| 120 |
destructor Destroy; override; |
137 |
destructor Destroy; override; |
| 121 |
|
|
|
| 122 |
end; |
138 |
end; |
| 123 |
|
139 |
|
| 124 |
implementation |
140 |
implementation |
| 125 |
|
141 |
|
|
|
142 |
{ TSelectionEnumerator } |
|
|
143 |
|
|
|
144 |
constructor TSelectionEnumerator.Create(Grid: TPatternGrid; Cursor, |
|
|
145 |
Other: TSelectionPos); |
|
|
146 |
begin |
|
|
147 |
Self.Grid := Grid; |
|
|
148 |
Self.Row := Cursor.Y-1; |
|
|
149 |
Self.Cursor := Cursor; |
|
|
150 |
Self.Other := Other; |
|
|
151 |
end; |
|
|
152 |
|
|
|
153 |
function TSelectionEnumerator.GetCurrent: TSelectionRow; |
|
|
154 |
var |
|
|
155 |
X, I: Integer; |
|
|
156 |
begin |
|
|
157 |
// Very ugly function |
|
|
158 |
SetLength(Result, (Other.X-Cursor.X)+1); |
|
|
159 |
|
|
|
160 |
Result[0].Cell := Grid[Cursor.X]^[Row]; |
|
|
161 |
if Cursor.X <> Other.X then |
|
|
162 |
Result[0].Parts := [Cursor.SelectedPart..High(TCellPart)] |
|
|
163 |
else |
|
|
164 |
Result[0].Parts := [Cursor.SelectedPart..Other.SelectedPart]; |
|
|
165 |
|
|
|
166 |
I := 1; |
|
|
167 |
for X := Cursor.X+1 to Other.X - 1 do begin |
|
|
168 |
Result[I].Cell := Grid[X]^[Row]; |
|
|
169 |
Result[I].Parts := [Low(TCellPart)..High(TCellPart)]; |
|
|
170 |
Inc(I); |
|
|
171 |
end; |
|
|
172 |
|
|
|
173 |
if Cursor.X <> Other.X then begin |
|
|
174 |
Result[High(Result)].Cell := Grid[Other.X]^[Row]; |
|
|
175 |
Result[High(Result)].Parts := [Low(TCellPart)..Other.SelectedPart]; |
|
|
176 |
end; |
|
|
177 |
end; |
|
|
178 |
|
|
|
179 |
function TSelectionEnumerator.MoveNext: Boolean; |
|
|
180 |
begin |
|
|
181 |
Result := True; |
|
|
182 |
Inc(Row); |
|
|
183 |
if Row > Other.Y then Result := False; |
|
|
184 |
end; |
|
|
185 |
|
|
|
186 |
function TSelectionEnumerator.GetEnumerator: TSelectionEnumerator; |
|
|
187 |
begin |
|
|
188 |
Result := Self; |
|
|
189 |
end; |
|
|
190 |
|
| 126 |
{ TTrackerGrid } |
191 |
{ TTrackerGrid } |
| 127 |
|
192 |
|
| 128 |
constructor TTrackerGrid.Create( |
193 |
constructor TTrackerGrid.Create( |
@@ -316,7 +381,7 @@ begin |
| 316 |
end; |
381 |
end; |
| 317 |
end; |
382 |
end; |
| 318 |
|
383 |
|
| 319 |
if not (ssShift in Shift) then |
384 |
if (not (ssCtrl in Shift)) and (not (ssShift in Shift)) then |
| 320 |
Other := Cursor; |
385 |
Other := Cursor; |
| 321 |
Selecting := ssShift in Shift; |
386 |
Selecting := ssShift in Shift; |
| 322 |
|
387 |
|
@@ -326,6 +391,14 @@ begin |
| 326 |
end; |
391 |
end; |
| 327 |
|
392 |
|
| 328 |
procedure TTrackerGrid.PerformPaste(Paste: TSelection); |
393 |
procedure TTrackerGrid.PerformPaste(Paste: TSelection); |
|
|
394 |
procedure OverlayCell(var Cell1: TCell; const Cell2: TSelectedCell); |
|
|
395 |
begin |
|
|
396 |
if cpNote in Cell2.Parts then Cell1.Note := Cell2.Cell.Note; |
|
|
397 |
if cpInstrument in Cell2.Parts then Cell1.Instrument := Cell2.Cell.Instrument; |
|
|
398 |
if cpEffectCode in Cell2.Parts then Cell1.EffectCode:=Cell2.Cell.EffectCode; |
|
|
399 |
if cpEffectParams in Cell2.Parts then |
|
|
400 |
Cell1.EffectParams.Value := Cell2.Cell.EffectParams.Value; |
|
|
401 |
end; |
| 329 |
var |
402 |
var |
| 330 |
X, Y: Integer; |
403 |
X, Y: Integer; |
| 331 |
begin |
404 |
begin |
@@ -334,7 +407,7 @@ begin |
| 334 |
if Cursor.Y+Y > High(TPattern) then Break; |
407 |
if Cursor.Y+Y > High(TPattern) then Break; |
| 335 |
for X := 0 to High(Paste[Y]) do begin |
408 |
for X := 0 to High(Paste[Y]) do begin |
| 336 |
if Cursor.X+X > High(Patterns) then Break; |
409 |
if Cursor.X+X > High(Patterns) then Break; |
| 337 |
Patterns[Cursor.X + X]^[Cursor.Y + Y] := Paste[Y, X]; |
410 |
OverlayCell(Patterns[Cursor.X + X]^[Cursor.Y + Y], Paste[Y, X]); |
| 338 |
end; |
411 |
end; |
| 339 |
end; |
412 |
end; |
| 340 |
Other.X := Cursor.X + X; |
413 |
Other.X := Cursor.X + X; |
@@ -380,16 +453,18 @@ end; |
| 380 |
procedure TTrackerGrid.DoCopy(var Msg: TLMessage); |
453 |
procedure TTrackerGrid.DoCopy(var Msg: TLMessage); |
| 381 |
var |
454 |
var |
| 382 |
Selection: TSelection; |
455 |
Selection: TSelection; |
| 383 |
R, C: Integer; |
456 |
R: Integer; |
| 384 |
Rect: TRect; |
457 |
Rect: TRect; |
|
|
458 |
SelRow: TSelectionRow; |
| 385 |
begin |
459 |
begin |
|
|
460 |
NormalizeCursors; |
|
|
461 |
|
| 386 |
Rect := SelectionGridRect; |
462 |
Rect := SelectionGridRect; |
| 387 |
SetLength(Selection, Rect.Height+1); |
463 |
SetLength(Selection, Rect.Height+1); |
| 388 |
for R := 0 to Rect.Height do begin |
464 |
R := 0; |
| 389 |
SetLength(Selection[R], Rect.Width+1); |
465 |
for SelRow in TSelectionEnumerator.Create(Patterns, Cursor, Other) do begin |
| 390 |
for C := 0 to Rect.Width do begin |
466 |
Selection[R] := SelRow; |
| 391 |
Selection[R, C] := Patterns[Rect.Left+C]^[Rect.Top+R]; |
467 |
Inc(R) |
| 392 |
end; |
|
|
| 393 |
end; |
468 |
end; |
| 394 |
|
469 |
|
| 395 |
CopyCells(Selection); |
470 |
CopyCells(Selection); |