/****************************************************************************
    STARTOP.C

    $Log:   S:\products\msprods\oiwh\display\startop.c_v  $
 * 
 *    Rev 1.44   10 May 1996 14:48:30   BEG06016
 * Added OiOpAbortOperation.
 * 
 *    Rev 1.43   22 Apr 1996 10:28:46   BEG06016
 * Cleaned up error checking.
 * 
 *    Rev 1.42   16 Apr 1996 10:28:50   BEG06016
 * Fixed attach-a-note marks.
 * 
 *    Rev 1.41   11 Apr 1996 15:13:06   BEG06016
 * Optimized named block access some.
 * 
 *    Rev 1.40   09 Jan 1996 14:06:28   BLJ
 * Fixed rendering.
 * 
 *    Rev 1.39   05 Jan 1996 13:59:40   BLJ
 * Fixed startop optimization.
 * 
 *    Rev 1.38   04 Jan 1996 14:45:48   BLJ
 * Fixed the startop optimization.
 * 
 *    Rev 1.37   04 Jan 1996 14:27:58   BLJ
 * Sped up startop.
 * 
 *    Rev 1.36   02 Jan 1996 10:33:18   BLJ
 * Changed alot of UINTs to ints.
 * Changed IMG structure to include the image data.
 * Changed lp prefix to p.
 * 
 *    Rev 1.35   22 Dec 1995 11:11:10   BLJ
 * Added a parameter for zero init'ing to some memory manager calls.
 * 
 *    Rev 1.34   14 Dec 1995 09:56:08   BLJ
 * Fixed 5580 - Unable to select right and bottom pixels.
 * 
 *    Rev 1.33   04 Dec 1995 10:49:04   RC
 * Check for left and top of point with image dimensions to ensure point is
 * on the image (top of startoperation)
 * 
 *    Rev 1.32   03 Nov 1995 14:01:30   BLJ
 * Add optimization to display.
 * 
 *    Rev 1.31   03 Nov 1995 11:58:50   BLJ
 * Add optimization to display.
 * 
 *    Rev 1.30   02 Nov 1995 10:13:20   BLJ
 * Adding Undo functionality.
 * 
****************************************************************************/

#include "privdisp.h"

/****************************************************************************

    FUNCTION:   OIOpStartOperation

    PURPOSE:    This routine starts the creation of an annotation.

****************************************************************************/

