Commit 3b678d8

Nick committed on
Finish undo/redo
commit 3b678d824e3685a21c15315b1732482f81f82abf parent 54e934c
5 changed files +119−34
ModifiedGBEmu.lpi +3−0
@@ -234,6 +234,9 @@
234 <CodeGeneration> 234 <CodeGeneration>
235 <TargetCPU Value="i386"/> 235 <TargetCPU Value="i386"/>
236 <TargetOS Value="win32"/> 236 <TargetOS Value="win32"/>
237 <Optimizations>
238 <OptimizationLevel Value="0"/>
239 </Optimizations>
237 </CodeGeneration> 240 </CodeGeneration>
238 <Other> 241 <Other>
239 <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/> 242 <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/>
Modifiedtracker.lfm +2−2
@@ -4,8 +4,8 @@ object frmTracker: TfrmTracker
4 Top = 161 4 Top = 161
5 Width = 2212 5 Width = 2212
6 Caption = 'hUGETracker' 6 Caption = 'hUGETracker'
7 ClientHeight = 0 7 ClientHeight = 1362
8 ClientWidth = 0 8 ClientWidth = 2212
9 DesignTimePPI = 168 9 DesignTimePPI = 168
10 Menu = MainMenu1 10 Menu = MainMenu1
11 OnCreate = FormCreate 11 OnCreate = FormCreate
Modifiedtracker.pas +12−11
@@ -368,7 +368,6 @@ procedure TfrmTracker.ReloadPatterns;
368 var 368 var
369 I: Integer; 369 I: Integer;
370 OrderNum: Integer; 370 OrderNum: Integer;
371 Pat: PPattern;
372 begin 371 begin
373 for I := 0 to 3 do begin 372 for I := 0 to 3 do begin
374 OrderNum := 0; 373 OrderNum := 0;
@@ -376,8 +375,7 @@ begin
376 OrderEditStringGrid.Cells[I+1, OrderEditStringGrid.Row], 375 OrderEditStringGrid.Cells[I+1, OrderEditStringGrid.Row],
377 OrderNum 376 OrderNum
378 ); 377 );
379 Pat := Song.Patterns.GetOrCreateNew(OrderNum); 378 TrackerGrid.LoadPattern(I, OrderNum);
380 TrackerGrid.LoadPattern(I, Pat);
381 end; 379 end;
382 380
383 CopyOrderGridToOrderMatrix; 381 CopyOrderGridToOrderMatrix;
@@ -619,6 +617,15 @@ var
619 begin 617 begin
620 ReturnNilIfGrowHeapFails := False; 618 ReturnNilIfGrowHeapFails := False;
621 619
620 // Create pattern editor control
621 Song.Patterns := TPatternMap.Create;
622 TrackerGrid := TTrackerGrid.Create(Self, ScrollBox1, Song.Patterns);
623
624
625 // Fix the size of the channel headers
626 for Section in HeaderControl1.Sections do
627 (Section as THeaderSection).Width := TrackerGrid.ColumnWidth;
628
622 FDCallback := @Self.OnFD; 629 FDCallback := @Self.OnFD;
623 630
624 for I := Low(Song.Instruments) to High(Song.Instruments) do 631 for I := Low(Song.Instruments) to High(Song.Instruments) do
@@ -654,16 +661,10 @@ begin
654 RoutinesNode := Items[3]; 661 RoutinesNode := Items[3];
655 end; 662 end;
656 663
657 // Create pattern editor control
658 TrackerGrid := TTrackerGrid.Create(Self, ScrollBox1);
659 for Section in HeaderControl1.Sections do
660 (Section as THeaderSection).Width := TrackerGrid.ColumnWidth;
661
662 // Initialize order table 664 // Initialize order table
663 Song.Patterns := TPatternMap.Create;
664 for I := 0 to 3 do begin 665 for I := 0 to 3 do begin
665 OrderEditStringGrid.Cells[I+1, 1] := IntToStr(I); 666 OrderEditStringGrid.Cells[I+1, 1] := IntToStr(I);
666 TrackerGrid.LoadPattern(I, Song.Patterns.GetOrCreateNew(I)); 667 TrackerGrid.LoadPattern(I, I);
667 end; 668 end;
668 CopyOrderGridToOrderMatrix; 669 CopyOrderGridToOrderMatrix;
669 670
@@ -955,7 +956,7 @@ begin
955 956
956 with OrderEditStringGrid do begin 957 with OrderEditStringGrid do begin
957 Cells[Col, Row] := IntToStr(Highest); 958 Cells[Col, Row] := IntToStr(Highest);
958 TrackerGrid.LoadPattern(Col - 1, Song.Patterns.GetOrCreateNew(Highest)); 959 TrackerGrid.LoadPattern(Col - 1, Highest);
959 end; 960 end;
960 end; 961 end;
961 962
Modifiedtrackergrid.pas +99−15
@@ -5,8 +5,8 @@ unit TrackerGrid;
5 interface 5 interface
6 6
7 uses 7 uses
8 Classes, SysUtils, Controls, Graphics, Constants, LCLType, math, contnrs, 8 Classes, SysUtils, Controls, Graphics, Constants, LCLType, math,
9 LCLIntf, LMessages, HugeDatatypes, ClipboardUtils; 9 LCLIntf, LMessages, HugeDatatypes, ClipboardUtils, gdeque, gstack, utils;
10 10
11 // TODO: Maybe read these from a config file 11 // TODO: Maybe read these from a config file
12 const 12 const
@@ -25,6 +25,7 @@ const
25 25
26 NUM_COLUMNS = 4; 26 NUM_COLUMNS = 4;
27 NUM_ROWS = 64; 27 NUM_ROWS = 64;
28 UNDO_STACK_SIZE = 100;
28 29
29 type 30 type
30 31
@@ -36,12 +37,16 @@ type
36 end; 37 end;
37 38
38 TUndoRedoAction = array[0..3] of TSavedPattern; 39 TUndoRedoAction = array[0..3] of TSavedPattern;
39 TUndoRedoStack = TObjectStack; 40 TUndoDeque = TDeque<TUndoRedoAction>;
41 TRedoStack = TStack<TUndoRedoAction>;
40 42
41 { TTrackerGrid } 43 { TTrackerGrid }
42 44
43 TTrackerGrid = class(TCustomControl) 45 TTrackerGrid = class(TCustomControl)
44 constructor Create(AOwner: TComponent; Parent: TWinControl); 46 constructor Create(
47 AOwner: TComponent;
48 Parent: TWinControl;
49 PatternMap: TPatternMap); reintroduce;
45 50
46 procedure Paint; override; 51 procedure Paint; override;
47 procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 52 procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
@@ -85,7 +90,9 @@ type
85 function KeycodeToHexNumber(Key: Word; out Num: Nibble): Boolean; overload; 90 function KeycodeToHexNumber(Key: Word; out Num: Nibble): Boolean; overload;
86 function KeycodeToHexNumber(Key: Word; out Num: Integer): Boolean; overload; 91 function KeycodeToHexNumber(Key: Word; out Num: Integer): Boolean; overload;
87 private 92 private
93 PatternMap: TPatternMap;
88 Patterns: array[0..3] of PPattern; 94 Patterns: array[0..3] of PPattern;
95 PatternNumbers: array[0..3] of Integer;
89 96
90 CharHeight: Integer; 97 CharHeight: Integer;
91 CharWidth: Integer; 98 CharWidth: Integer;
@@ -93,7 +100,8 @@ type
93 MouseButtonDown: Boolean; 100 MouseButtonDown: Boolean;
94 Selecting: Boolean; 101 Selecting: Boolean;
95 102
96 Performed, Recall: TUndoRedoStack; 103 Performed: TUndoDeque;
104 Recall: TRedoStack;
97 105
98 DigitInputting: Boolean; 106 DigitInputting: Boolean;
99 107
@@ -104,7 +112,7 @@ type
104 112
105 property HighlightedRow: Integer read FHighlightedRow write SetHighlightedRow; 113 property HighlightedRow: Integer read FHighlightedRow write SetHighlightedRow;
106 property SelectionGridRect: TRect read GetSelectionGridRect write SetSelectionGridRect; 114 property SelectionGridRect: TRect read GetSelectionGridRect write SetSelectionGridRect;
107 procedure LoadPattern(Idx: Integer; Pat: PPattern); 115 procedure LoadPattern(Idx: Integer; PatternNumber: Integer);
108 116
109 function GetAt(SelectionPos: TSelectionPos): Integer; 117 function GetAt(SelectionPos: TSelectionPos): Integer;
110 procedure SetAt(SelectionPos: TSelectionPos; Value: Integer); 118 procedure SetAt(SelectionPos: TSelectionPos; Value: Integer);
@@ -117,12 +125,15 @@ implementation
117 125
118 constructor TTrackerGrid.Create( 126 constructor TTrackerGrid.Create(
119 AOwner: TComponent; 127 AOwner: TComponent;
120 Parent: TWinControl); 128 Parent: TWinControl;
129 PatternMap: TPatternMap);
121 begin 130 begin
122 inherited Create(AOwner); 131 inherited Create(AOwner);
123 132
124 Performed := TUndoRedoStack.Create; 133 Self.PatternMap := PatternMap;
125 Recall := TUndoRedoStack.Create; 134
135 Performed := TUndoDeque.Create;
136 Recall := TRedoStack.Create;
126 137
127 DoubleBuffered := True; 138 DoubleBuffered := True;
128 ControlStyle := ControlStyle + [csCaptureMouse, csClickEvents, csDoubleClicks]; 139 ControlStyle := ControlStyle + [csCaptureMouse, csClickEvents, csDoubleClicks];
@@ -235,6 +246,8 @@ begin
235 inherited KeyDown(Key, Shift); 246 inherited KeyDown(Key, Shift);
236 247
237 case Key of 248 case Key of
249 VK_Z: if ssCtrl in Shift then DoUndo;
250 VK_Y: if ssCtrl in Shift then DoRedo;
238 VK_V: if ssShift in Shift then DoRepeatPaste; 251 VK_V: if ssShift in Shift then DoRepeatPaste;
239 VK_L: begin 252 VK_L: begin
240 if ssCtrl in Shift then begin 253 if ssCtrl in Shift then begin
@@ -272,7 +285,7 @@ begin
272 DigitInputting := False; 285 DigitInputting := False;
273 end; 286 end;
274 else begin 287 else begin
275 if not (ssCtrl in Shift) then 288 if (not (ssCtrl in Shift)) and (not (ssShift in Shift)) then
276 case Cursor.SelectedPart of 289 case Cursor.SelectedPart of
277 cpNote: InputNote(Key); 290 cpNote: InputNote(Key);
278 cpInstrument: InputInstrument(Key); 291 cpInstrument: InputInstrument(Key);
@@ -312,8 +325,6 @@ begin
312 on E: Exception do 325 on E: Exception do
313 WriteLn(StdErr, 'Clipboard did not contain valid note data!'); 326 WriteLn(StdErr, 'Clipboard did not contain valid note data!');
314 end; 327 end;
315
316 Invalidate;
317 end; 328 end;
318 329
319 procedure TTrackerGrid.PerformCopy; 330 procedure TTrackerGrid.PerformCopy;
@@ -333,11 +344,17 @@ begin
333 PerformPaste(Selection); 344 PerformPaste(Selection);
334 Inc(I, High(Selection)+1); 345 Inc(I, High(Selection)+1);
335 end; 346 end;
347
348 Invalidate;
349 SaveUndoState;
336 end; 350 end;
337 351
338 procedure TTrackerGrid.DoPaste(var Msg: TLMessage); 352 procedure TTrackerGrid.DoPaste(var Msg: TLMessage);
339 begin 353 begin
340 PerformPaste(GetPastedCells); 354 PerformPaste(GetPastedCells);
355
356 Invalidate;
357 SaveUndoState;
341 end; 358 end;
342 359
343 procedure TTrackerGrid.DoCopy(var Msg: TLMessage); 360 procedure TTrackerGrid.DoCopy(var Msg: TLMessage);
@@ -365,18 +382,66 @@ begin
365 end; 382 end;
366 383
367 procedure TTrackerGrid.SaveUndoState; 384 procedure TTrackerGrid.SaveUndoState;
385 var
386 Actn: TUndoRedoAction;
387 I: Integer;
368 begin 388 begin
389 // First, clear out the recall stack
390 while not Recall.IsEmpty do
391 Recall.Pop;
369 392
393 // Create the state we need to save
394 for I := Low(Patterns) to High(Patterns) do
395 with Actn[I] do begin
396 Pattern := Patterns[I]^;
397 PatternNumber := PatternNumbers[I];
398 end;
399
400 // Push it into the performed queue
401 Performed.PushFront(Actn);
402 while Performed.Size > UNDO_STACK_SIZE do
403 Performed.PopBack;
370 end; 404 end;
371 405
372 procedure TTrackerGrid.DoUndo; 406 procedure TTrackerGrid.DoUndo;
407 var
408 OldState, NewState: TUndoRedoAction;
409 I: Integer;
373 begin 410 begin
411 if Performed.IsEmpty then Exit;
412
413 OldState := Performed.Front;
414 Performed.PopFront;
415 NewState := Performed.Front;
374 416
417 Recall.Push(OldState);
418
419 for I := Low(NewState) to High(NewState) do begin
420 LoadPattern(I, NewState[I].PatternNumber);
421 Patterns[I]^ := NewState[I].Pattern;
422 end;
423
424 Invalidate;
375 end; 425 end;
376 426
377 procedure TTrackerGrid.DoRedo; 427 procedure TTrackerGrid.DoRedo;
428 var
429 State: TUndoRedoAction;
430 I: Integer;
378 begin 431 begin
432 if Recall.IsEmpty then Exit;
433
434 State := Recall.Top;
435 Recall.Pop;
379 436
437 Performed.PushFront(State);
438
439 for I := Low(State) to High(State) do begin
440 LoadPattern(I, State[I].PatternNumber);
441 Patterns[I]^ := State[I].Pattern;
442 end;
443
444 Invalidate;
380 end; 445 end;
381 446
382 procedure TTrackerGrid.RenderSelectedArea; 447 procedure TTrackerGrid.RenderSelectedArea;
@@ -443,6 +508,9 @@ begin
443 IncSelectionPos(X); 508 IncSelectionPos(X);
444 end; 509 end;
445 end; 510 end;
511
512 Invalidate;
513 SaveUndoState;
446 end; 514 end;
447 515
448 procedure TTrackerGrid.InputNote(Key: Word); 516 procedure TTrackerGrid.InputNote(Key: Word);
@@ -456,6 +524,9 @@ begin
456 Keybindings.TryGetData(Key, Temp); 524 Keybindings.TryGetData(Key, Temp);
457 if Temp <> 0 then Note := Temp; 525 if Temp <> 0 then Note := Temp;
458 end; 526 end;
527
528 Invalidate;
529 SaveUndoState;
459 end; 530 end;
460 531
461 procedure TTrackerGrid.InputInstrument(Key: Word); 532 procedure TTrackerGrid.InputInstrument(Key: Word);
@@ -466,6 +537,9 @@ begin
466 if Key = VK_DELETE then Instrument := 0 537 if Key = VK_DELETE then Instrument := 0
467 else if KeycodeToHexNumber(Key, Temp) and (Temp <= 9) then 538 else if KeycodeToHexNumber(Key, Temp) and (Temp <= 9) then
468 Instrument := ((Instrument mod 10) * 10) + Temp; 539 Instrument := ((Instrument mod 10) * 10) + Temp;
540
541 Invalidate;
542 SaveUndoState;
469 end; 543 end;
470 544
471 procedure TTrackerGrid.InputVolume(Key: Word); 545 procedure TTrackerGrid.InputVolume(Key: Word);
@@ -481,6 +555,9 @@ begin
481 EffectParams.Value := 0; 555 EffectParams.Value := 0;
482 end 556 end
483 else KeycodeToHexNumber(Key, EffectCode); 557 else KeycodeToHexNumber(Key, EffectCode);
558
559 Invalidate;
560 SaveUndoState;
484 end; 561 end;
485 562
486 procedure TTrackerGrid.InputEffectParams(Key: Word); 563 procedure TTrackerGrid.InputEffectParams(Key: Word);
@@ -503,6 +580,9 @@ begin
503 EffectParams.Param2 := Temp; 580 EffectParams.Param2 := Temp;
504 DigitInputting := False; 581 DigitInputting := False;
505 end; 582 end;
583
584 Invalidate;
585 SaveUndoState;
506 end; 586 end;
507 587
508 procedure TTrackerGrid.RenderRow(Row: Integer); 588 procedure TTrackerGrid.RenderRow(Row: Integer);
@@ -653,10 +733,13 @@ end;
653 733
654 function TTrackerGrid.MousePosToSelection(X, Y: Integer): TSelectionPos; 734 function TTrackerGrid.MousePosToSelection(X, Y: Integer): TSelectionPos;
655 begin 735 begin
736 X := Max(0, Min(Width-1, X));
737 Y := Max(0, Min(Height-1, Y));
738
656 Result.X := Trunc((X/Width)*NUM_COLUMNS); 739 Result.X := Trunc((X/Width)*NUM_COLUMNS);
657 Result.Y := Trunc((Y/Height)*NUM_ROWS); 740 Result.Y := Trunc((Y/Height)*NUM_ROWS);
658 741
659 X := (min(X, width-1) mod ColumnWidth); 742 X := X mod ColumnWidth;
660 X := Trunc((X/ColumnWidth)*13); 743 X := Trunc((X/ColumnWidth)*13);
661 case X of 744 case X of
662 0..3: Result.SelectedPart := cpNote; 745 0..3: Result.SelectedPart := cpNote;
@@ -736,9 +819,10 @@ begin
736 end; 819 end;
737 end; 820 end;
738 821
739 procedure TTrackerGrid.LoadPattern(Idx: Integer; Pat: PPattern); 822 procedure TTrackerGrid.LoadPattern(Idx: Integer; PatternNumber: Integer);
740 begin 823 begin
741 Patterns[Idx] := Pat; 824 Patterns[Idx] := PatternMap.GetOrCreateNew(PatternNumber);
825 PatternNumbers[Idx] := PatternNumber; // Ugh
742 Invalidate; 826 Invalidate;
743 end; 827 end;
744 828
Modifiedutils.pas +3−6
@@ -26,16 +26,13 @@ implementation
26 { TOrderMapHelper } 26 { TOrderMapHelper }
27 27
28 function TOrderMapHelper.GetOrCreateNew(Key: Integer): PPattern; 28 function TOrderMapHelper.GetOrCreateNew(Key: Integer): PPattern;
29 var
30 NewPat: PPattern;
31 begin 29 begin
32 if Self.IndexOf(Key) <> -1 then 30 if Self.IndexOf(Key) <> -1 then
33 Result := Self.KeyData[Key] 31 Result := Self.KeyData[Key]
34 else begin 32 else begin
35 New(NewPat); 33 New(Result);
36 BlankPattern(NewPat); 34 BlankPattern(Result);
37 Self.Add(Key, NewPat); 35 Self.Add(Key, Result);
38 Result := NewPat;
39 end; 36 end;
40 end; 37 end;
41 38