windows-nt/Source/XPSP1/NT/base/mvdm/wow16/write/pictdrag.c
2020-09-26 16:20:57 +08:00

1138 lines
33 KiB
C

/************************************************************/
/* 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 <windows.h>
#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;
}