/************************************************************/ /* Windows Write, Copyright 1985-1992 Microsoft Corporation */ /************************************************************/ /* pictdrag.c -- Routines for Move Picture and Size Picture */ //#define NOGDICAPMASKS #define NOWINSTYLES #define NOSYSMETRICS #define NOMENUS #define NOICON #define NOKEYSTATE #define NOSYSCOMMANDS #define NOSHOWWINDOW //#define NOATOM #define NOBRUSH #define NOCLIPBOARD #define NOCOLOR #define NOCREATESTRUCT #define NOCTLMGR #define NODRAWTEXT #define NOFONT #define NOHDC #define NOMB #define NOMEMMGR #define NOMENUS #define NOOPENFILE #define NOPEN #define NOREGION #define NOSCROLL #define NOSOUND #define NOWH #define NOWINOFFSETS #define NOWNDCLASS #define NOCOMM #include #include "mw.h" #define NOKCCODES #include "ch.h" #include "docdefs.h" #include "dispdefs.h" #include "cmddefs.h" #include "propdefs.h" #include "wwdefs.h" #include "filedefs.h" #include "editdefs.h" #include "prmdefs.h" #include "winddefs.h" #if defined(OLE) #include "obj.h" #endif extern struct DOD (**hpdocdod)[]; extern typeCP cpMacCur; extern int docCur; extern int wwCur; extern struct SEL selCur; extern struct WWD *pwwdCur; extern struct WWD rgwwd[]; extern typeCP vcpFirstParaCache; extern struct PAP vpapAbs; extern struct SEP vsepAbs; extern struct SEP vsepPage; extern int dxpLogInch; extern int dypLogInch; extern int vfPictSel; extern int vfPMS; extern int vfCancelPictMove; #ifdef DEBUG #define STATIC #else #define STATIC static #endif STATIC NEAR ModifyPicInfoDxa( int, int, int, unsigned, unsigned, BOOL ); STATIC NEAR ModifyPicInfoDxp( int, int, int, unsigned, unsigned ); STATIC NEAR ShowPictMultipliers( void ); #define dxpPicSizeMin dypPicSizeMin /* Type for possible positions of the "size box" icon while moving/sizing a picture */ /* WARNING: fnSizePicture relies on mdIconCenterFloat == 0 */ #define mdIconCenterFloat 0 /* In Center of picture; icon may float */ #define mdIconLeft 1 /* On Left Border */ #define mdIconRight 2 /* On Right Border */ #define mdIconCenterFix 3 /* In center of picture; border moves w/icon */ #define mdIconXMask 3 /* Masks left/right */ #define mdIconBottom 4 /* On bottom border */ #define mdIconSetCursor 8 /* Force set of mouse cursor position */ #define mdIconLL (mdIconLeft | mdIconBottom) #define mdIconLR (mdIconRight | mdIconBottom) /* "PMS" means "Picture Move or Size" */ HCURSOR vhcPMS=NULL; /* Handle to "size box" cursor */ STATIC RECT rcPicture; /* Rectangle containing picture */ STATIC RECT rcClip; /* Window clip box (may intersect above) */ STATIC int ilevelPMS; /* Level for DC save */ STATIC RECT rcInverted; /* Rectangle for last border drawn */ STATIC int fIsRcInverted=FALSE; /* Whether border is on */ STATIC int dxpKeyMove=8; /* # of pixels to move per arrow key (X) */ STATIC int dypKeyMove=4; /* # of pixels to move per arrow key (Y) */ STATIC int dxpPicMac; /* Rightmost edge (enforced for move only) */ STATIC int dypPicMac; /* Max. picture bottom edge */ STATIC int fPictModified; /* Set to TRUE if pic gets changed */ /* Special statics for resizing bitmaps with multipliers */ STATIC unsigned mxCurrent; /* Current Multipliers while resizing */ STATIC unsigned myCurrent; STATIC int fSizing; /* TRUE for sizing, FALSE for moving */ STATIC int dxpOrig; /* Object's original size in pixels */ STATIC int dypOrig; /* used as a basis for computing multipliers */ STATIC unsigned cxpPrinterPixel; /* For scaling devices, expand the 64K */ STATIC unsigned cypPrinterPixel; /* Limit */ int NEAR FStartPMS( int ); void NEAR EndPMS( void ); void NEAR DrawPMSFrameIcon( int, POINT ); void NEAR GetCursorClientPos( POINT * ); void NEAR SetCursorClientPos( POINT ); void NEAR InvertPMSFrame( void ); void NEAR SetupDCForPMS( void ); CmdUnscalePic() { /* Restore picture to the size that it originally was on import */ struct PICINFOX picInfo; int dxa, dya; GetPicInfo(selCur.cpFirst, selCur.cpLim, docCur, &picInfo); if (FComputePictSize( &picInfo.mfp, &dxa, &dya )) ModifyPicInfoDxa( 0, dxa, dya, mxMultByOne, myMultByOne, FALSE ); } fnMovePicture() { /* Handle the "Move Picture" command in the EDIT dropdown. */ MSG msg; int mdIcon=mdIconCenterFix; POINT pt; Assert( vfPictSel ); vfCancelPictMove = FALSE; if (!FStartPMS(FALSE)) return; GetCursorClientPos( &pt ); while (TRUE) { /* * If the main window proc was sent a kill focus message, * then we should cancel this move. */ if (vfCancelPictMove) { fPictModified = FALSE; goto SkipChange; } /* * Otherwise, continue normal processing for a picture move. */ if (!PeekMessage( (LPMSG) &msg, (HWND) NULL, 0, 0, PM_NOREMOVE )) { /* No message waiting -- scroll if we're above or below window */ mdIcon &= ~mdIconSetCursor; goto MoveFrame; } else { /* Absorb all messages, only process: left & right arrows, RETURN and ESC, mouse move & mouse down (left button) */ GetMessage( (LPMSG) &msg, (HWND) NULL, 0, 0 ); switch (msg.message) { default: break; case WM_KEYDOWN: mdIcon |= mdIconSetCursor; GetCursorClientPos( &pt ); pt.y = rcInverted.top + (unsigned)(rcInverted.bottom - rcInverted.top) / 2; switch (msg.wParam) { case VK_RETURN: goto MakeChange; case VK_ESCAPE: goto SkipChange; case VK_LEFT: pt.x -= dxpKeyMove; goto MoveFrame; case VK_RIGHT: pt.x += dxpKeyMove; goto MoveFrame; } break; case WM_MOUSEMOVE: mdIcon &= ~mdIconSetCursor; pt = MAKEPOINT( msg.lParam ); MoveFrame: DrawPMSFrameIcon( mdIcon, pt ); break; case WM_LBUTTONDOWN: goto MakeChange; break; } } /* end else */ } /* end while */ MakeChange: ModifyPicInfoDxp( rcInverted.left - xpSelBar + wwdCurrentDoc.xpMin, -1, -1, -1, -1 ); SkipChange: EndPMS(); } fnSizePicture() { /* Handle the "Size Picture" command in the EDIT dropdown. */ MSG msg; int mdIcon=mdIconCenterFloat; POINT pt; int fFirstMouse=TRUE; /* A workaround hack bug fix */ vfCancelPictMove = FALSE; if (!FStartPMS(TRUE)) return; ShowPictMultipliers(); GetCursorClientPos( &pt ); while (TRUE) { /* * If the main window proc was sent a killfocus message, * then we should cancel this sizing. */ if (vfCancelPictMove) { fPictModified = FALSE; goto SkipChange; } /* * Otherwise, continue normal processing for a picture size. */ if (!PeekMessage( (LPMSG) &msg, (HWND) NULL, 0, 0, PM_NOREMOVE )) { /* No message waiting -- scroll if we're above or below window */ mdIcon &= ~mdIconSetCursor; goto MoveFrame; } else { /* Absorb all messages, only process: left & right arrows, RETURN and ESC, mouse move & mouse down (left button) */ GetMessage( (LPMSG) &msg, (HWND) NULL, 0, 0 ); switch (msg.message) { default: break; case WM_KEYDOWN: GetCursorClientPos( &pt ); mdIcon |= mdIconSetCursor; switch (msg.wParam) { case VK_RETURN: goto MakeChange; case VK_ESCAPE: goto SkipChange; case VK_RIGHT: switch (mdIcon & mdIconXMask) { default: pt.x = rcInverted.right; mdIcon |= mdIconRight; break; case mdIconRight: case mdIconLeft: pt.x += dxpKeyMove; break; } goto MoveFrame; case VK_LEFT: switch (mdIcon & mdIconXMask) { default: pt.x = rcInverted.left; mdIcon |= mdIconRight; break; case mdIconRight: case mdIconLeft: pt.x -= dxpKeyMove; break; } goto MoveFrame; case VK_UP: if ( mdIcon & mdIconBottom ) pt.y -= dypKeyMove; else { pt.y = rcInverted.bottom; mdIcon |= mdIconBottom; } goto MoveFrame; case VK_DOWN: if ( mdIcon & mdIconBottom ) pt.y += dypKeyMove; else { pt.y = rcInverted.bottom; mdIcon |= mdIconBottom; } goto MoveFrame; } break; case WM_MOUSEMOVE: mdIcon &= ~mdIconSetCursor; if (fFirstMouse) { /* We sometimes get 1 bogus mouse message, so skip it */ fFirstMouse = FALSE; break; } pt = MAKEPOINT( msg.lParam ); /* Trap "breaking through" a border with a mouse */ if ( !(mdIcon & mdIconXMask) ) { /* Haven't broken through left or right */ if (pt.x >= rcInverted.right) mdIcon |= mdIconRight; else if (pt.x <= rcInverted.left) mdIcon |= mdIconLeft; } if ( !(mdIcon & mdIconBottom) ) { /* Haven't broken through bottom */ if (pt.y >= rcInverted.bottom) mdIcon |= mdIconBottom; } MoveFrame: /* Trap border crossings */ switch (mdIcon & mdIconXMask) { default: break; case mdIconLeft: if (pt.x >= rcInverted.right) { /* Moving left icon right, crossed right border */ mdIcon = (mdIcon & ~mdIconXMask) | mdIconRight; goto WholePic; } break; case mdIconRight: if (pt.x <= rcInverted.left) { /* Moving right icon left, crossed border */ mdIcon = (mdIcon & ~mdIconXMask) | mdIconLeft; WholePic: if (fIsRcInverted) InvertPMSFrame(); rcInverted = rcPicture; } break; } DrawPMSFrameIcon( mdIcon, pt ); break; case WM_LBUTTONDOWN: goto MakeChange; break; } } /* end else */ } /* end while */ MakeChange: { unsigned NEAR MxRoundMx( unsigned ); /* Round multipliers if near an even multiple */ unsigned mx = MxRoundMx( mxCurrent ); unsigned my = MxRoundMx( myCurrent ); /* Assert must be true for above call to work for an my */ Assert( mxMultByOne == myMultByOne ); ModifyPicInfoDxp( rcInverted.left - xpSelBar + wwdCurrentDoc.xpMin, rcInverted.right - rcInverted.left, rcInverted.bottom - rcInverted.top, mx, my ); } SkipChange: EndPMS(); } unsigned NEAR MxRoundMx( mx ) unsigned mx; { /* If mx is near an "interesting" multiple, round it to be exactly that multiple. Interesting multiples are: 1 (m=mxMultByOne), 2 (m=2 * mxMultByOne), 3 , ... 0.5 (m = .5 * mxMultByOne) This routine works for my, too, as long as mxMultByOne == myMultByOne */ /* This means close enough to round (1 decimal place accuracy) */ #define dmxRound (mxMultByOne / 20) unsigned mxRemainder; if (mx >= mxMultByOne - dmxRound) { /* Multiplier > 1 -- look for rounding to integer multiple */ if ((mxRemainder = mx % mxMultByOne) < dmxRound) mx -= mxRemainder; else if (mxRemainder >= mxMultByOne - dmxRound) mx += (mxMultByOne - mxRemainder); } else { /* Multiplier < 1 -- look for multiplication by 1/2 */ if ((mxRemainder = mx % (mxMultByOne >> 1)) < dmxRound) mx -= mxRemainder; else if (mxRemainder >= ((mxMultByOne >> 1) - dmxRound)) mx += (mxMultByOne >> 1) - mxRemainder; } return mx; } int NEAR FStartPMS( fSize ) int fSize; { /* Initialization for Picture Move/Size */ extern HCURSOR vhcHourGlass; extern HWND hParentWw; extern struct SEP vsepAbs; extern struct SEP vsepPage; extern HDC vhDCPrinter; struct PICINFOX picInfo; struct EDL *pedl; RECT rc; HDC hdcT; POINT pt; Assert(vhDCPrinter); fSizing = fSize; UpdateWw( wwCur, FALSE ); /* Screen must be up-to-date */ /* Set the rect that defines our display area */ SetRect( (LPRECT) &rcClip, xpSelBar, wwdCurrentDoc.ypMin, wwdCurrentDoc.xpMac, wwdCurrentDoc.ypMac ); GetPicInfo( selCur.cpFirst, selCur.cpLim, docCur, &picInfo ); if (fSize) { if (BStructMember( PICINFOX, my ) >= picInfo.cbHeader ) { /* OLD file format (no multipliers), scaling not supported */ return FALSE; } } /* Set multiplier factor used by the printer (will be { 1, 1 } if the printer is not a scaling device; greater if it is.) This info is used for the 64K limit test of picture growth. */ if (!(GetDeviceCaps( vhDCPrinter, RASTERCAPS ) & RC_BITMAP64)) /* doesn't support > 64K bitmaps */ { if (GetDeviceCaps( vhDCPrinter, RASTERCAPS ) & RC_SCALING) { POINT pt; pt.x = pt.y = 0; /* Just in case */ Escape( vhDCPrinter, GETSCALINGFACTOR, 0, (LPSTR) NULL, (LPSTR) (LPPOINT) &pt ); cxpPrinterPixel = 1 << pt.x; cypPrinterPixel = 1 << pt.y; } else { cxpPrinterPixel = cypPrinterPixel = 1; } } else { cxpPrinterPixel = cypPrinterPixel = 0xFFFF; } /* Compute picture's original (when pasted) size in screen pixels {dxpOrig, dypOrig}. These numbers are the bases for computing the multiplier. */ switch(picInfo.mfp.mm) { case MM_BITMAP: GetBitmapSize( &dxpOrig, &dypOrig, &picInfo, FALSE ); /* Compensate for effects of existing multipliers */ dxpOrig = MultDiv( dxpOrig, mxMultByOne, picInfo.mx ); dypOrig = MultDiv( dypOrig, myMultByOne, picInfo.my ); break; default: // OLE and META { int dxa, dya; if (!FComputePictSize( &picInfo.mfp, &dxa, &dya )) return FALSE; dxpOrig = DxpFromDxa( dxa, FALSE ); dypOrig = DypFromDya( dya, FALSE ); } break; } if (!FGetPictPedl( &pedl )) /* Picture must be on the screen */ return FALSE; ComputePictRect( &rcPicture, &picInfo, pedl, wwCur ); rcInverted = rcPicture; /* Initial grey box is the size of the picture */ vfPMS = TRUE; /* So ToggleSel knows not to invert the pict */ fPictModified = FALSE; /* Amt to move for arrow keys is derived from size of fixed font */ if ( ((hdcT=GetDC( hParentWw ))!=NULL) && (SelectObject( hdcT, GetStockObject( ANSI_FIXED_FONT ) )!=0)) { TEXTMETRIC tm; GetTextMetrics( hdcT, (LPTEXTMETRIC) &tm ); ReleaseDC( hParentWw, hdcT ); dxpKeyMove = tm.tmAveCharWidth; dypKeyMove = (tm.tmHeight + tm.tmExternalLeading) / 2; } SetupDCForPMS(); /* Save DC and select in a grey brush for border drawing */ /* Assure that the "size box" mouse cursor is loaded */ if (vhcPMS == NULL) { extern HANDLE hMmwModInstance; extern CHAR szPmsCur[]; vhcPMS = LoadCursor( hMmwModInstance, (LPSTR) szPmsCur ); } /* Compute maximum allowable area for picture to roam (relative to para left edge, picture top) */ CacheSectPic( docCur, selCur.cpFirst ); dxpPicMac = imax( DxpFromDxa( vsepAbs.dxaText, FALSE ), rcPicture.right - xpSelBar + wwdCurrentDoc.xpMin ); dypPicMac = DypFromDya( vsepAbs.yaMac, FALSE ); /* Since the picture is selected, need to un-invert it */ InvertRect( wwdCurrentDoc.hDC, (LPRECT) &rcPicture ); SetCapture( wwdCurrentDoc.wwptr ); /* Hog all mouse actions */ /* Draw initial size box icon in the center of the picture */ pt.x = rcInverted.left + (unsigned)(rcInverted.right - rcInverted.left)/2; pt.y = rcInverted.top + (unsigned)(rcInverted.bottom - rcInverted.top)/2; DrawPMSFrameIcon( mdIconCenterFix | mdIconSetCursor, pt ); SetCursor( vhcPMS ); /* Make the mouse cursor a size box */ ShowCursor( TRUE ); /* So cursor appears even on mouseless systems */ return TRUE; } void NEAR SetupDCForPMS() { /* Save current document DC & set it up for picture move/sizing: - A gray background brush for drawing the border - A drawing area resricted to rcClip */ ilevelPMS = SaveDC( wwdCurrentDoc.hDC ); SelectObject( wwdCurrentDoc.hDC, GetStockObject( GRAY_BRUSH ) ); IntersectClipRect( wwdCurrentDoc.hDC, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom ); } void NEAR EndPMS() { /* Leaving Picture Move/Size */ extern int docMode; struct PICINFOX picInfo; vfPMS = FALSE; ReleaseCapture(); /* Allow other windows to receive mouse events */ SetCursor( NULL ); docMode = docNil; CheckMode(); /* Compensate for multiplier display */ if (fIsRcInverted) InvertPMSFrame(); if (!fPictModified && !vfCancelPictMove) { /* Picture did not change, restore inversion to show selection */ /* Must do this BEFORE RestoreDC so excess above ypMin is clipped */ InvertRect( wwdCurrentDoc.hDC, (LPRECT) &rcPicture ); } RestoreDC( wwdCurrentDoc.hDC, ilevelPMS ); ShowCursor( FALSE ); /* Decrement cursor ref cnt (blanks if no mouse) */ /* Since we've been ignoring messages, make sure our key flags are OK */ SetShiftFlags(); } void NEAR DrawPMSFrameIcon( mdIcon, pt ) int mdIcon; POINT pt; { /* Draw Picture Move/Size frame and icon, with the icon at position pt. The icon type is given by mdIcon. Scrolls the correct part of the picture into view if necessary. Uses statics: rcPicture, rcClip, rcInverted, fIsRcInverted */ #define FEqualRect( r1, r2 ) ((r1.left==r2.left)&&(r1.right==r2.right)&&\ (r1.top==r2.top)&&(r1.bottom==r2.bottom)) extern int vfAwfulNoise; int xpCntr; int dxpCntr = ((unsigned)(rcInverted.right - rcInverted.left)) / 2; RECT rcT; rcT = rcInverted; /* Set pt.y so it does not exceed limits */ if (mdIcon & mdIconBottom) { if (pt.y - rcInverted.top > dypPicMac) { pt.y = rcInverted.top + dypPicMac; /* max y-size is 1 page */ } else if (pt.y < rcInverted.top + 1) pt.y = rcInverted.top + 1; /* min y-size is 1 pixel */ /* Restrict pt.x as necessary to keep printer bitmap < 64K */ if ((pt.y > rcInverted.bottom) && (cxpPrinterPixel < 0xFFFF) && (cypPrinterPixel < 0xFFFF)) { /* Really sizing in y */ unsigned dxpScreen = imax (imax(pt.x,rcInverted.right)-rcInverted.left, dxpPicSizeMin); unsigned dxpPrinter = DxpFromDxa(DxaFromDxp( dxpScreen, FALSE ), TRUE); unsigned dypLast = 0xFFFF / (dxpPrinter / 8); unsigned dyp = DypFromDya( DyaFromDyp( pt.y - rcInverted.top , FALSE), TRUE ); if (dyp / (cxpPrinterPixel * cypPrinterPixel) > dypLast ) { /* Bitmap would overflow 64K boundary */ pt.y = rcInverted.top + DypFromDya( DyaFromDyp( dypLast, TRUE ), FALSE ); } } } else if (pt.y < rcInverted.top) pt.y = rcInverted.top; /* Can't go above picture top */ else if (pt.y > rcInverted.bottom) pt.y = rcInverted.bottom; /* Necessary? */ /* Set pt.x so it does not execeed limits */ switch (mdIcon & mdIconXMask) { case mdIconCenterFloat: case mdIconRight: /* Restrict pt.x as necessary to keep printer bitmap < 64K */ if ((cxpPrinterPixel < 0xFFFF) && (cypPrinterPixel < 0xFFFF)) { unsigned dyp = DypFromDya( DyaFromDyp( imax( pt.y - rcInverted.top, dypPicSizeMin), FALSE ), TRUE ); unsigned dxpLast = 0xFFFF / (dyp / 8); unsigned dxp = DxpFromDxa( DxaFromDxp( pt.x - rcInverted.left, FALSE ), TRUE ); if (dxp / (cxpPrinterPixel * cypPrinterPixel) > dxpLast ) { /* Printer bitmap would overflow 64K boundary */ pt.x = rcInverted.left + DxpFromDxa( DxaFromDxp( dxpLast, TRUE ), FALSE ); } } default: break; case mdIconLeft: if ((pt.x < rcClip.left) && (wwdCurrentDoc.xpMin == 0)) pt.x = rcClip.left; /* Reached left scroll limit */ break; case mdIconCenterFix: if ( (pt.x - dxpCntr < rcClip.left) && (wwdCurrentDoc.xpMin == 0)) pt.x = rcClip.left + dxpCntr; /* Reached left scroll limit */ else if (pt.x - xpSelBar + wwdCurrentDoc.xpMin + dxpCntr > dxpPicMac) /* Move Picture only: can't move past margins */ pt.x = dxpPicMac + xpSelBar - wwdCurrentDoc.xpMin - dxpCntr; break; } /* Check for pt outside of clip rectangle; scroll/bail out as needed */ if (!PtInRect( (LPRECT)&rcClip, pt )) { int dxpHalfWidth = (unsigned)(rcClip.right - rcClip.left) / 2; int dypHalfHeight = (unsigned)(rcClip.bottom - rcClip.top) / 2; int dxpScroll=0; int dypScroll=0; if (pt.x < rcClip.left) { if (wwdCurrentDoc.xpMin == 0) { _beep(); /* Reached left-hand scroll limit */ pt.x = rcClip.left; } else { /* SCROLL LEFT */ dxpScroll = imax( -wwdCurrentDoc.xpMin, imin( -dxpHalfWidth, pt.x - rcClip.left ) ); } } else if (pt.x > rcClip.right) { if (wwdCurrentDoc.xpMin + rcClip.right - rcClip.left >= xpRightLim ) { _beep(); pt.x = rcClip.right; /* Reached right-hand scroll limit */ } else { /* SCROLL RIGHT */ dxpScroll = imin( xpRightLim - wwdCurrentDoc.xpMin + rcClip.right - rcClip.left, imax( dxpHalfWidth, pt.x - rcClip.right ) ); } } if (pt.y < rcClip.top) { struct EDL *pedl = &(**wwdCurrentDoc.hdndl)[wwdCurrentDoc.dlMac - 1]; if ( (rcInverted.top >= rcClip.top) || /* May not scroll all of the original picture off the screen */ (wwdCurrentDoc.dlMac <= 1) || ( (pedl->cpMin == selCur.cpFirst) && ( ((pedl-1)->cpMin != pedl->cpMin) || !(pedl-1)->fGraphics))) { _beep(); pt.y = rcClip.top; } else { /* SCROLL UP */ dypScroll = rcInverted.top - rcClip.top; } } else if (pt.y > rcClip.bottom) { struct EDL *pedl=&(**wwdCurrentDoc.hdndl)[0]; /* May not scroll all of the original picture off the screen */ if ( (wwdCurrentDoc.dlMac <= 1) || ( (pedl->cpMin == selCur.cpFirst) && ( ((pedl+1)->ichCpMin == 0) || !(pedl+1)->fGraphics) )) { _beep(); /* Reached downward scroll limit */ pt.y = rcClip.bottom; /* Must have at least 1 picture dl visible */ } else dypScroll = 1; /* SCROLL DOWN */ } if (dxpScroll || dypScroll) { /* SCROLL */ struct EDL *pedl; struct PICINFOX picInfo; int xpMinT = wwdCurrentDoc.xpMin; int ypTopT = rcPicture.top; int dxpAdjust, dypAdjust; if (dxpScroll && dypScroll) /* Did not need to truncate coordinates; re-enable beep */ vfAwfulNoise = FALSE; if (fIsRcInverted) InvertPMSFrame(); /* Scroll by the appropriate amount: dxpScroll in x-direction; one line in y-direction */ RestoreDC( wwdCurrentDoc.hDC, ilevelPMS ); /* Use orig DC props */ if (dxpScroll) AdjWwHoriz( dxpScroll ); if (dypScroll > 0) ScrollDownCtr( 1 ); else if (dypScroll < 0) ScrollUpCtr( 1 ); UpdateWw( wwCur, FALSE ); SetupDCForPMS(); /* Compensate for RestoreDC */ /* Update rcPicture to reflect new scroll position */ GetPicInfo( selCur.cpFirst, selCur.cpLim, docCur, &picInfo ); if (!FGetPictPedl( &pedl )) { Assert (FALSE); /* If we get here, we're in trouble */ _beep(); return; } ComputePictRect( &rcPicture, &picInfo, pedl, wwCur ); /* Adjust rcT, pt relative to the amount we actually scrolled */ dxpAdjust = xpMinT - wwdCurrentDoc.xpMin; dypAdjust = rcPicture.top - ypTopT; OffsetRect( (LPRECT) &rcT, dxpAdjust, dypAdjust ); pt.x += dxpAdjust; pt.y += dypAdjust; goto Display; /* Dont let rcInverted be edited until we have scrolled the icon into view */ } } /* Compute effect of new icon position and/or type on rcInverted */ switch (mdIcon & mdIconXMask) { case mdIconCenterFix: if (!fSizing) { xpCntr = rcInverted.left + dxpCntr; OffsetRect( (LPRECT) &rcT, pt.x - xpCntr, 0 ); } break; case mdIconLeft: rcT.left = pt.x; goto ComputeY; case mdIconRight: rcT.right = pt.x; default: case mdIconCenterFloat: ComputeY: if (mdIcon & mdIconBottom) rcT.bottom = pt.y; break; } Display: /* If redrawing the border is necessary, do it */ if (!FEqualRect( rcT, rcInverted ) || (mdIcon & mdIconSetCursor)) { if (fIsRcInverted) InvertPMSFrame(); rcInverted = rcT; InvertPMSFrame(); } if (mdIcon & mdIconSetCursor) { SetCursorClientPos( pt ); SetCursor( vhcPMS ); } /* If the multipliers have changed, redisplay them */ if (fSizing) { unsigned mx, my; mx = MultDiv( rcInverted.right - rcInverted.left, mxMultByOne, dxpOrig ); my = MultDiv( rcInverted.bottom - rcInverted.top, myMultByOne, dypOrig ); if (mx != mxCurrent || my != myCurrent) { /* Multipliers have changed */ mxCurrent = mx; myCurrent = my; ShowPictMultipliers(); } } } void NEAR InvertPMSFrame() { /* Draw a frame for rcInverted in XOR mode, update fIsRcInverted */ int dxpSize=rcInverted.right - rcInverted.left - 1; int dypSize=rcInverted.bottom - rcInverted.top - 1; PatBlt( wwdCurrentDoc.hDC, rcInverted.left, rcInverted.top, dxpSize, 1, PATINVERT ); PatBlt( wwdCurrentDoc.hDC, rcInverted.right - 1, rcInverted.top, 1, dypSize, PATINVERT ); PatBlt( wwdCurrentDoc.hDC, rcInverted.left + 1, rcInverted.bottom - 1, dxpSize, 1, PATINVERT ); PatBlt( wwdCurrentDoc.hDC, rcInverted.left, rcInverted.top + 1, 1, dypSize, PATINVERT ); fIsRcInverted ^= -1; } void NEAR GetCursorClientPos( ppt ) POINT *ppt; { /* Get current mouse cursor coordinates (window-relative) */ GetCursorPos( (LPPOINT) ppt ); ScreenToClient( wwdCurrentDoc.wwptr, (LPPOINT) ppt ); } void NEAR SetCursorClientPos( pt ) POINT pt; { /* Set current mouse cursor coordinates (window-relative) */ ClientToScreen( wwdCurrentDoc.wwptr, (LPPOINT) &pt ); SetCursorPos( pt.x, pt.y ); } STATIC NEAR ModifyPicInfoDxp( xpOffset, xpSize, ypSize, mx, my ) int xpOffset, xpSize, ypSize; unsigned mx, my; { /* Modify the currently selected picture by adjusting its offset and size to the pixel values specified. Negative values mean don't set that value. Added 9/23/85: mx and my parms give the multiplier, redundant info used for scaling bitmaps. */ int xaOffset, xaSize, yaSize; xaOffset = xaSize = yaSize = -1; if (xpSize >= 0) xaSize = DxaFromDxp( umax( xpSize, dxpPicSizeMin ), FALSE ); if (ypSize >= 0) yaSize = DyaFromDyp( umax( ypSize, dypPicSizeMin ), FALSE ); if (xpOffset >= 0) xaOffset = DxaFromDxp( xpOffset, FALSE ); ModifyPicInfoDxa( xaOffset, xaSize, yaSize, mx, my, TRUE ); } /* M O D I F Y P I C I N F O D X A */ STATIC NEAR ModifyPicInfoDxa( xaOffset, xaSize, yaSize, mx, my, fSetUndo ) int xaOffset, xaSize, yaSize; unsigned mx, my; BOOL fSetUndo; { /* Modify the currently selected picture by adjusting its offset and size to the twip values specified. Negative values mean don't set that value. Added 9/23/85: mx, my are size "multipliers", used for bitmaps only */ typeFC fcT; struct PICINFOX picInfo; typeCP cp = selCur.cpFirst; int dyaSizeOld; int fBitmap,fObj; fPictModified = TRUE; FreeBitmapCache(); GetPicInfo(cp, cpMacCur, docCur, &picInfo); fBitmap = (picInfo.mfp.mm == MM_BITMAP); fObj = (picInfo.mfp.mm == MM_OLE); dyaSizeOld = picInfo.dyaSize; if (fBitmap || fObj) { if ((int)mx > 0 && (int)my > 0) { picInfo.mx = mx; picInfo.my = my; } } else { if (xaSize >= 0) picInfo.dxaSize = xaSize; if (yaSize >= 0) picInfo.dyaSize = yaSize; } if (xaOffset >= 0) picInfo.dxaOffset = xaOffset; if (picInfo.cbHeader > cchOldPICINFO) /* Extended picture format, set extended format bit */ picInfo.mfp.mm |= MM_EXTENDED; if (!fObj) fcT = FcWScratch( &picInfo, picInfo.cbHeader ); picInfo.mfp.mm &= ~MM_EXTENDED; /* Right or center justify becomes invalid if the picture is moved without being sized */ CachePara(docCur, cp); if ( (xaSize < 0 && yaSize < 0) && (vpapAbs.jc == jcRight || vpapAbs.jc == jcCenter)) { CHAR rgb[2]; if (fSetUndo) SetUndo(uacPictSel, docCur, cp, selCur.cpLim - selCur.cpFirst, docNil, cpNil, cpNil, 0); TrashCache(); rgb[0] = sprmPJc; rgb[1] = jcLeft; AddSprm(&rgb[0]); } else { if (fSetUndo) SetUndo( uacPictSel, docCur, cp, (typeCP) picInfo.cbHeader, docNil, cpNil, cpNil, 0); } if (fObj) ObjSetPicInfo(&picInfo, docCur, cp); else Replace( docCur, cp, (typeCP) picInfo.cbHeader, fnScratch, fcT, (typeFC) picInfo.cbHeader); if ( ((fBitmap || fObj) && (my > myMultByOne)) || (!fBitmap && (dyaSizeOld < picInfo.dyaSize))) { /* If the picture height was increased, make sure proper EDLs are invalidated. */ typeCP dcp = cpMacCur - cp + (typeCP) 1; AdjustCp(docCur, cp, dcp, dcp); } } STATIC NEAR ShowPictMultipliers( ) { /* Display the current multipliers (mxCurrent, myCurrent) in the page info window in the form "n.nX/n.nY". */ CHAR *PchCvtMx( unsigned, CHAR * ); extern CHAR szMode[]; CHAR *pch = szMode; pch = PchCvtMx( mxCurrent, pch ); *(pch++) = 'X'; *(pch++) = '/'; Assert( mxMultByOne == myMultByOne ); /* Necessary for below to work w/ my */ pch = PchCvtMx( myCurrent, pch ); *(pch++) = 'Y'; *pch = '\0'; DrawMode(); } CHAR *PchCvtMx( mx, pch ) CHAR *pch; unsigned mx; { /* Convert the passed multiplier word to a string representation. Number is based on a mxMultByOne === 1 scale (e.g. mx == .9 * mxMultByOne yields "0.9") String always has at least one digit before the decimal point, and exactly one after. Examples of return strings: "10.5", "0.0", "5.5" */ int nTenths; int nWholes; int cch; extern CHAR vchDecimal; extern BOOL vbLZero; extern int viDigits; /* Round up to nearest single decimal place */ if (mx % (mxMultByOne / 10) >= mxMultByOne / 20) mx += mxMultByOne / 20; /* Write digit(s) before decimal place */ if (((nWholes = mx / mxMultByOne) == 0) && vbLZero) *(pch++) = '0'; else ncvtu( nWholes, &pch ); /* Write Decimal Point and following digit */ *(pch++) = vchDecimal; if (viDigits > 0) *(pch++) = ((mx % mxMultByOne) / (mxMultByOne / 10)) + '0'; *pch = '\0'; return pch; }