/* @(#) 1.3 com/src/samples/staff/iodstaff.cpp, odstaffpart, od96nt, odnt9712d 11/1/96 21:00:53 [3/21/97 17:38:14] */
//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: odother
//
//   CLASSES: none
//
//   ORIGINS: 82,27
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//   	
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//

// ---- Staff Part --------------------------------------------------------
//
//
//

#ifndef OpenDoc_Sample_StaffPart
#include "iodstaff.h"
#endif



// ---- StaffModel ----------------------------------------------------------
//
//      The StaffModel class manages the song content (notes, rests, key sig)
//
//



// Constructors / Destructors

StaffModel::StaffModel() : iNote(0), nNote(0)    { }
StaffModel::StaffModel(const StaffModel& model)  { }
StaffModel::~StaffModel()                        { }

void StaffModel::ClearSong(void) {
    iNote=0;
    nNote=0;

    fNote[nNote]=0;
    fType[nNote]=0;
    }

void StaffModel::PlaySong(void) {
    short i, note, type, duration, mSecs;
    char wavFile[24];

    for( i=First(); !AtEnd(); i=Next() ) {
        GetNote(note,type);

        sprintf(wavFile,"key%02d.wav",note);
        qprintf(wavFile);
        qprintf("\n");
        PlaySound(wavFile, NULL, SND_FILENAME | SND_ASYNC);

        switch (type) {
            case CMD(WholeNote):   duration=8; break;
            case CMD(HalfNote):    duration=4; break;
            case CMD(QuarterNote): duration=2; break;
            case CMD(EighthNote):  duration=1; break;
        }

        mSecs=325*duration;             // sleep needs millisecs
        SleepEx(mSecs,FALSE);           // sleep until time is up
        PlaySound(NULL, NULL, NULL);    // then turn off sound
        }
    }


// Getters and Setters
void    StaffModel::GetNote         (short &aNote, short &aType) {
  aNote=fNote[iNote];
  aType=fType[iNote];
  }

void    StaffModel::SetNote         (short  aNote, short  aType) {
  fNote[iNote]=aNote;
  fType[iNote]=aType;
  qprintf("SetNote: nNote=%d, iNote=%d, fNote[iNote]=%d, fType[iNote]=%d\n",
          nNote, iNote, fNote[iNote], fType[iNote]);
  }

// iterator functions
short   StaffModel::First   (void) { iNote=0;     return iNote; }
short   StaffModel::Next    (void) { iNote++; if(iNote>nNote) nNote=iNote; return iNote; }
short   StaffModel::Prev    (void) {
    iNote--;

    if(iNote<0) iNote=0;

    fNote[iNote]=0;
    fType[iNote]=0;
    nNote=iNote;

    return iNote;
    }
short   StaffModel::Last    (void) { iNote=nNote; return iNote;}

short   StaffModel::AtEnd   (void) {
    short tf;

    if( iNote < 0 ) {
      iNote=0;
      tf=1;
      }

    else if (iNote==nNote) {
      tf=1;
      }

    else tf=0;

    return tf;
    }




// -------------------------------------------------------------------------
// -----                                                               -----
// -----                  StaffPart     Class                          -----
// -----                                                               -----
// -----              Overriding Inherited Methods                     -----
// -----                                                               -----
// -------------------------------------------------------------------------




// ---- somInit ------------------------------------------------------------
//
//      Initializes the instance variables in the SOMObject of this part.
//
//      -> does not call parent method (called automatically by SOM)
//      -> optional for all parts
//      -> somInit must NOT fail (code that might fail goes to InitPart)
//
//


SOM_Scope void  SOMLINK StaffPartsomInit(StaffPart *somSelf)
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartsomInit");

    //  (1) call parent's method before starting
    StaffPart_parent_BaseContainer_somInit(somSelf);

    //  (2) initialize StaffPart attributes
    _fSession         = kODNULL;
    _fMenuBar         = kODNULL;
    _fStatusMsg       = kODNULL;

}