int  WINAPI OiOpStartOperation(HWND hWnd, LPOIOP_START_OPERATION_STRUCT pStartStruct,
                        POINT ptPoint, WPARAM fwKeys, int nFlags){
                                
int         nStatus;
PWINDOW    pWindow;
PANO_IMAGE pAnoImage;
PIMAGE     pImage;

int  nNamedBlockIndex;
int  nMarkIndex;

PMARK pMark;
PMARK pDefMark;
PMARK pMark2=0;

int  nLoop;
LRECT lrRect;
LRECT lrRectPoint;
BITMAP bm;
HANDLE hBitmap = 0;
HANDLE hDib = 0;
PBITMAPINFOHEADER pDib = 0;
long lWidth;
long lHeight;
long lHorzFudge;
long lVertFudge;
PAN_POINTS pPoints = 0;
BOOL bSelected;
HDC hDC = 0;
RECT rClientRect;
LRECT lrClientRect;
LRECT lrFullsizeClientRect;
BOOL bDeleteMark = FALSE;
BOOL bMarkComplete = FALSE;
BOOL bRepaint = FALSE;
BOOL bDone;
PSTR pTemp;
int  nHandle;
BOOL bFirstLevel = TRUE;
CLIP_COPY_STRUCT ClipCopy;
int  nIndex;
LPLRECT plrRect;
BOOL bPointNearMark;
BOOL bLeaveSelbyPt=FALSE;
LRECT lrWndRectPoint;
POINT *pWndPoint=0;
int  nTempMarkIndex;
int  nHScale;
int  nVScale;


    CheckError2( Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE));
    if (!(pImage = pAnoImage->pBaseImage)){
        goto Exit; // Not an error.
    }

    if (!pStartStruct){
        nStatus = Error(DISPLAY_NULLPOINTERINVALID);
        goto Exit;
    }

    if (!pStartStruct->Attributes.uType){
        nStatus = Error(DISPLAY_INVALID_OPTIONS);
        goto Exit;
    }

    CheckError2( TranslateScale(pWindow->nScale, pImage->nHRes, pImage->nVRes, &nHScale, &nVScale));

    // lrWndRectPoint saves the point in window coordinates to avoid
    // round off errors at mark selection time
    SetLRect(lrWndRectPoint, ptPoint.x, ptPoint.y, ptPoint.x, ptPoint.y); 
    if (nFlags & PARM_SCALED){
        ConvertRect(pWindow, &lrWndRectPoint, CONV_SCALED_TO_WINDOW);
    }else if (!(nFlags & PARM_WINDOW)){ // Default to window.
        ConvertRect(pWindow, &lrWndRectPoint, CONV_FULLSIZE_TO_WINDOW);
    }
     
    SetLRect(lrRectPoint, ptPoint.x, ptPoint.y, ptPoint.x, ptPoint.y); 
    if (nFlags & PARM_SCALED){
        ConvertRect(pWindow, &lrRectPoint, CONV_SCALED_TO_FULLSIZE);
    }else if (!(nFlags & PARM_FULLSIZE)){ // Default to window.
        ConvertRect(pWindow, &lrRectPoint, CONV_WINDOW_TO_FULLSIZE);
    } 

    // All operations must set ptPoint to a valid value.
    // Operations like OIOP_COPY and OIOP_CUT that don't nse it should set it to 0.
    if (lrRectPoint.left >=  pImage->nWidth
            || lrRectPoint.top >=  pImage->nHeight){
        nStatus = Error(DISPLAY_INVALIDRECT);
        goto Exit;
    }

    hDC = GetDC(hWnd);
    GetClientRect(hWnd, &rClientRect);
    CopyRect(lrFullsizeClientRect, rClientRect);
    ConvertRect(pWindow, &lrFullsizeClientRect, CONV_WINDOW_TO_FULLSIZE);

    // Clip client rect to image rect.
    if (lrFullsizeClientRect.right >  pImage->nWidth
            || lrFullsizeClientRect.bottom >  pImage->nHeight){
        lrFullsizeClientRect.right = lmin(lrFullsizeClientRect.right, pImage->nWidth);
        lrFullsizeClientRect.bottom = lmin(lrFullsizeClientRect.right, pImage->nHeight);
        CopyRect(lrClientRect, lrFullsizeClientRect);
        ConvertRect(pWindow, &lrClientRect, CONV_FULLSIZE_TO_WINDOW);
    }

    // Check for operation in progress.
    if (pAnoImage->Annotations.ppMarks){
        pMark = pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks];
        if (pMark){
            if ((int) pMark->Attributes.uType != OIOP_PASTE
                    || pStartStruct->Attributes.uType != OIOP_PASTE){
                OiOpEndOperation(hWnd);
                pMark = pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks];
                if (pMark){
                    OiOpEndOperation(hWnd);
                }
            }else{
                bFirstLevel = FALSE;
            }
        }
    } 

    if (bFirstLevel){
        // Save nndo info.
        switch (pStartStruct->Attributes.uType){
            case OIOP_SELECT_BY_POINT_OR_RECT:
            case OIOP_SELECT_BY_RECT_FIXED:
            case OIOP_SELECT_BY_RECT_VARIABLE:
            case OIOP_SELECT_BY_POINT:
            case OIOP_COPY: 
                if (UndoSaveSelectionState(pAnoImage)){
                    goto Exit;
                }
                if (UndoSavelpAnnotations(pAnoImage)){
                    goto Exit;
                }
                break;

            case OIOP_DELETE:
            case OIOP_CUT:
            case OIOP_PASTE:
                if (UndoSaveSelectionState(pAnoImage)){
                    goto Exit;
                }
                if (UndoSavelpAnnotations(pAnoImage)){
                    goto Exit;
                }
                if (UndoSavelpBaseImage(pAnoImage)){
                    goto Exit;
                }
                break;

            case OIOP_ACTIVATE:
            case OIOP_AN_LINE:
            case OIOP_AN_FREEHAND:
            case OIOP_AN_HOLLOW_RECT:
            case OIOP_AN_FILLED_RECT:
            case OIOP_AN_TEXT:
            case OIOP_AN_TEXT_FROM_A_FILE:
            case OIOP_AN_TEXT_STAMP:
            case OIOP_AN_ATTACH_A_NOTE:
            case OIOP_AN_IMAGE:
            case OIOP_AN_IMAGE_BY_REFERENCE:
            case OIOP_AN_FORM:
                if (UndoSavelpAnnotations(pAnoImage)){
                    goto Exit;
                }
                break;

            default:
                break;
        }

        // Find next available mark.
        CheckError2( ReAllocateMemory(sizeof(PMARK) * (pAnoImage->Annotations.nMarks + 2),
                (PPSTR) &pAnoImage->Annotations.ppMarks, ZERO_INIT));

        CheckError2( AllocateMemory(sizeof(MARK), 
                (PPSTR) &pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks], ZERO_INIT));
        pMark = pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks];

        pMark->Attributes = pStartStruct->Attributes;
        pMark->Attributes.dwPermissions = ACL_ALL;
        // copy default named blocks.
        switch (pStartStruct->Attributes.uType){
            case OIOP_SELECT_BY_POINT_OR_RECT:
            case OIOP_SELECT_BY_RECT_FIXED:
            case OIOP_SELECT_BY_RECT_VARIABLE:
            case OIOP_SELECT_BY_POINT:
            case OIOP_COPY: 
            case OIOP_DELETE:
            case OIOP_CUT:
            case OIOP_PASTE:
            case OIOP_ACTIVATE:
                break;

            default:
                if (pDefMark = pAnoImage->Annotations.pDefMark){
                    for (nNamedBlockIndex = 0; nNamedBlockIndex < 
                            pDefMark->nNamedBlocks; nNamedBlockIndex++){
                        pTemp = 0;
                        CheckError2( AddAMarkNamedBlock(pMark, pDefMark->ppNamedBlock[nNamedBlockIndex]->szName, 
                                (PPSTR) &pTemp, pDefMark->ppNamedBlock[nNamedBlockIndex]->lSize));
                        memcpy(pTemp, pDefMark->ppNamedBlock[nNamedBlockIndex]->pBlock,
                                pDefMark->ppNamedBlock[nNamedBlockIndex]->lSize);
                    }
                    if (pDefMark->pOiAnoDat){
                        pTemp = 0;
                        CheckError2( AddAMarkNamedBlock(pMark, szOiAnoDat, 
                                (PPSTR) &pTemp, pDefMark->nOiAnoDatSize));
                        memcpy(pTemp, pDefMark->pOiAnoDat, pDefMark->nOiAnoDatSize);
                    }
                    if (pDefMark->pOiGroup){
                        pTemp = 0;
                        CheckError2( AddAMarkNamedBlock(pMark, szOiGroup, 
                                (PPSTR) &pTemp, pDefMark->nOiGroupSize));
                        memcpy(pTemp, pDefMark->pOiGroup, pDefMark->nOiGroupSize);
                    }
                    if (pDefMark->pOiSelect){
                        pTemp = 0;
                        CheckError2( AddAMarkNamedBlock(pMark, szOiSelect, 
                                (PPSTR) &pTemp, pDefMark->nOiSelectSize));
                        memcpy(pTemp, pDefMark->pOiSelect, pDefMark->nOiSelectSize);
                    }
                    if (pDefMark->pOiIndex){
                        pTemp = 0;
                        CheckError2( AddAMarkNamedBlock(pMark, szOiIndex, 
                                (PPSTR) &pTemp, pDefMark->nOiIndexSize));
                        memcpy(pTemp, pDefMark->pOiIndex, pDefMark->nOiIndexSize);
                        strcpy(Buff1, pDefMark->pOiIndex);
                        nIndex = atoi(Buff1);
                        nIndex++;
                        _itoa(nIndex, Buff1, 10);
                        strcpy(pDefMark->pOiIndex, Buff1);
                    }
                }
                break;
        }
        pMark->Attributes.bVisible = TRUE;
    }

    lHorzFudge = lmax (1, SELECTION_FUDGE * SCALE_DENOMINATOR / nHScale);
    lVertFudge = lmax (1, SELECTION_FUDGE * SCALE_DENOMINATOR / nVScale);
    CopyRect(pMark->Attributes.lrBounds, lrRectPoint);

    pAnoImage->nStartOpFlags = nFlags;
    pAnoImage->nStartOpFwKeys = fwKeys;

    switch ((int) pMark->Attributes.uType){
        case OIOP_SELECT_BY_POINT_OR_RECT:
            for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                if (pMark2->Attributes.uType == OIOP_AN_FORM){
                    continue;
                }
                CheckError2( IsPointNearMark(lrRectPoint, pMark2, 
                        lHorzFudge, lVertFudge, &bPointNearMark, &nHandle));
                if (bPointNearMark){
                    (int) pMark->Attributes.uType = OIOP_SELECT_BY_POINT;
                    goto OiOpSelectByPoint;
                }
            }
            (int) pMark->Attributes.uType = OIOP_SELECT_BY_RECT_VARIABLE;
            goto OiOpSelectByRectVariable;

        case OIOP_SELECT_BY_RECT_FIXED:
            pWndPoint = 0;
            CheckError2( AddAMarkNamedBlock(pMark, szOiAnoDat, 
                    (PPSTR) &pWndPoint, sizeof(POINT)));
            pWndPoint->x = (int)lrWndRectPoint.left;
            pWndPoint->y = (int)lrWndRectPoint.top;

            plrRect = 0;
            CheckError2( AddAMarkNamedBlock(pMark, szOiCurPt, (PPSTR) &plrRect, sizeof(LRECT)));
            CopyRect(*plrRect, lrRectPoint);
            // First try nsing the current selection rect.
            GetSelectBox(pAnoImage, &lrRect);

            if (lrRect.right != lrRect.left && lrRect.bottom != lrRect.top){
                if (lrRectPoint.left >= lrRect.left - lHorzFudge
                        && lrRectPoint.left <= lrRect.right - lHorzFudge
                        && lrRectPoint.top >= lrRect.top - lVertFudge
                        && lrRectPoint.top <= lrRect.bottom - lHorzFudge){
                    // We are dragging not selecting.
                    CopyRect(pAnoImage->lrSelectBoxOrg, lrRect);
                    pAnoImage->Annotations.bMoving = TRUE;
                    pAnoImage->Annotations.bMoved = FALSE;
                    break;
                }else{
                    lWidth = lrRect.right - lrRect.left;
                    lHeight = lrRect.bottom - lrRect.top;

                    lrRect.left = max(0L, min( (pImage->nWidth - 1) - lWidth,
                            lrRectPoint.right - (lWidth / 2)));
                    lrRect.right = lrRect.left + lWidth;
                    lrRect.top = max(0L, min( (pImage->nHeight - 1) - lHeight,
                            lrRectPoint.bottom - (lHeight / 2)));
                    lrRect.bottom = lrRect.top + lHeight;
                    CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
                    CopyRect(pAnoImage->lrSelectBoxOrg, lrRect);
                    pAnoImage->Annotations.bMoving = TRUE;
                    pAnoImage->Annotations.bMoved = TRUE;
                    break;
                }
            }

            // Deselect all marks.
            if (!(fwKeys & MK_CONTROL) && !(fwKeys & MK_SHIFT)){
                for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    pMark2->bSelected = FALSE;
                }
            }

            // Next try the clipboard.
            if (OpenClipboard(hWnd)){
                hBitmap = GetClipboardData(CF_BITMAP);
                hDib = GetClipboardData(CF_DIB);
                CloseClipboard();
                if (hDib){
                    if (!(pDib = (PBITMAPINFOHEADER) GlobalLock(hDib))){
                        nStatus = Error(DISPLAY_CANTLOCK);
                        goto Exit;
                    }
                    lWidth = (int) pDib->biWidth;
                    lHeight = (int) pDib->biHeight;

                    lrRect.left = max(0L, min( pImage->nWidth - lWidth,
                            lrRectPoint.right - (lWidth / 2)));
                    lrRect.right = lrRect.left + lWidth;
                    lrRect.top = max(0L, min( pImage->nHeight - lHeight,
                            lrRectPoint.bottom - (lHeight / 2)));
                    lrRect.bottom = lrRect.top + lHeight;
                    CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
                    CopyRect(pAnoImage->lrSelectBoxOrg, lrRect);
                    GlobalUnlock(hDib);
                    pAnoImage->Annotations.bMoving = TRUE;
                    pAnoImage->Annotations.bMoved = TRUE;
                    break;
                }else if (hBitmap){
                    GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm);
                    lWidth = (int) pDib->biWidth;
                    lHeight = (int) pDib->biHeight;

                    lrRect.left = max(0L, min( pImage->nWidth - lWidth,
                            lrRectPoint.right - (lWidth / 2)));
                    lrRect.right = lrRect.left + lWidth;
                    lrRect.top = max(0L, min( pImage->nHeight - lHeight,
                            lrRectPoint.bottom - (lHeight / 2)));
                    lrRect.bottom = lrRect.top + lHeight;
                    CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
                    CopyRect(pAnoImage->lrSelectBoxOrg, lrRect);
                    pAnoImage->Annotations.bMoving = TRUE;
                    pAnoImage->Annotations.bMoved = TRUE;
                    break;
                }
            }

            // Last of all, fall through to variable selection.
            // This is not to finish a fixed selection but to perform a 
            // variable selection because you can not perform a fixed selection.
            (int) pMark->Attributes.uType = OIOP_SELECT_BY_RECT_VARIABLE;

OiOpSelectByRectVariable:
        case OIOP_SELECT_BY_RECT_VARIABLE:
            pWndPoint = 0;
            CheckError2( AddAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pWndPoint, sizeof(POINT)));
            pWndPoint->x = (int)lrWndRectPoint.left;
            pWndPoint->y = (int)lrWndRectPoint.top;

            pAnoImage->nHandle = 0;
            plrRect = 0;
            CheckError2( AddAMarkNamedBlock(pMark, szOiCurPt, (PPSTR) &plrRect, sizeof(LRECT)));
            CopyRect(*plrRect, lrRectPoint);

            GetSelectBox(pAnoImage, &lrRect);
            if (lrRect.right != lrRect.left && lrRect.bottom != lrRect.top){
                if (lrRectPoint.left >= lrRect.left - lHorzFudge
                        && lrRectPoint.left <= lrRect.right - lHorzFudge
                        && lrRectPoint.top >= lrRect.top - lVertFudge
                        && lrRectPoint.top <= lrRect.bottom - lHorzFudge){
                    // We are dragging not selecting.
                    CopyRect(pAnoImage->lrSelectBoxOrg, lrRect);
                    pAnoImage->Annotations.bMoving = TRUE;
                    pAnoImage->Annotations.bMoved = FALSE;
                    break;
                }
            }

            // Deselect all marks.
            if (!(fwKeys & MK_CONTROL) && !(fwKeys & MK_SHIFT)){
                for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    if (pMark2->bSelected){
                        pMark2->bSelected = FALSE;
                        bRepaint = TRUE;
                    }
                }
            }
            IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRectPoint, PARM_FULLSIZE);
            break;

