1138 lines
33 KiB
C
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;
|
|
}
|