// ---- somUninit -------------------------------------------------------
//
//      Disposes of storage for the SOMObject of this part.
//
//      -> optional for all parts
//      -> somUninit must NOT fail



SOM_Scope       void
SOMLINK         StaffPartsomUninit
                (
                StaffPart   *somSelf        // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartsomUninit");

    // call parent's method after you're finished and before you exit
    StaffPart_parent_BaseContainer_somUninit(somSelf);

}



// ---- HasExtension ----------------------------------------------------
//
// Description:   The HasExtension method is queried by other parts to
//                see what "extensions" are available. For the STAFF part
//                the ToStaffPart method can be called to update the
//                song table.
//


SOM_Scope       ODBoolean
SOMLINK         StaffPartHasExtension
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODType          extName         // in
                )

{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartHasExtension");

    ODBoolean doWeHandleIt;

    if(strcmp(extName,kStaffExtension)==0) {
      doWeHandleIt=kODTrue;
      }
    else {
      // call parent's method after you're finished and before you exit
      doWeHandleIt=StaffPart_parent_BaseContainer_HasExtension(somSelf,ev,extName);
      }

    qprintf("Do we handle it? %d %s==%s\n",doWeHandleIt,extName,kStaffExtension);
    return doWeHandleIt;
}


// ---- HandleMouseUp ----------------------------------------------------
//
// Description:   The HandleMouseUp method recieves mouse-up events
//                and saves the point of where it occurred. Using
//                the facet dimensions, HandleMouseUp determines
//                which square was selected on the TicTacToe board.
//


SOM_Scope       ODBoolean
SOMLINK         StaffPartHandleMouseUp
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODEventData     *event,         // in
                ODFrame         *frame,         // in
                ODFacet         *facet,         // in
                ODEventInfo     *eventInfo      // inout
                )
{
   StaffPartData *somThis = StaffPartGetData(somSelf);
   StaffPartMethodDebug("StaffPart","StaffPartHandleMouseUp");

   ODBoolean   eventHandled     = kODTrue;

   try
   {
      if ( facet != kODNULL && somSelf->ActivateFrame(ev, frame))
      {
         TempODTransform xform = facet->AcquireWindowFrameTransform(ev,kODNULL);

         // Get Bounding Box in OD coords
         TempODShape shape = frame->AcquireFrameShape(ev,facet->GetCanvas(ev));

         ODRect odRect;
         shape->GetBoundingBox(ev,&odRect);

         // Now convert to windows coords
         Rect winRect;

         SetRect(&winRect, FixedToInt(odRect.left),
                           FixedToInt(odRect.top),
                           FixedToInt(odRect.right),
                           FixedToInt(odRect.bottom));

         // Next determine dimensions of a game square
         int xBox = (winRect.right - winRect.left)/3;
         int yBox = (winRect.bottom - winRect.top)/3;

         // Extract the mouse position from the event params
         ODPoint mousePt;
         mousePt.x = ODIntToFixed(LOWORD(event->lParam));
         mousePt.y = ODIntToFixed(HIWORD(event->lParam));

         // Transform to the embedded game's coords
         xform->InvertPoint(ev,&mousePt);

         // and calculate the selected square
         int  xMove    = ODFixedRound(mousePt.x)/xBox;
         int  yMove    = ODFixedRound(mousePt.y)/yBox;

         eventHandled=StaffPart_parent_BaseContainer_HandleMouseUp(somSelf, ev,
                            event,frame, facet, eventInfo);

         facet->Invalidate(ev,kODNULL,kODNULL);
      }   // end of if we have a FACET

      else
         eventHandled=kODFalse;

    }
    catch(...)
    {
    }

    return eventHandled;

}



// ---- Draw ------------------------------------------------------------
//
//      The Draw method is called each time the screen needs to be redrawn
//      either due to resizing, window overlap, or update calls.
//
//