OiOpSelectByPoint:
        case OIOP_SELECT_BY_POINT:
            pWndPoint = 0;
            CheckError2( AddAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pWndPoint, sizeof(POINT)));
            pWndPoint->x = (int)lrWndRectPoint.left;
            pWndPoint->y = (int)lrWndRectPoint.top;

            // If ctrl not active, then deselect all marks.
            pAnoImage->Annotations.bMoving = TRUE;
            pAnoImage->Annotations.bMoved = FALSE;
            if (!(fwKeys & MK_CONTROL) && !(fwKeys & MK_SHIFT)){
                // Deselect by rect.
                SetLRect(lrRect, 0,0,0,0);
                CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
                // this is to check if a selected mark is being acted npon
                for (nMarkIndex = pAnoImage->Annotations.nMarks - 1;
                        (int) nMarkIndex >= 0; nMarkIndex--){
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    if (!pMark2->bSelected){
                        continue;
                    }                        

                    if ((nHandle = IsPointNearHandle(pMark2, 
                            lrRectPoint, lHorzFudge, lVertFudge)) > 8){
                        goto Exit;
                    }
                    if (!(pMark->Attributes.dwPermissions & ACL_MODIFY_MARK)){
                        nStatus = Error(DISPLAY_RESTRICTED_ACCESS);
                        goto Exit;
                    }
                    pAnoImage->nHandle = nHandle;
                    // this will break out of the for loop since we are
                    // on a handle of some mark
                    if (nHandle >0 && nHandle <= 8){
                        bRepaint = TRUE;
                        break;
                    }
                } 
                // if we find we are on a handle, then remember that mark
                // so we can deselect all other marks and then get out of
                // the switch statement
                if (nHandle >0 && nHandle <= 8){
                    nTempMarkIndex = nMarkIndex;
                    bLeaveSelbyPt = TRUE;
                }                    
                for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                    if (nMarkIndex == (int) nTempMarkIndex  &&  bLeaveSelbyPt){
                        continue;
                    }                        
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    if (pMark2->bSelected){
                        pMark2->bSelected = FALSE;
                        bRepaint = TRUE;
                    }
                }
                if (bLeaveSelbyPt){
                    break;
                }                    
            }

            GetSelectBox(pAnoImage, &lrRect);
            CopyRect(pAnoImage->lrSelectBoxOrg, lrRect);

            // Select the new mark by point.
            bSelected = FALSE;
            pAnoImage->nHandle = 0;
            for (nMarkIndex = pAnoImage->Annotations.nMarks - 1;
                    (int) nMarkIndex >= 0 && !bSelected; nMarkIndex--){
                pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                CheckError2( IsPointNearMark(lrRectPoint, pMark2, lHorzFudge, 
                        lVertFudge, &bPointNearMark, &nHandle));
                if (!bPointNearMark){
                    continue;
                }

                if ((fwKeys & MK_CONTROL)){
                    pMark2->bSelected ^= TRUE;
                }else{
                    pMark2->bSelected = TRUE;
                }

                if (!(pMark2->Attributes.dwPermissions & ACL_MODIFY_MARK)){
                    nStatus = Error(DISPLAY_RESTRICTED_ACCESS);
                    goto Exit;
                }
                pAnoImage->nHandle = nHandle;

                bSelected = TRUE;
                bRepaint = TRUE;
                break;
            }
            break;

        case OIOP_DELETE:
            bDone = FALSE;
            if (!ptPoint.x && !ptPoint.y){
                for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks;){
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    if (IsMarkSelected(pWindow, pMark2)){
                        if (pMark2->Attributes.uType == OIOP_AN_FORM){
                            CheckError2( InvalidateAllDisplayRects(pWindow, pImage, NULL, TRUE));
                        }                        
                        CheckError2( DeleteMark(pAnoImage, nMarkIndex));
                        bDone = TRUE;
                    }else{
                        nMarkIndex++;
                    }
                }
                GetSelectBox(pAnoImage, &lrRect);
                if (lrRect.right - lrRect.left && lrRect.bottom - lrRect.top){
                    CheckError2( ClearImage(pWindow, pImage, &lrRect));
                    bRepaint = TRUE;
                }
            }else{
                // Delete the mark by point instead of selection.
                for (nMarkIndex = pAnoImage->Annotations.nMarks - 1;
                        (int) nMarkIndex >= 0 && !bDone; nMarkIndex--){
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    if (pMark2->Attributes.uType == OIOP_DELETE){
                        // Don't delete the delete operation.
                        continue;
                    }
                    if (!IsPointNearRect(pMark2->Attributes.lrBounds, 
                            lrRectPoint, lHorzFudge, lVertFudge)){
                        continue;
                    }
                    if (pMark2->Attributes.uType == OIOP_AN_LINE
                            || pMark2->Attributes.uType == OIOP_AN_FREEHAND){
                        CheckError2( GetAMarkNamedBlock(pMark2, szOiAnoDat, (PPSTR) &pPoints));
                        if (!pPoints){
                            nStatus = Error(DISPLAY_DATACORRUPTED);
                            goto Exit;
                        }
                        for (nLoop = 0; nLoop < pPoints->nPoints - 1; nLoop++){
                            SetLRect(lrRect, pPoints->ptPoint[nLoop].x +
                                    pMark2->Attributes.lrBounds.left,
                                    pPoints->ptPoint[nLoop].y +
                                    pMark2->Attributes.lrBounds.top,
                                    pPoints->ptPoint[nLoop + 1].x +
                                    pMark2->Attributes.lrBounds.left,
                                    pPoints->ptPoint[nLoop + 1].y +
                                    pMark2->Attributes.lrBounds.top);
                            if (!IsPointNearLine(lrRect, lrRectPoint, lHorzFudge, lVertFudge)){
                                continue;
                            }
                            bDone = TRUE;
                        }
                    }else if(pMark2->Attributes.uType == OIOP_AN_HOLLOW_RECT){
                        // Check top edge.
                        lrRect.left   = pMark2->Attributes.lrBounds.left;
                        lrRect.top    = pMark2->Attributes.lrBounds.top;
                        lrRect.right  = pMark2->Attributes.lrBounds.right;
                        lrRect.bottom = pMark2->Attributes.lrBounds.top;
                        if (!IsPointNearLine(lrRect, lrRectPoint, lHorzFudge, lVertFudge)){
                            // Check bottom edge.
                            lrRect.left   = pMark2->Attributes.lrBounds.left;
                            lrRect.top    = pMark2->Attributes.lrBounds.bottom;
                            lrRect.right  = pMark2->Attributes.lrBounds.right;
                            lrRect.bottom = pMark2->Attributes.lrBounds.bottom;
                            if (!IsPointNearLine(lrRect, lrRectPoint, lHorzFudge, lVertFudge)){
                                // Check left edge.
                                lrRect.left   = pMark2->Attributes.lrBounds.left;
                                lrRect.top    = pMark2->Attributes.lrBounds.top;
                                lrRect.right  = pMark2->Attributes.lrBounds.left;
                                lrRect.bottom = pMark2->Attributes.lrBounds.bottom;
                                if (!IsPointNearLine(lrRect, lrRectPoint, lHorzFudge, lVertFudge)){
                                    // Check right edge.
                                    lrRect.left   = pMark2->Attributes.lrBounds.right;
                                    lrRect.top    = pMark2->Attributes.lrBounds.top;
                                    lrRect.right  = pMark2->Attributes.lrBounds.right;
                                    lrRect.bottom = pMark2->Attributes.lrBounds.bottom;
                                    if (!IsPointNearLine(lrRect, lrRectPoint, lHorzFudge, lVertFudge)){
                                        continue;
                                    }
                                }
                            }
                        }
                        bDone = TRUE;
                    }else{
                        bDone = TRUE;
                    }
                    if (bDone){
                        break;
                    }
                }
                if (bDone){
                    if (pMark2->Attributes.uType == OIOP_AN_FORM){
                        CheckError2( InvalidateAllDisplayRects(pWindow, pImage, NULL, TRUE));
                    }
                    CheckError2( DeleteMark(pAnoImage, nMarkIndex));
                }

                // Delete the image data.
                GetSelectBox(pAnoImage, &lrRect);
                if (lrRect.right != lrRect.left && lrRect.bottom != lrRect.top){
                    if (lrRectPoint.left >= lrRect.left - lHorzFudge
                            && lrRectPoint.left <= lrRect.right - lHorzFudge
                            && lrRectPoint.top >= lrRect.top - lVertFudge
                            && lrRectPoint.top <= lrRect.bottom - lHorzFudge){
                        CheckError2( ClearImage(pWindow, pImage, &lrRect));
                        bRepaint = TRUE;
                    }
                }
            }

            if (bDone){
                pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
                bRepaint = TRUE;
            }
            bDeleteMark = TRUE;
            SetLRect(lrRect, 0,0,0,0);
            CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
            break;
        
        case OIOP_ACTIVATE:
            // Deselect all marks.
            SetLRect(lrRect, 0,0,0,0);
            CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
            for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                if (pMark2->bSelected){
                    pMark2->bSelected = FALSE;
                    bRepaint = TRUE;
                }
            }

            // Select the new mark by point.
            bSelected = FALSE;
            for (nMarkIndex = pAnoImage->Annotations.nMarks - 1;
                    (int) nMarkIndex >= 0 && !bSelected; nMarkIndex--){
                pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                CheckError2( IsPointNearMark(lrRectPoint, pMark2, lHorzFudge, 
                        lVertFudge, &bPointNearMark, &nHandle));
                if (!bPointNearMark){
                    continue;
                }

                pMark2->bSelected = TRUE;

                if (!(pMark->Attributes.dwPermissions & ACL_ACTIVATE_MARK)){
                    nStatus = Error(DISPLAY_RESTRICTED_ACCESS);
                    goto Exit;
                }
                pAnoImage->nHandle = nHandle;
                bSelected = TRUE;
                bRepaint = TRUE;
                break;
            }

            if (!pMark2){
                bDeleteMark = TRUE;
                goto Exit;   //not an error, means there are no marks on image
            }
                            
            switch (pMark2->Attributes.uType){
                case OIOP_AN_TEXT:
                case OIOP_AN_TEXT_FROM_A_FILE:
                case OIOP_AN_TEXT_STAMP:
                case OIOP_AN_ATTACH_A_NOTE:
                    CheckError2( AnTextActivate(hWnd, pStartStruct, ptPoint, fwKeys, 
                            nFlags, pWindow, pImage, pMark2, hDC, rClientRect, lrFullsizeClientRect));
                    bRepaint = TRUE;
                    pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
                    break;

                case OIOP_AN_LINE:
                case OIOP_AN_FREEHAND:
                case OIOP_AN_HOLLOW_RECT:
                case OIOP_AN_FILLED_RECT:
                case OIOP_AN_AUDIO:
                case OIOP_AN_IMAGE:
                case OIOP_AN_IMAGE_BY_REFERENCE:
                case OIOP_AN_FORM:
                default:
                    nStatus = Error(DISPLAY_INVALID_OPTIONS);
                    goto Exit;
                    break;
            }

            bDeleteMark = TRUE;
            break;

        case OIOP_UNDO:
            // Terminate any nndo operations in progress.
            if (pAnoImage->bUndoOpInProgress){
                pAnoImage->nCurrentULUndo++;
                pAnoImage->bUndoOpInProgress = FALSE;
            }

            CheckError2( DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks));

            if (!pAnoImage->nCurrentULUndo){
                nStatus = Error(DISPLAY_NOTHING_TO_UNDO);
                goto Exit;
            }

            pAnoImage->nCurrentULUndo--;

            CheckError2( SwapUndoWithCurrent(pAnoImage, pWindow));

            bDeleteMark = TRUE;
            break;

        case OIOP_REDO:
            // Terminate any nndo operations in progress.
            if (pAnoImage->bUndoOpInProgress){
                pAnoImage->nCurrentULUndo++;
                pAnoImage->bUndoOpInProgress = FALSE;
            }

            if (!pAnoImage->pULUndos){
                nStatus = Error(DISPLAY_NOTHING_TO_UNDO);
                goto Exit;
            }

            if (!((PUSER_LEVEL_UNDO) pAnoImage->pULUndos)[pAnoImage->nCurrentULUndo + 1].nSize){
                nStatus = Error(DISPLAY_NOTHING_TO_UNDO);
                goto Exit;
            }

            pAnoImage->nCurrentULUndo++;

            if (!((PUSER_LEVEL_UNDO) pAnoImage->pULUndos)[pAnoImage->nCurrentULUndo].nSize){
                nStatus = Error(DISPLAY_NOTHING_TO_UNDO);
                goto Exit;
            }

            if (!pAnoImage->nCurrentULUndo){
                nStatus = Error(DISPLAY_NOTHING_TO_UNDO);
                goto Exit;
            }

            CheckError2( SwapUndoWithCurrent(pAnoImage, pWindow));

            bDeleteMark = TRUE;
            break;

        case OIOP_AN_LINE:
        case OIOP_AN_FREEHAND:
            pPoints = 0;
            if ((int) pMark->Attributes.uType == OIOP_AN_LINE){
                CheckError2( AddAMarkNamedBlock(pMark, szOiAnoDat, 
                        (PPSTR) &pPoints, sizeof(AN_POINTS) + (sizeof(POINT) * 1)));
                pPoints->nMaxPoints = 2;
                pPoints->nPoints = 2;
            }else{
                pPoints = 0;
                CheckError2( AddAMarkNamedBlock(pMark, szOiAnoDat, 
                        (PPSTR) &pPoints, sizeof(AN_POINTS) + (sizeof(POINT) * 99)));
                pPoints->nMaxPoints = 100;
                pPoints->nPoints = 1;
            }
            break;

        case OIOP_AN_HOLLOW_RECT:
        case OIOP_AN_FILLED_RECT:
            break;

        case OIOP_AN_TEXT:
        case OIOP_AN_TEXT_FROM_A_FILE:
        case OIOP_AN_TEXT_STAMP:
        case OIOP_AN_ATTACH_A_NOTE:
            CheckError2( StartOperationText(hWnd, pStartStruct, ptPoint, fwKeys,
                    nFlags, pWindow, pImage, pMark, hDC, rClientRect, 
                    lrFullsizeClientRect, &bDeleteMark, &bMarkComplete, &bRepaint));
            break;

        case OIOP_AN_IMAGE:
        case OIOP_AN_IMAGE_BY_REFERENCE:
        case OIOP_AN_FORM:
            CheckError2( StartOperationBitmap(hWnd, pAnoImage, pStartStruct, ptPoint, 
                    fwKeys, nFlags, pWindow, pImage, pMark, hDC, rClientRect, 
                    lrFullsizeClientRect, &bDeleteMark, &bMarkComplete, &bRepaint));
            // this will allow the form image to be merged with the base image
            if ((int) pMark->Attributes.uType == OIOP_AN_FORM){
                CheckError2( InvalidateAllDisplayRects(pWindow, pImage, NULL, TRUE));
            }            
            break;

        case OIOP_CUT:
            SetLRect (ClipCopy.lRect, 0, 0, 0, 0);
            ClipCopy.nScale = 1000;
            ClipCopy.bUseCurrentScale = 0;                
            CheckError2( IMGClipboardCgbw (hWnd, CLIP_CUT, &ClipCopy, PARM_DONT_REPAINT));
            bDeleteMark = TRUE;
            bRepaint = TRUE;
            break;                              

        case OIOP_COPY: 
            SetLRect (ClipCopy.lRect, 0, 0, 0, 0);
            ClipCopy.nScale = 1000;
            ClipCopy.bUseCurrentScale = 0;                
            CheckError2( IMGClipboardCgbw (hWnd, CLIP_COPY, &ClipCopy, PARM_DONT_REPAINT));
            bDeleteMark = TRUE;
            bRepaint = TRUE;
            break;                              

        case OIOP_PASTE:
            if (bFirstLevel){
                for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    if (pMark2->bSelected){
                        pMark2->bSelected = FALSE;
                    }
                }
                SetLRect(lrRect, 0,0,0,0);
                CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
            }
            pWndPoint = 0;
            CheckError2( AddAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pWndPoint, sizeof(POINT)));
            pWndPoint->x = (int)lrWndRectPoint.left;
            pWndPoint->y = (int)lrWndRectPoint.top;

            pAnoImage->nPasteFormat = *((PUINT) pStartStruct->szString);
            pAnoImage->Annotations.bMoving = TRUE;
            pAnoImage->Annotations.bMoved = FALSE;

            if (bFirstLevel){
                if (pAnoImage->nPasteFormat == nWangAnnotatedImageFormat
                        || pAnoImage->nPasteFormat == nWangAnnotationFormat){
                    CheckError2( StartPasteAnnotatedImage(hWnd, pWindow, pAnoImage, 
                            pImage, lrRectPoint, nFlags));
                }else if (pAnoImage->nPasteFormat == CF_DIB){
                    CheckError2( StartPasteImage(hWnd, pWindow, pAnoImage, 
                            pImage, lrRectPoint, nFlags));
                }else{
                    nStatus = Error(DISPLAY_INVALID_OPTIONS);
                    goto Exit;
                }
                bRepaint = TRUE;
            }
            pAnoImage->Annotations.bPasteInProgress = TRUE;
            break;

        case OIOP_AN_AUDIO:
        default:
            nStatus = Error(DISPLAY_INVALID_OPTIONS);
            bDeleteMark = TRUE;
            goto Exit;
    }

    if (bDeleteMark){
        CheckError2( DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks));
    }else{
        if(bMarkComplete){
            if (nStatus = CheckPermissionsMark(pWindow, pAnoImage, pMark)){
                DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks);
                goto Exit;
            }
            pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
            pAnoImage->Annotations.nMarks++;
        }
    }
    if (bRepaint & !(nFlags & PARM_DONT_REPAINT)){
        CheckError2( InvalidateAllDisplayRects(pWindow, pImage, NULL, FALSE));
        CheckError2(IMGRepaintDisplay(hWnd, (PRECT) -1) );
    }


