home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / TrackView.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  72.9 KB  |  2,314 lines  |  [TEXT/KAHL]

  1. /* TrackView.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "TrackView.h"
  31. #include "TrackObject.h"
  32. #include "Memory.h"
  33. #include "FrameObject.h"
  34. #include "Frequency.h"
  35. #include "EditImages.h"
  36. #include "StaffCalibration.h"
  37. #include "TrackDisplayScheduling.h"
  38. #include "Array.h"
  39. #include "EditCommandParameters.h"
  40. #include "Numbers.h"
  41. #include "TieTrackPixel.h"
  42. #include "Scrap.h"
  43. #include "Files.h"
  44. #include "BufferedFileInput.h"
  45. #include "BufferedFileOutput.h"
  46. #include "DataMunging.h"
  47. #include "MainWindowStuff.h"
  48. #include "LoadSaveNoteVectors.h"
  49. #include "Alert.h"
  50.  
  51.  
  52. /* so that tips of notes can be seen above last staff line */
  53. #define EDGESPACER (48)
  54.  
  55. /* so that you have space to add new notes */
  56. #define HORIZONTALEXTENTION (200)
  57.  
  58. /* width of the insertion point */
  59. #define INSERTIONPOINTWIDTH (2)
  60.  
  61. /* tie endpoint positioning correction values */
  62. #define TIESTARTXCORRECTION (11)
  63. #define TIESTARTYCORRECTION (9)
  64. #define TIEENDXCORRECTION (4)
  65. #define TIEENDYCORRECTION (9)
  66.  
  67. /* tie curve drawing parameters */
  68. #define NUMTIELINEINTERVALS (10)
  69. #define MAXTIEDEPTH (15)
  70.  
  71. /* the width of the box drawn for range selection */
  72. #define RANGESELECTTHICKNESS (3)
  73.  
  74.  
  75. #define MAGICSCRAPSTRING ("\xff\x00\x1f\xfe NoteRangeScrap")
  76.  
  77.  
  78. typedef enum
  79.     {
  80.         eTrackViewNoSelection EXECUTE(= -99),
  81.         eTrackViewSingleNoteSelection,
  82.         eTrackViewSingleCommandSelection,
  83.         eTrackViewRangeSelection
  84.     } SelectionModes;
  85.  
  86. typedef enum
  87.     {
  88.         eTrackViewNoUndo EXECUTE(= -5134),
  89.         eTrackViewUndoNoteInsertion,
  90.         eTrackViewUndoRangeInsertion,
  91.         eTrackViewUndoFromFile
  92.     } UndoChoices;
  93.  
  94. struct TrackViewRec
  95.     {
  96.         WinType*                            Window;
  97.         OrdType                                XLoc;
  98.         OrdType                                YLoc;
  99.         OrdType                                Width;
  100.         OrdType                                Height;
  101.         TrackObjectRec*                TrackObj;
  102.         MyBoolean                            CursorBarIsVisible;
  103.         OrdType                                CursorBarLoc;
  104.         long                                    PixelIndent;
  105.         long                                    VerticalOffset;
  106.  
  107.         SelectionModes                SelectionMode;
  108.         long                                    InsertionPointIndex; /* valid only for eTrackViewNoSelection */
  109.         NoteObjectRec*                SelectedNote; /* valid only for single selection */
  110.         long                                    SelectedNoteFrame; /* valid only for single selection */
  111.         long                                    RangeSelectStart; /* valid only for eTrackViewRangeSelection */
  112.         long                                    RangeSelectEnd; /* valid only for eTrackViewRangeSelection */
  113.  
  114.         UndoChoices                        UndoState;
  115.         long                                    UndoNoteInsertionFrameIndex; /* valid only for eTrackViewUndoNoteInsertion */
  116.         long                                    UndoNoteInsertionNoteIndex; /* valid only for eTrackViewUndoNoteInsertion */
  117.         long                                    UndoRangeStartIndex; /* valid only for eTrackViewUndoRangeInsertion */
  118.         long                                    UndoRangeElemCount; /* valid only for eTrackViewUndoRangeInsertion */
  119.         FileSpec*                            UndoTempFileLoc; /* valid only for eTrackViewUndoFromFile */
  120.         FileType*                            UndoTempFileDesc; /* valid only for eTrackViewUndoFromFile */
  121.  
  122.         TrackDispScheduleRec*    Schedule;
  123.     };
  124.  
  125.  
  126. static long                                StaffRefCount = 0;
  127. static short*                            MinorStaffList = NIL;
  128.  
  129.  
  130. /* create a new track view object */
  131. TrackViewRec*                        NewTrackView(struct TrackObjectRec* TrackObj, WinType* Window,
  132.                                                     OrdType X, OrdType Y, OrdType Width, OrdType Height)
  133.     {
  134.         TrackViewRec*                    View;
  135.         ArrayRec*                            BackgroundList;
  136.         long                                    Limit;
  137.         long                                    Scan;
  138.  
  139.         View = (TrackViewRec*)AllocPtrCanFail(sizeof(TrackViewRec),"TrackViewRec");
  140.         if (View == NIL)
  141.             {
  142.              FailurePoint1:
  143.                 return NIL;
  144.             }
  145.         View->Schedule = NewTrackDisplaySchedule(TrackObj);
  146.         if (View->Schedule == NIL)
  147.             {
  148.              FailurePoint3:
  149.                 ReleasePtr((char*)View);
  150.                 goto FailurePoint1;
  151.             }
  152.         BackgroundList = TrackObjectGetBackgroundList(TrackObj);
  153.         Limit = ArrayGetLength(BackgroundList);
  154.         for (Scan = 0; Scan < Limit; Scan += 1)
  155.             {
  156.                 if (!AddTrackToDisplaySchedule(View->Schedule,
  157.                     (TrackObjectRec*)ArrayGetElement(BackgroundList,Scan)))
  158.                     {
  159.                      FailurePoint4:
  160.                         goto FailurePoint3;
  161.                     }
  162.             }
  163.         if (!TrackObjectAddDependentView(TrackObj,View))
  164.             {
  165.              FailurePoint5:
  166.                 goto FailurePoint4;
  167.             }
  168.         for (Scan = 0; Scan < Limit; Scan += 1)
  169.             {
  170.                 if (!TrackObjectAddDependentView((TrackObjectRec*)ArrayGetElement(
  171.                     BackgroundList,Scan),View))
  172.                     {
  173.                      FailurePoint6:
  174.                         /* WARNING:  Scan must be valid from this loop */
  175.                         while (Scan > 0)
  176.                             {
  177.                                 Scan -= 1;
  178.                                 TrackObjectRemoveDependentView((TrackObjectRec*)ArrayGetElement(
  179.                                     BackgroundList,Scan),View);
  180.                             }
  181.                         TrackObjectRemoveDependentView(TrackObj,View);
  182.                         goto FailurePoint5;
  183.                     }
  184.             }
  185.         if (StaffRefCount == 0)
  186.             {
  187.                 MinorStaffList = GetMinorStaffList();
  188.                 if (MinorStaffList == NIL)
  189.                     {
  190.                         goto FailurePoint6;
  191.                     }
  192.             }
  193.         StaffRefCount += 1;
  194.         View->Window = Window;
  195.         View->XLoc = X;
  196.         View->YLoc = Y;
  197.         View->Width = Width;
  198.         View->Height = Height;
  199.         View->TrackObj = TrackObj;
  200.         View->PixelIndent = 0;
  201.         View->CursorBarIsVisible = False;
  202.         View->SelectionMode = eTrackViewNoSelection;
  203.         View->InsertionPointIndex = 0;
  204.         View->VerticalOffset = (MaxVerticalSize() - Height) / 2;
  205.         if (View->VerticalOffset < -EDGESPACER)
  206.             {
  207.                 View->VerticalOffset = -EDGESPACER;
  208.             }
  209.         View->VerticalOffset = (View->VerticalOffset / 4) * 4;
  210.         View->UndoState = eTrackViewNoUndo;
  211.         return View;
  212.     }
  213.  
  214.  
  215. /* dispose of the track view object */
  216. void                                        DisposeTrackView(TrackViewRec* View)
  217.     {
  218.         ArrayRec*                            BackgroundList;
  219.         long                                    Limit;
  220.         long                                    Scan;
  221.  
  222.         CheckPtrExistence(View);
  223.         TrackViewFlushUndoInfo(View);
  224.         BackgroundList = TrackObjectGetBackgroundList(View->TrackObj);
  225.         Limit = ArrayGetLength(BackgroundList);
  226.         for (Scan = 0; Scan < Limit; Scan += 1)
  227.             {
  228.                 TrackObjectRemoveDependentView((TrackObjectRec*)ArrayGetElement(
  229.                     BackgroundList,Scan),View);
  230.             }
  231.         TrackObjectRemoveDependentView(View->TrackObj,View);
  232.         DisposeTrackDisplaySchedule(View->Schedule);
  233.         StaffRefCount -= 1;
  234.         if (StaffRefCount == 0)
  235.             {
  236.                 ReleasePtr((char*)MinorStaffList);
  237.             }
  238.         ReleasePtr((char*)View);
  239.     }
  240.  
  241.  
  242. /* get the left edge of the track view area */
  243. OrdType                                    GetTrackViewXLoc(TrackViewRec* View)
  244.     {
  245.         CheckPtrExistence(View);
  246.         return View->XLoc;
  247.     }
  248.  
  249.  
  250. /* get the top edge of the track view area */
  251. OrdType                                    GetTrackViewYLoc(TrackViewRec* View)
  252.     {
  253.         CheckPtrExistence(View);
  254.         return View->YLoc;
  255.     }
  256.  
  257.  
  258. /* get the width of the track view area */
  259. OrdType                                    GetTrackViewWidth(TrackViewRec* View)
  260.     {
  261.         CheckPtrExistence(View);
  262.         return View->Width;
  263.     }
  264.  
  265.  
  266. /* get the height of the track view area */
  267. OrdType                                    GetTrackViewHeight(TrackViewRec* View)
  268.     {
  269.         CheckPtrExistence(View);
  270.         return View->Height;
  271.     }
  272.  
  273.  
  274. /* change the location of the track view area */
  275. void                                        SetTrackViewPosition(TrackViewRec* View, OrdType X, OrdType Y,
  276.                                                     OrdType Width, OrdType Height)
  277.     {
  278.         CheckPtrExistence(View);
  279.         View->VerticalOffset += (View->Height - Height) / 2;
  280.         if (View->VerticalOffset < -EDGESPACER)
  281.             {
  282.                 View->VerticalOffset = -EDGESPACER;
  283.             }
  284.         View->VerticalOffset = (View->VerticalOffset / 4) * 4;
  285.         View->XLoc = X;
  286.         View->YLoc = Y;
  287.         View->Width = Width;
  288.         View->Height = Height;
  289.         TrackViewRedrawAll(View);
  290.     }
  291.  
  292.  
  293. /* redraw the track view staff bars.  it assumes clipping rectangle has been */
  294. /* properly set up */
  295. void                                        TrackViewRedrawStaff(TrackViewRec* View, OrdType XStart,
  296.                                                     OrdType Width)
  297.     {
  298.         long                                    Scan;
  299.         short*                                MajorStaffList;
  300.  
  301.         CheckPtrExistence(View);
  302.         /* draw staff bars around C */
  303.         MajorStaffList = GetMajorStaffList();
  304.         for (Scan = GetMajorStaffListLength(); Scan >= 0; Scan -= 1)
  305.             {
  306.                 DrawLine(View->Window,eBlack,XStart,ConvertPitchToPixel(MajorStaffList[Scan],0)
  307.                     - View->VerticalOffset + View->YLoc,Width,0);
  308.             }
  309.         /* draw other staff bars */
  310.         for (Scan = PtrSize((char*)MinorStaffList) / sizeof(short) - 1; Scan >= 0; Scan -= 1)
  311.             {
  312.                 DrawLine(View->Window,eMediumGrey,XStart,ConvertPitchToPixel(
  313.                     MinorStaffList[Scan],0) - View->VerticalOffset + View->YLoc,Width,0);
  314.             }
  315.         /* draw all C lines */
  316.         for (Scan = 0; Scan <= (NUMNOTES - 1) / 2; Scan += 12)
  317.             {
  318.                 DrawLine(View->Window,eLightGrey,XStart,ConvertPitchToPixel(CENTERNOTE - Scan,0)
  319.                     - View->VerticalOffset + View->YLoc,Width,0);
  320.                 DrawLine(View->Window,eLightGrey,XStart,ConvertPitchToPixel(CENTERNOTE + Scan,0)
  321.                     - View->VerticalOffset + View->YLoc,Width,0);
  322.             }
  323.     }
  324.  
  325.  
  326. /* get the number of vertical degrees of freedom, for setting the vertical scroll bar */
  327. long                                        TrackViewGetVerticalDegreesOfFreedom(TrackViewRec* View)
  328.     {
  329.         long                                    ReturnValue;
  330.  
  331.         CheckPtrExistence(View);
  332.         ReturnValue = MaxVerticalSize() - View->Height + (2 * EDGESPACER);
  333.         if (ReturnValue < 0)
  334.             {
  335.                 ReturnValue = 0;
  336.             }
  337.         return ReturnValue;
  338.     }
  339.  
  340.  
  341. /* get the vertical offset for setting vertical scroll bar.  0 is top of score area. */
  342. long                                        TrackViewGetVerticalOffset(TrackViewRec* View)
  343.     {
  344.         CheckPtrExistence(View);
  345.         /* they want all positive numbers, so we add in EDGESPACER */
  346.         return View->VerticalOffset + EDGESPACER;
  347.     }
  348.  
  349.  
  350. /* hit test to see if the coordinates are within the track view area */
  351. MyBoolean                                TrackViewHitTest(TrackViewRec* View, OrdType X, OrdType Y)
  352.     {
  353.         CheckPtrExistence(View);
  354.         return (X >= View->XLoc) && (Y >= View->YLoc) && (X < View->XLoc + View->Width)
  355.             && (Y < View->YLoc + View->Height);
  356.     }
  357.  
  358.  
  359. /* change the vertical offset and redraw the track view area */
  360. void                                        TrackViewSetNewVerticalOffset(TrackViewRec* View, long Offset)
  361.     {
  362.         long                                    Delta;
  363.  
  364.         CheckPtrExistence(View);
  365.         TrackViewUndrawCursorBar(View);
  366.         /* do some bounds checking.  we don't use EDGESPACER since they are dealing */
  367.         /* in positive numbers, and so does TrackViewGetVerticalDegreesOfFreedom. */
  368.         if (Offset < 0)
  369.             {
  370.                 Offset = 0;
  371.             }
  372.         if (Offset > TrackViewGetVerticalDegreesOfFreedom(View) - 1)
  373.             {
  374.                 Offset = TrackViewGetVerticalDegreesOfFreedom(View) - 1;
  375.             }
  376.         /* they use positive numbers, but we need one with proper origin */
  377.         Offset -= EDGESPACER;
  378.         /* since we use patterns aligned to 2 and 4 pixels, keep things even so */
  379.         /* the patterns don't look weird */
  380.         Offset = (Offset / 4) * 4;
  381.         /* figure out how much to scroll by */
  382.         Delta = View->VerticalOffset - Offset;
  383.         if (Delta < ORDTYPEMIN)
  384.             {
  385.                 Delta = ORDTYPEMIN;
  386.             }
  387.         else if (Delta > ORDTYPEMAX)
  388.             {
  389.                 Delta = ORDTYPEMAX;
  390.             }
  391.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  392.         ScrollArea(View->Window,View->XLoc,View->YLoc,View->Width,View->Height,0,Delta);
  393.         if (Delta < 0)
  394.             {
  395.                 /* current offset < new offset, scroll up & open hole at bottom */
  396.                 AddClipRect(View->Window,View->XLoc,View->YLoc + View->Height + Delta
  397.                     - RANGESELECTTHICKNESS,View->Width,-Delta + RANGESELECTTHICKNESS);
  398.             }
  399.          else
  400.             {
  401.                 /* current offset > new offset, scroll down & open hole at top */
  402.                 AddClipRect(View->Window,View->XLoc,View->YLoc,View->Width,Delta
  403.                     + RANGESELECTTHICKNESS);
  404.             }
  405.         View->VerticalOffset = Offset;
  406.         TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  407.     }
  408.  
  409.  
  410. /* redraw the entire track view, including properly setting the clipping region. */
  411. void                                        TrackViewRedrawAll(TrackViewRec* View)
  412.     {
  413.         CheckPtrExistence(View);
  414.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  415.         TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  416.     }
  417.  
  418.  
  419. /* update the cursor and optionally draw the vertical (pitch) positioning bar */
  420. void                                        TrackViewUpdateMouseCursor(TrackViewRec* View,
  421.                                                     OrdType X, OrdType Y, MyBoolean DrawFunnyBarThing)
  422.     {
  423.         MyBoolean                            OnAFrameFlag;
  424.         long                                    Dummy;
  425.         OrdType                                NewCursorBar;
  426.  
  427.         CheckPtrExistence(View);
  428.         X -= View->XLoc;
  429.         Y -= View->YLoc;
  430.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  431.             &OnAFrameFlag,&Dummy))
  432.             {
  433.                 return;
  434.             }
  435.         if (DrawFunnyBarThing)
  436.             {
  437.                 NewCursorBar = ConvertPitchToPixel(ConvertPixelToPitch(Y + View->VerticalOffset),0);
  438.                 if ((NewCursorBar != View->CursorBarLoc) || !View->CursorBarIsVisible)
  439.                     {
  440.                         TrackViewUndrawCursorBar(View);
  441.                         View->CursorBarLoc = NewCursorBar;
  442.                         TrackViewDrawCursorBar(View);
  443.                     }
  444.             }
  445.         if (OnAFrameFlag)
  446.             {
  447.                 SetScoreOverlayCursor();
  448.             }
  449.          else
  450.             {
  451.                 SetScoreIntersticeCursor();
  452.             }
  453.     }
  454.  
  455.  
  456. /* the track data has been modified, so set some flags */
  457. void                                        TrackViewTrackObjectModified(TrackViewRec* View,
  458.                                                     TrackObjectRec* TrackObj, long Index)
  459.     {
  460.         CheckPtrExistence(View);
  461.         CheckPtrExistence(TrackObj);
  462.         TrackDisplayScheduleMarkChanged(View->Schedule,View->TrackObj,Index);
  463.     }
  464.  
  465.  
  466. /* another track has been deleted, so remove it from the background list */
  467. void                                        TrackViewObjectTrackDying(TrackViewRec* View,
  468.                                                     TrackObjectRec* TrackObj)
  469.     {
  470.         CheckPtrExistence(View);
  471.         CheckPtrExistence(TrackObj);
  472.         DeleteTrackFromDisplaySchedule(View->Schedule,TrackObj);
  473.     }
  474.  
  475.  
  476. /* insert a note at the specified mouse coordinate with the attributes */
  477. void                                        TrackViewAddNote(TrackViewRec* View,
  478.                                                     OrdType X, OrdType Y, unsigned long NoteAttributes)
  479.     {
  480.         MyBoolean                            AddToFrame;
  481.         long                                    Index;
  482.         NoteObjectRec*                Note;
  483.         unsigned long                    NoteSharpFlatTemp;
  484.         short                                    NotePitchTemp;
  485.  
  486.         CheckPtrExistence(View);
  487.         ERROR((NoteAttributes & eCommandFlag) != 0,PRERR(ForceAbort,
  488.             "TrackViewAddNote being used to insert command into score"));
  489.         TrackViewFlushUndoInfo(View);
  490.         X -= View->XLoc;
  491.         Y -= View->YLoc;
  492.         /* figure out where we are supposed to put this note. */
  493.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  494.             &AddToFrame,&Index))
  495.             {
  496.                 return;
  497.             }
  498.         /* construct the note to be added */
  499.         Note = NewNote();
  500.         if (Note == NIL)
  501.             {
  502.                 return;
  503.             }
  504.         SetUpNoteInfo(&NotePitchTemp,&NoteSharpFlatTemp,(NoteAttributes & eSharpModifier)
  505.             != 0,(NoteAttributes & eFlatModifier) != 0,Y + View->VerticalOffset);
  506.         PutNotePitch(Note,NotePitchTemp);
  507.         PutNoteDuration(Note,NoteAttributes & eDurationMask);
  508.         PutNoteDurationDivision(Note,NoteAttributes & eDivisionMask);
  509.         PutNoteDotStatus(Note,(NoteAttributes & eDotModifier) != 0);
  510.         PutNoteFlatOrSharpStatus(Note,NoteSharpFlatTemp);
  511.         PutNoteIsItARest(Note,(NoteAttributes & eRestModifier) != 0);
  512.         ERROR((NoteAttributes & ~(eSharpModifier | eFlatModifier | eDurationMask
  513.             | eDivisionMask | eDotModifier | eRestModifier)) != 0,PRERR(AllowResume,
  514.             "TrackViewAddNote:  some unknown bits in the note attributes word are set"));
  515.         /* add note to the appropriate place */
  516.         if (AddToFrame)
  517.             {
  518.                 FrameObjectRec*                Frame;
  519.  
  520.                 /* add to existing frame */
  521.                 Frame = TrackObjectGetFrame(View->TrackObj,Index);
  522.                 if (IsThisACommandFrame(Frame))
  523.                     {
  524.                         /* if it's a command frame, then insert note after it */
  525.                         Index += 1;
  526.                         goto InsertionPoint;
  527.                     }
  528.                 if (!AppendNoteToFrame(Frame,Note))
  529.                     {
  530.                      AppendFailurePoint1:
  531.                         DisposeNote(Note);
  532.                         return;
  533.                     }
  534.                 TrackObjectAltered(View->TrackObj,Index);
  535.                 /* remember the undo information */
  536.                 ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  537.                     "TrackViewAddNote:  undo info should have been purged"));
  538.                 View->UndoState = eTrackViewUndoNoteInsertion;
  539.                 View->UndoNoteInsertionFrameIndex = Index;
  540.                 View->UndoNoteInsertionNoteIndex = NumNotesInFrame(Frame) - 1;
  541.             }
  542.          else
  543.             {
  544.                 FrameObjectRec*                Frame;
  545.  
  546.                 /* create a new frame */
  547.              InsertionPoint:
  548.                 /* we hafta create a new frame */
  549.                 Frame = NewFrame();
  550.                 if (Frame == NIL)
  551.                     {
  552.                      InsertionFailurePoint1:
  553.                         goto AppendFailurePoint1;
  554.                     }
  555.                 if (!AppendNoteToFrame(Frame,Note))
  556.                     {
  557.                      InsertionFailurePoint2:
  558.                         DisposeFrameAndContents(Frame);
  559.                         goto InsertionFailurePoint1;
  560.                     }
  561.                 if (!TrackObjectInsertFrame(View->TrackObj,Index,Frame))
  562.                     {
  563.                      InsertionFailurePoint3:
  564.                         goto InsertionFailurePoint2;
  565.                     }
  566.                 /* remember the undo information */
  567.                 ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  568.                     "TrackViewAddNote:  undo info should have been purged"));
  569.                 View->UndoState = eTrackViewUndoNoteInsertion;
  570.                 View->UndoNoteInsertionFrameIndex = Index;
  571.                 View->UndoNoteInsertionNoteIndex = 0;
  572.                 /* we don't have to notify track of change because it knows already. */
  573.             }
  574.         /* adjust the insertion point */
  575.         View->SelectionMode = eTrackViewSingleNoteSelection;
  576.         View->SelectedNote = Note;
  577.         View->SelectedNoteFrame = Index;
  578.         /* redraw what needs to be redrawn.  this definitely needs to be fixed */
  579.         /* up since it's unnecessary to redraw the whole staff just to add a note. */
  580.         TrackViewRedrawAll(View);
  581.         View->CursorBarIsVisible = False; /* temporary */
  582.     }
  583.  
  584.  
  585. /* add a command at the specified mouse coordinates. */
  586. void                                        TrackViewAddCommand(TrackViewRec* View,
  587.                                                     OrdType X, OrdType Y, NoteCommands CommandOpcode)
  588.     {
  589.         MyBoolean                            AddToFrame;
  590.         long                                    Index;
  591.         NoteObjectRec*                Command;
  592.         FrameObjectRec*                Frame;
  593.  
  594.         CheckPtrExistence(View);
  595.         TrackViewFlushUndoInfo(View);
  596.         X -= View->XLoc;
  597.         Y -= View->YLoc;
  598.         /* figure out where we are supposed to put this note. */
  599.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  600.             &AddToFrame,&Index))
  601.             {
  602.                 return;
  603.             }
  604.         /* AddToFrame is ignored for adding commands */
  605.         /* construct the command to be added */
  606.         Command = NewCommand();
  607.         if (Command == NIL)
  608.             {
  609.                 return;
  610.             }
  611.         PutCommandOpcode(Command,CommandOpcode);
  612.         /* add command to the appropriate place */
  613.         /* create a new frame */
  614.         Frame = NewFrame();
  615.         if (Frame == NIL)
  616.             {
  617.              InsertionFailurePoint1:
  618.                 DisposeNote(Command);
  619.                 return;
  620.             }
  621.         if (!AppendNoteToFrame(Frame,Command))
  622.             {
  623.              InsertionFailurePoint2:
  624.                 DisposeFrameAndContents(Frame);
  625.                 goto InsertionFailurePoint1;
  626.             }
  627.         if (!TrackObjectInsertFrame(View->TrackObj,Index,Frame))
  628.             {
  629.              InsertionFailurePoint3:
  630.                 goto InsertionFailurePoint2;
  631.             }
  632.         /* remember the undo information */
  633.         ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  634.             "TrackViewAddCommand:  undo info should have been purged"));
  635.         View->UndoState = eTrackViewUndoNoteInsertion;
  636.         View->UndoNoteInsertionFrameIndex = Index;
  637.         View->UndoNoteInsertionNoteIndex = 0;
  638.         /* we don't have to notify track of change because it knows already. */
  639.         /* adjust the insertion point */
  640.         View->SelectionMode = eTrackViewSingleCommandSelection;
  641.         View->SelectedNote = Command;
  642.         View->SelectedNoteFrame = Index;
  643.         /* redraw what needs to be redrawn.  this definitely needs to be fixed */
  644.         /* up since it's unnecessary to redraw the whole staff just to add a command. */
  645.         TrackViewRedrawAll(View);
  646.         View->CursorBarIsVisible = False; /* temporary */
  647.     }
  648.  
  649.  
  650. /* erase the vertical (pitch) positioning bar */
  651. void                                        TrackViewUndrawCursorBar(TrackViewRec* View)
  652.     {
  653.         CheckPtrExistence(View);
  654.         if (View->CursorBarIsVisible)
  655.             {
  656.                 SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  657.                 AddClipRect(View->Window,View->XLoc,View->YLoc - View->VerticalOffset
  658.                     + View->CursorBarLoc - 1,View->Width,3);
  659.                 DrawBoxErase(View->Window,View->XLoc,View->YLoc - View->VerticalOffset
  660.                     + View->CursorBarLoc - 1,View->Width,3);
  661.                 TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  662.             }
  663.         View->CursorBarIsVisible = False;
  664.     }
  665.  
  666.  
  667. /* draw the vertical (pitch) positioning bar.  this assumes that it has been */
  668. /* previously undrawn (i.e. it doesn't erase any existing bars) */
  669. void                                        TrackViewDrawCursorBar(TrackViewRec* View)
  670.     {
  671.         CheckPtrExistence(View);
  672.         View->CursorBarIsVisible = True;
  673.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  674.         DrawBoxPaint(View->Window,eMediumGrey,View->XLoc,View->YLoc - View->VerticalOffset
  675.             + View->CursorBarLoc - 1,View->Width,3);
  676.     }
  677.  
  678.  
  679. /* draw a cute little paraboloid thing */
  680. static void                            DrawTieLine(WinType* ScreenID, Patterns Pattern,
  681.                                                     OrdType StartX, OrdType StartY, OrdType Width, OrdType Height)
  682.     {
  683.         long                                    Index;
  684.         OrdType                                PixelXLoc[NUMTIELINEINTERVALS];
  685.         OrdType                                PixelYLoc[NUMTIELINEINTERVALS];
  686.  
  687.         /* generate coordinates */
  688.         for (Index = 0; Index < NUMTIELINEINTERVALS; Index += 1)
  689.             {
  690.                 double                                FuncX;
  691.  
  692.                 FuncX = 2 * ((double)Index / (NUMTIELINEINTERVALS - 1)) - 1;
  693.                 PixelXLoc[Index] = Width * ((double)Index / (NUMTIELINEINTERVALS - 1));
  694.                 PixelYLoc[Index] = Height * ((double)Index / (NUMTIELINEINTERVALS - 1))
  695.                     + ((1 - FuncX * FuncX) * MAXTIEDEPTH);
  696.             }
  697.         /* draw the lines */
  698.         for (Index = 0; Index < NUMTIELINEINTERVALS - 1; Index += 1)
  699.             {
  700.                 OrdType                                PosX = StartX + PixelXLoc[Index];
  701.                 OrdType                                PosY = StartY + PixelYLoc[Index];
  702.  
  703.                 DrawLine(ScreenID,Pattern,PosX,PosY,(StartX + PixelXLoc[Index + 1]) - PosX,
  704.                     (StartY + PixelYLoc[Index + 1]) - PosY);
  705.             }
  706.     }
  707.  
  708.  
  709. /* redraw the whole track view, but don't mess with the clipping region.  XStart is */
  710. /* is in window coordinates, not local coordinates */
  711. void                                        TrackViewRedrawDontSetClip(TrackViewRec* View, OrdType XStart,
  712.                                                     OrdType Width)
  713.     {
  714.         long                                    NumTracks;
  715.         long                                    TrackScan;
  716.         long                                    CenterNotePixel;
  717.         FontType                            Font;
  718.         OrdType                                FontHeight;
  719.  
  720.         CheckPtrExistence(View);
  721.         /* erase the drawing area */
  722.         DrawBoxErase(View->Window,XStart,View->YLoc,Width,View->Height);
  723.         /* draw the staff */
  724.         TrackViewRedrawStaff(View,XStart,Width);
  725.         /* now we have to draw the notes */
  726.         CenterNotePixel = View->YLoc - View->VerticalOffset + GetCenterNotePixel();
  727.         Font = GetScreenFont();
  728.         FontHeight = GetFontHeight(Font,9);
  729.  
  730.         /* draw ties first, so they are under the notes */
  731.         {
  732.             TieIntersectListRec*    TieList;
  733.  
  734.             TieList = TrackDisplayGetTieIntervalList(View->Schedule,View->PixelIndent,Width);
  735.             if (TieList != NIL)
  736.                 {
  737.                     long                                    TieLimit;
  738.                     long                                    TieScan;
  739.  
  740.                     TieLimit = GetTieTrackIntersectListLength(TieList);
  741.                     for (TieScan = 0; TieScan < TieLimit; TieScan += 1)
  742.                         {
  743.                             long                                    StartX;
  744.                             long                                    StartY;
  745.                             long                                    EndX;
  746.                             long                                    EndY;
  747.  
  748.                             GetTieTrackIntersectElement(TieList,TieScan,&StartX,&StartY,&EndX,&EndY);
  749.                             DrawTieLine(View->Window,eBlack,(StartX + TIESTARTXCORRECTION)
  750.                                 - View->PixelIndent + View->XLoc,(StartY + TIESTARTYCORRECTION)
  751.                                 + View->YLoc - View->VerticalOffset,(EndX + TIEENDXCORRECTION)
  752.                                 - (StartX + TIESTARTXCORRECTION),(EndY + TIEENDYCORRECTION)
  753.                                 - (StartY + TIESTARTYCORRECTION));
  754.                         }
  755.                     DisposeTieTrackIntersectList(TieList);
  756.                 }
  757.         }
  758.  
  759.         /* draw the notes */
  760.         NumTracks = TrackDisplayGetNumTracks(View->Schedule);
  761.         /* note the less than or EQUAL to NumTracks in the loop... */
  762.         /* see note inside loop about why */
  763.         for (TrackScan = 0; TrackScan <= NumTracks; TrackScan += 1)
  764.             {
  765.                 TrackObjectRec*                TrackObj;
  766.                 long                                    ActualTrackIndex;
  767.  
  768.                 /* we want to draw our track, but we want to draw it last.  to do this, */
  769.                 /* we won't draw it when it comes around normally, but we'll loop one extra */
  770.                 /* (fake) time, during which we won't do the normal get track but instead, */
  771.                 /* we'll just use our own track.  not especially elegant, but it works */
  772.                 if (TrackScan < NumTracks)
  773.                     {
  774.                         TrackObj = TrackDisplayGetParticularTrack(View->Schedule,TrackScan);
  775.                     }
  776.                  else
  777.                     {
  778.                         TrackObj = View->TrackObj;
  779.                     }
  780.                 ActualTrackIndex = TrackDisplayGetTrackIndex(View->Schedule,TrackObj);
  781.                 if ((TrackObj != View->TrackObj) || (TrackScan == NumTracks))
  782.                     {
  783.                         MyBoolean                            Idiot;
  784.                         long                                    Position;
  785.  
  786.                         if (TrackDisplayPixelToIndex(View->Schedule,TrackObj,XStart
  787.                             + View->PixelIndent,&Idiot,&Position))
  788.                             {
  789.                                 long                                    Limit;
  790.                                 long                                    Scan;
  791.  
  792.                                 /* find out how much to draw.  this definitely needs to be */
  793.                                 /* fixed since there is no reason to draw frames until the */
  794.                                 /* end of the entire track */
  795.                                 Limit = TrackObjectGetNumFrames(TrackObj);
  796.  
  797.                                 if (Position > 0)
  798.                                     {
  799.                                         /* this draws the note just off the left edge of the */
  800.                                         /* screen to fix some update region alignment problems. */
  801.                                         Position -= 1;
  802.                                     }
  803.  
  804.                                 /* draw the insertion point, if there is one */
  805.                                 if ((TrackObj == View->TrackObj) && (View->SelectionMode
  806.                                     == eTrackViewNoSelection))
  807.                                     {
  808.                                         long                        TotalNumFrames;
  809.  
  810.                                         TotalNumFrames = TrackObjectGetNumFrames(TrackObj);
  811.                                         if (View->InsertionPointIndex < TotalNumFrames)
  812.                                             {
  813.                                                 long                        InsertionPixel;
  814.  
  815.                                                 /* draw the selection before it's corresponding frame */
  816.                                                 if (TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  817.                                                     View->InsertionPointIndex,&InsertionPixel))
  818.                                                     {
  819.                                                         DrawBoxPaint(View->Window,eBlack,View->XLoc
  820.                                                             - INSERTIONPOINTWIDTH / 2 + InsertionPixel
  821.                                                             - View->PixelIndent,View->YLoc,INSERTIONPOINTWIDTH,
  822.                                                             View->Height);
  823.                                                     }
  824.                                             }
  825.                                         else if (TotalNumFrames > 0)
  826.                                             {
  827.                                                 long                        InsertionPixel;
  828.  
  829.                                                 /* oops, no frame, so draw it after the last frame */
  830.                                                 if (TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  831.                                                     TrackObjectGetNumFrames(TrackObj) - 1,&InsertionPixel))
  832.                                                     {
  833.                                                         InsertionPixel += WidthOfFrameAndDraw(View->Window,
  834.                                                             0,0,0,0,0,TrackObjectGetFrame(TrackObj,TotalNumFrames - 1),
  835.                                                             False/*don't draw*/,False);
  836.                                                         DrawBoxPaint(View->Window,eBlack,View->XLoc
  837.                                                             - INSERTIONPOINTWIDTH / 2 + InsertionPixel
  838.                                                             + EXTERNALSEPARATION - View->PixelIndent,View->YLoc,
  839.                                                             INSERTIONPOINTWIDTH,View->Height);
  840.                                                     }
  841.                                             }
  842.                                         else
  843.                                             {
  844.                                                 /* oops, no frames at all, so just draw it at the beginning */
  845.                                                 /* oh, well, it doesn't get drawn... should fix. (not that */
  846.                                                 /* there's any doubt where an insertion would occur...) */
  847.                                             }
  848.                                     }
  849.  
  850.                                 /* draw all of the frames */
  851.                                 for (Scan = Position; Scan < Limit; Scan += 1)
  852.                                     {
  853.                                         long                                    PixelIndex;
  854.                                         OrdType                                TheFrameWidth EXECUTE(= -8181);
  855.  
  856.                                         /* see if we can draw.  if TrackDisplayIndexToPixel returns false, */
  857.                                         /* then it just won't be drawn.  if TrackDisplayShouldWeDrawIt */
  858.                                         /* returns False, then don't draw because it isn't scheduled. */
  859.                                         if (TrackDisplayIndexToPixel(View->Schedule,ActualTrackIndex,Scan,
  860.                                             &PixelIndex) && TrackDisplayShouldWeDrawIt(View->Schedule,
  861.                                             ActualTrackIndex,Scan))
  862.                                             {
  863.                                                 FrameObjectRec*                Frame;
  864.  
  865.                                                 /* escape if we have gone past the end of the window */
  866.                                                 if (PixelIndex - (View->PixelIndent - View->XLoc)
  867.                                                     - LEFTNOTEEDGEINSET >= XStart + Width)
  868.                                                     {
  869.                                                         goto DonePoint;
  870.                                                     }
  871.  
  872.                                                 /* get the frame to draw */
  873.                                                 Frame = TrackObjectGetFrame(TrackObj,Scan);
  874.  
  875.                                                 /* this section is for stuff that only works in */
  876.                                                 /* the current track */
  877.                                                 if (TrackObj == View->TrackObj)
  878.                                                     {
  879.                                                         long                            MeasureBarIndex;
  880.  
  881.                                                         /* if we should draw a measure bar, then do so.  this */
  882.                                                         /* is done before drawing the notes so that the notes */
  883.                                                         /* will appear on top of the measure bar numbers if */
  884.                                                         /* there is an overwrite */
  885.  
  886.                                                         /* draw the measure bar */
  887.                                                         MeasureBarIndex = TrackDisplayMeasureBarIndex(
  888.                                                             View->Schedule,Scan);
  889.                                                         if (MeasureBarIndex != -1)
  890.                                                             {
  891.                                                                 char*                            IndexText;
  892.                                                                 Patterns                    HowToDraw;
  893.  
  894.                                                                 if (TrackDisplayShouldMeasureBarBeGreyed(
  895.                                                                     View->Schedule,Scan))
  896.                                                                     {
  897.                                                                         HowToDraw = eMediumGrey;
  898.                                                                     }
  899.                                                                  else
  900.                                                                     {
  901.                                                                         HowToDraw = eBlack;
  902.                                                                     }
  903.                                                                 /* actually something to be drawn */
  904.                                                                 DrawLine(View->Window,HowToDraw,PixelIndex - 4/*!*/
  905.                                                                     - View->PixelIndent + View->XLoc,View->YLoc
  906.                                                                     - View->VerticalOffset,0,MaxVerticalSize());
  907.                                                                 IndexText = IntegerToString(MeasureBarIndex);
  908.                                                                 if (IndexText != NIL)
  909.                                                                     {
  910.                                                                         DrawTextLine(View->Window,GetScreenFont(),9,
  911.                                                                             IndexText,PtrSize(IndexText),PixelIndex - 4/*!*/
  912.                                                                             - View->PixelIndent + View->XLoc - (LengthOfText(
  913.                                                                             GetScreenFont(),9,IndexText,PtrSize(IndexText),
  914.                                                                             ePlain) / 2),CenterNotePixel - (GetFontHeight(
  915.                                                                             GetScreenFont(),9) / 2),ePlain);
  916.                                                                         ReleasePtr(IndexText);
  917.                                                                     }
  918.                                                             }
  919.                                                     }
  920.  
  921.                                                 /* draw the notes */
  922.                                                 TheFrameWidth = WidthOfFrameAndDraw(View->Window,PixelIndex
  923.                                                     - View->PixelIndent + View->XLoc,CenterNotePixel,Font,9,
  924.                                                     FontHeight,Frame,True/*draw*/,
  925.                                                     (TrackObj != View->TrackObj)/*greyed*/);
  926.  
  927.                                                 /* draw any hilighting for selected items */
  928.                                                 switch (View->SelectionMode)
  929.                                                     {
  930.                                                         default:
  931.                                                             EXECUTE(PRERR(ForceAbort,
  932.                                                                 "TrackViewRedrawDontSetClip:  bad selection mode"));
  933.                                                             break;
  934.                                                         case eTrackViewNoSelection:
  935.                                                             break;
  936.                                                         case eTrackViewSingleNoteSelection:
  937.                                                             {
  938.                                                                 long                            FrameEnd;
  939.                                                                 long                            Scan;
  940.  
  941.                                                                 FrameEnd = NumNotesInFrame(Frame);
  942.                                                                 Scan = 0;
  943.                                                                 while (Scan < FrameEnd)
  944.                                                                     {
  945.                                                                         if (GetNoteFromFrame(Frame,Scan)
  946.                                                                             == View->SelectedNote)
  947.                                                                             {
  948.                                                                                 DrawBoxFrame(View->Window,eMediumGrey,
  949.                                                                                     PixelIndex - View->PixelIndent + View->XLoc
  950.                                                                                     + (Scan * INTERNALSEPARATION),View->YLoc
  951.                                                                                     - View->VerticalOffset,ICONWIDTH,
  952.                                                                                     MaxVerticalSize());
  953.                                                                                 DrawBoxFrame(View->Window,eMediumGrey,
  954.                                                                                     PixelIndex - View->PixelIndent + View->XLoc
  955.                                                                                     + (Scan * INTERNALSEPARATION) + 1,View->YLoc
  956.                                                                                     - View->VerticalOffset + 1,ICONWIDTH - 2,
  957.                                                                                     MaxVerticalSize() - 2);
  958.                                                                                 goto SingleNoteSelectDonePoint;
  959.                                                                             }
  960.                                                                         Scan += 1;
  961.                                                                     }
  962.                                                             }
  963.                                                          SingleNoteSelectDonePoint:
  964.                                                             break;
  965.                                                         case eTrackViewSingleCommandSelection:
  966.                                                             if (IsThisACommandFrame(Frame))
  967.                                                                 {
  968.                                                                     if (View->SelectedNote == GetNoteFromFrame(Frame,0))
  969.                                                                         {
  970.                                                                             DrawBoxFrame(View->Window,eMediumGrey,PixelIndex
  971.                                                                                 - View->PixelIndent + View->XLoc,View->YLoc
  972.                                                                                 - View->VerticalOffset,TheFrameWidth,
  973.                                                                                 MaxVerticalSize());
  974.                                                                             DrawBoxFrame(View->Window,eMediumGrey,PixelIndex
  975.                                                                                 - View->PixelIndent + View->XLoc + 1,View->YLoc
  976.                                                                                 - View->VerticalOffset + 1,TheFrameWidth - 2,
  977.                                                                                 MaxVerticalSize() - 2);
  978.                                                                         }
  979.                                                                 }
  980.                                                             break;
  981.                                                         case eTrackViewRangeSelection:
  982.                                                             break;
  983.                                                     }
  984.                                             }
  985.                                     } /* end of frame scan */
  986.                                 /* jump here when end of visible note series is reached */
  987.                              DonePoint:
  988.                                 ;
  989.                             }
  990.                     }
  991.             } /* end of track scan */
  992.  
  993.         /* draw selection box */
  994.         if (View->SelectionMode == eTrackViewRangeSelection)
  995.             {
  996.                 long                            StartPixelIndex;
  997.                 long                            EndPixelIndex;
  998.                 long                            OurTrackIndex;
  999.  
  1000.                 OurTrackIndex = TrackDisplayGetTrackIndex(View->Schedule,View->TrackObj);
  1001.                 ERROR(View->RangeSelectStart >= View->RangeSelectEnd,
  1002.                     PRERR(ForceAbort,"TrackViewRedrawDontSetClip:  "
  1003.                     "range selection boundaries are invalid"));
  1004.  
  1005.                 if (!TrackDisplayIndexToPixel(View->Schedule,OurTrackIndex,
  1006.                     View->RangeSelectStart,&StartPixelIndex))
  1007.                     {
  1008.                         return;
  1009.                     }
  1010.                 StartPixelIndex += (View->XLoc - View->PixelIndent); /* normalize to screen */
  1011.                 if (StartPixelIndex < ORDTYPEMIN / 2)
  1012.                     {
  1013.                         StartPixelIndex = ORDTYPEMIN / 2;
  1014.                     }
  1015.                 if (StartPixelIndex > ORDTYPEMAX / 2)
  1016.                     {
  1017.                         StartPixelIndex = ORDTYPEMAX / 2;
  1018.                     }
  1019.  
  1020.                 if (!TrackDisplayIndexToPixel(View->Schedule,OurTrackIndex,
  1021.                     View->RangeSelectEnd - 1,&EndPixelIndex))
  1022.                     {
  1023.                         return;
  1024.                     }
  1025.                 EndPixelIndex += WidthOfFrameAndDraw(View->Window,0,0,0,0,0,
  1026.                     TrackObjectGetFrame(View->TrackObj,View->RangeSelectEnd - 1),
  1027.                     False/*nodraw*/,False);
  1028.                 EndPixelIndex += (View->XLoc - View->PixelIndent); /* normalize to screen */
  1029.                 if (EndPixelIndex < ORDTYPEMIN / 2)
  1030.                     {
  1031.                         EndPixelIndex = ORDTYPEMIN / 2;
  1032.                     }
  1033.                 if (EndPixelIndex > ORDTYPEMAX / 2)
  1034.                     {
  1035.                         EndPixelIndex = ORDTYPEMAX / 2;
  1036.                     }
  1037.  
  1038.                 /* draw upper and lower edges of bounding box */
  1039.                 DrawBoxPaint(View->Window,eBlack,StartPixelIndex,View->YLoc,EndPixelIndex
  1040.                     - StartPixelIndex + EXTERNALSEPARATION,RANGESELECTTHICKNESS);
  1041.                 DrawBoxPaint(View->Window,eBlack,StartPixelIndex,View->YLoc + View->Height
  1042.                     - RANGESELECTTHICKNESS,EndPixelIndex - StartPixelIndex + EXTERNALSEPARATION,
  1043.                     RANGESELECTTHICKNESS);
  1044.  
  1045.                 /* draw left edge of bounding box */
  1046.                 DrawBoxPaint(View->Window,eBlack,StartPixelIndex,View->YLoc,
  1047.                     RANGESELECTTHICKNESS,View->Height);
  1048.  
  1049.                 /* draw right edge of bounding box */
  1050.                 DrawBoxPaint(View->Window,eBlack,EndPixelIndex + EXTERNALSEPARATION,
  1051.                     View->YLoc,RANGESELECTTHICKNESS,View->Height);
  1052.             }
  1053.     }
  1054.  
  1055.  
  1056. /* get the horizontal offset from the start of the track, in pixels */
  1057. long                                        TrackViewGetHorizontalOffset(TrackViewRec* View)
  1058.     {
  1059.         CheckPtrExistence(View);
  1060.         return View->PixelIndent;
  1061.     }
  1062.  
  1063.  
  1064. /* get the horizontal extent of the track (in pixels) for setting the scroll bar */
  1065. long                                        TrackViewGetHorizontalDegreesOfFreedom(TrackViewRec* View)
  1066.     {
  1067.         long                                    Temp;
  1068.  
  1069.         CheckPtrExistence(View);
  1070.         if (!TrackDisplayGetTotalLength(View->Schedule,&Temp))
  1071.             {
  1072.                 return 0;
  1073.             }
  1074.         Temp = Temp - View->Width + HORIZONTALEXTENTION;
  1075.         if (Temp < 0)
  1076.             {
  1077.                 Temp = 0;
  1078.             }
  1079.         return Temp;
  1080.     }
  1081.  
  1082.  
  1083. /* change the horizontal position of the track display and redraw */
  1084. void                                        TrackViewSetNewHorizontalOffset(TrackViewRec* View, long Offset)
  1085.     {
  1086.         long                                    Delta;
  1087.  
  1088.         CheckPtrExistence(View);
  1089.         TrackViewUndrawCursorBar(View);
  1090.         /* do some bounds checking. */
  1091.         if (Offset < 0)
  1092.             {
  1093.                 Offset = 0;
  1094.             }
  1095.         if (Offset > TrackViewGetHorizontalDegreesOfFreedom(View) - 1)
  1096.             {
  1097.                 Offset = TrackViewGetHorizontalDegreesOfFreedom(View) - 1;
  1098.             }
  1099.         /* since we use patterns aligned to 2 and 4 pixels, keep things even so */
  1100.         /* the patterns don't look weird */
  1101.         Offset = (Offset / 4) * 4;
  1102.         /* figure out how much to shift by */
  1103.         Delta = View->PixelIndent - Offset;
  1104.         if (Delta < ORDTYPEMIN)
  1105.             {
  1106.                 Delta = ORDTYPEMIN;
  1107.             }
  1108.         else if (Delta > ORDTYPEMAX)
  1109.             {
  1110.                 Delta = ORDTYPEMAX;
  1111.             }
  1112.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  1113.         ScrollArea(View->Window,View->XLoc,View->YLoc,View->Width,View->Height,Delta,0);
  1114.         if (Delta < 0)
  1115.             {
  1116.                 /* current offset < new offset, scroll left & open hole at right */
  1117.                 AddClipRect(View->Window,View->XLoc + View->Width + Delta,View->YLoc,
  1118.                     -Delta,View->Height);
  1119.             }
  1120.          else
  1121.             {
  1122.                 /* current offset > new offset, scroll right & open hole at left */
  1123.                 AddClipRect(View->Window,View->XLoc,View->YLoc,Delta,View->Height);
  1124.             }
  1125.         View->PixelIndent = Offset;
  1126.         TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  1127.     }
  1128.  
  1129.  
  1130. /* try to select a single note, if there is one, at the specified mouse location */
  1131. void                                        TrackViewTrySingleNoteSelection(TrackViewRec* View,
  1132.                                                     OrdType X, OrdType Y)
  1133.     {
  1134.         NoteObjectRec*                Note;
  1135.         MyBoolean                            CommandFlag;
  1136.         long                                    FrameIndex;
  1137.  
  1138.         CheckPtrExistence(View);
  1139.         X -= View->XLoc;
  1140.         Y -= View->YLoc;
  1141.         Note = TrackDisplayGetUnderlyingNote(View->Schedule,TrackDisplayGetTrackIndex(
  1142.             View->Schedule,View->TrackObj),&CommandFlag,X + View->PixelIndent,&FrameIndex);
  1143.         if (Note != NIL)
  1144.             {
  1145.                 if (CommandFlag)
  1146.                     {
  1147.                         View->SelectionMode = eTrackViewSingleCommandSelection;
  1148.                     }
  1149.                  else
  1150.                     {
  1151.                         View->SelectionMode = eTrackViewSingleNoteSelection;
  1152.                     }
  1153.                 View->SelectedNote = Note;
  1154.                 View->SelectedNoteFrame = FrameIndex;
  1155.             }
  1156.          else
  1157.             {
  1158.                 View->SelectionMode = eTrackViewNoSelection;
  1159.                 View->InsertionPointIndex = FrameIndex;
  1160.                 ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1161.                     PRERR(ForceAbort,"TrackViewTrySingleNoteSelection:  insertion point beyond end of track"));
  1162.             }
  1163.         TrackViewUndrawCursorBar(View);
  1164.         TrackViewRedrawAll(View);
  1165.     }
  1166.  
  1167.  
  1168. /* is the current selection a single note? */
  1169. MyBoolean                                TrackViewIsASingleNoteSelected(TrackViewRec* View)
  1170.     {
  1171.         CheckPtrExistence(View);
  1172.         return (View->SelectionMode == eTrackViewSingleNoteSelection);
  1173.     }
  1174.  
  1175.  
  1176. /* is the current selection a single command? */
  1177. MyBoolean                                TrackViewIsASingleCommandSelected(TrackViewRec* View)
  1178.     {
  1179.         CheckPtrExistence(View);
  1180.         return (View->SelectionMode == eTrackViewSingleCommandSelection);
  1181.     }
  1182.  
  1183.  
  1184. /* is a range of frames selected? */
  1185. MyBoolean                                TrackViewIsARangeSelected(TrackViewRec* View)
  1186.     {
  1187.         CheckPtrExistence(View);
  1188.         return (View->SelectionMode == eTrackViewRangeSelection);
  1189.     }
  1190.  
  1191.  
  1192. /* is nothing selected, and thus there is an insertion point? */
  1193. MyBoolean                                TrackViewIsThereInsertionPoint(TrackViewRec* View)
  1194.     {
  1195.         CheckPtrExistence(View);
  1196.         return (View->SelectionMode == eTrackViewNoSelection);
  1197.     }
  1198.  
  1199.  
  1200. /* get the frame index of the insertion point.  it is an error if there is no */
  1201. /* valid insertion point */
  1202. long                                        TrackViewGetInsertionPointIndex(TrackViewRec* View)
  1203.     {
  1204.         CheckPtrExistence(View);
  1205.         ERROR(View->SelectionMode != eTrackViewNoSelection,PRERR(ForceAbort,
  1206.             "TrackViewGetInsertionPointIndex:  there is no valid insertion point"));
  1207.         ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1208.             PRERR(ForceAbort,"TrackViewGetInsertionPointIndex:  insertion point beyond end of track"));
  1209.         return View->InsertionPointIndex;
  1210.     }
  1211.  
  1212.  
  1213. /* get the beginning of a selection range.  it is an error if a range is not selected */
  1214. long                                        TrackViewGetRangeStart(TrackViewRec* View)
  1215.     {
  1216.         CheckPtrExistence(View);
  1217.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1218.             "TrackViewGetRangeStart:  there is no valid range selection"));
  1219.         return View->RangeSelectStart;
  1220.     }
  1221.  
  1222.  
  1223. /* get the frame after the end of a selection range.  it is an error if there is */
  1224. /* no selected range. */
  1225. long                                        TrackViewGetRangeEndPlusOne(TrackViewRec* View)
  1226.     {
  1227.         CheckPtrExistence(View);
  1228.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1229.             "TrackViewGetRangeEndPlusOne:  there is no valid range selection"));
  1230.         return View->RangeSelectEnd;
  1231.     }
  1232.  
  1233.  
  1234. /* get the frame number of a single note or command selection */
  1235. long                                        TrackViewGetSingleNoteSelectionFrameNumber(TrackViewRec* View)
  1236.     {
  1237.         CheckPtrExistence(View);
  1238.         ERROR(!TrackViewIsASingleNoteSelected(View)
  1239.             && !TrackViewIsASingleCommandSelected(View),PRERR(ForceAbort,
  1240.             "TrackViewGetSingleNoteSelectionFrameNumber:  no single note/command selection"));
  1241.         return View->SelectedNoteFrame;
  1242.     }
  1243.  
  1244.  
  1245. /* delete the selected single note or command.  it is an error if no single note */
  1246. /* or command is selected */
  1247. void                                        TrackViewDeleteSingleNoteOrCommand(TrackViewRec* View)
  1248.     {
  1249.         FrameObjectRec*                Frame;
  1250.         long                                    Limit;
  1251.         long                                    Scan;
  1252.  
  1253.         CheckPtrExistence(View);
  1254.         TrackViewFlushUndoInfo(View);
  1255.         ERROR((View->SelectionMode != eTrackViewSingleNoteSelection)
  1256.             && (View->SelectionMode != eTrackViewSingleCommandSelection),PRERR(ForceAbort,
  1257.             "TrackViewDeleteSingleNote:  no single note is selected"));
  1258.         if (!TrackViewBuildFullUndoBackingStore(View))
  1259.             {
  1260.                 switch (AskYesNoCancel("There is not enough disk space available to preserve "
  1261.                     "undo information.  Continue?",NIL,"Continue","Cancel",NIL))
  1262.                     {
  1263.                         default:
  1264.                             EXECUTE(PRERR(ForceAbort,
  1265.                                 "TrackViewDeleteSingleNoteOrCommand:  bad value from AskYesNoCancel"));
  1266.                             break;
  1267.                         case eYes:
  1268.                             break;
  1269.                         case eNo:
  1270.                             return; /* abort now */
  1271.                     }
  1272.             }
  1273.         Frame = TrackObjectGetFrame(View->TrackObj,View->SelectedNoteFrame);
  1274.         CheckPtrExistence(Frame);
  1275.         Limit = NumNotesInFrame(Frame);
  1276.         for (Scan = 0; Scan < Limit; Scan += 1)
  1277.             {
  1278.                 if (View->SelectedNote == GetNoteFromFrame(Frame,Scan))
  1279.                     {
  1280.                         /* we found the note to delete */
  1281.                         /* zap ties to this note */
  1282.                         TrackObjectNullifyTies(View->TrackObj,View->SelectedNote);
  1283.                         /* indicate that stuff needs to be redrawn */
  1284.                         TrackObjectAltered(View->TrackObj,View->SelectedNoteFrame);
  1285.                         /* now do the actual deletion */
  1286.                         if (NumNotesInFrame(Frame) == 1)
  1287.                             {
  1288.                                 /* since this is the only note in the frame, we'll just delete the */
  1289.                                 /* whole frame. */
  1290.                                 TrackObjectDeleteFrameRun(View->TrackObj,View->SelectedNoteFrame,1);
  1291.                             }
  1292.                          else
  1293.                             {
  1294.                                 /* there are other notes in the frame, so just delete this one note */
  1295.                                 if (!DeleteNoteFromFrame(Frame,Scan))
  1296.                                     {
  1297.                                         /* failed */
  1298.                                         return;
  1299.                                     }
  1300.                                 DisposeNote(View->SelectedNote);
  1301.                             }
  1302.                         View->SelectionMode = eTrackViewNoSelection;
  1303.                         View->InsertionPointIndex = View->SelectedNoteFrame;
  1304.                         ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1305.                             PRERR(ForceAbort,"TrackViewDeleteSingleNote:  insertion point beyond end of track"));
  1306.                         EXECUTE(View->SelectedNote = (NoteObjectRec*)0x81818181;)
  1307.                         EXECUTE(View->SelectedNoteFrame = -1;)
  1308.                         /* redrawing everything is overkill and should be fixed */
  1309.                         TrackViewRedrawAll(View);
  1310.                         return;
  1311.                     }
  1312.             }
  1313.         EXECUTE(PRERR(AllowResume,"TrackViewDeleteSingleNote:  couldn't find the note"));
  1314.     }
  1315.  
  1316.  
  1317. /* add a track to the greyed-out background display */
  1318. MyBoolean                                TrackViewAddBackgroundTrack(TrackViewRec* View,
  1319.                                                     struct TrackObjectRec* TrackObj)
  1320.     {
  1321.         MyBoolean                            Result;
  1322.         long                                    FrameIndex;
  1323.         MyBoolean                            OnAFrameFlag;
  1324.  
  1325.         CheckPtrExistence(View);
  1326.         CheckPtrExistence(TrackObj);
  1327.         (void)TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,View->PixelIndent,
  1328.             &OnAFrameFlag,&FrameIndex);
  1329.         Result = AddTrackToDisplaySchedule(View->Schedule,TrackObj);
  1330.         if (FrameIndex < TrackObjectGetNumFrames(View->TrackObj))
  1331.             {
  1332.                 (void)TrackDisplayIndexToPixel(View->Schedule,0,FrameIndex,&(View->PixelIndent));
  1333.             }
  1334.          else
  1335.             {
  1336.                 View->PixelIndent = 0;
  1337.             }
  1338.         TrackViewRedrawAll(View);
  1339.         return Result;
  1340.     }
  1341.  
  1342.  
  1343. /* remove a track from the greyed-out background display */
  1344. void                                        TrackViewRemoveBackgroundTrack(TrackViewRec* View,
  1345.                                                     struct TrackObjectRec* TrackObj)
  1346.     {
  1347.         long                                    FrameIndex;
  1348.         MyBoolean                            OnAFrameFlag;
  1349.  
  1350.         CheckPtrExistence(View);
  1351.         CheckPtrExistence(TrackObj);
  1352.         (void)TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,View->PixelIndent,
  1353.             &OnAFrameFlag,&FrameIndex);
  1354.         DeleteTrackFromDisplaySchedule(View->Schedule,TrackObj);
  1355.         if (FrameIndex < TrackObjectGetNumFrames(View->TrackObj))
  1356.             {
  1357.                 (void)TrackDisplayIndexToPixel(View->Schedule,0,FrameIndex,&(View->PixelIndent));
  1358.             }
  1359.          else
  1360.             {
  1361.                 View->PixelIndent = 0;
  1362.             }
  1363.         TrackViewRedrawAll(View);
  1364.     }
  1365.  
  1366.  
  1367. /* present a dialog box for editing the selected object's attributes.  it is an */
  1368. /* error if there is no single note or command selected. */
  1369. void                                        TrackViewEditSingleSelectionAttributes(TrackViewRec* View)
  1370.     {
  1371.         CheckPtrExistence(View);
  1372.         TrackViewFlushUndoInfo(View);
  1373.         ERROR(!TrackViewIsASingleNoteSelected(View)
  1374.             && !TrackViewIsASingleCommandSelected(View),PRERR(ForceAbort,
  1375.             "TrackViewEditSingleSelectionAttributes:  no singly select object"));
  1376.         EditNoteOrCommandAttributes(View->SelectedNote,View->TrackObj);
  1377.     }
  1378.  
  1379.  
  1380. /* set a tie from the currently selected note to the note at the specified position. */
  1381. /* it is an error if there is no single note selected. */
  1382. void                                        TrackViewSetTieOnNote(TrackViewRec* View, OrdType X, OrdType Y)
  1383.     {
  1384.         MyBoolean                            ActuallyOnAFrame;
  1385.         long                                    Index;
  1386.         long                                    DestinationFrameIndex;
  1387.         NoteObjectRec*                DestinationNote;
  1388.         MyBoolean                            CommandFlag;
  1389.  
  1390.         CheckPtrExistence(View);
  1391.         TrackViewFlushUndoInfo(View);
  1392.         ERROR(View->SelectionMode != eTrackViewSingleNoteSelection,PRERR(ForceAbort,
  1393.             "TrackViewSetTieOnNote:  single note selection is false."));
  1394.         X -= View->XLoc;
  1395.         Y -= View->YLoc;
  1396.         /* figure out where we are supposed to put this note. */
  1397.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  1398.             &ActuallyOnAFrame,&Index))
  1399.             {
  1400.                 return;
  1401.             }
  1402.  
  1403.         /* if they didn't click on anything, then cancel the tie */
  1404.         if (!ActuallyOnAFrame)
  1405.             {
  1406.                 goto DeleteTheTiePoint;
  1407.             }
  1408.  
  1409.         /* get the destination note */
  1410.         DestinationNote = TrackDisplayGetUnderlyingNote(View->Schedule,
  1411.             TrackDisplayGetTrackIndex(View->Schedule,View->TrackObj),&CommandFlag,
  1412.             X + View->PixelIndent,&DestinationFrameIndex);
  1413.  
  1414.         /* change the data */
  1415.         if ((DestinationFrameIndex <= View->SelectedNoteFrame) || (DestinationNote == NIL))
  1416.             {
  1417.                 /* delete the tie */
  1418.              DeleteTheTiePoint:
  1419.                 PutNoteTieTarget(View->SelectedNote,NIL);
  1420.                 TrackObjectAltered(View->TrackObj,View->SelectedNoteFrame);
  1421.             }
  1422.          else
  1423.             {
  1424.                 /* create the tie */
  1425.                 /* patch the tie flag thing */
  1426.                 PutNoteTieTarget(View->SelectedNote,DestinationNote);
  1427.                 TrackObjectAltered(View->TrackObj,View->SelectedNoteFrame);
  1428.                 /* change selection */
  1429.                 View->SelectedNote = DestinationNote;
  1430.                 View->SelectedNoteFrame = DestinationFrameIndex;
  1431.             }
  1432.  
  1433.         /* redraw */
  1434.         TrackViewRedrawAll(View);
  1435.         View->CursorBarIsVisible = False; /* temporary */
  1436.     }
  1437.  
  1438.  
  1439. /* select a range of frames. */
  1440. void                                        TrackViewSetRangeSelection(TrackViewRec* View, long StartFrame,
  1441.                                                     long EndFramePlusOne)
  1442.     {
  1443.         CheckPtrExistence(View);
  1444.         ERROR(StartFrame >= EndFramePlusOne,PRERR(ForceAbort,
  1445.             "TrackViewSetRangeSelection:  frame boundaries are invalid"));
  1446.         ERROR(StartFrame < 0,PRERR(ForceAbort,
  1447.             "TrackViewSetRangeSelection:  start frame is before beginning of track"));
  1448.         ERROR(EndFramePlusOne > TrackObjectGetNumFrames(View->TrackObj),PRERR(ForceAbort,
  1449.             "TrackViewSetRangeSelection:  end frame is after end of track"));
  1450.         View->SelectionMode = eTrackViewRangeSelection;
  1451.         View->RangeSelectStart = StartFrame;
  1452.         View->RangeSelectEnd = EndFramePlusOne;
  1453.         /* redraw with the selection changes */
  1454.         TrackViewRedrawAll(View);
  1455.         View->CursorBarIsVisible = False; /* temporary */
  1456.     }
  1457.  
  1458.  
  1459. /* set an insertion point at the specified frame index */
  1460. void                                        TrackViewSetInsertionPoint(TrackViewRec* View, long FrameIndex)
  1461.     {
  1462.         CheckPtrExistence(View);
  1463.         ERROR((FrameIndex < 0) || (FrameIndex > TrackObjectGetNumFrames(View->TrackObj)),
  1464.             PRERR(ForceAbort,"TrackViewSetInsertionPoint:  index is out of range"));
  1465.         View->SelectionMode = eTrackViewNoSelection;
  1466.         View->InsertionPointIndex = FrameIndex;
  1467.         /* redraw with the selection changes */
  1468.         TrackViewRedrawAll(View);
  1469.         View->CursorBarIsVisible = False; /* temporary */
  1470.     }
  1471.  
  1472.  
  1473. /* do a mouse down, which may select things.  ExtendSelection is true for shift-key */
  1474. /* type selection extending */
  1475. void                                        TrackViewDoMouseDown(TrackViewRec* View, OrdType XLoc,
  1476.                                                     OrdType YLoc, MyBoolean ExtendSelection,
  1477.                                                     void (*ScrollCallback)(void* Refcon), void* Refcon)
  1478.     {
  1479.         MyBoolean                            LandedOnAFrame;
  1480.         long                                    ClickFrameIndex;
  1481.         long                                    BaseSelectStart;
  1482.         long                                    BaseSelectEnd;
  1483.         long                                    PreviousSelectStart;
  1484.         long                                    PreviousSelectEnd;
  1485.  
  1486.         CheckPtrExistence(View);
  1487.  
  1488.         /* if we are NOT extending the selection, then we need to set the insertion */
  1489.         /* point to the specified location */
  1490.         if (!ExtendSelection || ((View->SelectionMode != eTrackViewNoSelection)
  1491.             && (View->SelectionMode != eTrackViewRangeSelection)))
  1492.             {
  1493.                 if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,
  1494.                     XLoc - View->XLoc + View->PixelIndent,&LandedOnAFrame,&ClickFrameIndex))
  1495.                     {
  1496.                         return;
  1497.                     }
  1498.                 ERROR((ClickFrameIndex < 0) || (ClickFrameIndex
  1499.                     > TrackObjectGetNumFrames(View->TrackObj)),PRERR(ForceAbort,
  1500.                     "TrackViewDoMouseDown:  click frame index is beyond the bounds of the track"));
  1501.                 View->SelectionMode = eTrackViewNoSelection;
  1502.                 View->InsertionPointIndex = ClickFrameIndex;
  1503.                 ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1504.                     PRERR(ForceAbort,"TrackViewDoMouseDown:  insertion point beyond end of track"));
  1505.             }
  1506.         ERROR((View->SelectionMode != eTrackViewNoSelection) && (View->SelectionMode
  1507.             != eTrackViewRangeSelection),PRERR(ForceAbort,
  1508.             "TrackViewDoMouseDown:  bad selection mode"));
  1509.  
  1510.         /* now figure out where the existing selection boundaries are */
  1511.         if (View->SelectionMode == eTrackViewRangeSelection)
  1512.             {
  1513.                 BaseSelectStart = View->RangeSelectStart;
  1514.                 BaseSelectEnd = View->RangeSelectEnd;
  1515.             }
  1516.          else
  1517.             {
  1518.                 BaseSelectStart = View->InsertionPointIndex;
  1519.                 BaseSelectEnd = View->InsertionPointIndex;
  1520.             }
  1521.         PreviousSelectStart = BaseSelectStart;
  1522.         PreviousSelectEnd = BaseSelectEnd;
  1523.         if (BaseSelectStart < BaseSelectEnd)
  1524.             {
  1525.                 TrackViewSetRangeSelection(View,BaseSelectStart,BaseSelectEnd);
  1526.             }
  1527.          else
  1528.             {
  1529.                 TrackViewSetInsertionPoint(View,BaseSelectStart);
  1530.             }
  1531.  
  1532.         /* enter the selection tracking loop */
  1533.         do
  1534.             {
  1535.                 long                                    NewSelectStart;
  1536.                 long                                    NewSelectEnd;
  1537.  
  1538.                 /* scroll if necessary */
  1539.                 if (XLoc - View->XLoc < 0)
  1540.                     {
  1541.                         /* scroll left */
  1542.                         TrackViewSetNewHorizontalOffset(View,TrackViewGetHorizontalOffset(
  1543.                             View) - (1 * GetTrackViewWidth(View)) / 8);
  1544.                         ScrollCallback(Refcon);
  1545.                     }
  1546.                 if (XLoc - View->XLoc >= View->Width)
  1547.                     {
  1548.                         /* scroll right */
  1549.                         TrackViewSetNewHorizontalOffset(View,TrackViewGetHorizontalOffset(
  1550.                             View) + (1 * GetTrackViewWidth(View)) / 8);
  1551.                         ScrollCallback(Refcon);
  1552.                     }
  1553.                 if (YLoc - View->YLoc < 0)
  1554.                     {
  1555.                         /* scroll up */
  1556.                         TrackViewSetNewVerticalOffset(View,TrackViewGetVerticalOffset(
  1557.                             View) - (1 * GetTrackViewHeight(View)) / 8);
  1558.                         ScrollCallback(Refcon);
  1559.                     }
  1560.                 if (YLoc - View->YLoc >= View->Height)
  1561.                     {
  1562.                         /* scroll down */
  1563.                         TrackViewSetNewVerticalOffset(View,TrackViewGetVerticalOffset(
  1564.                             View) + (1 * GetTrackViewHeight(View)) / 8);
  1565.                         ScrollCallback(Refcon);
  1566.                     }
  1567.  
  1568.                 /* figure out where the thang goes now */
  1569.                 if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,
  1570.                     XLoc - View->XLoc + View->PixelIndent,&LandedOnAFrame,&ClickFrameIndex))
  1571.                     {
  1572.                         return;
  1573.                     }
  1574.                 ERROR((ClickFrameIndex < 0) || (ClickFrameIndex
  1575.                     > TrackObjectGetNumFrames(View->TrackObj)),PRERR(ForceAbort,
  1576.                     "TrackViewDoMouseDown:  click frame index is beyond the bounds of the track"));
  1577.                 NewSelectStart = BaseSelectStart;
  1578.                 NewSelectEnd = BaseSelectEnd;
  1579.                 if (ClickFrameIndex < NewSelectStart)
  1580.                     {
  1581.                         NewSelectStart = ClickFrameIndex;
  1582.                     }
  1583.                 if (ClickFrameIndex > NewSelectEnd)
  1584.                     {
  1585.                         NewSelectEnd = ClickFrameIndex;
  1586.                     }
  1587.                 if ((NewSelectStart != PreviousSelectStart)
  1588.                     || (NewSelectEnd != PreviousSelectEnd))
  1589.                     {
  1590.                         PreviousSelectStart = NewSelectStart;
  1591.                         PreviousSelectEnd = NewSelectEnd;
  1592.                         if (NewSelectStart < NewSelectEnd)
  1593.                             {
  1594.                                 TrackViewSetRangeSelection(View,NewSelectStart,NewSelectEnd);
  1595.                             }
  1596.                          else
  1597.                             {
  1598.                                 TrackViewSetInsertionPoint(View,NewSelectStart);
  1599.                             }
  1600.                     }
  1601.             } while (eMouseUp != GetAnEvent(&XLoc,&YLoc,NIL,NIL,NIL,NIL));
  1602.     }
  1603.  
  1604.  
  1605. /* set the range selection to the entire track */
  1606. void                                        TrackViewSelectAll(TrackViewRec* View)
  1607.     {
  1608.         long                                    NumFrames;
  1609.  
  1610.         CheckPtrExistence(View);
  1611.         NumFrames = TrackObjectGetNumFrames(View->TrackObj);
  1612.         if (NumFrames > 0)
  1613.             {
  1614.                 View->SelectionMode = eTrackViewRangeSelection;
  1615.                 View->RangeSelectStart = 0;
  1616.                 View->RangeSelectEnd = NumFrames;
  1617.             }
  1618.          else
  1619.             {
  1620.                 View->SelectionMode = eTrackViewNoSelection;
  1621.                 View->InsertionPointIndex = 0;
  1622.             }
  1623.         /* redraw with the selection changes */
  1624.         TrackViewRedrawAll(View);
  1625.         View->CursorBarIsVisible = False; /* temporary */
  1626.     }
  1627.  
  1628.  
  1629. /* delete the selected range.  it is an error if there is no selected range. it */
  1630. /* returns False if it fails.  undo information is automatically maintained */
  1631. MyBoolean                                TrackViewDeleteRangeSelection(TrackViewRec* View)
  1632.     {
  1633.         CheckPtrExistence(View);
  1634.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1635.             "TrackViewDeleteRangeSelection:  called with no range selected"));
  1636.         TrackViewFlushUndoInfo(View);
  1637.         if (!TrackViewBuildFullUndoBackingStore(View))
  1638.             {
  1639.                 switch (AskYesNoCancel("There is not enough disk space available to preserve "
  1640.                     "undo information.  Continue?",NIL,"Continue","Cancel",NIL))
  1641.                     {
  1642.                         default:
  1643.                             EXECUTE(PRERR(ForceAbort,
  1644.                                 "TrackViewDeleteSingleNoteOrCommand:  bad value from AskYesNoCancel"));
  1645.                             break;
  1646.                         case eYes:
  1647.                             break;
  1648.                         case eNo:
  1649.                             return False; /* abort now */
  1650.                     }
  1651.             }
  1652.  
  1653.         /* delete the stuff */
  1654.         TrackObjectDeleteFrameRun(View->TrackObj,View->RangeSelectStart,
  1655.             View->RangeSelectEnd - View->RangeSelectStart);
  1656.         View->SelectionMode = eTrackViewNoSelection;
  1657.         View->InsertionPointIndex = View->RangeSelectStart;
  1658.         ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1659.             PRERR(ForceAbort,"TrackViewDeleteRangeSelection:  insertion point beyond end of track"));
  1660.  
  1661.         /* redraw with changes */
  1662.         TrackViewRedrawAll(View);
  1663.         View->CursorBarIsVisible = False; /* temporary */
  1664.         TrackViewShowSelection(View);
  1665.  
  1666.         return True;
  1667.     }
  1668.  
  1669.  
  1670. /* attempt to paste notes into the track.  returns False if it fails.  undo */
  1671. /* information is automatically maintained. */
  1672. MyBoolean                                TrackViewAttemptPaste(TrackViewRec* View)
  1673.     {
  1674.         char*                                    Scrap;
  1675.         MyBoolean                            TotalSuccessFlag = False;
  1676.  
  1677.         CheckPtrExistence(View);
  1678.         TrackViewFlushUndoInfo(View);
  1679.         if (View->SelectionMode == eTrackViewRangeSelection)
  1680.             {
  1681.                 if (!TrackViewDeleteRangeSelection(View))
  1682.                     {
  1683.                         return False;
  1684.                     }
  1685.             }
  1686.         ERROR(View->SelectionMode != eTrackViewNoSelection,PRERR(ForceAbort,
  1687.             "TrackViewAttemptPaste:  no insertion point"));
  1688.         Scrap = GetCopyOfScrap();
  1689.         if (Scrap != NIL)
  1690.             {
  1691.                 if ((PtrSize(Scrap) >= sizeof(MAGICSCRAPSTRING))
  1692.                     && MemEqu(MAGICSCRAPSTRING,Scrap,sizeof(MAGICSCRAPSTRING)))
  1693.                     {
  1694.                         FileSpec*                            TempFileLoc;
  1695.  
  1696.                         TempFileLoc = NewTempFileSpec(CODE4BYTES('\?','\?','\?','\?'),
  1697.                             CODE4BYTES('\?','\?','\?','\?'));
  1698.                         if (TempFileLoc != NIL)
  1699.                             {
  1700.                                 FileType*                            FileDesc;
  1701.  
  1702.                                 if (OpenFile(TempFileLoc,&FileDesc,eReadAndWrite))
  1703.                                     {
  1704.                                         if (0 == WriteToFile(FileDesc,Scrap + sizeof(MAGICSCRAPSTRING),
  1705.                                             PtrSize(Scrap) - sizeof(MAGICSCRAPSTRING)))
  1706.                                             {
  1707.                                                 if (SetFilePosition(FileDesc,0))
  1708.                                                     {
  1709.                                                         BufferedInputRec*        BuffFile;
  1710.  
  1711.                                                         BuffFile = NewBufferedInput(FileDesc);
  1712.                                                         if (BuffFile != NIL)
  1713.                                                             {
  1714.                                                                 ArrayRec*                        FrameArray EXECUTE(= (ArrayRec*)0x81818181);
  1715.  
  1716.                                                                 if (eFileLoadNoError == ReadNoteVector(&FrameArray,BuffFile))
  1717.                                                                     {
  1718.                                                                         long                                Scan;
  1719.  
  1720.                                                                         CheckPtrExistence(FrameArray);
  1721.                                                                         Scan = 0;
  1722.                                                                         while (ArrayGetLength(FrameArray) > 0)
  1723.                                                                             {
  1724.                                                                                 FrameObjectRec*            Thing;
  1725.  
  1726.                                                                                 Thing = (FrameObjectRec*)ArrayGetElement(
  1727.                                                                                     FrameArray,0);
  1728.                                                                                 if (!TrackObjectInsertFrame(View->TrackObj,
  1729.                                                                                     Scan + View->InsertionPointIndex,Thing))
  1730.                                                                                     {
  1731.                                                                                         long                                Limit;
  1732.  
  1733.                                                                                         /* delete all the ones we added */
  1734.                                                                                         TrackObjectDeleteFrameRun(View->TrackObj,
  1735.                                                                                             View->InsertionPointIndex,Scan);
  1736.                                                                                         /* delete the ones we didn't add */
  1737.                                                                                         Limit = ArrayGetLength(FrameArray);
  1738.                                                                                         for (Scan = 0; Scan < Limit; Scan += 1)
  1739.                                                                                             {
  1740.                                                                                                 DisposeFrameAndContents(
  1741.                                                                                                     (FrameObjectRec*)ArrayGetElement(
  1742.                                                                                                     FrameArray,Scan));
  1743.                                                                                             }
  1744.                                                                                         goto ExitPoint;
  1745.                                                                                     }
  1746.                                                                                 ArrayDeleteElement(FrameArray,0);
  1747.                                                                                 Scan += 1;
  1748.                                                                             }
  1749.                                                                         /* remember undo information */
  1750.                                                                         View->UndoState = eTrackViewUndoRangeInsertion;
  1751.                                                                         View->UndoRangeStartIndex = View->InsertionPointIndex;
  1752.                                                                         View->UndoRangeElemCount = Scan;
  1753.                                                                         /* update display parameters */
  1754.                                                                         View->InsertionPointIndex += Scan;
  1755.                                                                         ERROR(View->InsertionPointIndex
  1756.                                                                             > TrackObjectGetNumFrames(View->TrackObj),
  1757.                                                                             PRERR(ForceAbort,"TrackViewAttemptPaste:  "
  1758.                                                                             "insertion point beyond end of track"));
  1759.                                                                         TotalSuccessFlag = True;
  1760.                                                                         TrackViewRedrawAll(View);
  1761.                                                                         View->CursorBarIsVisible = False; /* temporary */
  1762.                                                                         TrackViewShowSelection(View);
  1763.                                                                         /* jump here when something bad happens */
  1764.                                                                      ExitPoint:
  1765.                                                                         DisposeArray(FrameArray);
  1766.                                                                     }
  1767.                                                                 EndBufferedInput(BuffFile);
  1768.                                                             }
  1769.                                                     }
  1770.                                             }
  1771.                                         CloseFile(FileDesc);
  1772.                                     }
  1773.                                 DeleteFile(TempFileLoc);
  1774.                                 DisposeFileSpec(TempFileLoc);
  1775.                             }
  1776.                     }
  1777.                 ReleasePtr(Scrap);
  1778.             }
  1779.         return TotalSuccessFlag;
  1780.     }
  1781.  
  1782.  
  1783. /* copy the selected range to the clipboard.  it is an error if there is no selected */
  1784. /* range.  it returns True if successful. */
  1785. MyBoolean                                TrackViewCopyRangeSelection(TrackViewRec* View)
  1786.     {
  1787.         MyBoolean                            TotalSuccessFlag;
  1788.         ArrayRec*                            CopyOfSelection;
  1789.  
  1790.         CheckPtrExistence(View);
  1791.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1792.             "TrackViewDeleteRangeSelection:  called with no range selected"));
  1793.         TrackViewFlushUndoInfo(View);
  1794.         CopyOfSelection = TrackObjectCopyFrameRun(View->TrackObj,View->RangeSelectStart,
  1795.             View->RangeSelectEnd - View->RangeSelectStart);
  1796.         if (CopyOfSelection != NIL)
  1797.             {
  1798.                 long                                    Limit;
  1799.                 long                                    Scan;
  1800.                 FileSpec*                            TempFileLoc;
  1801.  
  1802.                 TempFileLoc = NewTempFileSpec(CODE4BYTES('\?','\?','\?','\?'),
  1803.                     CODE4BYTES('\?','\?','\?','\?'));
  1804.                 if (TempFileLoc != NIL)
  1805.                     {
  1806.                         FileType*                            FileDesc;
  1807.  
  1808.                         if (OpenFile(TempFileLoc,&FileDesc,eReadAndWrite))
  1809.                             {
  1810.                                 BufferedOutputRec*        BuffOut;
  1811.  
  1812.                                 BuffOut = NewBufferedOutput(FileDesc);
  1813.                                 if (BuffOut != NIL)
  1814.                                     {
  1815.                                         MyBoolean                            WriteSucceeded = False;
  1816.  
  1817.                                         if (WriteBufferedOutput(BuffOut,sizeof(MAGICSCRAPSTRING),
  1818.                                             MAGICSCRAPSTRING))
  1819.                                             {
  1820.                                                 if (eFileLoadNoError == WriteNoteVector(CopyOfSelection,BuffOut))
  1821.                                                     {
  1822.                                                         WriteSucceeded = True;
  1823.                                                     }
  1824.                                             }
  1825.                                         if (EndBufferedOutput(BuffOut) && WriteSucceeded)
  1826.                                             {
  1827.                                                 if (SetFilePosition(FileDesc,0))
  1828.                                                     {
  1829.                                                         char*                                    Scrap;
  1830.  
  1831.                                                         Scrap = AllocPtrCanFail(GetFileLength(FileDesc),
  1832.                                                             "TrackViewCopyRangeSelection:  scrap temp");
  1833.                                                         if (Scrap != NIL)
  1834.                                                             {
  1835.                                                                 if (0 == ReadFromFile(FileDesc,Scrap,PtrSize(Scrap)))
  1836.                                                                     {
  1837.                                                                         if (SetScrapToThis(Scrap))
  1838.                                                                             {
  1839.                                                                                 TotalSuccessFlag = True;
  1840.                                                                             }
  1841.                                                                     }
  1842.                                                                 ReleasePtr(Scrap);
  1843.                                                             }
  1844.                                                     }
  1845.                                             }
  1846.                                     }
  1847.                                 CloseFile(FileDesc);
  1848.                             }
  1849.                         DeleteFile(TempFileLoc);
  1850.                         DisposeFileSpec(TempFileLoc);
  1851.                     }
  1852.                 Limit = ArrayGetLength(CopyOfSelection);
  1853.                 for (Scan = 0; Scan < Limit; Scan += 1)
  1854.                     {
  1855.                         DisposeFrameAndContents((FrameObjectRec*)ArrayGetElement(
  1856.                             CopyOfSelection,Scan));
  1857.                     }
  1858.                 DisposeArray(CopyOfSelection);
  1859.             }
  1860.         return TotalSuccessFlag;
  1861.     }
  1862.  
  1863.  
  1864. /* cut the range selection (copy to clipboard, then delete).  returns True if */
  1865. /* successful.  it is an error if there is no range selected.  automatically */
  1866. /* updates undo information. */
  1867. MyBoolean                                TrackViewCutRangeSelection(TrackViewRec* View)
  1868.     {
  1869.         CheckPtrExistence(View);
  1870.         TrackViewFlushUndoInfo(View);
  1871.         if (TrackViewCopyRangeSelection(View))
  1872.             {
  1873.                 if (TrackViewDeleteRangeSelection(View))
  1874.                     {
  1875.                         return True;
  1876.                     }
  1877.             }
  1878.         return False;
  1879.     }
  1880.  
  1881.  
  1882. /* show the selection or insertion point by scrolling the view area */
  1883. void                                        TrackViewShowSelection(TrackViewRec* View)
  1884.     {
  1885.         long                                    CenteringIndex;
  1886.         long                                    PixelIndex;
  1887.  
  1888.         CheckPtrExistence(View);
  1889.         switch (View->SelectionMode)
  1890.             {
  1891.                 default:
  1892.                     EXECUTE(PRERR(ForceAbort,"TrackViewShowSelection:  illegal selection mode"));
  1893.                     break;
  1894.                 case eTrackViewNoSelection:
  1895.                     CenteringIndex = View->InsertionPointIndex;
  1896.                     break;
  1897.                 case eTrackViewSingleNoteSelection:
  1898.                 case eTrackViewSingleCommandSelection:
  1899.                     CenteringIndex = View->SelectedNoteFrame;
  1900.                     break;
  1901.                 case eTrackViewRangeSelection:
  1902.                     CenteringIndex = View->RangeSelectStart;
  1903.                     break;
  1904.             }
  1905.         if (CenteringIndex < TrackObjectGetNumFrames(View->TrackObj))
  1906.             {
  1907.                 if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  1908.                     CenteringIndex,&PixelIndex))
  1909.                     {
  1910.                         return;
  1911.                     }
  1912.             }
  1913.         else if (TrackObjectGetNumFrames(View->TrackObj) > 0)
  1914.             {
  1915.                 if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  1916.                     CenteringIndex - 1,&PixelIndex))
  1917.                     {
  1918.                         return;
  1919.                     }
  1920.             }
  1921.         else
  1922.             {
  1923.                 /* no frames at all. */
  1924.                 PixelIndex = 0;
  1925.             }
  1926.         PixelIndex -= View->Width / 2;
  1927.         if (PixelIndex < 0)
  1928.             {
  1929.                 PixelIndex = 0;
  1930.             }
  1931.         TrackViewSetNewHorizontalOffset(View,PixelIndex);
  1932.     }
  1933.  
  1934.  
  1935. /* find out if we can undo the last operation */
  1936. MyBoolean                                TrackViewCanWeUndo(TrackViewRec* View)
  1937.     {
  1938.         CheckPtrExistence(View);
  1939.         return (eTrackViewNoUndo != View->UndoState);
  1940.     }
  1941.  
  1942.  
  1943. /* dispose of all undo information. */
  1944. void                                        TrackViewFlushUndoInfo(TrackViewRec* View)
  1945.     {
  1946.         CheckPtrExistence(View);
  1947.         switch (View->UndoState)
  1948.             {
  1949.                 default:
  1950.                     EXECUTE(PRERR(ForceAbort,"TrackViewFlushUndoInfo:  bad undo state"));
  1951.                     break;
  1952.                 case eTrackViewNoUndo:
  1953.                 case eTrackViewUndoNoteInsertion:
  1954.                 case eTrackViewUndoRangeInsertion:
  1955.                     break;
  1956.                 case eTrackViewUndoFromFile:
  1957.                     CloseFile(View->UndoTempFileDesc);
  1958.                     DeleteFile(View->UndoTempFileLoc);
  1959.                     DisposeFileSpec(View->UndoTempFileLoc);
  1960.                     break;
  1961.             }
  1962.         View->UndoState = eTrackViewNoUndo;
  1963.     }
  1964.  
  1965.  
  1966. /* save the undo information for the track.  returns False if it fails. */
  1967. MyBoolean                                TrackViewBuildFullUndoBackingStore(TrackViewRec* View)
  1968.     {
  1969.         BufferedOutputRec*        Output;
  1970.  
  1971.         CheckPtrExistence(View);
  1972.         TrackViewFlushUndoInfo(View);
  1973.         ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  1974.             "TrackViewBuildFullUndoBackingStore:  expected undo information to be purged"));
  1975.         /* make backups (see, even my programs do it!) */
  1976.         View->UndoTempFileLoc = NewTempFileSpec(CODE4BYTES('\?','\?','\?','\?'),
  1977.             CODE4BYTES('\?','\?','\?','\?'));
  1978.         if (View->UndoTempFileLoc == NIL)
  1979.             {
  1980.              FailurePoint1:
  1981.                 return False;
  1982.             }
  1983.         if (!OpenFile(View->UndoTempFileLoc,&(View->UndoTempFileDesc),eReadAndWrite))
  1984.             {
  1985.              FailurePoint2:
  1986.                 DeleteFile(View->UndoTempFileLoc);
  1987.                 DisposeFileSpec(View->UndoTempFileLoc);
  1988.                 goto FailurePoint1;
  1989.             }
  1990.         Output = NewBufferedOutput(View->UndoTempFileDesc);
  1991.         if (Output == NIL)
  1992.             {
  1993.              FailurePoint3:
  1994.                 CloseFile(View->UndoTempFileDesc);
  1995.                 goto FailurePoint2;
  1996.             }
  1997.         if (!TrackObjectWriteNotesOutToFile(View->TrackObj,Output))
  1998.             {
  1999.              FailurePoint3a:
  2000.                 EndBufferedOutput(Output);
  2001.                 goto FailurePoint3;
  2002.             }
  2003.         if (!EndBufferedOutput(Output))
  2004.             {
  2005.              FailurePoint4:
  2006.                 goto FailurePoint3;
  2007.             }
  2008.         View->UndoState = eTrackViewUndoFromFile;
  2009.         return True;
  2010.     }
  2011.  
  2012.  
  2013. /* undo the last operation.  if it fails, well... */
  2014. void                                        TrackViewUndo(TrackViewRec* View)
  2015.     {
  2016.         UndoChoices                        LocalUndoState;
  2017.         long                                    LocalUndoNoteInsertionFrameIndex;
  2018.         long                                    LocalUndoNoteInsertionNoteIndex;
  2019.         long                                    LocalUndoRangeStartIndex;
  2020.         long                                    LocalUndoRangeElemCount;
  2021.         FileSpec*                            LocalUndoTempFileLoc;
  2022.         FileType*                            LocalUndoTempFileDesc;
  2023.  
  2024.         CheckPtrExistence(View);
  2025.         /* first, make a backup of the undo information, so we can undo the undo */
  2026.         LocalUndoState = View->UndoState;
  2027.         LocalUndoNoteInsertionFrameIndex = View->UndoNoteInsertionFrameIndex;
  2028.         LocalUndoNoteInsertionNoteIndex = View->UndoNoteInsertionNoteIndex;
  2029.         LocalUndoRangeStartIndex = View->UndoRangeStartIndex;
  2030.         LocalUndoRangeElemCount = View->UndoRangeElemCount;
  2031.         LocalUndoTempFileLoc = View->UndoTempFileLoc;
  2032.         LocalUndoTempFileDesc = View->UndoTempFileDesc;
  2033.         /* reset the undo state */
  2034.         View->UndoState = eTrackViewNoUndo;
  2035.         /* build backup for our undo */
  2036.         if (!TrackViewBuildFullUndoBackingStore(View))
  2037.             {
  2038.                 switch (AskYesNoCancel("There is not enough disk space available to preserve "
  2039.                     "undo information.  Continue?",NIL,"Continue","Cancel",NIL))
  2040.                     {
  2041.                         default:
  2042.                             EXECUTE(PRERR(ForceAbort,
  2043.                                 "TrackViewDeleteSingleNoteOrCommand:  bad value from AskYesNoCancel"));
  2044.                             break;
  2045.                         case eYes:
  2046.                             /* continue */
  2047.                             break;
  2048.                         case eNo:
  2049.                             /* abort now -- restore the undo information */
  2050.                             View->UndoState = LocalUndoState;
  2051.                             View->UndoNoteInsertionFrameIndex = LocalUndoNoteInsertionFrameIndex;
  2052.                             View->UndoNoteInsertionNoteIndex = LocalUndoNoteInsertionNoteIndex;
  2053.                             View->UndoRangeStartIndex = LocalUndoRangeStartIndex;
  2054.                             View->UndoRangeElemCount = LocalUndoRangeElemCount;
  2055.                             View->UndoTempFileLoc = LocalUndoTempFileLoc;
  2056.                             View->UndoTempFileDesc = LocalUndoTempFileDesc;
  2057.                             return;
  2058.                     }
  2059.             }
  2060.         /* do the undoing */
  2061.         switch (LocalUndoState)
  2062.             {
  2063.                 default:
  2064.                     EXECUTE(PRERR(ForceAbort,"TrackViewUndo:  bad undo state"));
  2065.                     break;
  2066.                 case eTrackViewUndoNoteInsertion:
  2067.                     /* delete the note */
  2068.                     {
  2069.                         FrameObjectRec*            Frame;
  2070.  
  2071.                         Frame = TrackObjectGetFrame(View->TrackObj,LocalUndoNoteInsertionFrameIndex);
  2072.                         if (NumNotesInFrame(Frame) == 1)
  2073.                             {
  2074.                                 /* delete whole frame */
  2075.                                 TrackObjectDeleteFrameRun(View->TrackObj,
  2076.                                     LocalUndoNoteInsertionFrameIndex,1);
  2077.                             }
  2078.                          else
  2079.                             {
  2080.                                 NoteObjectRec*            Note;
  2081.  
  2082.                                 /* just delete a note from the frame */
  2083.                                 Note = GetNoteFromFrame(Frame,LocalUndoNoteInsertionNoteIndex);
  2084.                                 if (!IsItACommand(Note))
  2085.                                     {
  2086.                                         TrackObjectNullifyTies(View->TrackObj,Note);
  2087.                                     }
  2088.                                 DeleteNoteFromFrame(Frame,LocalUndoNoteInsertionNoteIndex);
  2089.                             }
  2090.                     }
  2091.                     break;
  2092.                 case eTrackViewUndoRangeInsertion:
  2093.                     TrackObjectDeleteFrameRun(View->TrackObj,LocalUndoRangeStartIndex,
  2094.                         LocalUndoRangeElemCount);
  2095.                     break;
  2096.                 case eTrackViewUndoFromFile:
  2097.                     /* recover all the notes from the file */
  2098.                     if (SetFilePosition(LocalUndoTempFileDesc,0))
  2099.                         {
  2100.                             BufferedInputRec*            Input;
  2101.  
  2102.                             Input = NewBufferedInput(LocalUndoTempFileDesc);
  2103.                             if (Input != NIL)
  2104.                                 {
  2105.                                     if (TrackObjectRecoverNotesFromFile(View->TrackObj,Input))
  2106.                                         {
  2107.                                             /* successful */
  2108.                                         }
  2109.                                     EndBufferedInput(Input);
  2110.                                 }
  2111.                         }
  2112.                     CloseFile(LocalUndoTempFileDesc);
  2113.                     DeleteFile(LocalUndoTempFileLoc);
  2114.                     DisposeFileSpec(LocalUndoTempFileLoc);
  2115.                     break;
  2116.             }
  2117.         TrackViewRedrawAll(View);
  2118.         View->CursorBarIsVisible = False; /* temporary */
  2119.     }
  2120.  
  2121.  
  2122. /* transpose the selection by adding AddHalfSteps to the pitch of each selected note */
  2123. /* AddHalfSteps can be negative.  it is an error if there is no single note selection */
  2124. /* or no range selection */
  2125. void                                        TrackViewTransposeSelection(TrackViewRec* View, long AddHalfSteps)
  2126.     {
  2127.         CheckPtrExistence(View);
  2128.         TrackViewFlushUndoInfo(View);
  2129.         if (TrackViewIsASingleNoteSelected(View))
  2130.             {
  2131.                 long                                    NewPitch;
  2132.  
  2133.                 NewPitch = GetNotePitch(View->SelectedNote) + AddHalfSteps;
  2134.                 if (NewPitch < 0)
  2135.                     {
  2136.                         NewPitch = 0;
  2137.                     }
  2138.                 else if (NewPitch > NUMNOTES - 1)
  2139.                     {
  2140.                         NewPitch = NUMNOTES - 1;
  2141.                     }
  2142.                 PutNotePitch(View->SelectedNote,NewPitch);
  2143.                 switch (NewPitch % 12)
  2144.                     {
  2145.                         case 0: /* C */
  2146.                         case 2: /* D */
  2147.                         case 4: /* E */
  2148.                         case 5: /* F */
  2149.                         case 7: /* G */
  2150.                         case 9: /* A */
  2151.                         case 11: /* B */
  2152.                             PutNoteFlatOrSharpStatus(View->SelectedNote,0);
  2153.                             break;
  2154.                         case 1: /* C# / Db */
  2155.                         case 3: /* D# / Eb */
  2156.                         case 6: /* F# / Gb */
  2157.                         case 8: /* G# / Ab */
  2158.                         case 10: /* A# / Bb */
  2159.                             if (AddHalfSteps >= 0)
  2160.                                 {
  2161.                                     if (GetNoteFlatOrSharpStatus(View->SelectedNote) == eFlatModifier)
  2162.                                         {
  2163.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eFlatModifier);
  2164.                                         }
  2165.                                      else
  2166.                                         {
  2167.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eSharpModifier);
  2168.                                         }
  2169.                                 }
  2170.                              else
  2171.                                 {
  2172.                                     if (GetNoteFlatOrSharpStatus(View->SelectedNote) == eSharpModifier)
  2173.                                         {
  2174.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eSharpModifier);
  2175.                                         }
  2176.                                      else
  2177.                                         {
  2178.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eFlatModifier);
  2179.                                         }
  2180.                                 }
  2181.                             break;
  2182.                     }
  2183.             }
  2184.         else if (TrackViewIsARangeSelected(View))
  2185.             {
  2186.                 long                                    FrameScan;
  2187.  
  2188.                 for (FrameScan = View->RangeSelectStart; FrameScan < View->RangeSelectEnd;
  2189.                     FrameScan += 1)
  2190.                     {
  2191.                         FrameObjectRec*                Frame;
  2192.  
  2193.                         Frame = TrackObjectGetFrame(View->TrackObj,FrameScan);
  2194.                         CheckPtrExistence(Frame);
  2195.                         if (!IsThisACommandFrame(Frame))
  2196.                             {
  2197.                                 long                                    NoteScan;
  2198.                                 long                                    NoteLimit;
  2199.  
  2200.                                 NoteLimit = NumNotesInFrame(Frame);
  2201.                                 for (NoteScan = 0; NoteScan < NoteLimit; NoteScan += 1)
  2202.                                     {
  2203.                                         NoteObjectRec*                Note;
  2204.                                         long                                    NewPitch;
  2205.  
  2206.                                         Note = GetNoteFromFrame(Frame,NoteScan);
  2207.                                         CheckPtrExistence(Note);
  2208.                                         NewPitch = GetNotePitch(Note) + AddHalfSteps;
  2209.                                         if (NewPitch < 0)
  2210.                                             {
  2211.                                                 NewPitch = 0;
  2212.                                             }
  2213.                                         else if (NewPitch > NUMNOTES - 1)
  2214.                                             {
  2215.                                                 NewPitch = NUMNOTES - 1;
  2216.                                             }
  2217.                                         PutNotePitch(Note,NewPitch);
  2218.                                         switch (NewPitch % 12)
  2219.                                             {
  2220.                                                 case 0: /* C */
  2221.                                                 case 2: /* D */
  2222.                                                 case 4: /* E */
  2223.                                                 case 5: /* F */
  2224.                                                 case 7: /* G */
  2225.                                                 case 9: /* A */
  2226.                                                 case 11: /* B */
  2227.                                                     PutNoteFlatOrSharpStatus(Note,0);
  2228.                                                     break;
  2229.                                                 case 1: /* C# / Db */
  2230.                                                 case 3: /* D# / Eb */
  2231.                                                 case 6: /* F# / Gb */
  2232.                                                 case 8: /* G# / Ab */
  2233.                                                 case 10: /* A# / Bb */
  2234.                                                     if (AddHalfSteps >= 0)
  2235.                                                         {
  2236.                                                             if (GetNoteFlatOrSharpStatus(Note) == eFlatModifier)
  2237.                                                                 {
  2238.                                                                     PutNoteFlatOrSharpStatus(Note,eFlatModifier);
  2239.                                                                 }
  2240.                                                              else
  2241.                                                                 {
  2242.                                                                     PutNoteFlatOrSharpStatus(Note,eSharpModifier);
  2243.                                                                 }
  2244.                                                         }
  2245.                                                      else
  2246.                                                         {
  2247.                                                             if (GetNoteFlatOrSharpStatus(Note) == eSharpModifier)
  2248.                                                                 {
  2249.                                                                     PutNoteFlatOrSharpStatus(Note,eSharpModifier);
  2250.                                                                 }
  2251.                                                              else
  2252.                                                                 {
  2253.                                                                     PutNoteFlatOrSharpStatus(Note,eFlatModifier);
  2254.                                                                 }
  2255.                                                         }
  2256.                                                     break;
  2257.                                             }
  2258.                                     }
  2259.                             }
  2260.                     }
  2261.             }
  2262.         else
  2263.             {
  2264.                 EXECUTE(PRERR(ForceAbort,"TrackViewTransposeSelection:  improper selection"));
  2265.             }
  2266.         TrackViewRedrawAll(View);
  2267.         View->CursorBarIsVisible = False; /* temporary */
  2268.     }
  2269.  
  2270.  
  2271. /* scroll to the specified measure.  invalid measure numbers may be specified. */
  2272. void                                        TrackViewShowMeasure(TrackViewRec* View, long MeasureNumber)
  2273.     {
  2274.         long                                    FrameIndex;
  2275.  
  2276.         CheckPtrExistence(View);
  2277.         if (!TrackDisplayMeasureIndexToFrame(View->Schedule,MeasureNumber,&FrameIndex))
  2278.             {
  2279.                 ErrorBeep();
  2280.             }
  2281.          else
  2282.             {
  2283.                 long                                    PixelIndex;
  2284.  
  2285.                 if (FrameIndex < TrackObjectGetNumFrames(View->TrackObj))
  2286.                     {
  2287.                         if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  2288.                             FrameIndex,&PixelIndex))
  2289.                             {
  2290.                                 return;
  2291.                             }
  2292.                     }
  2293.                 else if (TrackObjectGetNumFrames(View->TrackObj) > 0)
  2294.                     {
  2295.                         if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  2296.                             FrameIndex - 1,&PixelIndex))
  2297.                             {
  2298.                                 return;
  2299.                             }
  2300.                     }
  2301.                 else
  2302.                     {
  2303.                         /* no frames at all. */
  2304.                         PixelIndex = 0;
  2305.                     }
  2306.                 PixelIndex -= (View->Width / 3);
  2307.                 if (PixelIndex < 0)
  2308.                     {
  2309.                         PixelIndex = 0;
  2310.                     }
  2311.                 TrackViewSetNewHorizontalOffset(View,PixelIndex);
  2312.             }
  2313.     }
  2314.