SOM_Scope       void
SOMLINK         StaffPartDraw
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODFacet         *facet,         // in
                ODShape         *invalidShape   // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartDraw");


    try
    {
        StaffPart_parent_BaseContainer_Draw(somSelf,ev,facet,invalidShape);

        // get the drawing canvas
        ODWin32Canvas *pc = (ODWin32Canvas *)facet->GetCanvas(ev)->GetPlatformCanvas(ev,kODWin32);

        // do we have the window if not then no need to draw anything
        if(pc->HasWindow(ev))
        {
            // yes, then get a Windows device context
            ODFrame* displayFrame = facet->GetFrame(ev);

            // Get the frame bounding rectangle and convert to Window's rectangle
            ODRect rect;
            TempODShape shape = displayFrame->AcquireFrameShape(ev, facet->GetCanvas(ev));


            shape->GetBoundingBox(ev, &rect);
            Rect frameRect;
               SetRect(&frameRect, FixedToInt(rect.left),
                       FixedToInt(rect.top),
                       FixedToInt(rect.right),
                       FixedToInt(rect.bottom));

            HDC hdc;



            // Use the focuslib code to set up transforms and clipping
            CFocus Focus(facet, invalidShape, &hdc);

            // Create a solid PARCHMENT brush
            HBRUSH hbr;
            hbr=CreateSolidBrush(RGB(255,255,128));

            // Fill the Window background with the brush
            FillRect (hdc, &frameRect, hbr);

            // Get rid of the brush
            DeleteObject (hbr);

            // Compute the sheet music dimensions
            _fLineSpace    = (frameRect.bottom - frameRect.top)/24.0;
            _fMeasureSpace = (frameRect.right - frameRect.left)/12.0;

            // Set up a font for the text - ensure it doesn't get too small
            LOGFONT labelFont;
            memset(&labelFont, 0, sizeof(labelFont));
            labelFont.lfPitchAndFamily = FF_SCRIPT;
            labelFont.lfItalic = 1;
            labelFont.lfHeight = (frameRect.bottom - frameRect.top) / 8;
            if(labelFont.lfHeight<8) labelFont.lfHeight=8;
            labelFont.lfQuality = PROOF_QUALITY;
            lstrcpy((LPSTR)labelFont.lfFaceName, (LPSTR)"Cursive");

            // Create the font and select it
            HFONT hFont = CreateFontIndirect(&labelFont);
            HFONT hOldFont;
            hOldFont = SelectObject(hdc, hFont);

            // Set background to transparent and text color to white
            SetBkMode(hdc, TRANSPARENT);
            SetTextColor(hdc, 0x00FF0000);

            // draw status line
            DrawText(hdc,
                     _fStatusMsg,
                     strlen(_fStatusMsg),
                     &frameRect,
                     DT_CENTER | DT_SINGLELINE);

            // Restore the old font settings
            SelectObject(hdc, hOldFont);
            DeleteObject(hFont);

            somSelf->DrawSelectionBorder (ev, facet, invalidShape);

            HPEN hPen, hOldPen;

            // Create a thin (1 pixel) BLACK pen
            hPen=CreatePen(PS_SOLID, 1, RGB(0,0,0));

            // Select it and save the old pen for restoration
            hOldPen=SelectObject(hdc,hPen);

            for(int i=0; i<11; i++) {

                // draw the Measure Spacers
                int spcOffset = frameRect.left + (i+1)*_fMeasureSpace;
                POINT vLine[] = { {spcOffset, frameRect.top + 4*_fLineSpace},
                                  {spcOffset, frameRect.top + 14*_fLineSpace} };
                Polyline(hdc,vLine,2);
                }


            // restore Old Pen settings
            SelectObject(hdc, hOldPen);
            DeleteObject(hPen);


            // Create a thick (3 pixel) DARK GRAY pen
            hPen=CreatePen(PS_SOLID, 3, RGB( 96, 96, 96 ) );

            // Select it and save the old pen for restoration
            hOldPen=SelectObject(hdc,hPen);

            // draw the horizontals
            int spcOffset = frameRect.left + _fMeasureSpace;
            for (i=0; i<11; i++) {

                POINT hLine[] = { {spcOffset,  frameRect.top + (i+4)*_fLineSpace},
                                  {spcOffset + 10.0*_fMeasureSpace, frameRect.top + (i+4)*_fLineSpace}  };

                if (i != 5 ) Polyline(hdc,hLine,2);

                }

            // restore Old Pen Settings
            SelectObject(hdc,hOldPen);
            DeleteObject(hPen);

            // draw the notes onto the staff
            int penWidth = _fLineSpace * 0.9;

            HBRUSH hbr1=CreateSolidBrush(RGB(0,0,0));
            HBRUSH hbr2=CreateSolidBrush(RGB(128,128,255));

            float xPos1 = frameRect.left + _fMeasureSpace;
            float yPos1 = frameRect.top + 16*_fLineSpace;
            float xPos2, yPos2;

            short note, type, duration;

            for( i=_fStaffModel->First(); !_fStaffModel->AtEnd(); i=_fStaffModel->Next() ) {

                _fStaffModel->GetNote(note,type);

                switch (type) {
                    case CMD(WholeNote):   duration=8; break;
                    case CMD(HalfNote):    duration=4; break;
                    case CMD(QuarterNote): duration=2; break;
                    case CMD(EighthNote):  duration=1; break;
                    }

                // do we have a note or a rest
                if(note>=0) hbr=hbr1;
                else {
                  note=28;      // draw rest on middle C line
                  hbr=hbr2;
                  }

                // line length = duration of note
                xPos2=xPos1 + _fMeasureSpace*0.125*duration;
                yPos2=yPos1 - _fLineSpace*0.5*(note/2 + 1);

                Rect noteRect = { xPos1, yPos2, xPos2, (yPos2+penWidth) };

                // do we have a note or rest (draw white for rest)
                SelectObject(hdc,hbr);
                FillRect(hdc,&noteRect,hbr);

                // position offset for next note
                xPos1=xPos2;

                }

            // remove brush from device context
            DeleteObject(hbr1);
            DeleteObject(hbr2);

        } // end of DO-WE-HAVE-A-WINDOW


    }
    catch(...)
    {
    }


}