Exit:
    if (nStatus){
        if (pAnoImage){
            DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks);
            if (pWindow){
                InvalidateAllDisplayRects(pWindow, pImage, NULL, FALSE);
            }
        }
    }
    if (hDC){
        ReleaseDC(hWnd, hDC);
    }
    DeInit(FALSE, TRUE);
    return(nStatus);
}
//
/****************************************************************************

    FUNCTION:   OIOpContinueOperation

    PURPOSE:    This routine continues the annotation.

****************************************************************************/

int  WINAPI OiOpContinueOperation(HWND hWnd, POINT ptPoint, int nFlags){

int       nStatus;
PWINDOW  pWindow;
PANO_IMAGE pAnoImage;
PIMAGE   pImage;

PMARK pMark;

LRECT lrRect;
LRECT lrRectNew;
LRECT lrRectPoint;
HDC hDC = 0;
RECT rClientRect;
LRECT lrClientRect;
LRECT lrFullsizeClientRect;
int  nOldROP;
HBRUSH hOldBrush;
HPEN hPen = 0;
HPEN hOldPen;
PAN_POINTS pPoints;
int  nSize;
LRECT lrWndRectPoint;
int  nHScale;
int  nVScale;


    nDontCallStartFirst++; // Prevent Startfirst from being called.
    if (nStatus = Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE)){
        nDontCallStartFirst--;
        goto Exit;
    }
    nDontCallStartFirst--;

    pImage = pAnoImage->pBaseImage;

    CheckError2( TranslateScale(pWindow->nScale, pImage->nHRes, pImage->nVRes, &nHScale, &nVScale));

    // Find current mark.
    if (!pAnoImage->Annotations.ppMarks){
        goto Exit; // Nothing to do.
    }
    pMark = pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks];

    // If there is no operation in progress, then return.
    if (!pMark){
        goto Exit; // Nothing to do.
    }

    // lrWndRectPoint saves the point in window coordinates to avoid
    // round off errors at mark selection time
    SetLRect(lrWndRectPoint, ptPoint.x, ptPoint.y, ptPoint.x, ptPoint.y); 
    if (nFlags & PARM_SCALED){
        ConvertRect(pWindow, &lrWndRectPoint, CONV_SCALED_TO_WINDOW);
    }else if (!(nFlags & PARM_WINDOW)){ // Default to window.
        ConvertRect(pWindow, &lrWndRectPoint, CONV_FULLSIZE_TO_WINDOW);
    } 

    SetLRect(lrRectPoint, ptPoint.x, ptPoint.y, ptPoint.x, ptPoint.y); 
    if (nFlags & PARM_SCALED){
        ConvertRect(pWindow, &lrRectPoint, CONV_SCALED_TO_FULLSIZE);
    }else if (!(nFlags & PARM_FULLSIZE)){ // Default to window.
        ConvertRect(pWindow, &lrRectPoint, CONV_WINDOW_TO_FULLSIZE);
    }


    // Clip lrRectPoint to image rect.
    lrRectPoint.left = lmax(0, lmin(lrRectPoint.left,  pImage->nWidth));
    lrRectPoint.right = lrRectPoint.left;
    lrRectPoint.top = lmax(0, lmin(lrRectPoint.top,  pImage->nHeight));
    lrRectPoint.bottom = lrRectPoint.top;

    hDC = GetDC(hWnd);
    GetClientRect(hWnd, &rClientRect);

    CopyRect(lrClientRect, rClientRect);
    CopyRect(lrFullsizeClientRect, rClientRect);
    ConvertRect(pWindow, &lrFullsizeClientRect, CONV_WINDOW_TO_FULLSIZE);

    // Clip client rect to image rect.
    if (lrFullsizeClientRect.right >  pImage->nWidth
            || lrFullsizeClientRect.bottom >  pImage->nHeight){
        lrFullsizeClientRect.right = lmin(lrFullsizeClientRect.right,  pImage->nWidth);
        lrFullsizeClientRect.bottom = lmin(lrFullsizeClientRect.bottom,  pImage->nHeight);
        CopyRect(lrClientRect, lrFullsizeClientRect);
        ConvertRect(pWindow, &lrClientRect, CONV_FULLSIZE_TO_WINDOW);
        CopyRectLtoR(rClientRect, lrClientRect);
    }

    switch ((int) pMark->Attributes.uType){
        case OIOP_SELECT_BY_RECT_VARIABLE:
        case OIOP_SELECT_BY_RECT_FIXED:
        case OIOP_SELECT_BY_POINT:
            if (!pAnoImage->Annotations.bMoving 
                    && (int) pMark->Attributes.uType == OIOP_SELECT_BY_RECT_VARIABLE){
                lrRectPoint.right = lmax(0, lmin(lrRectPoint.right, pImage->nWidth)); 
                lrRectPoint.bottom = lmax(0, lmin(lrRectPoint.bottom, pImage->nHeight)); 

                IMGGetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE);
                lrRect.right = lrRectPoint.right;
                lrRect.bottom = lrRectPoint.bottom;
                IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE);
            }
            if (pAnoImage->Annotations.bMoving){
                // MoveSelectedMarks will move both the marks and the selection rect
                // as specified by the flags.
                CheckError2( MoveSelectedMarks(hWnd, pWindow, pAnoImage, pMark, hDC, 
                        rClientRect, lrFullsizeClientRect, lrRectPoint, lrWndRectPoint, TRUE));
            }
            break;

        case OIOP_AN_FILLED_RECT:
            if (lrRectPoint.right > pMark->Attributes.lrBounds.left){
                lrRectPoint.right++;
            }
            if (lrRectPoint.bottom > pMark->Attributes.lrBounds.top){
                lrRectPoint.bottom++;
            }

            // lrRect = old rect.
            lrRect.left = min(pMark->Attributes.lrBounds.left, pMark->Attributes.lrBounds.right);
            lrRect.top = min(pMark->Attributes.lrBounds.top, pMark->Attributes.lrBounds.bottom);
            lrRect.right = lmax(pMark->Attributes.lrBounds.left, pMark->Attributes.lrBounds.right);
            lrRect.bottom = lmax(pMark->Attributes.lrBounds.top, pMark->Attributes.lrBounds.bottom);
            ConvertRect(pWindow, &lrRect, CONV_FULLSIZE_TO_WINDOW);

            // lrRectNew = new rect.
            lrRectNew.left = min(pMark->Attributes.lrBounds.left, lrRectPoint.right);
            lrRectNew.top = min(pMark->Attributes.lrBounds.top, lrRectPoint.bottom);
            lrRectNew.right = lmax(pMark->Attributes.lrBounds.left, lrRectPoint.right);
            lrRectNew.bottom = lmax(pMark->Attributes.lrBounds.top, lrRectPoint.bottom);
            ConvertRect(pWindow, &lrRectNew, CONV_FULLSIZE_TO_WINDOW);

            // To avoid flicker, erase and draw only the modified parts.
            nOldROP = SetROP2(hDC, R2_XORPEN);
            hOldPen = SelectObject(hDC, GetStockObject(NULL_PEN));
            hOldBrush = SelectObject(hDC, GetStockObject(WHITE_BRUSH));

            // Erase the left part of the old rect that doesn't exsist any more.
            if (lrRect.left < lrRectNew.left){
                Rectangle(hDC, (int) lmax(0, lrRect.left),
                        (int) lmax(0, lrRect.top),
                        (int) min(rClientRect.right, lrRectNew.left) + 1,
                        (int) min(rClientRect.bottom, lrRect.bottom) + 1);
            }
            // Erase the right part of the old rect that doesn't exsist any more.
            if (lrRect.right > lrRectNew.right){
                Rectangle(hDC, (int) lmax(0, lrRectNew.right),
                        (int) lmax(0, lrRect.top),
                        (int) min(rClientRect.right, lrRect.right) + 1,
                        (int) min(rClientRect.bottom, lrRect.bottom) + 1);
            }
            // Erase the top part of the old rect that doesn't exsist any more.
            if (lrRect.top < lrRectNew.top){
                Rectangle(hDC, (int) lmax(0, lmax(lrRect.left, lrRectNew.left)),
                        (int) lmax(0, lrRect.top),
                        (int) min(rClientRect.right, min(lrRect.right, lrRectNew.right)) + 1,
                        (int) min(rClientRect.bottom, lrRectNew.top) + 1);
            }
            // Erase the bottom part of the old rect that doesn't exsist any more.
            if (lrRect.bottom > lrRectNew.bottom){
                Rectangle(hDC, (int) lmax(0, lmax(lrRect.left, lrRectNew.left)),
                        (int) lmax(0, lrRectNew.bottom),
                        (int) min(rClientRect.right, min(lrRect.right, lrRectNew.right)) + 1,
                        (int) min(rClientRect.bottom, lrRect.bottom) + 1);
            }

            // Draw the new left part of the rect that didn't exsist before.
            if (lrRectNew.left < lrRect.left){
                Rectangle(hDC, (int) lmax(0, lrRectNew.left),
                        (int) lmax(0, lmax(lrRect.top, lrRectNew.top)),
                        (int) min(rClientRect.right, lrRect.left) + 1,
                        (int) min(rClientRect.bottom, min(lrRect.bottom, lrRectNew.bottom)) + 1);
            }
            // Draw the new right part of the rect that didn't exsist before.
            if (lrRectNew.right > lrRect.right){
                Rectangle(hDC, (int) lmax(0, lrRect.right),
                        (int) lmax(0, lmax(lrRect.top, lrRectNew.top)),
                        (int) min(rClientRect.right, lrRectNew.right) + 1,
                        (int) min(rClientRect.bottom, min(lrRect.bottom, lrRectNew.bottom)) + 1);
            }
            // Draw the new top part of the rect that didn't exsist before.
            if (lrRectNew.top < lrRect.top){
                Rectangle(hDC, (int) lmax(0, lrRectNew.left),
                        (int) lmax(0, lrRectNew.top),
                        (int) min(rClientRect.right, lrRectNew.right) + 1,
                        (int) min(rClientRect.bottom, lrRect.top) + 1);
            }
            // Draw the new bottom part of the rect that didn't exsist before.
            if (lrRectNew.bottom > lrRect.bottom){
                Rectangle(hDC, (int) lmax(0, lrRectNew.left),
                        (int) lmax(0, lrRect.bottom),
                        (int) min(rClientRect.right, lrRectNew.right) + 1,
                        (int) min(rClientRect.bottom, lrRectNew.bottom) + 1);
            }
            pMark->Attributes.lrBounds.right = lrRectPoint.right;
            pMark->Attributes.lrBounds.bottom = lrRectPoint.bottom;

            SelectObject(hDC, hOldBrush);
            SelectObject(hDC, hOldPen);
            SetROP2(hDC, nOldROP);

            break;

        case OIOP_AN_HOLLOW_RECT:
            // Erase the old XORed mark.
            CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                    pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_XOR, 
                    pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                    pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                    DONT_FORCE_OPAQUE_RECTANGLES));

            // Update rectangle.
            pMark->Attributes.lrBounds.right = lrRectPoint.right;
            pMark->Attributes.lrBounds.bottom = lrRectPoint.bottom;

            // Draw the new XORed mark.
            CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                    pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_XOR, 
                    pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                    pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                    DONT_FORCE_OPAQUE_RECTANGLES));
            break;

        case OIOP_AN_LINE:
            CheckError2( GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints));
            if (!pPoints){
                nStatus = Error(DISPLAY_DATACORRUPTED);
                goto Exit;
            }

            // Erase the old XORed mark.
            CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                    pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_XOR, 
                    pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                    pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                    DONT_FORCE_OPAQUE_RECTANGLES));

            // Update the line segment.
            pPoints->ptPoint[pPoints->nPoints - 1].x
                    = (int)(lrRectPoint.left - pMark->Attributes.lrBounds.left);
            pPoints->ptPoint[pPoints->nPoints - 1].y
                    = (int)(lrRectPoint.top - pMark->Attributes.lrBounds.top);

            // Draw the new XORed mark.
            CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                    pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_XOR, 
                    pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                    pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                    DONT_FORCE_OPAQUE_RECTANGLES));
            break;

        case OIOP_AN_FREEHAND:
            CheckError2( GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints));
            if (!pPoints){
                nStatus = Error(DISPLAY_DATACORRUPTED);
                goto Exit;
            }

            if (pPoints->nPoints == pPoints->nMaxPoints){
                // We exceeded the max number of line segments.
                pPoints->nMaxPoints += 100;
                CheckError2( ReAllocateAMarkNamedBlock(pMark, szOiAnoDat, 
                        (PPSTR) &pPoints, sizeof(AN_POINTS) + (sizeof(POINT)
                        * (pPoints->nMaxPoints - 1))));
            }

            pPoints->ptPoint[pPoints->nPoints].x
                    = (int)(lrRectPoint.left - pMark->Attributes.lrBounds.left);
            pPoints->ptPoint[pPoints->nPoints].y
                    = (int)(lrRectPoint.top - pMark->Attributes.lrBounds.top);

            // Draw the line segment.
            nSize = max(1, (pMark->Attributes.uLineSize 
                    * pWindow->nScale / SCALE_DENOMINATOR));
            if (pMark->Attributes.bHighlighting){
                nOldROP = SetROP2(hDC, R2_MASKPEN);
            }else{
                nOldROP = SetROP2(hDC, R2_COPYPEN);
            }
            hPen = CreatePen(PS_SOLID, nSize,
                    RGB(pMark->Attributes.rgbColor1.rgbRed,
                    pMark->Attributes.rgbColor1.rgbGreen,
                    pMark->Attributes.rgbColor1.rgbBlue));
            hOldPen = SelectObject(hDC, hPen);
            hOldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH));

            SetLRect(lrRect, pPoints->ptPoint[pPoints->nPoints - 1].x 
                    + pMark->Attributes.lrBounds.left,
                    pPoints->ptPoint[pPoints->nPoints - 1].y 
                    + pMark->Attributes.lrBounds.top,
                    pPoints->ptPoint[pPoints->nPoints].x 
                    + pMark->Attributes.lrBounds.left,
                    pPoints->ptPoint[pPoints->nPoints].y 
                    + pMark->Attributes.lrBounds.top);
            ConvertRect(pWindow, &lrRect, CONV_FULLSIZE_TO_WINDOW);
            if (ReduceLineToLRect(&lrRect, lrClientRect)){
                MoveToEx(hDC, (int) lrRect.left, (int) lrRect.top, NULL);
                LineTo(hDC, (int) lrRect.right, (int) lrRect.bottom);
            }
            pPoints->nPoints++;

            SelectObject(hDC, hOldBrush);
            SelectObject(hDC, hOldPen);
            DeleteObject(hPen);
            SetROP2(hDC, nOldROP);
            break;

        case OIOP_AN_TEXT:
        case OIOP_AN_TEXT_FROM_A_FILE:
        case OIOP_AN_TEXT_STAMP:
        case OIOP_AN_ATTACH_A_NOTE:
            CheckError2( ContinueOperationText(hWnd, ptPoint,
                    nFlags, pWindow, pImage, pMark, hDC, rClientRect,
                    lrFullsizeClientRect));
            break;

        case OIOP_AN_IMAGE:
        case OIOP_AN_IMAGE_BY_REFERENCE:
        case OIOP_AN_FORM:
            CheckError2( ContinueOperationBitmap(hWnd, ptPoint, nFlags, pWindow, 
                    pImage, pMark, hDC, rClientRect, lrFullsizeClientRect));
            break;

        case OIOP_PASTE:
            if (pAnoImage->Annotations.bPasteInProgress){
                CheckError2( MoveSelectedMarks(hWnd, pWindow, pAnoImage, 
                        pMark, hDC, rClientRect, lrFullsizeClientRect, 
                        lrRectPoint, lrWndRectPoint, FALSE));
            }
            break;

        case OIOP_AN_AUDIO:
        default:
            break;
    }

