Commit 0372aba

Nick committed on
Copying/pasting better!
commit 0372aba65e4e4be50b236844ad1ca3ad589889da parent e412a9d
5 changed files +144−42
Modifiedclipboardutils.pas +45−26
@@ -12,35 +12,42 @@ procedure CopyCells(Selection: TSelection);
12 12
13 implementation 13 implementation
14 14
15 function ParseCell(Cell: String): TCell; 15 function ParseCell(Cell: String): TSelectedCell;
16
17 function StrToInt_(S: String; out I: Integer; Hex: Boolean = False): Boolean;
18 begin
19 if Trim(S) = '' then Exit(False);
20 if Hex then S := 'x'+S;
21 if not TryStrToInt(S, I) then
22 I := 0;
23 Result := True;
24 end;
25
16 var 26 var
17 Note, Instr, EffectCode, EffectParam1, EffectParam2: String; 27 Note, Instr, EffectCode, EffectParam: String;
18 Temp: Integer; 28 Temp: Integer;
19 begin 29 begin
20 Note := Cell.Substring(0, 3); 30 Note := Cell.Substring(0, 3);
21 Instr := Cell.Substring(3, 2); 31 Instr := Cell.Substring(3, 2);
22 EffectCode := Cell.Substring(8, 1); 32 EffectCode := Cell.Substring(8, 1);
23 EffectParam1 := Cell.Substring(9, 1); 33 EffectParam := Cell.Substring(9, 2);
24 EffectParam2 := Cell.Substring(10, 1); 34 //EffectParam1 := Cell.Substring(9, 1);
25 35 //EffectParam2 := Cell.Substring(10, 1);
26 if not NoteToCodeMap.TryGetData(Note, Result.Note) then 36
27 Result.Note := NO_NOTE; 37 Result.Parts := [cpNote, cpInstrument, cpEffectCode, cpEffectParams];
28 38
29 if not TryStrToInt(Instr, Result.Instrument) then 39 if Trim(Note) = '' then Exclude(Result.Parts, cpNote)
30 Result.Instrument := 0; 40 else if not NoteToCodeMap.TryGetData(Note, Result.Cell.Note) then
31 41 Result.Cell.Note := NO_NOTE;
32 if not TryStrToInt('x'+EffectCode, Result.EffectCode) then 42
33 Result.EffectCode := 0; 43 if not StrToInt_(Instr, Result.Cell.Instrument) then
34 44 Exclude(Result.Parts, cpInstrument);
35 if TryStrToInt('x'+EffectParam1, Temp) then 45 if not StrToInt_(EffectCode, Result.Cell.EffectCode, True) then
36 Result.EffectParams.Param1 := Temp 46 Exclude(Result.Parts, cpEffectCode);
47 if StrToInt_(EffectParam, Temp, True) then
48 Result.Cell.EffectParams.Value := Temp
37 else 49 else
38 Result.EffectParams.Value := 0; 50 Exclude(Result.Parts, cpEffectParams);
39
40 if TryStrToInt('x'+EffectParam2, Temp) then
41 Result.EffectParams.Param2 := Temp
42 else
43 Result.EffectParams.Value := 0;
44 end; 51 end;
45 52
46 function GetPastedCells: TSelection; 53 function GetPastedCells: TSelection;
@@ -73,14 +80,26 @@ begin
73 end; 80 end;
74 end; 81 end;
75 82
76 function SerializeCell(Cell: TCell): String; 83 function SerializeCell(Cell: TSelectedCell): String;
77 begin 84 begin
78 Result := '|'; 85 Result := '|';
79 86
80 Result += NoteCodeToString(Cell.Note); 87 if cpNote in Cell.Parts then
81 Result += FormatFloat('00', Cell.Instrument); 88 Result += NoteCodeToString(Cell.Cell.Note)
89 else
90 Result += ' ';
91
92 if cpInstrument in Cell.Parts then
93 Result += FormatFloat('00', Cell.Cell.Instrument)
94 else
95 Result += ' ';
96
82 Result += '...'; // volume 97 Result += '...'; // volume
83 Result += EffectCodeToStr(Cell.EffectCode, Cell.EffectParams); 98
99 if (cpEffectCode in Cell.Parts) or (cpEffectParams in Cell.Parts) then
100 Result += EffectCodeToStr(Cell.Cell.EffectCode, Cell.Cell.EffectParams)
101 else
102 Result += ' ';
84 end; 103 end;
85 104
86 procedure CopyCells(Selection: TSelection); 105 procedure CopyCells(Selection: TSelection);
Modifiedhugedatatypes.pas +9−3
@@ -16,7 +16,7 @@ type
16 TEffectParams = bitpacked record 16 TEffectParams = bitpacked record
17 case Boolean of 17 case Boolean of
18 True: (Param2, Param1: Nibble); 18 True: (Param2, Param1: Nibble);
19 False: (Value: Word); 19 False: (Value: Byte);
20 end; 20 end;
21 21
22 TCell = record 22 TCell = record
@@ -32,8 +32,6 @@ type
32 TPatternMap = specialize TFPGMap<Integer, PPattern>; 32 TPatternMap = specialize TFPGMap<Integer, PPattern>;
33 TOrderMatrix = array[0..3] of array of Integer; 33 TOrderMatrix = array[0..3] of array of Integer;
34 34
35 TSelection = array of array of TCell;
36
37 TCellPart = ( 35 TCellPart = (
38 cpNote = 0, 36 cpNote = 0,
39 cpInstrument = 1, 37 cpInstrument = 1,
@@ -47,6 +45,14 @@ type
47 SelectedPart: TCellPart 45 SelectedPart: TCellPart
48 end; 46 end;
49 47
48 TSelectedCell = record
49 Cell: TCell;
50 Parts: set of TCellPart;
51 end;
52
53 TSelectionRow = array of TSelectedCell;
54 TSelection = array of TSelectionRow;
55
50 operator > (L, R: TSelectionPos): Boolean; 56 operator > (L, R: TSelectionPos): Boolean;
51 operator < (L, R: TSelectionPos): Boolean; 57 operator < (L, R: TSelectionPos): Boolean;
52 operator >= (L, R: TSelectionPos): Boolean; 58 operator >= (L, R: TSelectionPos): Boolean;
Modifiedtracker.lfm +2−2
@@ -53,10 +53,10 @@ object frmTracker: TfrmTracker
53 Height = 966 53 Height = 966
54 Top = 0 54 Top = 0
55 Width = 1865 55 Width = 1865
56 ActivePage = WavesTabSheet 56 ActivePage = GeneralTabSheet
57 Align = alClient 57 Align = alClient
58 ParentFont = False 58 ParentFont = False
59 TabIndex = 3 59 TabIndex = 0
60 TabOrder = 0 60 TabOrder = 0
61 object GeneralTabSheet: TTabSheet 61 object GeneralTabSheet: TTabSheet
62 Caption = 'General' 62 Caption = 'General'
Modifiedtracker.pas +2−0
@@ -287,6 +287,8 @@ begin
287 287
288 OrderEditStringGrid.Row := 1; 288 OrderEditStringGrid.Row := 1;
289 ReloadPatterns; 289 ReloadPatterns;
290
291 PageControl1.ActivePageIndex := 0;
290 end; 292 end;
291 293
292 procedure TfrmTracker.DrawWaveform(PB: TPaintBox; Wave: TWave); 294 procedure TfrmTracker.DrawWaveform(PB: TPaintBox; Wave: TWave);
Modifiedtrackergrid.pas +86−11
@@ -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);