// ---- Initialize -----------------------------------------------------
//
//      The Initialize method is called each time a Staff is first started
//      in OpenDoc. It creates the Staff menu and calls its parent to
//      create the part embedding menu.
//
//


SOM_Scope       void
SOMLINK         StaffPartInitialize
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODPart          *partWrapper    // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart", "StaffPartInitialize");


    try
    {

        // call the parent to initialize the Container features
        StaffPart_parent_BaseContainer_Initialize(somSelf, ev, partWrapper);

        _fPartWrapper=partWrapper;

        // Establish part's locale
        nl_catd nlsCat;                 // NLS message catalog handle
        char *nlsText;                   // pointer for NLS message

        setlocale(LC_ALL,"");

        nlsCat=catopen(SS_NLS_CATALOG, NL_CAT_LOCALE);

        // Initialize Game Engine
        _fStaffModel = new StaffModel();


        // Initialize the Staff message and Status Message
        _fStaffMsg=catgets(nlsCat, SS_MSG_SET, SS_STAFF_TITLE, "I B M");
        _fStatusMsg=_fStaffMsg;


        _fOctaves=4;
        _fWhiteKeys= _fOctaves * 7 ;


         //-------//   Create MenuBar for StaffPart Part   //------//

        _fMenuBar = somSelf->GetMenuBar(ev);

        _fMenuBar->Acquire(ev);

        // add Staff menu to MenuBar line
        ODPlatformMenu newMenu = (ODPlatformMenu)CreateMenu();
        ODPlatformMenuItem *mi = new ODPlatformMenuItem;

        mi->id=kODStaffMenuID;
        _fMenuBar->AddMenuLast(ev, kODStaffMenuID, newMenu, _fPartWrapper);

        mi->afAttribute=0;                      //  use default attributes
        nlsText=catgets(nlsCat, SS_MSG_SET, SS_STAFFMENU, "Staff");
        _fMenuBar->SetMenuItemText(ev, ID_BASEMENUBAR, mi->id, nlsText);

        // add CLEAR Staff selection item to Staff menu
        mi->id=CMD(ClearSong);
        _fMenuBar->AddMenuItemLast(ev, kODStaffMenuID, kODNULL, mi);
        nlsText=catgets(nlsCat, SS_MSG_SET, SS_CLEARSONG, "Clear Song");
        _fMenuBar->SetMenuItemText(ev, kODStaffMenuID, mi->id, nlsText);

        // add PLAY Staff selection item to Staff menu
        mi->id=CMD(PlaySong);
        _fMenuBar->AddMenuItemLast(ev, kODStaffMenuID, kODNULL, mi);
        nlsText=catgets(nlsCat, SS_MSG_SET, SS_PLAYSONG, "Play Song");
        _fMenuBar->SetMenuItemText(ev, kODStaffMenuID, mi->id, nlsText);


        // we can now release the MenuBar
        _fMenuBar->Release(ev);

        delete mi;                      // cleanup menuitem buffer
        catclose(nlsCat);               // close the message catalog


    }
    catch(...)
    {
    }

}