Exit:
    if (hDC){
        ReleaseDC(hWnd, hDC);
    }
    DeInit(FALSE, TRUE);
    return(nStatus);
}
//
/****************************************************************************

    FUNCTION:   OIOpEndOperation

    PURPOSE:    This routine Ends the annotation.

****************************************************************************/

int  WINAPI OiOpEndOperation(HWND hWnd){

int       nStatus;
PWINDOW  pWindow;
PANO_IMAGE pAnoImage;
PIMAGE   pImage = 0;

int  nMarkIndex;
int  nMarkIndex2;

PMARK pMark = 0;
PMARK pMark2;
PMARK pTempMark;

int  nLoop;
HDC hDC = 0;
RECT rClientRect;
LRECT lrFullsizeClientRect;
PAN_POINTS pPoints;
long lHOffset;
long lVOffset;
BOOL bDeleteMark = FALSE;
BOOL bRepaint = FALSE;
LRECT lrRect; 
LRECT lrMarkBounds;
BOOL bMarkComplete = TRUE;
PSTR pBlock;
PBITMAPINFOHEADER pDib = 0;
PAN_NEW_ROTATE_STRUCT pAnRotation =0;
PAN_IMAGE_STRUCT pAnImage = 0;
PBITMAPINFOHEADER pFormDib = 0;
BOOL bInvalidateAllDisplayRects = FALSE;
BOOL bInvalidateAllDisplayRectsFlag = FALSE;
long lTemp;
int  nHScale;
int  nVScale;


    CheckError2( Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE));
    pImage = pAnoImage->pBaseImage;

    CheckError2( TranslateScale(pWindow->nScale, pImage->nHRes, pImage->nVRes, &nHScale, &nVScale));

    // Find next available mark.
    if (!pAnoImage->Annotations.ppMarks){
        goto Exit; // Nothing to do.
    }
    pMark = pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks];

    // If there is no operation in progress, then return.
    if (!pMark){
        goto Exit; // Nothing to do.
    }

    hDC = GetDC(hWnd);
    GetClientRect(hWnd, &rClientRect);
    CopyRect(lrFullsizeClientRect, rClientRect);
    ConvertRect(pWindow, &lrFullsizeClientRect, CONV_WINDOW_TO_FULLSIZE);

    switch ((int) pMark->Attributes.uType){
        case OIOP_SELECT_BY_RECT_VARIABLE:
        case OIOP_SELECT_BY_RECT_FIXED:
        case OIOP_SELECT_BY_POINT:
            if (pAnoImage->Annotations.bMoving && !pAnoImage->Annotations.bMoved){
                // Erase the selection rect if it is still there.
                SetLRect(lrRect, 0, 0, 0, 0);
                CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
            }

            if (!pAnoImage->Annotations.bMoving 
                    && (int) pMark->Attributes.uType != OIOP_SELECT_BY_POINT
                    && !(pAnoImage->nStartOpFlags & OIOP_IMAGE_ONLY)){

                // Change the selection state of all marks inside the rect.
                GetSelectBox(pAnoImage, &lrRect);
                if (lrRect.right == lrRect.left || lrRect.bottom == lrRect.top){
                    // Erase the selection rect if it contains no space.
                    SetLRect(lrRect, 0, 0, 0, 0);
                    CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
                }
                if (lrRect.right && lrRect.bottom){
                    for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                        pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                        CopyRect(lrMarkBounds, pMark2->Attributes.lrBounds);
                        // If the mark is aligned with the right or bottom 
                        // edge of the image, we must fudge the selection
                        // rect to be able to select it.
                        if (lrMarkBounds.right >= (int) pImage->nWidth ||
                            lrMarkBounds.bottom >= (int) pImage->nHeight){
                            if (lrMarkBounds.left >= lrRect.left && lrMarkBounds.right <= (lrRect.right + 2)
                                    && lrMarkBounds.top >= lrRect.top && lrMarkBounds.bottom <= (lrRect.bottom + 2)){
                                if (pAnoImage->nStartOpFwKeys & MK_CONTROL){
                                    pMark2->bSelected ^= TRUE;
                                }else{
                                    pMark2->bSelected = TRUE;
                                }
                            }
                        }else{
                            if (lrMarkBounds.left >= lrRect.left && lrMarkBounds.right <= lrRect.right
                                    && lrMarkBounds.top >= lrRect.top && lrMarkBounds.bottom <= lrRect.bottom){
                                if (pAnoImage->nStartOpFwKeys & MK_CONTROL){
                                    pMark2->bSelected ^= TRUE;
                                }else{
                                    pMark2->bSelected = TRUE;
                                }
                            }
                        }
                    }
                }
            }
            if (pAnoImage->Annotations.bMoved){
                lHOffset = pMark->Attributes.lrBounds.right - pMark->Attributes.lrBounds.left;
                lVOffset = pMark->Attributes.lrBounds.bottom - pMark->Attributes.lrBounds.top;
                if (lHOffset || lVOffset){
                    for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                        pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                        if (!pMark2->bSelected){
                            continue;
                        }
                        CheckError2( ResizeMark(pMark2, pAnoImage->nHandle, lHOffset, lVOffset));
                        pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
                        // swap bounds  if mark has flipped over on itself
                        if (pMark2->Attributes.lrBounds.top >  
                                pMark2->Attributes.lrBounds.bottom){
                            lTemp = pMark2->Attributes.lrBounds.top;
                            pMark2->Attributes.lrBounds.top = pMark2->Attributes.lrBounds.bottom;
                            pMark2->Attributes.lrBounds.bottom = lTemp;
                        }                                                                                                
                        if (pMark2->Attributes.lrBounds.left >  
                                pMark2->Attributes.lrBounds.right){
                            lTemp = pMark2->Attributes.lrBounds.left;
                            pMark2->Attributes.lrBounds.left = pMark2->Attributes.lrBounds.right;
                            pMark2->Attributes.lrBounds.right = lTemp;
                        }                                                                                                
                    }
                }
                if (pAnoImage->pBasePlusFormImg != pImage->pImg){
                    pAnoImage->nBPFValidLines = 0;
                    FreeImgBuf (&pAnoImage->pBasePlusFormImg);
                    bInvalidateAllDisplayRectsFlag = TRUE;
                }                
            }

            if ((pAnoImage->nStartOpFlags & OIOP_ANNOTATIONS_ONLY)){
                SetLRect(lrRect, 0, 0, 0, 0);
                CheckError2( IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE));
            }
            // if a form mark is moved, the BPF buffer must be regenerated
            if (pAnoImage->Annotations.bMoved &&
                pAnoImage->Annotations.ppMarks[0]->Attributes.uType == OIOP_AN_FORM &&
                pAnoImage->Annotations.ppMarks[0]->bSelected){
                bInvalidateAllDisplayRectsFlag = TRUE;
            }                                
            
            bRepaint = TRUE;    
            bDeleteMark = TRUE;
            pAnoImage->Annotations.bMoving = FALSE;
            pAnoImage->Annotations.bMoved = FALSE;
            break; // All done.

        case OIOP_AN_FILLED_RECT:
        case OIOP_AN_HOLLOW_RECT:
            if (pMark->Attributes.lrBounds.left == pMark->Attributes.lrBounds.right
                    && pMark->Attributes.lrBounds.top == pMark->Attributes.lrBounds.bottom){
                bDeleteMark = TRUE;
                break; // All done.
            }
            JustifyLRect(&pMark->Attributes.lrBounds);
            // Erase the XORed mark.
            CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                    pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_XOR, 
                    pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                    pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                    DONT_FORCE_OPAQUE_RECTANGLES));
            // Draw the correct mark.
            CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                    pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_NORMAL, 
                    pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                    pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                    DONT_FORCE_OPAQUE_RECTANGLES));
            bInvalidateAllDisplayRectsFlag = FALSE;
            bRepaint = TRUE;
            
            break;

        case OIOP_AN_LINE:
        case OIOP_AN_FREEHAND:
            CheckError2( GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints));
            if (!pPoints){
                bDeleteMark = TRUE;
                break; // All done.
            }

            if (!pPoints->nPoints){
                bDeleteMark = TRUE;
                break; // All done.
            }

            // Make the left and top of the bounding rect correct.
            lHOffset = pPoints->ptPoint[0].x;
            lVOffset = pPoints->ptPoint[0].y;
            for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
                lHOffset = min(lHOffset, pPoints->ptPoint[nLoop].x);
                lVOffset = min(lVOffset, pPoints->ptPoint[nLoop].y);
            }
            pMark->Attributes.lrBounds.left += lHOffset;
            pMark->Attributes.lrBounds.top  += lVOffset;

            // Reset all line segments to the new offsets.
            for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
                pPoints->ptPoint[nLoop].x -= (int) lHOffset;
                pPoints->ptPoint[nLoop].y -= (int) lVOffset;
            }

            // Make right and bottom correct.
            lHOffset = 0;
            lVOffset = 0;
            for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
                lHOffset = lmax(lHOffset, pPoints->ptPoint[nLoop].x);
                lVOffset = lmax(lVOffset, pPoints->ptPoint[nLoop].y);
            }
            pMark->Attributes.lrBounds.right  
                    = pMark->Attributes.lrBounds.left + lHOffset;
            pMark->Attributes.lrBounds.bottom 
                    = pMark->Attributes.lrBounds.top + lVOffset;

            if ((int) pMark->Attributes.uType == OIOP_AN_LINE){
                // Erase the XORed mark.
                CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                        pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_XOR, 
                        pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                        pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                        DONT_FORCE_OPAQUE_RECTANGLES));
                // Draw the correct mark.
                CheckError2( PaintAnnotation(hWnd, hDC, pWindow, pImage,
                        pMark, rClientRect, lrFullsizeClientRect, PAINT_MODE_NORMAL, 
                        pWindow->nScale, nHScale, nVScale, pWindow->lHOffset, 
                        pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
                        DONT_FORCE_OPAQUE_RECTANGLES));
            }
            bInvalidateAllDisplayRectsFlag = FALSE;
            bRepaint = TRUE;
            
            break;

        case OIOP_AN_TEXT:
        case OIOP_AN_TEXT_FROM_A_FILE:
        case OIOP_AN_TEXT_STAMP:
        case OIOP_AN_ATTACH_A_NOTE:
            CheckError2( EndOperationText(hWnd, pWindow, pImage, pMark,
                    hDC, rClientRect, lrFullsizeClientRect, &bDeleteMark, 
                    &bRepaint));
            break;

        case OIOP_AN_IMAGE:
        case OIOP_AN_IMAGE_BY_REFERENCE:
        case OIOP_AN_FORM:
            CheckError2( EndOperationBitmap(hWnd, pWindow, pImage, pMark,
                    hDC, rClientRect, lrFullsizeClientRect, &bDeleteMark, &bRepaint));
            
            // if form, move it to the top of the mark array
            if (!bDeleteMark && (pMark != 0) && ((int) pMark->Attributes.uType
                        == OIOP_AN_FORM) && (pAnoImage->Annotations.nMarks > 0)){
                pTempMark = pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks];
                for (nMarkIndex = pAnoImage->Annotations.nMarks; nMarkIndex > 0; nMarkIndex--){
                    pAnoImage->Annotations.ppMarks[nMarkIndex] =
                        pAnoImage->Annotations.ppMarks[nMarkIndex - 1];
                }
                pAnoImage->Annotations.ppMarks[0] = pTempMark;                                                                                    
            }
            // force form to be redrawn at new position
            if ((int) pMark->Attributes.uType == OIOP_AN_FORM){
                bInvalidateAllDisplayRectsFlag = TRUE;
                bRepaint = TRUE;
            }            
            break;

        case OIOP_PASTE:
            if (pAnoImage->Annotations.bPasteInProgress){
                if (pAnoImage->Annotations.bMoved){
                    lHOffset = pMark->Attributes.lrBounds.right - pMark->Attributes.lrBounds.left;
                    lVOffset = pMark->Attributes.lrBounds.bottom - pMark->Attributes.lrBounds.top;
                    if (lHOffset || lVOffset){
                        for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                            pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                            if (!pMark2->bSelected){
                                continue;
                            }
                            CheckError2( ResizeMark(pMark2, pAnoImage->nHandle, lHOffset, lVOffset));
                        }
                    }
                }
                pAnoImage->Annotations.bPasteInProgress = FALSE;
                bMarkComplete = FALSE;
            }else{
                for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                    pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                    if (!pMark2->bSelected){
                        continue;
                    }

                    if (pMark2->Attributes.uType == OIOP_AN_IMAGE){
                        CheckError2( GetAMarkNamedBlock(pMark2, szOiAnoDat, (PPSTR) &pAnRotation));
                        if (pAnRotation->bFormMark && !pAnoImage->pFormImage){
                            pMark2->Attributes.uType = OIOP_AN_FORM;
                            pMark2->Attributes.bTransparent = FALSE;
                            pAnRotation->bClipboardOp = FALSE;

                            // if form, move it to the top of the mark array
                            if (pAnoImage->Annotations.nMarks > 0){
                                for (nMarkIndex2 = nMarkIndex; 
                                        nMarkIndex2 > 0; nMarkIndex2--){
                                    pAnoImage->Annotations.ppMarks[nMarkIndex2] 
                                            = pAnoImage->Annotations.ppMarks[nMarkIndex2 - 1];
                                }
                                pAnoImage->Annotations.ppMarks[0] = pMark2;                                                                                    
                            }
                                
                            // Load pAnoImage->pFormImage, pAnoImage->pFormMark. 
                            CheckError2( AllocateMemory(sizeof(IMAGE),
                                    (PPSTR) &pAnoImage->pFormImage, ZERO_INIT));
                            CheckError2( AllocateMemory(sizeof(IMG),
                                (PPSTR) pAnoImage->pFormImage->pImg, ZERO_INIT));
                            CheckError2( GetAMarkNamedBlock(pMark2, szOiDIB, 
                                (PPSTR) &pAnImage));
                            if (pAnImage){
                                pFormDib = (PBITMAPINFOHEADER) pAnImage;
                            }else{
                                Error (DISPLAY_DATACORRUPTED);
                                goto Exit;
                            }                                                                            
                            pAnoImage->pFormImage->nHeight =  pFormDib->biHeight;
                            pAnoImage->pFormImage->nWidth =  pFormDib->biWidth;
                            pAnoImage->pFormImage->nHRes = pAnRotation->nOrigHRes;
                            pAnoImage->pFormImage->nVRes = pAnRotation->nOrigVRes;
                            CheckError2( DibToIpNoPal(&pAnoImage->pFormImage->pImg, pFormDib));
                            pAnoImage->pFormMark = pMark2;
                            CheckError2( DeleteAMarkNamedBlock (pMark2, szOiDIB));
                            
                            // Regenerate BasePlusForm image.
                            if (pAnoImage->pBasePlusFormImg != pImage->pImg){
                                pAnoImage->nBPFValidLines = 0;
                                FreeImgBuf (&pAnoImage->pBasePlusFormImg);
                                bInvalidateAllDisplayRectsFlag = TRUE;
                            }
                        }else if (pAnRotation->bFormMark && pAnoImage->pFormImage){
                            pMark2->Attributes.uType = OIOP_AN_IMAGE_BY_REFERENCE;
                        }                        
                        pAnRotation->bFormMark = FALSE;

                        CheckError2( GetAMarkNamedBlock(pMark2, szOiBaseIm, (PPSTR) &pBlock));
                        if (pBlock){
                            if ((pAnoImage->nPasteFormat == nWangAnnotatedImageFormat) ||
                                    (pAnoImage->nPasteFormat == CF_DIB)){
                                // This mark is supposed to be put into the base image.
                                CheckError2( GetAMarkNamedBlock(pMark2, szOiZDpDIB, (PPSTR) &pDib));
                                CheckError2( RenderDibToImage(&pAnoImage->pBaseImage->pImg, 
                                        pDib, 1000, 1000, pMark2->Attributes.lrBounds));
                                CheckError2( DeleteMark(pAnoImage, nMarkIndex));
                                // Regenerate BasePlusForm image.
                                if (pAnoImage->pBasePlusFormImg != pImage->pImg){
                                    pAnoImage->nBPFValidLines = 0;
                                    CheckError2( FreeImgBuf (&pAnoImage->pBasePlusFormImg));
                                    bInvalidateAllDisplayRectsFlag = TRUE;
                                }
                                nMarkIndex--;
                                pImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
                                continue;
                            }
                            if (pAnoImage->nPasteFormat == nWangAnnotationFormat){
                                CheckError2( DeleteAMarkNamedBlock(pMark2, szOiBaseIm));
                            }
                        }
                    }
                    pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
                }

                CheckError2( CheckPermissions(pWindow, pAnoImage));
                bDeleteMark = TRUE;
                bInvalidateAllDisplayRectsFlag = TRUE;
            }
            bRepaint = TRUE;
            pAnoImage->Annotations.bMoving = FALSE;
            pAnoImage->Annotations.bMoved = FALSE;
            break;

        case OIOP_AN_AUDIO:
        default:
            bDeleteMark = TRUE;
            bRepaint = TRUE; 
            break;
    }

    if (bDeleteMark){
        CheckError2( DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks));
    }else{
        if (bMarkComplete){
            if (nStatus = CheckPermissionsMark(pWindow, pAnoImage, pMark)){
                CheckError2( DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks));
                goto Exit;
            }
            pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
            pAnoImage->Annotations.nMarks++;
        }
    }
    // if the current window needs repaint, repaint all associated windows
    if (bRepaint){
        bInvalidateAllDisplayRects = TRUE;
    }
            
    if (bInvalidateAllDisplayRects){
        CheckError2( InvalidateAllDisplayRects(pWindow, pImage, NULL, bInvalidateAllDisplayRectsFlag));
    }

    if (!bRepaint && !bDeleteMark){
        GetSelectBox(pAnoImage, &lrRect);
        if (pMark->Attributes.lrBounds.left >= lrRect.left
                && pMark->Attributes.lrBounds.top >= lrRect.top
                && pMark->Attributes.lrBounds.right <= lrRect.right
                && pMark->Attributes.lrBounds.bottom <= lrRect.bottom){
            bRepaint = TRUE;
        }
    }
    if (hWnd != pWindow->hImageWnd || pWindow->hDisplayWnd[0]){
        bRepaint = TRUE;
    }

    if (bRepaint & !(pAnoImage->nStartOpFlags & PARM_DONT_REPAINT)){
        CheckError2( IMGRepaintDisplay(hWnd, (PRECT) -1));
    }


