mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3087 lines
111 KiB
3087 lines
111 KiB
/****************************************************************************
|
|
ANNOT.C
|
|
|
|
$Log: S:\products\msprods\oiwh\display\annot.c_v $
|
|
*
|
|
* Rev 1.57 20 Jun 1996 16:01:12 RC
|
|
* Fixed resize of image and text marks
|
|
*
|
|
* Rev 1.56 18 Apr 1996 11:01:42 BEG06016
|
|
* Added CheckError2 for error handling.
|
|
*
|
|
* Rev 1.55 16 Apr 1996 15:24:38 BEG06016
|
|
* Added #ifdef IN_PROG_CHANNEL_SAFARI.
|
|
*
|
|
* Rev 1.54 11 Apr 1996 15:11:58 BEG06016
|
|
* Optimized named block access some.
|
|
*
|
|
* Rev 1.53 09 Jan 1996 14:08:00 BLJ
|
|
* Fixed rendering.
|
|
*
|
|
* Rev 1.52 02 Jan 1996 09:56:06 BLJ
|
|
* Changed alot of UINTs to ints.
|
|
* Changed IMG structure to include the image data.
|
|
* Changed lp prefix to p.
|
|
*
|
|
* Rev 1.51 22 Dec 1995 11:13:22 BLJ
|
|
* Added a parameter for zero init'ing to some memory manager calls.
|
|
*
|
|
* Rev 1.50 12 Dec 1995 10:04:04 BLJ
|
|
* Modified the memory manager to allow decommitts of image memory.
|
|
*
|
|
* Rev 1.49 13 Nov 1995 15:27:22 RC
|
|
* Fixed a bad xor paint of pasted data in paintannotations by including
|
|
* offsets for the paste operation
|
|
*
|
|
* Rev 1.48 10 Nov 1995 14:19:30 RC
|
|
* Took out abort if pumarks is 0, change lead to problems when drawing
|
|
* first mark and auto-scrolling
|
|
*
|
|
* Rev 1.47 09 Nov 1995 15:44:28 RC
|
|
* Dont call paintannotation if *pumarks is 0
|
|
*
|
|
* Rev 1.46 08 Nov 1995 12:27:58 RC
|
|
* Added drawing of dashed rect around text marks in painthandles
|
|
*
|
|
* Rev 1.45 08 Nov 1995 11:12:24 RC
|
|
* Took out PAINT_MODE_SELECTED flag as its function is now performed by
|
|
* PaintHandles
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "privdisp.h"
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: PaintAnnotations
|
|
|
|
PURPOSE: This routine Paints the annotations on an hDC.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI PaintAnnotations(HWND hWnd, HDC hDC, PWINDOW pWindow,
|
|
PIMAGE pImage, RECT rRepaintRect, int nSaveAno,
|
|
BOOL bPaintSelectedAsNonselected, int nScale,
|
|
int nHScale, int nVScale, long lHOffset, long lVOffset,
|
|
PMARK **pppMarks, int *pnMarks,
|
|
int nFlags, BOOL bUseBilevelDithering,
|
|
BOOL bForceOpaqueRectangles){
|
|
|
|
int nStatus = 0;
|
|
PANO_IMAGE pAnoImage;
|
|
|
|
int nMarkIndex;
|
|
PMARK pMark;
|
|
LRECT lrFullsizeRepaintRect;
|
|
long lHPointOffset;
|
|
long lVPointOffset;
|
|
BOOL bOverride;
|
|
int nSize;
|
|
BOOL bProcessMark;
|
|
int nBilevelFlag;
|
|
RGBQUAD rgbColorOld;
|
|
|
|
|
|
nBilevelFlag = nSaveAno & 0x000c;
|
|
pAnoImage = pWindow->pDisplay->pAnoImage;
|
|
|
|
if (nSaveAno & OIAN_PRIV_OVERRIDE){
|
|
bOverride = TRUE;
|
|
nSaveAno -= OIAN_PRIV_OVERRIDE;
|
|
}else{
|
|
bOverride = FALSE;
|
|
}
|
|
|
|
if ((nSaveAno & 0x0003) == SAVE_ANO_NONE || !(*pppMarks)){
|
|
goto Exit;
|
|
}
|
|
|
|
CopyRectRtoL(lrFullsizeRepaintRect, rRepaintRect);
|
|
ConvertRect2(&lrFullsizeRepaintRect, CONV_WINDOW_TO_FULLSIZE,
|
|
nHScale, nVScale, lHOffset, lVOffset);
|
|
|
|
// Set PointOffsets for marks being dragged.
|
|
lHPointOffset = 0;
|
|
lVPointOffset = 0;
|
|
if (*pppMarks){
|
|
if (pMark = (*pppMarks)[*pnMarks]){
|
|
if ((int) pMark->Attributes.uType == OIOP_SELECT_BY_POINT ||
|
|
(int) pMark->Attributes.uType == OIOP_PASTE){
|
|
lHPointOffset = pMark->Attributes.lrBounds.right - pMark->Attributes.lrBounds.left;
|
|
lVPointOffset = pMark->Attributes.lrBounds.bottom - pMark->Attributes.lrBounds.top;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (nMarkIndex = 0; nMarkIndex <= *pnMarks; nMarkIndex++){
|
|
if (!(pMark = (*pppMarks)[nMarkIndex])){
|
|
break;
|
|
}
|
|
bProcessMark = TRUE;
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_AN_LINE:
|
|
case OIOP_AN_FREEHAND:
|
|
case OIOP_AN_HOLLOW_RECT:
|
|
nSize = max(1, ((int) pMark->Attributes.uLineSize
|
|
* nScale / SCALE_DENOMINATOR));
|
|
break;
|
|
|
|
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_AUDIO:
|
|
case OIOP_AN_IMAGE:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
case OIOP_AN_FORM:
|
|
nSize = 0;
|
|
break;
|
|
|
|
default:
|
|
bProcessMark = FALSE;
|
|
break;
|
|
}
|
|
if (!bProcessMark || (!((nSaveAno & 0x0003) == SAVE_ANO_ALL)
|
|
&& ((((nSaveAno & 0x0003) == SAVE_ANO_VISIBLE) && !pMark->Attributes.bVisible)
|
|
|| (((nSaveAno & 0x0003)== SAVE_ANO_SELECTED) && !IsMarkSelected(pWindow, pMark))))){
|
|
continue;
|
|
}
|
|
|
|
rgbColorOld = pMark->Attributes.rgbColor1;
|
|
if (nBilevelFlag == SAVE_ANO_BILEVEL_ALL_BLACK){
|
|
pMark->Attributes.rgbColor1.rgbRed = 0;
|
|
pMark->Attributes.rgbColor1.rgbGreen = 0;
|
|
pMark->Attributes.rgbColor1.rgbBlue = 0;
|
|
pMark->Attributes.rgbColor2.rgbRed = 0;
|
|
pMark->Attributes.rgbColor2.rgbGreen = 0;
|
|
pMark->Attributes.rgbColor2.rgbBlue = 0;
|
|
}else if (nBilevelFlag == SAVE_ANO_BILEVEL_ALL_WHITE){
|
|
pMark->Attributes.rgbColor1.rgbRed = 255;
|
|
pMark->Attributes.rgbColor1.rgbGreen = 255;
|
|
pMark->Attributes.rgbColor1.rgbBlue = 255;
|
|
pMark->Attributes.rgbColor2.rgbRed = 255;
|
|
pMark->Attributes.rgbColor2.rgbGreen = 255;
|
|
pMark->Attributes.rgbColor2.rgbBlue = 255;
|
|
}
|
|
|
|
if (nMarkIndex == *pnMarks && (int) pMark->Attributes.uType != OIOP_AN_FREEHAND){
|
|
CheckError2(PaintAnnotation(hWnd, hDC, pWindow, pImage,
|
|
pMark, rRepaintRect, lrFullsizeRepaintRect,
|
|
PAINT_MODE_XOR, nScale, nHScale, nVScale, lHOffset, lVOffset,
|
|
nFlags, bUseBilevelDithering, bForceOpaqueRectangles))
|
|
}else{
|
|
if (nMarkIndex == *pnMarks
|
|
|| (pMark->Attributes.lrBounds.left - ((int) (nSize + 1) / 2) < lrFullsizeRepaintRect.right
|
|
&& pMark->Attributes.lrBounds.top - ((int) (nSize + 1) / 2) < lrFullsizeRepaintRect.bottom
|
|
&& pMark->Attributes.lrBounds.right + ((int) (nSize + 1) / 2) > lrFullsizeRepaintRect.left
|
|
&& pMark->Attributes.lrBounds.bottom + ((int) (nSize + 1) / 2) > lrFullsizeRepaintRect.top)){
|
|
CheckError2(PaintAnnotation(hWnd, hDC, pWindow, pImage,
|
|
pMark, rRepaintRect, lrFullsizeRepaintRect,
|
|
PAINT_MODE_NORMAL, nScale, nHScale, nVScale, lHOffset, lVOffset,
|
|
nFlags, bUseBilevelDithering, bForceOpaqueRectangles))
|
|
}
|
|
if (!bPaintSelectedAsNonselected && IsMarkSelected(pWindow, pMark)){
|
|
CheckError2(ResizeMark(pMark, pAnoImage->nHandle, lHPointOffset, lVPointOffset))
|
|
if (pMark->Attributes.lrBounds.left - ((int) (nSize + 1) / 2) < lrFullsizeRepaintRect.right
|
|
&& pMark->Attributes.lrBounds.top - ((int) (nSize + 1) / 2) < lrFullsizeRepaintRect.bottom
|
|
&& pMark->Attributes.lrBounds.right + ((int) (nSize + 1) / 2) > lrFullsizeRepaintRect.left
|
|
&& pMark->Attributes.lrBounds.bottom + ((int) (nSize + 1) / 2) > lrFullsizeRepaintRect.top){
|
|
if (pAnoImage->Annotations.bMoved){
|
|
CheckError2(PaintAnnotation(hWnd, hDC, pWindow, pImage,
|
|
pMark, rRepaintRect, lrFullsizeRepaintRect,
|
|
PAINT_MODE_DRAG, nScale, nHScale, nVScale, lHOffset, lVOffset,
|
|
nFlags, bUseBilevelDithering, bForceOpaqueRectangles))
|
|
}
|
|
}
|
|
CheckError2(ResizeMark(pMark, pAnoImage->nHandle, -lHPointOffset, -lVPointOffset))
|
|
}
|
|
pMark->Attributes.rgbColor1 = rgbColorOld;
|
|
}
|
|
}
|
|
|
|
if (bPaintSelectedAsNonselected){
|
|
goto Exit;
|
|
}
|
|
|
|
for (nMarkIndex = 0; nMarkIndex <= *pnMarks; nMarkIndex++){
|
|
if (!(pMark = (*pppMarks)[nMarkIndex])){
|
|
break;
|
|
}
|
|
bProcessMark = TRUE;
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_AN_LINE:
|
|
case OIOP_AN_FREEHAND:
|
|
case OIOP_AN_HOLLOW_RECT:
|
|
nSize = max(1, ((int) pMark->Attributes.uLineSize
|
|
* nScale / SCALE_DENOMINATOR));
|
|
break;
|
|
|
|
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_AUDIO:
|
|
case OIOP_AN_IMAGE:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
case OIOP_AN_FORM:
|
|
nSize = 0;
|
|
break;
|
|
|
|
default:
|
|
bProcessMark = FALSE;
|
|
break;
|
|
}
|
|
if (!bProcessMark || !IsMarkSelected(pWindow, pMark)
|
|
|| ((nSaveAno & 0x0003)== SAVE_ANO_VISIBLE && !pMark->Attributes.bVisible)){
|
|
continue;
|
|
}
|
|
|
|
if (pMark->Attributes.lrBounds.left - ((int) (nSize + 1) / 2) < lrFullsizeRepaintRect.right
|
|
&& pMark->Attributes.lrBounds.top - ((int) (nSize + 1) / 2) < lrFullsizeRepaintRect.bottom
|
|
&& pMark->Attributes.lrBounds.right + ((int) (nSize + 1) / 2) > lrFullsizeRepaintRect.left
|
|
&& pMark->Attributes.lrBounds.bottom + ((int) (nSize + 1) / 2) > lrFullsizeRepaintRect.top){
|
|
CheckError2(PaintHandles(hDC, pWindow, pImage, pMark, rRepaintRect,
|
|
lrFullsizeRepaintRect, nHScale, nVScale, lHOffset, lVOffset))
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: PaintAnnotation
|
|
|
|
PURPOSE: This routine Paints an annotation on an hDC.
|
|
|
|
INPUTS: nMode - PAINT_MODE_XOR - Draw the mark XORed with white.
|
|
PAINT_MODE_DRAG - Draw the mark for dragging purposes.
|
|
PAINT_MODE_NORMAL - Draw the mark as it normally appears.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI PaintAnnotation(HWND hWnd, HDC hDC, PWINDOW pWindow,
|
|
PIMAGE pImage, PMARK pMark, RECT rRepaintRect,
|
|
LRECT lrFullsizeRepaintRect, int nMode, int nScale,
|
|
int nHScale, int nVScale, long lHOffset, long lVOffset,
|
|
int nFlags, BOOL bUseBilevelDithering,
|
|
BOOL bForceOpaqueRectangles){
|
|
|
|
int nStatus = 0;
|
|
|
|
LRECT lrRect;
|
|
RECT rRect;
|
|
int nOldROP;
|
|
HBRUSH hBrush = 0;
|
|
HBRUSH hOldBrush;
|
|
BOOL bBrushSelected = FALSE;
|
|
HPEN hPen = 0;
|
|
HPEN hOldPen;
|
|
BOOL bPenSelected = FALSE;
|
|
int nLoop;
|
|
int nSize;
|
|
PAN_POINTS pPoints;
|
|
RGBQUAD RGBQuad1;
|
|
RGBQUAD RGBQuad2;
|
|
|
|
COLORREF rgbColor;
|
|
int nRopCode;
|
|
LRECT lrRepaintRect;
|
|
int nGray8;
|
|
int nBrush;
|
|
BOOL bDeleteBrush = TRUE;
|
|
PBITMAPINFOHEADER pSolidDIB = NULL;
|
|
|
|
|
|
switch (nMode){
|
|
case PAINT_MODE_XOR:
|
|
nRopCode = R2_XORPEN;
|
|
rgbColor = RGB(255, 255, 255);
|
|
break;
|
|
|
|
case PAINT_MODE_DRAG:
|
|
nRopCode = R2_XORPEN;
|
|
rgbColor = RGB(128, 128, 128);
|
|
break;
|
|
|
|
case PAINT_MODE_NORMAL:
|
|
nRopCode = R2_COPYPEN;
|
|
if (pMark->Attributes.bHighlighting){
|
|
nRopCode = R2_MASKPEN;
|
|
}
|
|
rgbColor = RGB(pMark->Attributes.rgbColor1.rgbRed,
|
|
pMark->Attributes.rgbColor1.rgbGreen,
|
|
pMark->Attributes.rgbColor1.rgbBlue);
|
|
break;
|
|
}
|
|
nOldROP = SetROP2(hDC, nRopCode);
|
|
|
|
if (!pMark->Attributes.bVisible){
|
|
goto Exit;
|
|
}
|
|
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_AN_LINE:
|
|
case OIOP_AN_FREEHAND:
|
|
case OIOP_AN_HOLLOW_RECT:
|
|
// These require a pen.
|
|
if (nMode == PAINT_MODE_XOR){
|
|
nSize = 1;
|
|
}else{
|
|
nSize = max(1, ((int) pMark->Attributes.uLineSize
|
|
* nScale / SCALE_DENOMINATOR));
|
|
}
|
|
if (rgbColor == RGB(255, 255, 255) && nSize == 1){
|
|
hOldPen = SelectObject(hDC, GetStockObject(WHITE_PEN));
|
|
}else{
|
|
hPen = CreatePen(PS_SOLID, nSize, rgbColor);
|
|
hOldPen = SelectObject(hDC, hPen);
|
|
}
|
|
bPenSelected = TRUE;
|
|
hOldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH));
|
|
bBrushSelected = TRUE;
|
|
break;
|
|
|
|
case OIOP_AN_FILLED_RECT:
|
|
// These require a brush.
|
|
if (rgbColor == RGB(255, 255, 255)){
|
|
hOldBrush = SelectObject(hDC, GetStockObject(WHITE_BRUSH));
|
|
}else{
|
|
if (bUseBilevelDithering != USE_BI_LEVEL_DITHERING
|
|
&& GetDeviceCaps(hDC, NUMCOLORS) != 1){ // 1 = 1 Bit Per Pixel.
|
|
hBrush = CreateSolidBrush(rgbColor);
|
|
}else{
|
|
nGray8 = ((((rgbColor & 0x00ff0000) >> 16) * 15)
|
|
+ (((rgbColor & 0x0000ff00) >> 8) * 56)
|
|
+ ((rgbColor & 0x000000ff) * 29)) / 100;
|
|
nBrush = nGray8 >> 4;
|
|
if (nBrush > 7){
|
|
nBrush++;
|
|
}
|
|
bDeleteBrush = FALSE;
|
|
hBrush = hPatternBrush[nBrush];
|
|
}
|
|
hOldBrush = SelectObject(hDC, hBrush);
|
|
}
|
|
bBrushSelected = TRUE;
|
|
hOldPen = SelectObject(hDC, GetStockObject(NULL_PEN));
|
|
bPenSelected = TRUE;
|
|
break;
|
|
|
|
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_AUDIO:
|
|
case OIOP_AN_IMAGE:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
case OIOP_AN_FORM:
|
|
// These require special handling.
|
|
// Don't do anything here for these.
|
|
// Thier routines will be called later.
|
|
break;
|
|
}
|
|
|
|
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_AN_FILLED_RECT:
|
|
CopyRect(lrRect, pMark->Attributes.lrBounds);
|
|
JustifyLRect(&lrRect);
|
|
ConvertRect2(&lrRect, CONV_FULLSIZE_TO_WINDOW,
|
|
nHScale, nVScale, lHOffset, lVOffset);
|
|
rRect.left = (int) max(rRepaintRect.left, lrRect.left);
|
|
rRect.top = (int) max(rRepaintRect.top, lrRect.top);
|
|
rRect.right = (int) min(rRepaintRect.right, lrRect.right) + 1;
|
|
rRect.bottom = (int) min(rRepaintRect.bottom, lrRect.bottom) + 1;
|
|
if (!pMark->Attributes.bHighlighting && bForceOpaqueRectangles){
|
|
// Use StretchDIBits() instead of Rectangle() for non-highlighted
|
|
// filled rectangles (only when printing). Work around for printer
|
|
// drivers (HPLJ4 drivers) that ignore SetROP2() drawing mode.
|
|
CheckError2(CreateSolidDIB(&pSolidDIB, pMark->Attributes.rgbColor1))
|
|
StretchDIBits(hDC, rRect.left, rRect.top,
|
|
rRect.right - rRect.left - 1, rRect.bottom - rRect.top - 1,
|
|
0, 0, 32, 32, (PSTR)pSolidDIB + sizeof(BITMAPINFOHEADER) + 8,
|
|
(PBITMAPINFO)pSolidDIB, DIB_RGB_COLORS, SRCCOPY);
|
|
}else{
|
|
Rectangle(hDC, rRect.left, rRect.top, rRect.right, rRect.bottom);
|
|
}
|
|
break;
|
|
|
|
case OIOP_AN_HOLLOW_RECT:
|
|
nSize = max(1, ((int) pMark->Attributes.uLineSize
|
|
* nScale / SCALE_DENOMINATOR));
|
|
CopyRect(lrRect, pMark->Attributes.lrBounds);
|
|
JustifyLRect(&lrRect);
|
|
ConvertRect2(&lrRect, CONV_FULLSIZE_TO_WINDOW,
|
|
nHScale, nVScale, lHOffset, lVOffset);
|
|
if (lrRect.left < -32767 || lrRect.left > 32767
|
|
|| lrRect.top < -32767 || lrRect.top > 32767
|
|
|| lrRect.right < -32767 || lrRect.right > 32767
|
|
|| lrRect.bottom < -32767 || lrRect.bottom > 32767){
|
|
SetRRect(rRect,
|
|
max(rRepaintRect.left - (int)((nSize + 3) / 2), lrRect.left),
|
|
max(rRepaintRect.top - (int)((nSize + 3) / 2), lrRect.top),
|
|
min(rRepaintRect.right + (int)((nSize + 3) / 2), lrRect.right) + 1,
|
|
min(rRepaintRect.bottom + (int)((nSize + 3) / 2), lrRect.bottom) + 1);
|
|
}else{
|
|
CopyRectLtoR(rRect, lrRect);
|
|
}
|
|
Rectangle(hDC, rRect.left, rRect.top, rRect.right, rRect.bottom);
|
|
break;
|
|
|
|
case OIOP_AN_LINE:
|
|
case OIOP_AN_FREEHAND:
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
if (pPoints->nPoints < 2){
|
|
goto Exit; // Not enough points to paint.
|
|
}
|
|
|
|
SetLRect(lrRepaintRect, rRepaintRect.left - ((nSize + 1) / 2),
|
|
rRepaintRect.top - ((nSize + 1) / 2),
|
|
rRepaintRect.right + ((nSize + 1) / 2),
|
|
rRepaintRect.bottom + ((nSize + 1) / 2));
|
|
|
|
for (nLoop = 0; nLoop < pPoints->nPoints - 1; nLoop++){
|
|
// Draw the line segment.
|
|
SetLRect(lrRect, pPoints->ptPoint[nLoop].x + pMark->Attributes.lrBounds.left,
|
|
pPoints->ptPoint[nLoop].y + pMark->Attributes.lrBounds.top,
|
|
pPoints->ptPoint[nLoop + 1].x + pMark->Attributes.lrBounds.left,
|
|
pPoints->ptPoint[nLoop + 1].y + pMark->Attributes.lrBounds.top);
|
|
ConvertRect2(&lrRect, CONV_FULLSIZE_TO_WINDOW,
|
|
nHScale, nVScale, lHOffset, lVOffset);
|
|
if (ReduceLineToLRect(&lrRect, lrRepaintRect)){
|
|
MoveToEx(hDC, (int) lrRect.left, (int) lrRect.top, NULL);
|
|
LineTo(hDC, (int) lrRect.right, (int) lrRect.bottom);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OIOP_AN_TEXT:
|
|
case OIOP_AN_TEXT_FROM_A_FILE:
|
|
case OIOP_AN_TEXT_STAMP:
|
|
CheckError2(PaintAnnotationText(hWnd, hDC, pWindow, pImage,
|
|
pMark, rRepaintRect, lrFullsizeRepaintRect, nMode,
|
|
nHScale, nVScale, lHOffset, lVOffset, DONT_FORCE_OPAQUE_RECTANGLES))
|
|
break;
|
|
|
|
case OIOP_AN_ATTACH_A_NOTE:
|
|
RGBQuad1 = pMark->Attributes.rgbColor1;
|
|
RGBQuad2 = pMark->Attributes.rgbColor2;
|
|
|
|
// If painting to B + W context, then change colors.
|
|
if (bUseBilevelDithering == USE_BI_LEVEL_DITHERING
|
|
|| GetDeviceCaps(hDC, NUMCOLORS) == 1){ // 1 = 1 Bit Per Pixel.
|
|
if (((pMark->Attributes.rgbColor1.rgbBlue * 15)
|
|
+ (pMark->Attributes.rgbColor1.rgbGreen * 56)
|
|
+ (pMark->Attributes.rgbColor1.rgbRed * 29))
|
|
<= ((pMark->Attributes.rgbColor2.rgbBlue * 15)
|
|
+ (pMark->Attributes.rgbColor2.rgbGreen * 56)
|
|
+ (pMark->Attributes.rgbColor2.rgbRed * 29))){
|
|
pMark->Attributes.rgbColor1.rgbBlue = 0;
|
|
pMark->Attributes.rgbColor1.rgbGreen = 0;
|
|
pMark->Attributes.rgbColor1.rgbRed = 0;
|
|
pMark->Attributes.rgbColor2.rgbBlue = 255;
|
|
pMark->Attributes.rgbColor2.rgbGreen = 255;
|
|
pMark->Attributes.rgbColor2.rgbRed = 255;
|
|
}else{
|
|
pMark->Attributes.rgbColor1.rgbBlue = 255;
|
|
pMark->Attributes.rgbColor1.rgbGreen = 255;
|
|
pMark->Attributes.rgbColor1.rgbRed = 255;
|
|
pMark->Attributes.rgbColor2.rgbBlue = 0;
|
|
pMark->Attributes.rgbColor2.rgbGreen = 0;
|
|
pMark->Attributes.rgbColor2.rgbRed = 0;
|
|
}
|
|
}
|
|
|
|
// Don't check errors yet so we can restore the colors.
|
|
nStatus = PaintAnnotationText(hWnd, hDC, pWindow, pImage,
|
|
pMark, rRepaintRect, lrFullsizeRepaintRect, nMode,
|
|
nHScale, nVScale, lHOffset, lVOffset, bForceOpaqueRectangles);
|
|
// Restore old colors
|
|
pMark->Attributes.rgbColor1 = RGBQuad1;
|
|
pMark->Attributes.rgbColor2 = RGBQuad2;
|
|
if (nStatus){
|
|
goto Exit;
|
|
}
|
|
break;
|
|
|
|
case OIOP_AN_IMAGE:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
case OIOP_AN_FORM:
|
|
CheckError2(PaintAnnotationBitmap(hWnd, hDC, pWindow, pImage,
|
|
pMark, rRepaintRect, lrFullsizeRepaintRect, nMode, nScale,
|
|
nHScale, nVScale, lHOffset, lVOffset, nFlags))
|
|
break;
|
|
|
|
case OIOP_AN_AUDIO:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (pSolidDIB){
|
|
nStatus = FreeMemory((PPSTR) &pSolidDIB);
|
|
}
|
|
if (bBrushSelected){
|
|
SelectObject(hDC, hOldBrush);
|
|
if (hBrush && bDeleteBrush){
|
|
DeleteObject(hBrush);
|
|
}
|
|
}
|
|
if (bPenSelected){
|
|
SelectObject(hDC, hOldPen);
|
|
if (hPen){
|
|
DeleteObject(hPen);
|
|
}
|
|
}
|
|
SetROP2(hDC, nOldROP);
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: PaintHandles
|
|
|
|
PURPOSE: This routine Paints the selection handles.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI PaintHandles(HDC hDC, PWINDOW pWindow, PIMAGE pImage,
|
|
PMARK pMark, RECT rRepaintRect,
|
|
LRECT lrFullsizeRepaintRect,
|
|
int nHScale, int nVScale, long lHOffset, long lVOffset){
|
|
|
|
int nStatus = 0;
|
|
|
|
LRECT lrRect;
|
|
int nOldROP;
|
|
HBRUSH hOldBrush;
|
|
HPEN hOldPen;
|
|
BOOL bPenSelected = FALSE;
|
|
PAN_POINTS pPoints;
|
|
PSTR pBlock;
|
|
HPEN hPen;
|
|
HPEN hTextPen;
|
|
BOOL bPenCreated = FALSE;
|
|
BOOL bTextPenCreated = FALSE;
|
|
RECT rRect;
|
|
LOGPEN LogPen;
|
|
|
|
|
|
CopyRect(lrRect, pMark->Attributes.lrBounds);
|
|
JustifyLRect(&lrRect);
|
|
ConvertRect2(&lrRect, CONV_FULLSIZE_TO_WINDOW, nHScale, nVScale, lHOffset, lVOffset);
|
|
|
|
nOldROP = SetROP2(hDC, R2_COPYPEN);
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiBaseIm, (PPSTR) &pBlock))
|
|
if (pBlock){
|
|
hOldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH));
|
|
hPen = CreatePen(PS_DASH, 1, RGB(0, 0, 0));
|
|
bPenCreated = TRUE;
|
|
hOldPen = SelectObject(hDC, hPen);
|
|
Rectangle(hDC, lrRect.left, lrRect.top, lrRect.right, lrRect.bottom);
|
|
goto Exit; // This is not an error.
|
|
}
|
|
|
|
hOldBrush = SelectObject(hDC, GetStockObject(BLACK_BRUSH));
|
|
hOldPen = SelectObject(hDC, GetStockObject(NULL_PEN));
|
|
bPenSelected = TRUE;
|
|
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_LINE){
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
if (pPoints->nPoints < 2){
|
|
goto Exit; // Not enough points to paint.
|
|
}
|
|
SetLRect(lrRect,
|
|
pPoints->ptPoint[0].x + pMark->Attributes.lrBounds.left,
|
|
pPoints->ptPoint[0].y + pMark->Attributes.lrBounds.top,
|
|
pPoints->ptPoint[1].x + pMark->Attributes.lrBounds.left,
|
|
pPoints->ptPoint[1].y + pMark->Attributes.lrBounds.top);
|
|
ConvertRect2(&lrRect, CONV_FULLSIZE_TO_WINDOW,
|
|
nHScale, nVScale, lHOffset, lVOffset);
|
|
Rectangle(hDC,
|
|
(int) max(lrRect.left - MINUS_HALF_HANDLE_SIZE, rRepaintRect.left),
|
|
(int) max(lrRect.top - MINUS_HALF_HANDLE_SIZE, rRepaintRect.top),
|
|
(int) min(lrRect.left + MINUS_HALF_HANDLE_SIZE, rRepaintRect.right + 1),
|
|
(int) min(lrRect.top + MINUS_HALF_HANDLE_SIZE, rRepaintRect.bottom + 1));
|
|
Rectangle(hDC,
|
|
(int) max(lrRect.right - MINUS_HALF_HANDLE_SIZE, rRepaintRect.left),
|
|
(int) max(lrRect.bottom - MINUS_HALF_HANDLE_SIZE, rRepaintRect.top),
|
|
(int) min(lrRect.right + MINUS_HALF_HANDLE_SIZE, rRepaintRect.right + 1),
|
|
(int) min(lrRect.bottom + MINUS_HALF_HANDLE_SIZE, rRepaintRect.bottom + 1));
|
|
}else{
|
|
// left, top
|
|
Rectangle(hDC,
|
|
(int) lrRect.left - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.top - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.left + PLUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.top + PLUS_HALF_HANDLE_SIZE);
|
|
// middle, top
|
|
Rectangle(hDC,
|
|
(int) (lrRect.left + ((lrRect.right - lrRect.left) / 2) - MINUS_HALF_HANDLE_SIZE),
|
|
(int) lrRect.top - MINUS_HALF_HANDLE_SIZE,
|
|
(int) (lrRect.left + ((lrRect.right - lrRect.left) / 2) + PLUS_HALF_HANDLE_SIZE),
|
|
(int) lrRect.top + PLUS_HALF_HANDLE_SIZE);
|
|
// right, top
|
|
Rectangle(hDC,
|
|
(int) lrRect.right - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.top - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.right + PLUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.top + PLUS_HALF_HANDLE_SIZE);
|
|
// right, middle
|
|
Rectangle(hDC,
|
|
(int) lrRect.right - MINUS_HALF_HANDLE_SIZE,
|
|
(int) (lrRect.top + ((lrRect.bottom - lrRect.top) / 2) - MINUS_HALF_HANDLE_SIZE),
|
|
(int) lrRect.right + PLUS_HALF_HANDLE_SIZE,
|
|
(int) (lrRect.top + ((lrRect.bottom - lrRect.top) / 2) + PLUS_HALF_HANDLE_SIZE));
|
|
// right, bottom
|
|
Rectangle(hDC,
|
|
(int) lrRect.right - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.bottom - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.right + PLUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.bottom + PLUS_HALF_HANDLE_SIZE);
|
|
// middle, bottom
|
|
Rectangle(hDC,
|
|
(int) (lrRect.left + ((lrRect.right - lrRect.left) / 2) - MINUS_HALF_HANDLE_SIZE),
|
|
(int) lrRect.bottom - MINUS_HALF_HANDLE_SIZE,
|
|
(int) (lrRect.left + ((lrRect.right - lrRect.left) / 2) + PLUS_HALF_HANDLE_SIZE),
|
|
(int) lrRect.bottom + PLUS_HALF_HANDLE_SIZE);
|
|
// left, bottom
|
|
Rectangle(hDC,
|
|
(int) lrRect.left - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.bottom - MINUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.left + PLUS_HALF_HANDLE_SIZE,
|
|
(int) lrRect.bottom + PLUS_HALF_HANDLE_SIZE);
|
|
// left, middle
|
|
Rectangle(hDC,
|
|
(int) lrRect.left - MINUS_HALF_HANDLE_SIZE,
|
|
(int) (lrRect.top + ((lrRect.bottom - lrRect.top) / 2) - MINUS_HALF_HANDLE_SIZE),
|
|
(int) lrRect.left + PLUS_HALF_HANDLE_SIZE,
|
|
(int) (lrRect.top + ((lrRect.bottom - lrRect.top) / 2) + PLUS_HALF_HANDLE_SIZE));
|
|
}
|
|
|
|
// this draws a dashed rect around text marks
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_TEXT ||
|
|
(int) pMark->Attributes.uType == OIOP_AN_TEXT_STAMP ||
|
|
(int) pMark->Attributes.uType == OIOP_AN_TEXT_FROM_A_FILE){
|
|
|
|
SelectObject(hDC, GetStockObject(NULL_BRUSH));
|
|
LogPen.lopnStyle = PS_DOT;
|
|
LogPen.lopnWidth.x = 1;
|
|
LogPen.lopnColor = RGB(pMark->Attributes.rgbColor1.rgbRed,
|
|
pMark->Attributes.rgbColor1.rgbGreen,
|
|
pMark->Attributes.rgbColor1.rgbBlue);
|
|
|
|
|
|
if (hTextPen = CreatePenIndirect(&LogPen)){
|
|
SelectObject(hDC, hTextPen);
|
|
}
|
|
bTextPenCreated = TRUE;
|
|
|
|
CopyRect(lrRect, pMark->Attributes.lrBounds);
|
|
JustifyLRect(&lrRect);
|
|
|
|
ConvertRect2(&lrRect, CONV_FULLSIZE_TO_WINDOW,
|
|
nHScale, nVScale, lHOffset, lVOffset);
|
|
|
|
rRect.left = (int) max(0, lrRect.left);
|
|
rRect.top = (int) max(0, lrRect.top);
|
|
rRect.right = (int) min(rRepaintRect.right, lrRect.right) + 1;
|
|
rRect.bottom = (int) min(rRepaintRect.bottom, lrRect.bottom)+1;
|
|
Rectangle(hDC, rRect.left, rRect.top, rRect.right,rRect.bottom);
|
|
}
|
|
|
|
Exit:
|
|
if (bPenSelected){
|
|
SelectObject(hDC, hOldBrush);
|
|
SelectObject(hDC, hOldPen);
|
|
SetROP2(hDC, nOldROP);
|
|
}
|
|
if (bPenCreated){
|
|
DeleteObject(hPen);
|
|
}
|
|
if (bTextPenCreated){
|
|
DeleteObject(hTextPen);
|
|
}
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: OrientAnnotations
|
|
|
|
PURPOSE: This routine orients the annotations.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI OrientAnnotations(HWND hWnd, PWINDOW pWindow,
|
|
PIMAGE pImage, int nOrientation){
|
|
|
|
int nStatus = 0;
|
|
PANO_IMAGE pAnoImage;
|
|
|
|
int nMarkIndex;
|
|
PMARK pMark;
|
|
int nLoop;
|
|
LRECT lrOldMarkBounds;
|
|
long lWidth;
|
|
long lHeight;
|
|
PAN_POINTS pPoints;
|
|
POINT ptOldPoint;
|
|
|
|
|
|
pAnoImage = pWindow->pDisplay->pAnoImage;
|
|
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
|
|
switch ((int) pMark->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(OrientAnnotationText(hWnd, pWindow, pImage, nOrientation, pMark))
|
|
break;
|
|
|
|
case OIOP_AN_IMAGE:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
case OIOP_AN_FORM:
|
|
CheckError2(OrientAnnotationBitmap(hWnd, pWindow, pImage, nOrientation, pMark))
|
|
break;
|
|
|
|
case OIOP_AN_LINE:
|
|
case OIOP_AN_FREEHAND:
|
|
case OIOP_AN_HOLLOW_RECT:
|
|
case OIOP_AN_FILLED_RECT:
|
|
CopyRect(lrOldMarkBounds, pMark->Attributes.lrBounds);
|
|
switch (nOrientation){
|
|
case OD_ROTRIGHT:
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_FREEHAND
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_LINE){
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat,
|
|
(PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
lWidth = lrOldMarkBounds.right - lrOldMarkBounds.left;
|
|
lHeight = lrOldMarkBounds.bottom - lrOldMarkBounds.top;
|
|
for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
|
|
ptOldPoint = pPoints->ptPoint[nLoop];
|
|
pPoints->ptPoint[nLoop].x = (int) (lHeight - ptOldPoint.y);
|
|
pPoints->ptPoint[nLoop].y = ptOldPoint.x;
|
|
}
|
|
}
|
|
pMark->Attributes.lrBounds.left = pImage->nHeight - lrOldMarkBounds.bottom;
|
|
pMark->Attributes.lrBounds.top = lrOldMarkBounds.left;
|
|
pMark->Attributes.lrBounds.right = pImage->nHeight - lrOldMarkBounds.top;
|
|
pMark->Attributes.lrBounds.bottom = lrOldMarkBounds.right;
|
|
break;
|
|
|
|
case OD_ROTLEFT:
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_FREEHAND
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_LINE){
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
lWidth = lrOldMarkBounds.right - lrOldMarkBounds.left;
|
|
lHeight = lrOldMarkBounds.bottom - lrOldMarkBounds.top;
|
|
for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
|
|
ptOldPoint = pPoints->ptPoint[nLoop];
|
|
pPoints->ptPoint[nLoop].x = ptOldPoint.y;
|
|
pPoints->ptPoint[nLoop].y
|
|
= (int) (lWidth - ptOldPoint.x);
|
|
}
|
|
}
|
|
pMark->Attributes.lrBounds.left = lrOldMarkBounds.top;
|
|
pMark->Attributes.lrBounds.top = pImage->nWidth - lrOldMarkBounds.right;
|
|
pMark->Attributes.lrBounds.right = lrOldMarkBounds.bottom;
|
|
pMark->Attributes.lrBounds.bottom = pImage->nWidth - lrOldMarkBounds.left;
|
|
break;
|
|
|
|
case OD_FLIP:
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_FREEHAND
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_LINE){
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
lWidth = lrOldMarkBounds.right - lrOldMarkBounds.left;
|
|
lHeight = lrOldMarkBounds.bottom - lrOldMarkBounds.top;
|
|
for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
|
|
ptOldPoint = pPoints->ptPoint[nLoop];
|
|
pPoints->ptPoint[nLoop].x = (int) (lWidth - ptOldPoint.x);
|
|
pPoints->ptPoint[nLoop].y = (int) (lHeight - ptOldPoint.y);
|
|
}
|
|
}
|
|
pMark->Attributes.lrBounds.left = pImage->nWidth - lrOldMarkBounds.right;
|
|
pMark->Attributes.lrBounds.top = pImage->nHeight - lrOldMarkBounds.bottom;
|
|
pMark->Attributes.lrBounds.right = pImage->nWidth - lrOldMarkBounds.left;
|
|
pMark->Attributes.lrBounds.bottom = pImage->nHeight - lrOldMarkBounds.top;
|
|
break;
|
|
|
|
case OD_HMIRROR:
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_FREEHAND
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_LINE){
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
lHeight = lrOldMarkBounds.bottom - lrOldMarkBounds.top;
|
|
for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
|
|
pPoints->ptPoint[nLoop].y = (int) (lHeight - pPoints->ptPoint[nLoop].y);
|
|
}
|
|
}
|
|
pMark->Attributes.lrBounds.top = pImage->nHeight - lrOldMarkBounds.bottom;
|
|
pMark->Attributes.lrBounds.bottom = pImage->nHeight - lrOldMarkBounds.top;
|
|
break;
|
|
|
|
case OD_VMIRROR:
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_FREEHAND
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_LINE){
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
lWidth = lrOldMarkBounds.right - lrOldMarkBounds.left;
|
|
for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
|
|
pPoints->ptPoint[nLoop].x = (int) (lWidth - pPoints->ptPoint[nLoop].x);
|
|
}
|
|
}
|
|
pMark->Attributes.lrBounds.left = pImage->nWidth - lrOldMarkBounds.right;
|
|
pMark->Attributes.lrBounds.right = pImage->nWidth - lrOldMarkBounds.left;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case OIOP_AN_AUDIO:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: IsPointNearMark
|
|
|
|
PURPOSE: This routine starts the creation of an annotation.
|
|
|
|
INPUTS: lrRect - The rect being tested.
|
|
lrRectPoint - left, top = The point being tested.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI IsPointNearMark(LRECT lrRectPoint, PMARK pMark, long lHorzFudge,
|
|
long lVertFudge, PBOOL pbPointNearMark, PINT pnHandle){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nLoop;
|
|
PAN_POINTS pPoints;
|
|
LRECT lrRect;
|
|
|
|
|
|
*pbPointNearMark = FALSE;
|
|
*pnHandle = 0;
|
|
if (!IsPointNearRect(pMark->Attributes.lrBounds, lrRectPoint, lHorzFudge, lVertFudge)){
|
|
goto Exit;
|
|
}
|
|
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_LINE
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_FREEHAND
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_HOLLOW_RECT){
|
|
lHorzFudge += (((int) pMark->Attributes.uLineSize + 1) / 2);
|
|
lVertFudge += (((int) pMark->Attributes.uLineSize + 1) / 2);
|
|
}
|
|
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_LINE
|
|
|| (int) pMark->Attributes.uType == OIOP_AN_FREEHAND){
|
|
CheckError2(GetAMarkNamedBlock(pMark, 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 +
|
|
pMark->Attributes.lrBounds.left,
|
|
pPoints->ptPoint[nLoop].y +
|
|
pMark->Attributes.lrBounds.top,
|
|
pPoints->ptPoint[nLoop + 1].x +
|
|
pMark->Attributes.lrBounds.left,
|
|
pPoints->ptPoint[nLoop + 1].y +
|
|
pMark->Attributes.lrBounds.top);
|
|
if (IsPointNearLine(lrRect, lrRectPoint, lHorzFudge, lVertFudge)){
|
|
break;
|
|
}
|
|
}
|
|
if (nLoop != pPoints->nPoints - 1){ // Not this mark.
|
|
*pbPointNearMark = TRUE;
|
|
}
|
|
}else if((int) pMark->Attributes.uType == OIOP_AN_HOLLOW_RECT){
|
|
if (IsPointNearBorder(pMark->Attributes.lrBounds,
|
|
lrRectPoint, lHorzFudge, lVertFudge)){
|
|
*pbPointNearMark = TRUE;
|
|
}
|
|
}else{
|
|
*pbPointNearMark = TRUE;
|
|
}
|
|
|
|
if ((*pnHandle = IsPointNearHandle(pMark, lrRectPoint, lHorzFudge, lVertFudge)) > 8){
|
|
nStatus = *pnHandle;
|
|
*pnHandle = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: IsPointNearRect
|
|
|
|
PURPOSE: This routine checks if the point is near the rect.
|
|
|
|
INPUTS: lrRect - The rect being tested.
|
|
lrRectPoint - left, top = The point being tested.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL WINAPI IsPointNearRect(LRECT lrRect, LRECT lrRectPoint,
|
|
long lHorzFudge, long lVertFudge){
|
|
|
|
JustifyLRect(&lrRect);
|
|
if (lrRectPoint.left < lrRect.left - lHorzFudge
|
|
|| lrRectPoint.left > lrRect.right + lHorzFudge
|
|
|| lrRectPoint.top < lrRect.top - lVertFudge
|
|
|| lrRectPoint.top > lrRect.bottom + lVertFudge){
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: IsPointNearLine
|
|
|
|
PURPOSE: This routine checks if the point is near the line.
|
|
|
|
INPUTS: lrRect - left, top = One end of the line.
|
|
right, bottom = The other end of the line.
|
|
lrRectPoint - left, top = The point being tested.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL WINAPI IsPointNearLine(LRECT lrRect, LRECT lrRectPoint,
|
|
long lHorzFudge, long lVertFudge){
|
|
|
|
long lWidth;
|
|
long lHeight;
|
|
long lHorz;
|
|
long lVert;
|
|
|
|
if (!IsPointNearRect(lrRect, lrRectPoint, lHorzFudge, lVertFudge)){
|
|
return(FALSE);
|
|
}
|
|
|
|
lWidth = lrRect.right - lrRect.left;
|
|
lHeight = lrRect.bottom - lrRect.top;
|
|
|
|
// Prevent divide by zero.
|
|
if (labs(lWidth) < 1L){
|
|
lWidth = 1;
|
|
}
|
|
if (labs(lHeight) < 1L){
|
|
lHeight = 1;
|
|
}
|
|
|
|
if (labs(lWidth) < labs(lHeight)){
|
|
// Line is more vertical than horizontal.
|
|
lHorz = ((lrRectPoint.top - lrRect.top)
|
|
* lWidth / lHeight) + lrRect.left;
|
|
if (lHorz <= lrRectPoint.left + lHorzFudge
|
|
&& lHorz >= lrRectPoint.left - lHorzFudge){
|
|
return(TRUE);
|
|
}else{
|
|
return(FALSE);
|
|
}
|
|
}else{
|
|
// Line is more horizontal than vertical.
|
|
lVert = ((lrRectPoint.left - lrRect.left)
|
|
* lHeight / lWidth) + lrRect.top;
|
|
if (lVert <= lrRectPoint.top + lVertFudge
|
|
&& lVert >= lrRectPoint.top - lVertFudge){
|
|
return(TRUE);
|
|
}else{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: IsPointNearBorder
|
|
|
|
PURPOSE: This routine determines if the point is near the border of a rectangle.
|
|
|
|
INPUTS:
|
|
|
|
RETURN: TRUE = Yes.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL WINAPI IsPointNearBorder(LRECT lrRect, LRECT lrRectPoint,
|
|
long lHorzFudge, long lVertFudge){
|
|
|
|
LRECT lrRect2;
|
|
|
|
|
|
// Check top edge.
|
|
lrRect2.left = lrRect.left;
|
|
lrRect2.top = lrRect.top;
|
|
lrRect2.right = lrRect.right;
|
|
lrRect2.bottom = lrRect.top;
|
|
if (IsPointNearLine(lrRect2, lrRectPoint, lHorzFudge, lVertFudge)){
|
|
return(TRUE);
|
|
}
|
|
|
|
// Check bottom edge.
|
|
lrRect2.left = lrRect.left;
|
|
lrRect2.top = lrRect.bottom;
|
|
lrRect2.right = lrRect.right;
|
|
lrRect2.bottom = lrRect.bottom;
|
|
if (IsPointNearLine(lrRect2, lrRectPoint, lHorzFudge, lVertFudge)){
|
|
return(TRUE);
|
|
}
|
|
|
|
// Check left edge.
|
|
lrRect2.left = lrRect.left;
|
|
lrRect2.top = lrRect.top;
|
|
lrRect2.right = lrRect.left;
|
|
lrRect2.bottom = lrRect.bottom;
|
|
if (IsPointNearLine(lrRect2, lrRectPoint, lHorzFudge, lVertFudge)){
|
|
return(TRUE);
|
|
}
|
|
|
|
// Check right edge.
|
|
lrRect2.left = lrRect.right;
|
|
lrRect2.top = lrRect.top;
|
|
lrRect2.right = lrRect.right;
|
|
lrRect2.bottom = lrRect.bottom;
|
|
if (IsPointNearLine(lrRect2, lrRectPoint, lHorzFudge, lVertFudge)){
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: IsPointNearHandle
|
|
|
|
PURPOSE: This routine determines if the point is near a selection handle
|
|
and returns which on if it is.
|
|
|
|
INPUTS: lrRect - left, top = One end of the line.
|
|
right, bottom = The other end of the line.
|
|
lrRectPoint - left, top = The point being tested.
|
|
|
|
RETURN: 0 = Not near a handle.
|
|
1-8 = Handle that it is near. Clockwise. 1 = npper right corner.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI IsPointNearHandle(PMARK pMark, LRECT lrRectPoint,
|
|
long lHorzFudge, long lVertFudge){
|
|
|
|
int nStatus = 0;
|
|
|
|
LRECT lrRect;
|
|
LRECT lrBounds;
|
|
PAN_POINTS pPoints;
|
|
long lHalfWidth;
|
|
long lHalfHeight;
|
|
|
|
|
|
if (!pMark->bSelected){
|
|
goto Exit;
|
|
}
|
|
|
|
CopyRect(lrBounds, pMark->Attributes.lrBounds);
|
|
JustifyLRect(&lrBounds);
|
|
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_LINE){
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
if (pPoints->nPoints < 2){
|
|
goto Exit; // Not enough points.
|
|
}
|
|
SetLRect(lrRect,
|
|
pPoints->ptPoint[0].x + lrRect.left,
|
|
pPoints->ptPoint[0].y + lrRect.top,
|
|
pPoints->ptPoint[1].x + lrRect.left,
|
|
pPoints->ptPoint[1].y + lrRect.top);
|
|
if (lrRectPoint.left >= (pPoints->ptPoint[0].x + lrBounds.left - lHorzFudge)
|
|
&& lrRectPoint.left <= (pPoints->ptPoint[0].x + lrBounds.left + lHorzFudge)
|
|
&& lrRectPoint.top >= (pPoints->ptPoint[0].y + lrBounds.top - lVertFudge)
|
|
&& lrRectPoint.top <= (pPoints->ptPoint[0].y + lrBounds.top + lVertFudge)){
|
|
nStatus = 1;
|
|
goto Exit;
|
|
}
|
|
if (lrRectPoint.left >= (pPoints->ptPoint[1].x + lrBounds.left - lHorzFudge)
|
|
&& lrRectPoint.left <= (pPoints->ptPoint[1].x + lrBounds.left + lHorzFudge)
|
|
&& lrRectPoint.top >= (pPoints->ptPoint[1].y + lrBounds.top - lVertFudge)
|
|
&& lrRectPoint.top <= (pPoints->ptPoint[1].y + lrBounds.top + lVertFudge)){
|
|
nStatus = 2;
|
|
goto Exit;
|
|
}
|
|
}else{
|
|
lHalfWidth = (lrBounds.right - lrBounds.left) / 2;
|
|
lHalfHeight = (lrBounds.bottom - lrBounds.top) / 2;
|
|
// right, top
|
|
if (lrRectPoint.left >= (lrBounds.right - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.right + lHorzFudge)
|
|
&& lrRectPoint.top >= (lrBounds.top - lVertFudge)
|
|
&& lrRectPoint.top <= (lrBounds.top + lVertFudge)){
|
|
nStatus = 1;
|
|
goto Exit;
|
|
}
|
|
// right, middle
|
|
if (lrRectPoint.left >= (lrBounds.right - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.right + lHorzFudge)
|
|
&& lrRectPoint.top >= (lrBounds.bottom - lHalfHeight - lVertFudge)
|
|
&& lrRectPoint.top <= (lrBounds.bottom - lHalfHeight + lVertFudge)){
|
|
nStatus = 2;
|
|
goto Exit;
|
|
}
|
|
// right, bottom
|
|
if (lrRectPoint.left >= (lrBounds.right - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.right + lHorzFudge)
|
|
&& lrRectPoint.top >= (lrBounds.bottom - lVertFudge)
|
|
&& lrRectPoint.top <= (lrBounds.bottom + lVertFudge)){
|
|
nStatus = 3;
|
|
goto Exit;
|
|
}
|
|
// middle, bottom
|
|
if (lrRectPoint.left >= (lrBounds.left + lHalfWidth - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.left + lHalfWidth + lHorzFudge)
|
|
&& lrRectPoint.bottom >= (lrBounds.bottom - lVertFudge)
|
|
&& lrRectPoint.bottom <= (lrBounds.bottom + lVertFudge)){
|
|
nStatus = 4;
|
|
goto Exit;
|
|
}
|
|
// left, bottom
|
|
if (lrRectPoint.left >= (lrBounds.left - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.left + lHorzFudge)
|
|
&& lrRectPoint.top >= (lrBounds.bottom - lVertFudge)
|
|
&& lrRectPoint.top <= (lrBounds.bottom + lVertFudge)){
|
|
nStatus = 5;
|
|
goto Exit;
|
|
}
|
|
// left, middle
|
|
if (lrRectPoint.left >= (lrBounds.left - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.left + lHorzFudge)
|
|
&& lrRectPoint.top >= (lrBounds.top + lHalfHeight - lVertFudge)
|
|
&& lrRectPoint.top <= (lrBounds.top + lHalfHeight + lVertFudge)){
|
|
nStatus = 6;
|
|
goto Exit;
|
|
}
|
|
// left, top
|
|
if (lrRectPoint.left >= (lrBounds.left - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.left + lHorzFudge)
|
|
&& lrRectPoint.top >= (lrBounds.top - lVertFudge)
|
|
&& lrRectPoint.top <= (lrBounds.top + lVertFudge)){
|
|
nStatus = 7;
|
|
goto Exit;
|
|
}
|
|
// middle, top
|
|
if (lrRectPoint.left >= (lrBounds.left + lHalfWidth - lHorzFudge)
|
|
&& lrRectPoint.left <= (lrBounds.left + lHalfWidth + lHorzFudge)
|
|
&& lrRectPoint.top >= (lrBounds.top - lVertFudge)
|
|
&& lrRectPoint.top <= (lrBounds.top + lVertFudge)){
|
|
nStatus = 8;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: ReduceLineToLRect
|
|
|
|
PURPOSE: This routine reduces the size of a line so that it only
|
|
has the part that is wholly contained within lrRect.
|
|
|
|
INPUTS: lrRectLine - left, top = One end of the line.
|
|
right, bottom = The other end of the line.
|
|
lrRectArea - The area to contain it.
|
|
|
|
RETURN: TRUE = Part of the line is within the rect.
|
|
FALSE = No part of the line is within the rect.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL WINAPI ReduceLineToLRect(LPLRECT plrRectLine, LRECT lrRectArea){
|
|
|
|
long lWidth;
|
|
long lHeight;
|
|
|
|
LRECT lrRectLineNew;
|
|
LRECT lrRectLine = *plrRectLine;
|
|
|
|
|
|
JustifyLRect(&lrRectArea);
|
|
|
|
lWidth = lrRectLine.right - lrRectLine.left;
|
|
lHeight = lrRectLine.bottom - lrRectLine.top;
|
|
|
|
// Prevent divide by zero.
|
|
if (labs(lWidth) < 1L){
|
|
lWidth = 1;
|
|
}
|
|
if (labs(lHeight) < 1L){
|
|
lHeight = 1;
|
|
}
|
|
|
|
CopyRect(lrRectLineNew, lrRectLine);
|
|
|
|
|
|
// Does this line go down and to the right?
|
|
if (lrRectLine.left <= lrRectLine.right
|
|
&& lrRectLine.top <= lrRectLine.bottom){
|
|
if (lrRectLine.right < lrRectArea.left || lrRectLine.bottom < lrRectArea.top
|
|
|| lrRectLine.left > lrRectArea.right || lrRectLine.top > lrRectArea.bottom){
|
|
return(FALSE);
|
|
}
|
|
|
|
// Put left edge of line at left edge of rect.
|
|
if (lrRectLineNew.left < lrRectArea.left){
|
|
lrRectLineNew.left = lrRectArea.left;
|
|
lrRectLineNew.top = ((lrRectArea.left - lrRectLine.left)
|
|
* lHeight / lWidth) + lrRectLine.top;
|
|
}
|
|
|
|
// Put top edge of line at top edge of rect.
|
|
if (lrRectLineNew.top < lrRectArea.top){
|
|
lrRectLineNew.top = lrRectArea.top;
|
|
lrRectLineNew.left = ((lrRectArea.top - lrRectLine.top)
|
|
* lWidth / lHeight) + lrRectLine.left;
|
|
}
|
|
|
|
// Put right edge of line at right edge of rect.
|
|
if (lrRectLineNew.right > lrRectArea.right){
|
|
lrRectLineNew.right = lrRectArea.right;
|
|
lrRectLineNew.bottom = ((lrRectArea.right - lrRectLine.right)
|
|
* lHeight / lWidth) + lrRectLine.bottom;
|
|
}
|
|
|
|
// Put bottom edge of line at bottom edge of rect.
|
|
if (lrRectLineNew.bottom > lrRectArea.bottom){
|
|
lrRectLineNew.bottom = lrRectArea.bottom;
|
|
lrRectLineNew.right = ((lrRectArea.bottom - lrRectLine.bottom)
|
|
* lWidth / lHeight) + lrRectLine.right;
|
|
}
|
|
if (lrRectArea.left <= lrRectLineNew.right
|
|
&& lrRectArea.right >= lrRectLineNew.right
|
|
&& lrRectArea.top <= lrRectLineNew.bottom
|
|
&& lrRectArea.bottom >= lrRectLineNew.bottom){
|
|
CopyRect(*plrRectLine, lrRectLineNew);
|
|
return(TRUE);
|
|
}else{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Does this line go down and to the left?
|
|
}else if(lrRectLine.left >= lrRectLine.right
|
|
&& lrRectLine.top <= lrRectLine.bottom){
|
|
if (lrRectLine.right > lrRectArea.right || lrRectLine.bottom < lrRectArea.top
|
|
|| lrRectLine.left < lrRectArea.left || lrRectLine.top > lrRectArea.bottom){
|
|
return(FALSE);
|
|
}
|
|
|
|
// Put left edge of line at right edge of rect.
|
|
if (lrRectLineNew.left > lrRectArea.right){
|
|
lrRectLineNew.left = lrRectArea.right;
|
|
lrRectLineNew.top = ((lrRectArea.right - lrRectLine.left)
|
|
* lHeight / lWidth) + lrRectLine.top;
|
|
}
|
|
|
|
// Put top edge of line at top edge of rect.
|
|
if (lrRectLineNew.top < lrRectArea.top){
|
|
lrRectLineNew.top = lrRectArea.top;
|
|
lrRectLineNew.left = ((lrRectArea.top - lrRectLine.top)
|
|
* lWidth / lHeight) + lrRectLine.left;
|
|
}
|
|
|
|
// Put right edge of line at left edge of rect.
|
|
if (lrRectLineNew.right < lrRectArea.left){
|
|
lrRectLineNew.right = lrRectArea.left;
|
|
lrRectLineNew.bottom = ((lrRectArea.left - lrRectLine.right)
|
|
* lHeight / lWidth) + lrRectLine.bottom;
|
|
}
|
|
|
|
// Put bottom edge of line at bottom edge of rect.
|
|
if (lrRectLineNew.bottom > lrRectArea.bottom){
|
|
lrRectLineNew.bottom = lrRectArea.bottom;
|
|
lrRectLineNew.right = ((lrRectArea.bottom - lrRectLine.bottom)
|
|
* lWidth / lHeight) + lrRectLine.right;
|
|
}
|
|
if (lrRectArea.left <= lrRectLineNew.right
|
|
&& lrRectArea.right >= lrRectLineNew.right
|
|
&& lrRectArea.top <= lrRectLineNew.bottom
|
|
&& lrRectArea.bottom >= lrRectLineNew.bottom){
|
|
CopyRect(*plrRectLine, lrRectLineNew);
|
|
return(TRUE);
|
|
}else{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Does this line go np and to the left?
|
|
}else if(lrRectLine.left >= lrRectLine.right
|
|
&& lrRectLine.top >= lrRectLine.bottom){
|
|
if (lrRectLine.right > lrRectArea.right || lrRectLine.bottom > lrRectArea.bottom
|
|
|| lrRectLine.left < lrRectArea.left || lrRectLine.top < lrRectArea.top){
|
|
return(FALSE);
|
|
}
|
|
|
|
// Put left edge of line at right edge of rect.
|
|
if (lrRectLineNew.left > lrRectArea.right){
|
|
lrRectLineNew.left = lrRectArea.right;
|
|
lrRectLineNew.top = ((lrRectArea.right - lrRectLine.left)
|
|
* lHeight / lWidth) + lrRectLine.top;
|
|
}
|
|
|
|
// Put top edge of line at bottom edge of rect.
|
|
if (lrRectLineNew.top > lrRectArea.bottom){
|
|
lrRectLineNew.top = lrRectArea.bottom;
|
|
lrRectLineNew.left = ((lrRectArea.bottom - lrRectLine.top)
|
|
* lWidth / lHeight) + lrRectLine.left;
|
|
}
|
|
|
|
// Put right edge of line at left edge of rect.
|
|
if (lrRectLineNew.right < lrRectArea.left){
|
|
lrRectLineNew.right = lrRectArea.left;
|
|
lrRectLineNew.bottom = ((lrRectArea.left - lrRectLine.right)
|
|
* lHeight / lWidth) + lrRectLine.bottom;
|
|
}
|
|
|
|
// Put bottom edge of line at top edge of rect.
|
|
if (lrRectLineNew.bottom < lrRectArea.top){
|
|
lrRectLineNew.bottom = lrRectArea.top;
|
|
lrRectLineNew.right = ((lrRectArea.top - lrRectLine.bottom)
|
|
* lWidth / lHeight) + lrRectLine.right;
|
|
}
|
|
if (lrRectArea.left <= lrRectLineNew.right
|
|
&& lrRectArea.right >= lrRectLineNew.right
|
|
&& lrRectArea.top <= lrRectLineNew.bottom
|
|
&& lrRectArea.bottom >= lrRectLineNew.bottom){
|
|
CopyRect(*plrRectLine, lrRectLineNew);
|
|
return(TRUE);
|
|
}else{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Else it must go np and to the right.
|
|
}else{
|
|
if (lrRectLine.right < lrRectArea.left || lrRectLine.bottom > lrRectArea.bottom
|
|
|| lrRectLine.left > lrRectArea.right || lrRectLine.top < lrRectArea.top){
|
|
return(FALSE);
|
|
}
|
|
|
|
// Put left edge of line at left edge of rect.
|
|
if (lrRectLineNew.left < lrRectArea.left){
|
|
lrRectLineNew.left = lrRectArea.left;
|
|
lrRectLineNew.top = ((lrRectArea.left - lrRectLine.left)
|
|
* lHeight / lWidth) + lrRectLine.top;
|
|
}
|
|
|
|
// Put top edge of line at bottom edge of rect.
|
|
if (lrRectLineNew.top > lrRectArea.bottom){
|
|
lrRectLineNew.top = lrRectArea.bottom;
|
|
lrRectLineNew.left = ((lrRectArea.bottom - lrRectLine.top)
|
|
* lWidth / lHeight) + lrRectLine.left;
|
|
}
|
|
|
|
// Put right edge of line at right edge of rect.
|
|
if (lrRectLineNew.right > lrRectArea.right){
|
|
lrRectLineNew.right = lrRectArea.right;
|
|
lrRectLineNew.bottom = ((lrRectArea.right - lrRectLine.right)
|
|
* lHeight / lWidth) + lrRectLine.bottom;
|
|
}
|
|
|
|
// Put bottom edge of line at top edge of rect.
|
|
if (lrRectLineNew.bottom < lrRectArea.top){
|
|
lrRectLineNew.bottom = lrRectArea.top;
|
|
lrRectLineNew.right = ((lrRectArea.top - lrRectLine.bottom)
|
|
* lWidth / lHeight) + lrRectLine.right;
|
|
}
|
|
if (lrRectArea.left <= lrRectLineNew.right
|
|
&& lrRectArea.right >= lrRectLineNew.right
|
|
&& lrRectArea.top <= lrRectLineNew.bottom
|
|
&& lrRectArea.bottom >= lrRectLineNew.bottom){
|
|
CopyRect(*plrRectLine, lrRectLineNew);
|
|
return(TRUE);
|
|
}else{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: CreateSolidDIB
|
|
|
|
PURPOSE: This routine creates a 32x32 solid DIB of a specified color.
|
|
|
|
INPUTS: pRGBQuad - color of the DIB
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI CreateSolidDIB(PBITMAPINFOHEADER* ppSolidDIB, RGBQUAD rgbColor){
|
|
|
|
PBITMAPINFOHEADER pSolidDIB = NULL;
|
|
RGBQUAD* pRGBTmp = NULL;
|
|
int nStatus = 0;
|
|
|
|
|
|
if (nStatus = AllocateMemory(sizeof(BITMAPINFOHEADER) + 8 + 128, (PPSTR) ppSolidDIB, ZERO_INIT)){
|
|
*ppSolidDIB = NULL;
|
|
goto Exit;
|
|
}
|
|
pSolidDIB = *ppSolidDIB;
|
|
memset((PSTR)pSolidDIB + sizeof(BITMAPINFOHEADER) + 8, 0xff, 128);
|
|
pSolidDIB->biSize = sizeof(BITMAPINFOHEADER);
|
|
pSolidDIB->biWidth = 32;
|
|
pSolidDIB->biHeight = 32;
|
|
pSolidDIB->biPlanes = 1;
|
|
pSolidDIB->biBitCount = 1;
|
|
pSolidDIB->biCompression = BI_RGB;
|
|
pSolidDIB->biSizeImage = 128;
|
|
pSolidDIB->biXPelsPerMeter = 0;
|
|
pSolidDIB->biYPelsPerMeter = 0;
|
|
pSolidDIB->biClrUsed = 2;
|
|
pSolidDIB->biClrImportant = 0;
|
|
memset((PSTR)pSolidDIB + sizeof(BITMAPINFOHEADER), 0, 8);
|
|
pRGBTmp = (RGBQUAD*)((PSTR)pSolidDIB + sizeof(BITMAPINFOHEADER) + 4);
|
|
*pRGBTmp = rgbColor;
|
|
|
|
Exit:
|
|
return nStatus;
|
|
}
|
|
//
|
|
#define ANO_BLOCK_SIZE 32000
|
|
/****************************************************************************
|
|
|
|
FUNCTION: BlockedAnoRead
|
|
|
|
PURPOSE: This routine reads chunks of data from disk in big blocks and
|
|
gives it to seqfile in little blocks.
|
|
|
|
INPUTS:
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI BlockedAnoRead(HWND hWnd, PANO_IMAGE pAnoImage, LONG lSize, HPSTR hpBlock){
|
|
|
|
int nStatus = 0;
|
|
|
|
PIMAGE pImage;
|
|
DWORD dwStart;
|
|
|
|
DWORD dwTransfer;
|
|
int nBytesRead;
|
|
|
|
|
|
pImage = pAnoImage->pBaseImage;
|
|
|
|
if (!pAnoImage->hpAnoBlock){
|
|
CheckError2(AllocateMemory(ANO_BLOCK_SIZE, (PPSTR) &pAnoImage->hpAnoBlock, NO_INIT))
|
|
pAnoImage->lAnoBlockIndex = 0;
|
|
pAnoImage->lAnoBlockCount = 0;
|
|
}
|
|
|
|
while(lSize){
|
|
if (!pAnoImage->lAnoBlockCount){
|
|
if (pAnoImage->bAnoBlockUseMemOnly){
|
|
nStatus = Error2(DISPLAY_EOF);
|
|
goto Exit;
|
|
}else if (pAnoImage->nFileId){
|
|
nBytesRead = IMGFileBinaryRead32(hWnd, pAnoImage->nFileId,
|
|
pAnoImage->hpAnoBlock, ANO_BLOCK_SIZE, &nStatus);
|
|
if (!nBytesRead || nBytesRead == -1){
|
|
if (nStatus){
|
|
Error(nStatus);
|
|
goto Exit;
|
|
}
|
|
nStatus = Error2(DISPLAY_EOF);
|
|
goto Exit;
|
|
}
|
|
pAnoImage->lAnoBlockIndex = 0;
|
|
pAnoImage->lAnoBlockCount = (int) nBytesRead;
|
|
}else{
|
|
dwTransfer = ANO_BLOCK_SIZE;
|
|
dwStart = pAnoImage->lAnoStart;
|
|
if (nStatus = IMGFileReadData(pImage->hFileProp, hWnd, &dwStart,
|
|
&dwTransfer, pAnoImage->hpAnoBlock, FIO_ANNO_DATA)){
|
|
if (nStatus != FIO_EOF){ // Ignor FIO_EOF.
|
|
Error(nStatus);
|
|
goto Exit;
|
|
}
|
|
nStatus = 0;
|
|
}
|
|
pAnoImage->lAnoStart = dwStart;
|
|
if (!dwTransfer){
|
|
// Generate our own EOF if it is really EOF (No data).
|
|
nStatus = Error2(DISPLAY_EOF);
|
|
goto Exit;
|
|
}
|
|
pAnoImage->lAnoBlockIndex = 0;
|
|
pAnoImage->lAnoBlockCount = dwTransfer;
|
|
}
|
|
}
|
|
dwTransfer = lmin(lSize, pAnoImage->lAnoBlockCount);
|
|
memcpy(hpBlock, &pAnoImage->hpAnoBlock[pAnoImage->lAnoBlockIndex], dwTransfer);
|
|
hpBlock += dwTransfer;
|
|
pAnoImage->lAnoBlockIndex += dwTransfer;
|
|
pAnoImage->lAnoBlockCount -= dwTransfer;
|
|
lSize -= dwTransfer;
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (nStatus && pAnoImage->hpAnoBlock){
|
|
if (!pAnoImage->bAnoBlockUseMemOnly){
|
|
FreeMemory((PPSTR) &pAnoImage->hpAnoBlock);
|
|
}
|
|
pAnoImage->hpAnoBlock = NULL;
|
|
pAnoImage->lAnoBlockIndex = 0;
|
|
pAnoImage->lAnoBlockCount = 0;
|
|
}
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: BlockedAnoWrite
|
|
|
|
PURPOSE: This routine takes small blocks of data from seqfile and
|
|
writes big chunks of data to disk.
|
|
|
|
INPUTS:
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI BlockedAnoWrite(HWND hWnd, PANO_IMAGE pAnoImage, LONG lSize, HPSTR hpBlock){
|
|
|
|
int nStatus = 0;
|
|
|
|
DWORD dwTransfer;
|
|
HANDLE hGlobal = 0;
|
|
PSTR pGlobal = 0;
|
|
|
|
|
|
if (pAnoImage->bAnoBlockUseMemOnly){
|
|
CheckError2(ReAllocateMemory(pAnoImage->lAnoBlockIndex + lSize, (PPSTR) &pAnoImage->hpAnoBlock, NO_INIT))
|
|
memcpy(&pAnoImage->hpAnoBlock[pAnoImage->lAnoBlockIndex], hpBlock, lSize);
|
|
pAnoImage->lAnoBlockIndex += lSize;
|
|
pAnoImage->lAnoBlockCount = 0;
|
|
}else{
|
|
if (!pAnoImage->hpAnoBlock){
|
|
CheckError2(AllocateMemory(ANO_BLOCK_SIZE, (PPSTR) &pAnoImage->hpAnoBlock, NO_INIT))
|
|
pAnoImage->lAnoBlockIndex = 0;
|
|
pAnoImage->lAnoBlockCount = ANO_BLOCK_SIZE;
|
|
}
|
|
|
|
while(lSize){
|
|
if (lSize >= pAnoImage->lAnoBlockCount){
|
|
CheckError2(BlockedAnoWriteFlushBuffer(hWnd, pAnoImage))
|
|
}
|
|
dwTransfer = lmin(lSize, pAnoImage->lAnoBlockCount);
|
|
memcpy(&pAnoImage->hpAnoBlock[pAnoImage->lAnoBlockIndex], hpBlock, dwTransfer);
|
|
hpBlock += dwTransfer;
|
|
pAnoImage->lAnoBlockIndex += dwTransfer;
|
|
pAnoImage->lAnoBlockCount -= dwTransfer;
|
|
lSize -= dwTransfer;
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (nStatus){
|
|
FreeMemory((PPSTR) &pAnoImage->hpAnoBlock);
|
|
}
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: BlockedAnoWriteFlushBuffer
|
|
|
|
PURPOSE: This routine takes small blocks of data from seqfile and
|
|
writes big chunks of data to disk.
|
|
|
|
INPUTS:
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI BlockedAnoWriteFlushBuffer(HWND hWnd, PANO_IMAGE pAnoImage){
|
|
|
|
int nStatus = 0;
|
|
|
|
DWORD dwTransfer;
|
|
int nBytesWritten;
|
|
PIMAGE pImage;
|
|
|
|
pImage = pAnoImage->pBaseImage;
|
|
if (pAnoImage->bAnoBlockUseMemOnly){
|
|
// Ignor this call if nsing memory block only.
|
|
}else if (pAnoImage->nFileId){
|
|
nBytesWritten = IMGFileBinaryWrite32(hWnd, pAnoImage->nFileId,
|
|
pAnoImage->hpAnoBlock, pAnoImage->lAnoBlockIndex, &nStatus);
|
|
if (!nBytesWritten || nBytesWritten == -1){
|
|
if (nStatus){
|
|
Error(nStatus);
|
|
goto Exit;
|
|
}
|
|
nStatus = Error(DISPLAY_EOF);
|
|
goto Exit;
|
|
}
|
|
pAnoImage->lAnoBlockIndex = 0;
|
|
pAnoImage->lAnoBlockCount = ANO_BLOCK_SIZE;
|
|
}else{
|
|
dwTransfer = pAnoImage->lAnoBlockIndex;
|
|
CheckError(IMGFileWriteData(pImage->hFileProp, hWnd, &dwTransfer,
|
|
pAnoImage->hpAnoBlock, FIO_ANNO_DATA, 0))
|
|
if (!dwTransfer){
|
|
nStatus = Error(DISPLAY_EOF);
|
|
goto Exit;
|
|
}
|
|
pAnoImage->lAnoBlockIndex = 0;
|
|
pAnoImage->lAnoBlockCount = ANO_BLOCK_SIZE;
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (nStatus){
|
|
FreeMemory((PPSTR) &pAnoImage->hpAnoBlock);
|
|
}
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: OiAnSelectByMarkAttrib
|
|
|
|
PURPOSE: This routine selects or deselects marks based on their attributes.
|
|
|
|
INPUTS:
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI OiAnSelectByMarkAttrib(HWND hWnd,
|
|
LPOIAN_MARK_ATTRIBUTES pAttributes,
|
|
LPOIAN_MARK_ATTRIBUTE_ENABLES pEnables,
|
|
BOOL bSelect, BOOL bModifyIfEqual, int nFlags){
|
|
|
|
int nStatus;
|
|
PWINDOW pWindow;
|
|
PANO_IMAGE pAnoImage;
|
|
PIMAGE pImage;
|
|
|
|
int nMarkIndex;
|
|
|
|
PMARK pMark;
|
|
OIAN_MARK_ATTRIBUTE_ENABLES Enables;
|
|
OIAN_MARK_ATTRIBUTES Attributes;
|
|
BOOL bEqual;
|
|
LRECT lrRect;
|
|
BOOL bInvalidateAllDisplayRects = FALSE;
|
|
|
|
|
|
CheckError2(Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE))
|
|
pImage = pAnoImage->pBaseImage;
|
|
|
|
CheckError2(ValidateCache(hWnd, pAnoImage))
|
|
|
|
if (!(nFlags & OIAN_SELECT_ALL) && !(nFlags & OIAN_SELECT_LAST_CREATED)
|
|
&& (!pAttributes || !pEnables)){
|
|
nStatus = Error(DISPLAY_NULLPOINTERINVALID);
|
|
goto Exit;
|
|
}
|
|
|
|
// End any operation currently in progress.
|
|
if (pAnoImage->Annotations.ppMarks){
|
|
while(pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks]){
|
|
OiOpEndOperation(hWnd);
|
|
}
|
|
}
|
|
|
|
if (!(nFlags & OIAN_SELECT_ALL) && !(nFlags & OIAN_SELECT_LAST_CREATED)){
|
|
Attributes = *pAttributes;
|
|
Enables = *pEnables;
|
|
}
|
|
if ((nFlags & OIAN_SELECT_ALL) && !bSelect && !(nFlags & OIAN_DONT_CHANGE_SELECT_RECT)){
|
|
SetLRect(lrRect, 0,0,0,0);
|
|
IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE);
|
|
}
|
|
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
bEqual = TRUE;
|
|
if ((nFlags & OIAN_SELECT_LAST_CREATED)
|
|
&& nMarkIndex < pAnoImage->Annotations.nMarks - 1){
|
|
bEqual = FALSE;
|
|
}
|
|
|
|
if (!(nFlags & OIAN_SELECT_ALL) && !(nFlags & OIAN_SELECT_LAST_CREATED)){
|
|
if (Enables.bType){
|
|
if ((int) pMark->Attributes.uType != Attributes.uType){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bBounds){
|
|
if (memcmp(&pMark->Attributes.lrBounds, &Attributes.lrBounds, sizeof(LRECT))){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bColor1){
|
|
if (memcmp(&pMark->Attributes.rgbColor1, &Attributes.rgbColor1, sizeof(RGBQUAD))){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bColor2){
|
|
if (memcmp(&pMark->Attributes.rgbColor2, &Attributes.rgbColor2, sizeof(RGBQUAD))){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bHighlighting){
|
|
if (pMark->Attributes.bHighlighting != Attributes.bHighlighting){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bTransparent){
|
|
if (pMark->Attributes.bTransparent != Attributes.bTransparent){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bLineSize){
|
|
if ((int) pMark->Attributes.uLineSize != Attributes.uLineSize){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bStartingPoint){
|
|
if (pMark->Attributes.uStartingPoint != Attributes.uStartingPoint){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bEndPoint){
|
|
if (pMark->Attributes.uEndPoint != Attributes.uEndPoint){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bFont){
|
|
if (memcmp(&pMark->Attributes.lfFont, &Attributes.lfFont, sizeof(LOGFONT))){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bMinimizable){
|
|
if (pMark->Attributes.bMinimizable != Attributes.bMinimizable){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bTime){
|
|
if (memcmp(&pMark->Attributes.Time, &Attributes.Time, sizeof(time_t))){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bVisible){
|
|
if (pMark->Attributes.bVisible != Attributes.bVisible){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
if (Enables.bPermissions){
|
|
if (pMark->Attributes.dwPermissions != Attributes.dwPermissions){
|
|
bEqual = FALSE;
|
|
}
|
|
}
|
|
}
|
|
if ((bEqual && bModifyIfEqual) || (!bEqual && !bModifyIfEqual)){
|
|
if (pMark->bSelected != bSelect){
|
|
pMark->bSelected = bSelect;
|
|
bInvalidateAllDisplayRects = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (bInvalidateAllDisplayRects){
|
|
CheckError2(InvalidateAllDisplayRects(pWindow, pImage, NULL, FALSE))
|
|
}
|
|
if (nFlags & OIAN_REPAINT){
|
|
CheckError2(IMGRepaintDisplay(hWnd, (PRECT) -1))
|
|
}
|
|
|
|
|
|
Exit:
|
|
DeInit(FALSE, TRUE);
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: OiAnSelectByMarkNamedBlock
|
|
|
|
PURPOSE: This routine selects or deselects marks based on their named blocks.
|
|
|
|
INPUTS:
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI OiAnSelectByMarkNamedBlock(HWND hWnd, PSTR pBlockName,
|
|
PSTR pBlock, long lBlockLength,
|
|
BOOL bSelect, BOOL bModifyIfEqual, int nFlags){
|
|
|
|
int nStatus;
|
|
PWINDOW pWindow;
|
|
PANO_IMAGE pAnoImage;
|
|
PIMAGE pImage;
|
|
|
|
int nMarkIndex;
|
|
int nNamedBlockIndex;
|
|
|
|
PMARK pMark;
|
|
BOOL bEqual;
|
|
BOOL bInvalidateAllDisplayRects = FALSE;
|
|
|
|
|
|
CheckError2(Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE))
|
|
pImage = pAnoImage->pBaseImage;
|
|
|
|
CheckError2(ValidateCache(hWnd, pAnoImage))
|
|
|
|
if (!pBlock){
|
|
nStatus = Error(DISPLAY_NULLPOINTERINVALID);
|
|
goto Exit;
|
|
}
|
|
|
|
// End any operation currently in progress.
|
|
if (pAnoImage->Annotations.ppMarks){
|
|
while(pAnoImage->Annotations.ppMarks[pAnoImage->Annotations.nMarks]){
|
|
OiOpEndOperation(hWnd);
|
|
}
|
|
}
|
|
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
bEqual = FALSE;
|
|
if (!memcmp(pBlockName, szOiAnoDat, 8)){
|
|
if (pMark->nOiAnoDatSize == lBlockLength){
|
|
if (!memcmp(pMark->pOiAnoDat, pBlock, lmin(65535, lBlockLength))){
|
|
bEqual = TRUE;
|
|
}
|
|
}
|
|
}else if (!memcmp(pBlockName, szOiGroup, 8)){
|
|
if (pMark->nOiGroupSize == lBlockLength){
|
|
if (!memcmp(pMark->pOiGroup, pBlock, lmin(65535, lBlockLength))){
|
|
bEqual = TRUE;
|
|
}
|
|
}
|
|
}else if (!memcmp(pBlockName, szOiSelect, 8)){
|
|
if (pMark->nOiSelectSize == lBlockLength){
|
|
if (!memcmp(pMark->pOiSelect, pBlock, lmin(65535, lBlockLength))){
|
|
bEqual = TRUE;
|
|
}
|
|
}
|
|
}else if (!memcmp(pBlockName, szOiIndex, 8)){
|
|
if (pMark->nOiIndexSize == lBlockLength){
|
|
if (!memcmp(pMark->pOiIndex, pBlock, lmin(65535, lBlockLength))){
|
|
bEqual = TRUE;
|
|
}
|
|
}
|
|
}else{
|
|
for (nNamedBlockIndex = 0; nNamedBlockIndex < pMark->nNamedBlocks; nNamedBlockIndex++){
|
|
if (!memcmp(pMark->ppNamedBlock[nNamedBlockIndex]->szName, pBlockName, 8)){
|
|
if (pMark->ppNamedBlock[nNamedBlockIndex]->lSize == lBlockLength){
|
|
if (!memcmp(pMark->ppNamedBlock[nNamedBlockIndex]->pBlock,
|
|
pBlock, lmin(65535, lBlockLength))){
|
|
bEqual = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((bEqual && bModifyIfEqual) || (!bEqual && !bModifyIfEqual)){
|
|
if (pMark->bSelected != bSelect){
|
|
pMark->bSelected = bSelect;
|
|
bInvalidateAllDisplayRects = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (bInvalidateAllDisplayRects){
|
|
CheckError2(InvalidateAllDisplayRects(pWindow, pImage, NULL, FALSE))
|
|
}
|
|
if (nFlags & OIAN_REPAINT){
|
|
CheckError2(IMGRepaintDisplay(hWnd, (PRECT) -1))
|
|
}
|
|
|
|
|
|
Exit:
|
|
DeInit(FALSE, TRUE);
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: IsMarkSelected
|
|
|
|
PURPOSE: This routine determines if a mark is selected.
|
|
|
|
INPUTS:
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL WINAPI IsMarkSelected(PWINDOW pWindow, PMARK pMark){
|
|
|
|
int nStatus = 0;
|
|
|
|
|
|
if (pMark->bSelected || pMark->bTempSelected){
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: DeleteAnnotations
|
|
|
|
PURPOSE: This routine deletes all annotations.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI DeleteAnnotations(PANO_IMAGE pAnoImage){
|
|
|
|
int nStatus = 0;
|
|
|
|
|
|
// Delete all marks.
|
|
while(pAnoImage->Annotations.nMarks){
|
|
CheckError2(DeleteMark(pAnoImage, pAnoImage->Annotations.nMarks - 1))
|
|
}
|
|
CheckError2(FreeMemory((PPSTR) &pAnoImage->Annotations.ppMarks))
|
|
pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: DeleteMark
|
|
|
|
PURPOSE: This routine deletes a mark.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI DeleteMark(PANO_IMAGE pAnoImage, int nMarkIndex){
|
|
|
|
int nStatus = 0;
|
|
|
|
PWINDOW pWindow; // Not always valid.
|
|
PMARK pMark;
|
|
|
|
|
|
if (!(pAnoImage->Annotations.ppMarks)){
|
|
goto Exit;
|
|
}
|
|
if (!(pMark = pAnoImage->Annotations.ppMarks[nMarkIndex])){
|
|
goto Exit;
|
|
}
|
|
if (!(pMark->Attributes.dwPermissions & ACL_DELETE_MARK)){
|
|
nStatus = Error(DISPLAY_RESTRICTED_ACCESS);
|
|
goto Exit;
|
|
}
|
|
// free the structures associated with forms
|
|
if ((int) pMark->Attributes.uType == OIOP_AN_FORM && nMarkIndex == 0){
|
|
if (pAnoImage->pDisplayFormImage){
|
|
CheckError2(FreeImgBuf(&pAnoImage->pDisplayFormImage->pImg))
|
|
CheckError2(FreeMemory((PPSTR) &pAnoImage->pDisplayFormImage))
|
|
}
|
|
pAnoImage->pDisplayFormImage = 0;
|
|
if (pAnoImage->pFormImage){
|
|
pAnoImage->pFormImage->nLockCount = max(0, pAnoImage->pFormImage->nLockCount -1);
|
|
if (!pAnoImage->pFormImage->nLockCount){
|
|
CheckError2(CacheClear(&pAnoImage->pFormImage))
|
|
}
|
|
pAnoImage->pFormImage = 0;
|
|
pAnoImage->nBPFValidLines = 0;
|
|
CheckError2(FreeImgBuf(&pAnoImage->pBasePlusFormImg))
|
|
|
|
if (pAnoImage->phWnd){
|
|
CheckError2(GetPWindow(pAnoImage->phWnd[0], &pWindow))
|
|
CheckError2(InvalidateAllDisplayRects(pWindow, pAnoImage->pBaseImage, NULL, TRUE))
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free the named block info.
|
|
CheckError2(DeleteMarkNamedBlocks(pMark))
|
|
|
|
// Free the mark structure.
|
|
CheckError2(FreeMemory((PPSTR) &pMark))
|
|
// Now that the mark has been deleted, make the pointer to it NULL.
|
|
pAnoImage->Annotations.ppMarks[nMarkIndex] = NULL;
|
|
|
|
if (nMarkIndex < pAnoImage->Annotations.nMarks){
|
|
// Condense the list.
|
|
for (; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pAnoImage->Annotations.ppMarks[nMarkIndex] = pAnoImage->Annotations.ppMarks[nMarkIndex + 1];
|
|
}
|
|
pAnoImage->Annotations.ppMarks[nMarkIndex] = NULL;
|
|
|
|
CheckError2(ReAllocateMemory(sizeof(PMARK) * (pAnoImage->Annotations.nMarks),
|
|
(PPSTR) &pAnoImage->Annotations.ppMarks, ZERO_INIT))
|
|
pAnoImage->Annotations.nMarks--;
|
|
pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
|
|
}
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: DeleteMarkNamedBlocks
|
|
|
|
PURPOSE: This routine deletes a marks named blocks.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI DeleteMarkNamedBlocks(PMARK pMark){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nNamedBlockIndex;
|
|
|
|
// Free the named block info.
|
|
if (pMark->ppNamedBlock){
|
|
for (nNamedBlockIndex = 0; nNamedBlockIndex <
|
|
pMark->nNamedBlocks; nNamedBlockIndex++){
|
|
CheckError2(FreeMemory(&pMark->ppNamedBlock[nNamedBlockIndex]->pBlock))
|
|
CheckError2(FreeMemory((PPSTR) &pMark->ppNamedBlock[nNamedBlockIndex]))
|
|
}
|
|
CheckError2(FreeMemory((PPSTR) &pMark->ppNamedBlock))
|
|
}
|
|
CheckError2(FreeMemory(&pMark->pOiAnoDat))
|
|
pMark->nOiAnoDatSize = 0;
|
|
CheckError2(FreeMemory(&pMark->pOiGroup))
|
|
pMark->nOiGroupSize = 0;
|
|
CheckError2(FreeMemory(&pMark->pOiSelect))
|
|
pMark->nOiSelectSize = 0;
|
|
CheckError2(FreeMemory(&pMark->pOiIndex))
|
|
pMark->nOiIndexSize = 0;
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetAMarkNamedBlock
|
|
|
|
PURPOSE: This gets a named block.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI GetAMarkNamedBlock(PMARK pMark, PSTR pName, PPSTR ppBlock){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nNamedBlockIndex;
|
|
|
|
|
|
if (!memcmp(pName, szOiAnoDat, 8)){
|
|
*ppBlock = pMark->pOiAnoDat;
|
|
}else if (!memcmp(pName, szOiGroup, 8)){
|
|
*ppBlock = pMark->pOiGroup;
|
|
}else if (!memcmp(pName, szOiSelect, 8)){
|
|
*ppBlock = pMark->pOiSelect;
|
|
}else if (!memcmp(pName, szOiIndex, 8)){
|
|
*ppBlock = pMark->pOiIndex;
|
|
}else{
|
|
*ppBlock = 0;
|
|
for (nNamedBlockIndex = 0; nNamedBlockIndex < pMark->nNamedBlocks; nNamedBlockIndex++){
|
|
if (!memcmp(pMark->ppNamedBlock[nNamedBlockIndex]->szName, pName, 8)){
|
|
*ppBlock = pMark->ppNamedBlock[nNamedBlockIndex]->pBlock;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: DeleteAMarkNamedBlock
|
|
|
|
PURPOSE: This deletes a named block. No error if it doesn't exist.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI DeleteAMarkNamedBlock(PMARK pMark, PSTR pName){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nNamedBlockIndex;
|
|
|
|
|
|
if (!memcmp(pName, szOiAnoDat, 8)){
|
|
CheckError2(FreeMemory(&pMark->pOiAnoDat))
|
|
pMark->nOiAnoDatSize = 0;
|
|
}else if (!memcmp(pName, szOiGroup, 8)){
|
|
CheckError2(FreeMemory(&pMark->pOiGroup))
|
|
pMark->nOiGroupSize = 0;
|
|
}else if (!memcmp(pName, szOiSelect, 8)){
|
|
CheckError2(FreeMemory(&pMark->pOiSelect))
|
|
pMark->nOiSelectSize = 0;
|
|
}else if (!memcmp(pName, szOiIndex, 8)){
|
|
CheckError2(FreeMemory(&pMark->pOiIndex))
|
|
pMark->nOiIndexSize = 0;
|
|
}else{
|
|
for (nNamedBlockIndex = 0; nNamedBlockIndex <
|
|
pMark->nNamedBlocks; nNamedBlockIndex++){
|
|
if (!memcmp(pMark->ppNamedBlock[nNamedBlockIndex]->szName, pName, 8)){
|
|
CheckError2(FreeMemory(&pMark->ppNamedBlock[nNamedBlockIndex]->pBlock))
|
|
CheckError2(FreeMemory((PPSTR) &pMark->ppNamedBlock[nNamedBlockIndex]))
|
|
// Condense the list.
|
|
for (; nNamedBlockIndex < pMark->nNamedBlocks - 1; nNamedBlockIndex++){
|
|
pMark->ppNamedBlock[nNamedBlockIndex] = pMark->ppNamedBlock[nNamedBlockIndex + 1];
|
|
}
|
|
CheckError2(ReAllocateMemory(sizeof(PNAMED_BLOCK) * (pMark->nNamedBlocks - 1),
|
|
(PPSTR) &pMark->ppNamedBlock, ZERO_INIT))
|
|
pMark->nNamedBlocks--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: AddAMarkNamedBlock
|
|
|
|
PURPOSE: This adds a named block. Deletes it if previously already existing.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI AddAMarkNamedBlock(PMARK pMark, PSTR pName, PPSTR ppBlock, long lSize){
|
|
|
|
int nStatus = 0;
|
|
|
|
PSTR pBlock;
|
|
|
|
|
|
pBlock = *ppBlock;
|
|
CheckError2(DeleteAMarkNamedBlock(pMark, pName))
|
|
|
|
if (!lSize){
|
|
goto Exit;
|
|
}
|
|
|
|
if (!pBlock){
|
|
CheckError2(AllocateMemory(lSize, &pBlock, ZERO_INIT))
|
|
}
|
|
|
|
if (!memcmp(pName, szOiAnoDat, 8)){
|
|
pMark->pOiAnoDat = pBlock;
|
|
pMark->nOiAnoDatSize = lSize;
|
|
}else if (!memcmp(pName, szOiGroup, 8)){
|
|
pMark->pOiGroup = pBlock;
|
|
pMark->nOiGroupSize = lSize;
|
|
}else if (!memcmp(pName, szOiSelect, 8)){
|
|
pMark->pOiSelect = pBlock;
|
|
pMark->nOiSelectSize = lSize;
|
|
}else if (!memcmp(pName, szOiIndex, 8)){
|
|
pMark->pOiIndex = pBlock;
|
|
pMark->nOiIndexSize = lSize;
|
|
}else{
|
|
CheckError2(ReAllocateMemory(sizeof(PNAMED_BLOCK) * (pMark->nNamedBlocks + 1),
|
|
(PPSTR) &pMark->ppNamedBlock, ZERO_INIT))
|
|
CheckError2(AllocateMemory(sizeof(NAMED_BLOCK),
|
|
(PPSTR) &pMark->ppNamedBlock[pMark->nNamedBlocks], ZERO_INIT))
|
|
pMark->ppNamedBlock[pMark->nNamedBlocks]->pBlock = pBlock;
|
|
pMark->ppNamedBlock[pMark->nNamedBlocks]->lSize = lSize;
|
|
memcpy(pMark->ppNamedBlock[pMark->nNamedBlocks]->szName, pName, 8);
|
|
pMark->nNamedBlocks++;
|
|
}
|
|
*ppBlock = pBlock;
|
|
|
|
|
|
Exit:
|
|
if (nStatus){
|
|
if (!*ppBlock){
|
|
if (pBlock){
|
|
FreeMemory(&pBlock);
|
|
}
|
|
}
|
|
}
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: ReAllocateAMarkNamedBlock
|
|
|
|
PURPOSE: This reallocates a named block and returns the pointer to the new one.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI ReAllocateAMarkNamedBlock(PMARK pMark, char szName[8],
|
|
PPSTR ppBlock, long lSize){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nNamedBlockIndex;
|
|
|
|
|
|
CheckError2(ReAllocateMemory(lSize, ppBlock, ZERO_INIT))
|
|
|
|
if (!memcmp(szName, szOiAnoDat, 8)){
|
|
pMark->pOiAnoDat = *ppBlock;
|
|
pMark->nOiAnoDatSize = lSize;
|
|
}else if (!memcmp(szName, szOiGroup, 8)){
|
|
pMark->pOiGroup = *ppBlock;
|
|
pMark->nOiGroupSize = lSize;
|
|
}else if (!memcmp(szName, szOiSelect, 8)){
|
|
pMark->pOiSelect = *ppBlock;
|
|
pMark->nOiSelectSize = lSize;
|
|
}else if (!memcmp(szName, szOiIndex, 8)){
|
|
pMark->pOiIndex = *ppBlock;
|
|
pMark->nOiIndexSize = lSize;
|
|
}else{
|
|
for (nNamedBlockIndex = 0; nNamedBlockIndex < pMark->nNamedBlocks; nNamedBlockIndex++){
|
|
if (!memcmp(pMark->ppNamedBlock[nNamedBlockIndex]->szName, szName, 8)){
|
|
pMark->ppNamedBlock[nNamedBlockIndex]->pBlock = *ppBlock;
|
|
pMark->ppNamedBlock[nNamedBlockIndex]->lSize = lSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: ScaleAnnotation
|
|
|
|
PURPOSE: This scales an annotation down to the size specified.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI ScaleAnnotation(HWND hWnd, PMARK pMark, int nHScale, int nVScale,
|
|
int nScaleAlgorithm){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nLoop;
|
|
PAN_POINTS pPoints;
|
|
|
|
|
|
if (nHScale == 1000 && nVScale == 1000){
|
|
goto Exit; // Nothing to do.
|
|
}
|
|
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_SELECT_BY_RECT_VARIABLE:
|
|
case OIOP_SELECT_BY_RECT_FIXED:
|
|
case OIOP_SELECT_BY_POINT:
|
|
case OIOP_ACTIVATE:
|
|
case OIOP_DELETE:
|
|
case OIOP_UNDO:
|
|
case OIOP_REDO:
|
|
break;
|
|
|
|
case OIOP_AN_LINE:
|
|
case OIOP_AN_FREEHAND:
|
|
pMark->Attributes.lrBounds.left = ( pMark->Attributes.lrBounds.left
|
|
* nHScale) / 1000;
|
|
pMark->Attributes.lrBounds.right = ( pMark->Attributes.lrBounds.right
|
|
* nHScale) / 1000;
|
|
pMark->Attributes.lrBounds.top = ( pMark->Attributes.lrBounds.top
|
|
* nVScale) / 1000;
|
|
pMark->Attributes.lrBounds.bottom = ( pMark->Attributes.lrBounds.bottom
|
|
* nVScale) / 1000;
|
|
(int) pMark->Attributes.uLineSize = (( (int) pMark->Attributes.uLineSize
|
|
* nHScale) / 1000);
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
|
|
for (nLoop = 0; nLoop < pPoints->nPoints; nLoop++){
|
|
pPoints->ptPoint[nLoop].x = (int) (( pPoints->ptPoint[nLoop].x * nHScale) / 1000);
|
|
pPoints->ptPoint[nLoop].y = (int) (( pPoints->ptPoint[nLoop].y * nVScale) / 1000);
|
|
}
|
|
break;
|
|
|
|
case OIOP_AN_HOLLOW_RECT:
|
|
case OIOP_AN_FILLED_RECT:
|
|
pMark->Attributes.lrBounds.left = (pMark->Attributes.lrBounds.left * nHScale) / 1000;
|
|
pMark->Attributes.lrBounds.right = (pMark->Attributes.lrBounds.right * nHScale) / 1000;
|
|
pMark->Attributes.lrBounds.top = (pMark->Attributes.lrBounds.top * nVScale) / 1000;
|
|
pMark->Attributes.lrBounds.bottom = (pMark->Attributes.lrBounds.bottom * nVScale) / 1000;
|
|
(int) pMark->Attributes.uLineSize = (((int)pMark->Attributes.uLineSize * nHScale) / 1000);
|
|
break;
|
|
|
|
case OIOP_AN_TEXT:
|
|
case OIOP_AN_TEXT_FROM_A_FILE:
|
|
case OIOP_AN_TEXT_STAMP:
|
|
case OIOP_AN_ATTACH_A_NOTE:
|
|
CheckError2(ScaleAnnotationText(hWnd, pMark, nHScale, nVScale))
|
|
break;
|
|
|
|
case OIOP_AN_IMAGE:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
case OIOP_AN_FORM:
|
|
CheckError2(ScaleAnnotationImage(hWnd, pMark, nHScale, nVScale, nScaleAlgorithm))
|
|
break;
|
|
|
|
// These aren't implemented yet.
|
|
case OIOP_AN_AUDIO:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: CanMarkBeScaled
|
|
|
|
PURPOSE: This tests an annotation to see if it can be scaled to a
|
|
particular scale factor.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI CanMarkBeScaled(HWND hWnd, PMARK pMark, int nScale){
|
|
|
|
int nStatus = 0;
|
|
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_SELECT_BY_RECT_VARIABLE:
|
|
case OIOP_SELECT_BY_RECT_FIXED:
|
|
case OIOP_SELECT_BY_POINT:
|
|
case OIOP_ACTIVATE:
|
|
case OIOP_DELETE:
|
|
case OIOP_UNDO:
|
|
case OIOP_REDO:
|
|
case OIOP_AN_LINE:
|
|
case OIOP_AN_FREEHAND:
|
|
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:
|
|
nStatus = CanMarkBeScaledText(hWnd, pMark, nScale);
|
|
break;
|
|
|
|
case OIOP_AN_IMAGE:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
case OIOP_AN_FORM:
|
|
nStatus = CanMarkBeScaledImage(hWnd, pMark, nScale);
|
|
break;
|
|
|
|
// These aren't implemented yet.
|
|
case OIOP_AN_AUDIO:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: CheckPermissions
|
|
|
|
PURPOSE: This check all permissions and sets the flags appropriately.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI CheckPermissions(PWINDOW pWindow, PANO_IMAGE pAnoImage){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nUserACLIndex;
|
|
int nTargetACLIndex;
|
|
int nMarkIndex;
|
|
PMARK pMark;
|
|
LPOI_ACL_BLOCK pUserACL;
|
|
LPOI_ACL_BLOCK pTargetACL;
|
|
BOOL bSuperUser = FALSE;
|
|
|
|
|
|
CheckError2(GetAMarkNamedBlock(pWindow->pUserMark, szOiACL, (PPSTR) &pUserACL))
|
|
if (!pUserACL){
|
|
CheckError2(AddAMarkNamedBlock(pWindow->pUserMark, szOiACL,
|
|
(PPSTR) &pUserACL, sizeof(OI_ACL_BLOCK)))
|
|
pUserACL->uIDs = 1;
|
|
memcpy((PSTR) pUserACL->ACL[0].ID, szACLWorld, 8);
|
|
}else{
|
|
for (nUserACLIndex = 0; nUserACLIndex < (int) pUserACL->uIDs; nUserACLIndex++){
|
|
if (!memcmp(pUserACL->ACL[nUserACLIndex].ID, szACLSuperUser, 8)){
|
|
bSuperUser = TRUE;
|
|
}
|
|
}
|
|
}
|
|
// Assign permissions for all marks.
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiACL, (PPSTR) &pTargetACL))
|
|
if (!pTargetACL || bSuperUser){
|
|
pMark->Attributes.dwPermissions = ACL_ALL;
|
|
continue;
|
|
}
|
|
pMark->Attributes.dwPermissions = 0;
|
|
for (nTargetACLIndex = 0; nTargetACLIndex < (int) pTargetACL->uIDs; nTargetACLIndex++){
|
|
for (nUserACLIndex = 0; nUserACLIndex < (int) pUserACL->uIDs; nUserACLIndex++){
|
|
if (!memcmp(pTargetACL->ACL[nTargetACLIndex].ID, pUserACL->ACL[nUserACLIndex].ID, 8)){
|
|
pMark->Attributes.dwPermissions = pTargetACL->ACL[nTargetACLIndex].dwPermissions;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: CheckPermissionsMark
|
|
|
|
PURPOSE: This check all permissions and sets the flags appropriately.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI CheckPermissionsMark(PWINDOW pWindow, PANO_IMAGE pAnoImage, PMARK pMark){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nUserACLIndex;
|
|
int nTargetACLIndex;
|
|
LPOI_ACL_BLOCK pUserACL;
|
|
LPOI_ACL_BLOCK pTargetACL;
|
|
BOOL bSuperUser = FALSE;
|
|
|
|
|
|
CheckError2(GetAMarkNamedBlock(pWindow->pUserMark, szOiACL, (PPSTR) &pUserACL))
|
|
if (!pUserACL){
|
|
CheckError2(AddAMarkNamedBlock(pWindow->pUserMark, szOiACL,
|
|
(PPSTR) &pUserACL, sizeof(OI_ACL_BLOCK)))
|
|
pUserACL->uIDs = 1;
|
|
memcpy((PSTR) pUserACL->ACL[0].ID, szACLWorld, 8);
|
|
}else{
|
|
for (nUserACLIndex = 0; nUserACLIndex < (int) pUserACL->uIDs; nUserACLIndex++){
|
|
if (!memcmp(pUserACL->ACL[nUserACLIndex].ID, szACLSuperUser, 8)){
|
|
bSuperUser = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Assign permissions for this mark.
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiACL, (PPSTR) &pTargetACL))
|
|
if (!pTargetACL || bSuperUser){
|
|
pMark->Attributes.dwPermissions = ACL_ALL;
|
|
goto Exit;
|
|
}
|
|
|
|
pMark->Attributes.dwPermissions = 0;
|
|
for (nTargetACLIndex = 0; nTargetACLIndex < (int) pTargetACL->uIDs; nTargetACLIndex++){
|
|
for (nUserACLIndex = 0; nUserACLIndex < (int) pUserACL->uIDs; nUserACLIndex++){
|
|
if (!memcmp(pTargetACL->ACL[nTargetACLIndex].ID, pUserACL->ACL[nUserACLIndex].ID, 8)){
|
|
pMark->Attributes.dwPermissions = pTargetACL->ACL[nTargetACLIndex].dwPermissions;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: ResizeMark
|
|
|
|
PURPOSE: This routine Resizes a mark via the specified offsets.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI ResizeMark(PMARK pMark, int nHandle, long lHOffset, long lVOffset){
|
|
|
|
int nStatus = 0;
|
|
|
|
PAN_POINTS pPoints;
|
|
int nLoop;
|
|
|
|
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_AN_LINE:
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pPoints))
|
|
if (!pPoints){
|
|
nStatus = Error(DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
switch (nHandle){
|
|
case 1: // Point 0.
|
|
pPoints->ptPoint[0].x += (int)lHOffset;
|
|
pPoints->ptPoint[0].y += (int)lVOffset;
|
|
break;
|
|
|
|
case 2: // Point 1.
|
|
pPoints->ptPoint[1].x += (int)lHOffset;
|
|
pPoints->ptPoint[1].y += (int)lVOffset;
|
|
break;
|
|
|
|
default: // Move
|
|
pMark->Attributes.lrBounds.left += lHOffset;
|
|
pMark->Attributes.lrBounds.top += lVOffset;
|
|
pMark->Attributes.lrBounds.right += lHOffset;
|
|
pMark->Attributes.lrBounds.bottom += lVOffset;
|
|
break;
|
|
}
|
|
// Make the left and top of the bounding rect correct.
|
|
lHOffset = pPoints->ptPoint[0].x;
|
|
lVOffset = pPoints->ptPoint[0].y;
|
|
for (nLoop = 1; 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;
|
|
break;
|
|
|
|
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:
|
|
switch (nHandle){
|
|
case 1: // Top, right
|
|
pMark->Attributes.lrBounds.right += lHOffset;
|
|
pMark->Attributes.lrBounds.top += lVOffset;
|
|
break;
|
|
|
|
case 2: // Middle, right
|
|
pMark->Attributes.lrBounds.right += lHOffset;
|
|
break;
|
|
|
|
case 3: // Bottom, right
|
|
pMark->Attributes.lrBounds.right += lHOffset;
|
|
pMark->Attributes.lrBounds.bottom += lVOffset;
|
|
break;
|
|
|
|
case 4: // Bottom, middle
|
|
pMark->Attributes.lrBounds.bottom += lVOffset;
|
|
break;
|
|
|
|
case 5: // Bottom, left
|
|
pMark->Attributes.lrBounds.left += lHOffset;
|
|
pMark->Attributes.lrBounds.bottom += lVOffset;
|
|
break;
|
|
|
|
case 6: // Middle, left
|
|
pMark->Attributes.lrBounds.left += lHOffset;
|
|
break;
|
|
|
|
case 7: // Top, left
|
|
pMark->Attributes.lrBounds.left += lHOffset;
|
|
pMark->Attributes.lrBounds.top += lVOffset;
|
|
break;
|
|
|
|
case 8: // Top, middle
|
|
pMark->Attributes.lrBounds.top += lVOffset;
|
|
break;
|
|
|
|
default: // Move
|
|
pMark->Attributes.lrBounds.left += lHOffset;
|
|
pMark->Attributes.lrBounds.top += lVOffset;
|
|
pMark->Attributes.lrBounds.right += lHOffset;
|
|
pMark->Attributes.lrBounds.bottom += lVOffset;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// These marks don't currently support resize, only move.
|
|
case OIOP_AN_AUDIO:
|
|
case OIOP_AN_FREEHAND:
|
|
default:
|
|
pMark->Attributes.lrBounds.left += lHOffset;
|
|
pMark->Attributes.lrBounds.top += lVOffset;
|
|
pMark->Attributes.lrBounds.right += lHOffset;
|
|
pMark->Attributes.lrBounds.bottom += lVOffset;
|
|
break;
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: MoveSelectedMarks
|
|
|
|
PURPOSE: This routine moves the selected marks
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI MoveSelectedMarks(HWND hWnd, PWINDOW pWindow, PANO_IMAGE pAnoImage,
|
|
PMARK pMark, HDC hDC, RECT rClientRect,
|
|
LRECT lrFullsizeClientRect, LRECT lrRectPoint,
|
|
LRECT lrwRectPoint, BOOL bCheckACL){
|
|
|
|
int nStatus = 0;
|
|
PIMAGE pImage;
|
|
|
|
int nMarkIndex;
|
|
PMARK pMark2;
|
|
|
|
LRECT lrRect;
|
|
long lHOffset;
|
|
long lVOffset;
|
|
long lwHOffset;
|
|
long lwVOffset;
|
|
long lHOffsetNew;
|
|
long lVOffsetNew;
|
|
BOOL bSelectionRectPresent = FALSE;
|
|
BOOL bSelectedMarksPresent = FALSE;
|
|
POINT *pwPoint = 0;
|
|
int nHScale;
|
|
int nVScale;
|
|
|
|
|
|
pImage = pAnoImage->pBaseImage;
|
|
if (pAnoImage->Annotations.bMoving && !pAnoImage->Annotations.bMoved){
|
|
// get window coordinates of the point from the named block
|
|
CheckError2(GetAMarkNamedBlock(pMark, szOiAnoDat, (PPSTR) &pwPoint))
|
|
if (!pwPoint){
|
|
nStatus = Error (DISPLAY_DATACORRUPTED);
|
|
goto Exit;
|
|
}
|
|
lwHOffset = lrwRectPoint.right - pwPoint->x;
|
|
lwVOffset = lrwRectPoint.bottom - pwPoint->y;
|
|
// Check to see if we should start moving.
|
|
lHOffset = lrRectPoint.right - pMark->Attributes.lrBounds.left;
|
|
lVOffset = lrRectPoint.bottom - pMark->Attributes.lrBounds.top;
|
|
if (lwHOffset > SELECTION_FUDGE || lwHOffset < -SELECTION_FUDGE
|
|
|| lwVOffset > SELECTION_FUDGE || lwVOffset < -SELECTION_FUDGE){
|
|
pAnoImage->Annotations.bMoved = TRUE;
|
|
if (!bCheckACL){
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
if (pMark2->bSelected || pMark2->bTempSelected){
|
|
if (!(pMark->Attributes.dwPermissions & ACL_MODIFY_MARK)){
|
|
nStatus = Error(DISPLAY_RESTRICTED_ACCESS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pAnoImage->Annotations.bMoved = TRUE;
|
|
}
|
|
}
|
|
if (!pAnoImage->Annotations.bMoved){
|
|
goto Exit;
|
|
}
|
|
|
|
// Move the selected marks.
|
|
lHOffset = pMark->Attributes.lrBounds.right - pMark->Attributes.lrBounds.left;
|
|
lVOffset = pMark->Attributes.lrBounds.bottom - pMark->Attributes.lrBounds.top;
|
|
|
|
// Update drag offset.
|
|
pMark->Attributes.lrBounds.right = lrRectPoint.right;
|
|
pMark->Attributes.lrBounds.bottom = lrRectPoint.bottom;
|
|
lHOffsetNew = pMark->Attributes.lrBounds.right - pMark->Attributes.lrBounds.left;
|
|
lVOffsetNew = pMark->Attributes.lrBounds.bottom - pMark->Attributes.lrBounds.top;
|
|
|
|
|
|
if (!(pAnoImage->nStartOpFlags & OIOP_ANNOTATIONS_ONLY)){
|
|
// Check for selection rect being dragged off image area and
|
|
// clip offset to keep it on.
|
|
GetSelectBox(pAnoImage, &lrRect);
|
|
if (lrRect.right - lrRect.left && lrRect.bottom - lrRect.top){
|
|
// Move the selection box with everything else.
|
|
bSelectionRectPresent = TRUE;
|
|
if (pAnoImage->lrSelectBoxOrg.left + lHOffsetNew < 0){
|
|
lHOffsetNew = -(pAnoImage->lrSelectBoxOrg.left);
|
|
}
|
|
if (pAnoImage->lrSelectBoxOrg.right + lHOffsetNew >= pImage->nWidth){
|
|
lHOffsetNew = pImage->nWidth - pAnoImage->lrSelectBoxOrg.right - 1;
|
|
}
|
|
if (pAnoImage->lrSelectBoxOrg.top + lVOffsetNew < 0){
|
|
lVOffsetNew = -(pAnoImage->lrSelectBoxOrg.top);
|
|
}
|
|
if (pAnoImage->lrSelectBoxOrg.bottom + lVOffsetNew >= pImage->nHeight){
|
|
lVOffsetNew = pImage->nHeight - pAnoImage->lrSelectBoxOrg.bottom - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(pAnoImage->nStartOpFlags & OIOP_IMAGE_ONLY)){
|
|
// Check for marks being dragged off image area and
|
|
// clip offset to keep them on.
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
if (!pMark2->bSelected){
|
|
continue;
|
|
}
|
|
bSelectedMarksPresent = TRUE;
|
|
if (pMark2->Attributes.lrBounds.left + lHOffsetNew > pImage->nWidth - 5){
|
|
lHOffsetNew = pImage->nWidth - pMark2->Attributes.lrBounds.left - 5;
|
|
}
|
|
if (pMark2->Attributes.lrBounds.right + lHOffsetNew < 5){
|
|
lHOffsetNew = -(pMark2->Attributes.lrBounds.right - 5);
|
|
}
|
|
if (pMark2->Attributes.lrBounds.top + lVOffsetNew > pImage->nHeight - 5){
|
|
lVOffsetNew = pImage->nHeight - pMark2->Attributes.lrBounds.top - 5;
|
|
}
|
|
if (pMark2->Attributes.lrBounds.bottom + lVOffsetNew < 5){
|
|
lVOffsetNew = -(pMark2->Attributes.lrBounds.bottom - 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
pMark->Attributes.lrBounds.right = pMark->Attributes.lrBounds.left + lHOffsetNew;
|
|
pMark->Attributes.lrBounds.bottom = pMark->Attributes.lrBounds.top + lVOffsetNew;
|
|
|
|
if (!(pAnoImage->nStartOpFlags & OIOP_ANNOTATIONS_ONLY) && bSelectionRectPresent){
|
|
SetLRect(lrRect, pAnoImage->lrSelectBoxOrg.left + lHOffsetNew,
|
|
pAnoImage->lrSelectBoxOrg.top + lVOffsetNew,
|
|
pAnoImage->lrSelectBoxOrg.right + lHOffsetNew,
|
|
pAnoImage->lrSelectBoxOrg.bottom + lVOffsetNew);
|
|
IMGSetParmsCgbw(hWnd, PARM_SELECTION_BOX, &lrRect, PARM_FULLSIZE);
|
|
}
|
|
|
|
CheckError2(TranslateScale(pWindow->nScale, pImage->nHRes, pImage->nVRes, &nHScale, &nVScale))
|
|
|
|
if (!(pAnoImage->nStartOpFlags & OIOP_IMAGE_ONLY) && bSelectedMarksPresent){
|
|
// Move the mark(s).
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark2 = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
if (!pMark2->bSelected){
|
|
continue;
|
|
}
|
|
// Erase the selected marks from their old drag position.
|
|
CheckError2(ResizeMark(pMark2, pAnoImage->nHandle, lHOffset, lVOffset))
|
|
|
|
CheckError2(PaintAnnotation(hWnd, hDC, pWindow, pImage,
|
|
pMark2, rClientRect, lrFullsizeClientRect, PAINT_MODE_DRAG,
|
|
pWindow->nScale, nHScale, nVScale, pWindow->lHOffset,
|
|
pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
|
|
DONT_FORCE_OPAQUE_RECTANGLES))
|
|
|
|
// Draw the selected marks in thier new location via drag mode.
|
|
CheckError2(ResizeMark(pMark2, pAnoImage->nHandle,
|
|
lHOffsetNew - lHOffset, lVOffsetNew - lVOffset))
|
|
|
|
CheckError2(PaintAnnotation(hWnd, hDC, pWindow, pImage,
|
|
pMark2, rClientRect, lrFullsizeClientRect, PAINT_MODE_DRAG,
|
|
pWindow->nScale, nHScale, nVScale, pWindow->lHOffset,
|
|
pWindow->lVOffset, 0, DONT_USE_BI_LEVEL_DITHERING,
|
|
DONT_FORCE_OPAQUE_RECTANGLES))
|
|
|
|
// Reset the selected bounds back to where they were.
|
|
CheckError2(ResizeMark(pMark2, pAnoImage->nHandle, -lHOffsetNew, -lVOffsetNew))
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
return(nStatus);
|
|
}
|
|
/****************************************************************************
|
|
|
|
FUNCTION: RenderDibToImage
|
|
|
|
PURPOSE: This routine renders a DIB into the image.
|
|
|
|
****************************************************************************/
|
|
|
|
int WINAPI RenderDibToImage(PPIMG ppImg, PBITMAPINFOHEADER pDib,
|
|
int nHScale, int nVScale, LRECT lrDestRect){
|
|
|
|
int nStatus = 0;
|
|
|
|
int nScaledWidth;
|
|
int nScaledHeight;
|
|
PIMG pTempImg = 0;
|
|
PIMG pTempImg2 = 0;
|
|
RECT rSourceRect;
|
|
RECT rDestRect;
|
|
LRECT lrScaledRect;
|
|
|
|
|
|
if (!ppImg || !*ppImg){
|
|
nStatus = Error(DISPLAY_IMAGETYPENOTSUPPORTED);
|
|
goto Exit;
|
|
}
|
|
if (!pDib){
|
|
nStatus = Error(DISPLAY_INVALID_OPTIONS);
|
|
goto Exit;
|
|
}
|
|
|
|
// make sure dest rect is within image bounds
|
|
lrDestRect.right = lmin((*ppImg)->nWidth, lrDestRect.right);
|
|
lrDestRect.bottom = lmin((*ppImg)->nHeight, lrDestRect.bottom);
|
|
if (lrDestRect.left >= (*ppImg)->nWidth || lrDestRect.right <= 0
|
|
|| lrDestRect.top >= (*ppImg)->nHeight || lrDestRect.bottom <= 0){
|
|
goto Exit; // Nothing to do.
|
|
}
|
|
|
|
CheckError2(DibToIpNoPal(&pTempImg, pDib))
|
|
if ((*ppImg)->nType != pTempImg->nType
|
|
&& ((*ppImg)->nType == ITYPE_PAL4 || (*ppImg)->nType == ITYPE_CUSPAL8)){
|
|
nStatus = Error(DISPLAY_INVALIDOPFORPALIMAGE);
|
|
goto Exit;
|
|
}
|
|
|
|
nScaledWidth = (lrDestRect.right - lrDestRect.left);
|
|
nScaledHeight = (lrDestRect.bottom - lrDestRect.top);
|
|
// this is the paste rect with respect to coordinates (0,0)
|
|
SetLRect (lrScaledRect, 0, 0, nScaledWidth, nScaledHeight);
|
|
|
|
// Scale it into pTempImg2.
|
|
CheckError2(ScaleImageRect(pTempImg, &pTempImg2, nHScale, nVScale, lrScaledRect, 0,
|
|
(LP_FIO_RGBQUAD) ((PSTR) pDib + sizeof(BITMAPINFOHEADER)), pDib->biClrUsed))
|
|
|
|
// Convert it to Original format, back into Temp.
|
|
FreeImgBuf(&pTempImg);
|
|
|
|
if ((*ppImg)->nType == pTempImg2->nType){
|
|
MoveImage(&pTempImg2, &pTempImg);
|
|
}else{
|
|
CheckError2(CreateAnyImgBuf(&pTempImg, nScaledWidth, nScaledHeight, (*ppImg)->nType))
|
|
|
|
CheckError2(ConvertImgType(pTempImg2, pTempImg,
|
|
(LP_FIO_RGBQUAD) ((PSTR) pDib + sizeof(BITMAPINFOHEADER))))
|
|
CheckError2(FreeImgBuf(&pTempImg2))
|
|
}
|
|
|
|
// Copy it into Image.
|
|
SetRect(&rSourceRect, 0, 0, pTempImg->nWidth, pTempImg->nHeight);
|
|
if (lrDestRect.left < 0){
|
|
rSourceRect.left += abs(lrDestRect.left);
|
|
lrDestRect.left = 0;
|
|
}
|
|
if (lrDestRect.top < 0){
|
|
rSourceRect.top += abs(lrDestRect.top);
|
|
lrDestRect.top = 0;
|
|
}
|
|
|
|
CopyRectLtoR(rDestRect, lrDestRect);
|
|
|
|
CheckError2(CopyImageIDK(pTempImg, *ppImg, rSourceRect, rDestRect))
|
|
|
|
|
|
Exit:
|
|
FreeImgBuf(&pTempImg);
|
|
FreeImgBuf(&pTempImg2);
|
|
return(nStatus);
|
|
}
|
|
//
|
|
/******************************************************************************
|
|
|
|
FUNCTION: OiAnEmbedAllData
|
|
|
|
PURPOSE: Change reference marks, like image by reference and forms to
|
|
non reference marks like embedded images
|
|
|
|
*********************************************************************************/
|
|
int WINAPI OiAnEmbedAllData(HWND hWnd, int nFlags){
|
|
|
|
int nStatus = 0;
|
|
|
|
PWINDOW pWindow;
|
|
PANO_IMAGE pAnoImage;
|
|
PMARK pMark;
|
|
int nMarkIndex;
|
|
|
|
|
|
CheckError2(Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE))
|
|
CheckError2(ValidateCache(hWnd, pAnoImage))
|
|
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
switch ((int) pMark->Attributes.uType){
|
|
case OIOP_AN_FORM:
|
|
case OIOP_AN_IMAGE_BY_REFERENCE:
|
|
CheckError2(EmbedImageData(hWnd, pMark, pAnoImage))
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
pAnoImage->bArchive |= ARCHIVE_MODIFIED_ANNOTATIONS;
|
|
|
|
Exit:
|
|
DeInit(FALSE, TRUE);
|
|
return (nStatus);
|
|
}
|
|
//
|
|
/******************************************************************************
|
|
|
|
FUNCTION: OiIsPointOverSelection
|
|
|
|
PURPOSE: Determines if the point is over any of the selected data.
|
|
|
|
*********************************************************************************/
|
|
int WINAPI OiIsPointOverSelection(HWND hWnd, POINT ptPoint,
|
|
PBOOL pbPointIsOverSelection, int nFlags){
|
|
|
|
int nStatus = 0;
|
|
|
|
PWINDOW pWindow;
|
|
PANO_IMAGE pAnoImage;
|
|
PIMAGE pImage;
|
|
PMARK pMark;
|
|
int nMarkIndex;
|
|
LRECT lrRectPoint;
|
|
LRECT lrRect;
|
|
long lHorzFudge;
|
|
long lVertFudge;
|
|
BOOL bPointNearMark;
|
|
int nHandle;
|
|
int nHScale;
|
|
int nVScale;
|
|
|
|
|
|
CheckError2(Init(hWnd, &pWindow, &pAnoImage, FALSE, TRUE))
|
|
if (!(pImage = pAnoImage->pBaseImage)){
|
|
nStatus = Error(DISPLAY_IHANDLEINVALID);
|
|
goto Exit;
|
|
}
|
|
|
|
*pbPointIsOverSelection = FALSE;
|
|
SetLRect(lrRectPoint, ptPoint.x, ptPoint.y, 0, 0);
|
|
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);
|
|
}
|
|
|
|
if (lrRectPoint.left < 0 || lrRectPoint.left >= (int) pImage->nWidth
|
|
|| lrRectPoint.top < 0 || lrRectPoint.top >= (int) pImage->nHeight){
|
|
*pbPointIsOverSelection = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
CheckError2(ValidateCacheLines(hWnd, pAnoImage, 1))
|
|
CheckError2(TranslateScale(pWindow->nScale, pImage->nHRes, pImage->nVRes, &nHScale, &nVScale))
|
|
|
|
lHorzFudge = lmax (1, SELECTION_FUDGE * SCALE_DENOMINATOR / nHScale);
|
|
lVertFudge = lmax (1, SELECTION_FUDGE * SCALE_DENOMINATOR / nVScale);
|
|
|
|
GetSelectBox(pAnoImage, &lrRect);
|
|
if (lrRect.left != lrRect.right && lrRect.top != lrRect.bottom){
|
|
if (lrRect.left <= (lrRectPoint.left + lHorzFudge)
|
|
&& lrRect.right >= (lrRectPoint.left - lHorzFudge)
|
|
&& lrRect.top <= (lrRectPoint.top + lVertFudge)
|
|
&& lrRect.bottom >= (lrRectPoint.bottom - lVertFudge)){
|
|
*pbPointIsOverSelection = TRUE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
for (nMarkIndex = 0; nMarkIndex < pAnoImage->Annotations.nMarks; nMarkIndex++){
|
|
pMark = pAnoImage->Annotations.ppMarks[nMarkIndex];
|
|
if (!pMark->bSelected){
|
|
continue;
|
|
}
|
|
CheckError2(IsPointNearMark(lrRectPoint, pMark, lHorzFudge,
|
|
lVertFudge, &bPointNearMark, &nHandle))
|
|
if (!bPointNearMark){
|
|
continue;
|
|
}
|
|
*pbPointIsOverSelection = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (nStatus){
|
|
*pbPointIsOverSelection = FALSE;
|
|
}
|
|
DeInit(FALSE, TRUE);
|
|
return (nStatus);
|
|
}
|