// ---- ReadContents ---------------------------------------------------
//
//      The ReadContents method retrieves a suspended song from Bento
//      storage.
//
//

SOM_Scope       void
SOMLINK         StaffPartReadContents
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODStorageUnit   *fromSU,        // in
                BCCloneInfo     *cloneInfo,     // in
                BCTransferKind  readKind        // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartReadContents");


    try
    {
        // call parent's ReadContents
        StaffPart_parent_BaseContainer_ReadContents(somSelf, ev,
                                                     fromSU, cloneInfo,
                                                     readKind);

        if ( fromSU->Exists(ev, kODPropContents, kStaffProp, 0) )
        {
            fromSU->Focus(ev, kODPropContents, kODPosUndefined, kStaffProp, 0, kODPosUndefined);

            // first read back the number of notes in the array
            short noteCount;
            StorageUnitGetValue(fromSU, ev, sizeof(short), (ODValue)&noteCount );

            // next write out the note/type pair
            short note, type;

            for (short i=0; i<noteCount; i++, _fStaffModel->Next()) {
              StorageUnitGetValue(fromSU, ev, sizeof(short), (ODValue)&note );
              StorageUnitGetValue(fromSU, ev, sizeof(short), (ODValue)&type );
              _fStaffModel->SetNote(note, type);
              }
        }

    }
    catch(...)
    {
    }


}


// ---- WriteContents -------------------------------------------------
//
//      This method saves a song to Bento storage for retrieval at a
//      later date.
//
//

SOM_Scope       void
SOMLINK         StaffPartWriteContents
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODStorageUnit   *toSU,          // in
                BCCloneInfo     *cloneInfo,     // in
                BCTransferKind  writeKind       // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart", "StaffPartWriteContents");

    try
    {
        // call parent's WriteContents
        StaffPart_parent_BaseContainer_WriteContents(somSelf, ev,
                                                      toSU, cloneInfo,
                                                      writeKind);
        // Ensure a StaffPart property is present
        if (!toSU->Exists(ev, kODPropContents, kStaffProp, 0) )
             toSU->AddProperty(ev,kODPropContents)->AddValue(ev,kStaffProp);

        // first write out the number of notes in the array
        toSU->Focus(ev, kODPropContents, kODPosUndefined, kStaffProp, 0, kODPosUndefined);
        short noteCount=_fStaffModel->Last();

        StorageUnitSetValue(toSU, ev, sizeof(short), (ODValue)&noteCount );

        // next write out the note/tpe pair
        short note, type;

        for ( _fStaffModel->First();
                    !_fStaffModel->AtEnd();
                             _fStaffModel->Next()) {

          _fStaffModel->GetNote(note, type);

          StorageUnitSetValue(toSU, ev, sizeof(short), (ODValue)&note );
          StorageUnitSetValue(toSU, ev, sizeof(short), (ODValue)&type );
          }

    }
    catch(...)
    {
    }


}