Exit:
    // if we error out of paste, delete the marks that were going to be pasted
    if (pMark){
        if (nStatus && ((int) pMark->Attributes.uType == OIOP_PASTE)){
            for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks; nMarkIndex++){
                pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                if (pMark2->bSelected){
                    DeleteMark(pAnoImage, nMarkIndex);
                    nMarkIndex--;
                }                    
            }
        }
    }
    if (nStatus && pImage){
        if (pImage){
            DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks);
            if (pWindow){
                InvalidateAllDisplayRects(pWindow, pImage, NULL, TRUE);
            }
        }
    }
    if (hDC){
        ReleaseDC(hWnd, hDC);
    }
    DeInit(FALSE, TRUE);
    return(nStatus);
}
//
/****************************************************************************

    FUNCTION:   OIOpEndOperation

    PURPOSE:    This routine Ends the annotation.

****************************************************************************/

int  WINAPI OiOpAbortOperation(HWND hWnd, int nFlags){

int       nStatus;
PWINDOW  pWindow;
PANO_IMAGE pAnoImage;
PIMAGE   pImage = 0;

int  nMarkIndex;
BOOL bArchive;
PMARK pMark;
PMARK pMark2;



    CheckError2( Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE));
    pImage = pAnoImage->pBaseImage;

    // Find next available mark.
    if (!pAnoImage->Annotations.ppMarks){
        goto Exit; // Nothing to do.
    }
    pMark = pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks];

    // If there is no operation in progress, then return.
    if (!pMark){
        goto Exit; // Nothing to do.
    }
    bArchive = pAnoImage->bArchive;

    switch ((int) pMark->Attributes.uType){
        case OIOP_PASTE:
            CheckError2( DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks));
            for (nMarkIndex = 0; nMarkIndex < (int) pAnoImage->Annotations.nMarks;){
                pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
                if (IsMarkSelected(pWindow, pMark2)){
                    if (pMark2->Attributes.uType == OIOP_AN_FORM){
                        CheckError2( InvalidateAllDisplayRects(pWindow, pImage, NULL, TRUE));
                    }                        
                    CheckError2( DeleteMark(pAnoImage, nMarkIndex));
                }else{
                    nMarkIndex++;
                }
            }
            pAnoImage->Annotations.bPasteInProgress = FALSE;
            pAnoImage->Annotations.bMoving = FALSE;
            pAnoImage->Annotations.bMoved = FALSE;

            break;

        default:
            break;
    }

    CheckError2( InvalidateAllDisplayRects(pWindow, pImage, NULL, TRUE));
    pAnoImage->bArchive = bArchive;


    if (!(nFlags & PARM_DONT_REPAINT)){
        CheckError2( IMGRepaintDisplay(hWnd, (PRECT) -1));
    }


Exit:
    // if we error out of paste, delete the marks that were going to be pasted
    DeInit(FALSE, TRUE);
    return(nStatus);
}