// ---- HandleMenuEvent ---------------------------------------------------
//
//      This method handles the StaffParts pulldown menus.
//
//

SOM_Scope       ODBoolean
SOMLINK         StaffPartHandleMenuEvent
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODFrame         *frame,         // in
                ODEventData     *event          // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartHandleMenuEvent");

    ODBoolean   eventHandled     = kODFalse;

    try
    {

        switch(LOWORD(event->wParam)) // determine which menu pulldown it was
        {
            case CMD(ClearSong):
                 _fStaffModel->ClearSong();
                 frame->Invalidate(ev,kODNULL,kODNULL);
                 eventHandled=kODTrue;
                 break;

            case CMD(PlaySong):
                 _fStaffModel->PlaySong();
                 eventHandled=kODTrue;
                 break;

            default:
                 eventHandled=StaffPart_parent_BaseContainer_HandleMenuEvent(somSelf,ev,frame,event);
                 break;

        } // endswitch which menu pulldown?


    }
    catch(...)
    {
    }

    return eventHandled;

} // StaffPartHandleMenuEvent()




// -------------------------------------------------------------------------
// -----                                                               -----
// -----                  StaffPart    Class                          -----
// -----                                                               -----
// -----              StaffPart Specific  Methods                      -----
// -----                                                               -----
// -------------------------------------------------------------------------




// ---- PlaySong -----------------------------------------------------------
//
//

SOM_Scope       void
SOMLINK         StaffPartPlaySong
                (
                StaffPart       *somSelf,       // in
                Environment     *ev             // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartPlaySong");


}




// ---- ToStaffPart --------------------------------------------------------
//
//      ToStaffPart receives Piano commands from the embedded PianoPart.
//      StaffPart will use these commands to edit its song buffer.
//
//

SOM_Scope       void
SOMLINK         StaffPartToStaffPart
                (
                StaffPart       *somSelf,       // in
                Environment     *ev,            // in
                ODFrame         *frame,         // in
                short           cmd,            // in
                short           noteType,       // in
                short           whatNote        // in
                )
{
    StaffPartData *somThis = StaffPartGetData(somSelf);
    StaffPartMethodDebug("StaffPart","StaffPartToStaffPart");


    try
    {
      int i;
      qprintf(">>> cmd=%d, notetype=%d, key=%d\n", cmd, noteType, whatNote);

      switch(cmd) {
        case CMD(OneNote):
             _fStaffModel->SetNote(whatNote,noteType);
             _fStaffModel->Next();
             break;

        case CMD(BackupOne):
             i=_fStaffModel->Prev();
             qprintf(">>> backing up (%d)\n",i);
             break;

        case CMD(SkipFwdOne):
             i=_fStaffModel->Next();
             qprintf(">>> skipping fwd (%d)\n",i);
             break;

        case CMD(RestSome):
             _fStaffModel->SetNote(-1,noteType);
             _fStaffModel->Next();
             break;
        }

      frame->Invalidate(ev,kODNULL, kODNULL);

    }
    catch(...)
    {
    }

}



// -------------------------------------------------------------------------
// -----                                                               -----
// -----                StaffPart    MetaClass                        -----
// -----                                                               -----
// -----              Overriding Inherited Methods                     -----
// -----                                                               -----
// -------------------------------------------------------------------------



// ---- clsGetODPartHandlerName --------------------------------------------
//
//

SOM_Scope       ISOString
SOMLINK         M_StaffPartclsGetODPartHandlerName
                (
                M_StaffPart     *somSelf,       // in
                Environment     *ev             // in
                )

{
//  M_StaffPartData *somThis = M_StaffPartGetData(somSelf);
    M_StaffPartMethodDebug("M_StaffPart","M_StaffPartclsGetODPartHandlerName");


    string handlerName = (string)SOMMalloc(strlen(kPartHandlerName)+1);
    strcpy(handlerName,kPartHandlerName);


    return (ISOString) handlerName;

}



// ---- clsGetODPartHandlerDisplayName ------------------------------------
//
//

SOM_Scope       string
SOMLINK         M_StaffPartclsGetODPartHandlerDisplayName
                (
                M_StaffPart     *somSelf,       // in
                Environment     *ev             // in
                )
{
//  M_StaffPartData *somThis = M_StaffPartGetData(somSelf);
    M_StaffPartMethodDebug("M_StaffPart","M_StaffPartclsGetODPartHandlerDisplayName") ;



    string displayName = (string)SOMMalloc(strlen(kPartHandlerName)+1);
    strcpy(displayName,kPartHandlerName);

    return displayName;

}



// ---- clsGetODPartKinds -------------------------------------------------
//
//

SOM_Scope       _IDL_SEQUENCE_PartKindInfo
SOMLINK         M_StaffPartclsGetODPartKinds
                (
                M_StaffPart     *somSelf,       // in
                Environment     *ev             // in
                )
{
//  M_StaffPartData *somThis = M_StaffPartGetData(somSelf);
    M_StaffPartMethodDebug("M_StaffPart","M_StaffPartclsGetODPartKinds");



    _IDL_SEQUENCE_PartKindInfo partKindInfo;

    // Create structure PartKindInfo  and allocate memory for its fields
    PartKindInfo * info       =  (PartKindInfo *)SOMMalloc(sizeof(PartKindInfo));
    info->partKindName        =  (ISOString) SOMMalloc(strlen(kPartKindName) + 1);
    info->partKindDisplayName =  (string)SOMMalloc(strlen(kPartKindDisplayName)+1);
    info->filenameFilters     =  (string)SOMMalloc(strlen("")+1);
    info->filenameTypes       =  (string)SOMMalloc(strlen("")+1);
    info->categories          =  (string)SOMMalloc(strlen(kPartCategory)+1);
    info->categoryDisplayName =  (string)SOMMalloc(strlen(kPartCategory)+1);
    info->objectID            =  (string)SOMMalloc(strlen("")+1);

    // Copy the information into the structure
    strcpy(info->partKindName , kPartKindName);
    strcpy(info->partKindDisplayName, kPartKindDisplayName);
    strcpy(info->filenameFilters, "");
    strcpy(info->filenameTypes, "");
    strcpy(info->categories, kPartCategory);
    strcpy(info->categoryDisplayName, kPartCategory);
    strcpy(info->objectID, "");

    partKindInfo._maximum = 1;
    partKindInfo._length = 1;
    partKindInfo._buffer = info;



    return partKindInfo;

}



// ---- clsGetOLE2ClassId -------------------------------------------------
//
//

SOM_Scope       string
SOMLINK         M_StaffPartclsGetOLE2ClassId
                (
                M_StaffPart     *somSelf,       // in
                Environment     *ev             // in
                )
{
//  M_StaffPartData *somThis = M_StaffPartGetData(somSelf);
    M_StaffPartMethodDebug("M_StaffPart","M_StaffPartclsGetOLE2ClassId");


    // OLE2 Class ID is determined by running the tool UUIDGEN.EXE
    // found in the IBM VAC++ %CPPMAIN%\SDK\BIN directory
    // this tool is guaranteed to generate a unique ID based on your
    // network address and the time of day (DCE Standard)


    char *kID = "{cea8ea30-07fa-11d0-b476-08005ac0e890}";

    string OLE2ClassID = (string)SOMMalloc(strlen(kID)+1);
    strcpy(OLE2ClassID,kID);



    return OLE2ClassID;

}



// ---- clsGetWindowsIconFileName ----------------------------------------
//
//

SOM_Scope       string
SOMLINK         M_StaffPartclsGetWindowsIconFileName
                (
                M_StaffPart     *somSelf,       // in
                Environment     *ev             // in
                )
{
//  M_StaffPartData *somThis = M_StaffPartGetData(somSelf);
    M_StaffPartMethodDebug("M_StaffPart","M_StaffPartclsGetWindowsIconFileName");

    string windowsIcon = (string)SOMMalloc(strlen(kWindowsIcon)+1);
    strcpy(windowsIcon,kWindowsIcon);

    return windowsIcon;

}
