Source code of Windows XP (NT5)
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.

1137 lines
33 KiB

  1. /************************************************************/
  2. /* Windows Write, Copyright 1985-1992 Microsoft Corporation */
  3. /************************************************************/
  4. /* pictdrag.c -- Routines for Move Picture and Size Picture */
  5. //#define NOGDICAPMASKS
  6. #define NOWINSTYLES
  7. #define NOSYSMETRICS
  8. #define NOMENUS
  9. #define NOICON
  10. #define NOKEYSTATE
  11. #define NOSYSCOMMANDS
  12. #define NOSHOWWINDOW
  13. //#define NOATOM
  14. #define NOBRUSH
  15. #define NOCLIPBOARD
  16. #define NOCOLOR
  17. #define NOCREATESTRUCT
  18. #define NOCTLMGR
  19. #define NODRAWTEXT
  20. #define NOFONT
  21. #define NOHDC
  22. #define NOMB
  23. #define NOMEMMGR
  24. #define NOMENUS
  25. #define NOOPENFILE
  26. #define NOPEN
  27. #define NOREGION
  28. #define NOSCROLL
  29. #define NOSOUND
  30. #define NOWH
  31. #define NOWINOFFSETS
  32. #define NOWNDCLASS
  33. #define NOCOMM
  34. #include <windows.h>
  35. #include "mw.h"
  36. #define NOKCCODES
  37. #include "ch.h"
  38. #include "docdefs.h"
  39. #include "dispdefs.h"
  40. #include "cmddefs.h"
  41. #include "propdefs.h"
  42. #include "wwdefs.h"
  43. #include "filedefs.h"
  44. #include "editdefs.h"
  45. #include "prmdefs.h"
  46. #include "winddefs.h"
  47. #if defined(OLE)
  48. #include "obj.h"
  49. #endif
  50. extern struct DOD (**hpdocdod)[];
  51. extern typeCP cpMacCur;
  52. extern int docCur;
  53. extern int wwCur;
  54. extern struct SEL selCur;
  55. extern struct WWD *pwwdCur;
  56. extern struct WWD rgwwd[];
  57. extern typeCP vcpFirstParaCache;
  58. extern struct PAP vpapAbs;
  59. extern struct SEP vsepAbs;
  60. extern struct SEP vsepPage;
  61. extern int dxpLogInch;
  62. extern int dypLogInch;
  63. extern int vfPictSel;
  64. extern int vfPMS;
  65. extern int vfCancelPictMove;
  66. #ifdef DEBUG
  67. #define STATIC
  68. #else
  69. #define STATIC static
  70. #endif
  71. STATIC NEAR ModifyPicInfoDxa( int, int, int, unsigned, unsigned, BOOL );
  72. STATIC NEAR ModifyPicInfoDxp( int, int, int, unsigned, unsigned );
  73. STATIC NEAR ShowPictMultipliers( void );
  74. #define dxpPicSizeMin dypPicSizeMin
  75. /* Type for possible positions of the "size box" icon while
  76. moving/sizing a picture */
  77. /* WARNING: fnSizePicture relies on mdIconCenterFloat == 0 */
  78. #define mdIconCenterFloat 0 /* In Center of picture; icon may float */
  79. #define mdIconLeft 1 /* On Left Border */
  80. #define mdIconRight 2 /* On Right Border */
  81. #define mdIconCenterFix 3 /* In center of picture; border moves w/icon */
  82. #define mdIconXMask 3 /* Masks left/right */
  83. #define mdIconBottom 4 /* On bottom border */
  84. #define mdIconSetCursor 8 /* Force set of mouse cursor position */
  85. #define mdIconLL (mdIconLeft | mdIconBottom)
  86. #define mdIconLR (mdIconRight | mdIconBottom)
  87. /* "PMS" means "Picture Move or Size" */
  88. HCURSOR vhcPMS=NULL; /* Handle to "size box" cursor */
  89. STATIC RECT rcPicture; /* Rectangle containing picture */
  90. STATIC RECT rcClip; /* Window clip box (may intersect above) */
  91. STATIC int ilevelPMS; /* Level for DC save */
  92. STATIC RECT rcInverted; /* Rectangle for last border drawn */
  93. STATIC int fIsRcInverted=FALSE; /* Whether border is on */
  94. STATIC int dxpKeyMove=8; /* # of pixels to move per arrow key (X) */
  95. STATIC int dypKeyMove=4; /* # of pixels to move per arrow key (Y) */
  96. STATIC int dxpPicMac; /* Rightmost edge (enforced for move only) */
  97. STATIC int dypPicMac; /* Max. picture bottom edge */
  98. STATIC int fPictModified; /* Set to TRUE if pic gets changed */
  99. /* Special statics for resizing bitmaps with multipliers */
  100. STATIC unsigned mxCurrent; /* Current Multipliers while resizing */
  101. STATIC unsigned myCurrent;
  102. STATIC int fSizing; /* TRUE for sizing, FALSE for moving */
  103. STATIC int dxpOrig; /* Object's original size in pixels */
  104. STATIC int dypOrig; /* used as a basis for computing multipliers */
  105. STATIC unsigned cxpPrinterPixel; /* For scaling devices, expand the 64K */
  106. STATIC unsigned cypPrinterPixel; /* Limit */
  107. int NEAR FStartPMS( int );
  108. void NEAR EndPMS( void );
  109. void NEAR DrawPMSFrameIcon( int, POINT );
  110. void NEAR GetCursorClientPos( POINT * );
  111. void NEAR SetCursorClientPos( POINT );
  112. void NEAR InvertPMSFrame( void );
  113. void NEAR SetupDCForPMS( void );
  114. CmdUnscalePic()
  115. { /* Restore picture to the size that it originally was on import */
  116. struct PICINFOX picInfo;
  117. int dxa, dya;
  118. GetPicInfo(selCur.cpFirst, selCur.cpLim, docCur, &picInfo);
  119. if (FComputePictSize( &picInfo.mfp, &dxa, &dya ))
  120. ModifyPicInfoDxa( 0, dxa, dya, mxMultByOne, myMultByOne, FALSE );
  121. }
  122. fnMovePicture()
  123. { /* Handle the "Move Picture" command in the EDIT dropdown. */
  124. MSG msg;
  125. int mdIcon=mdIconCenterFix;
  126. POINT pt;
  127. Assert( vfPictSel );
  128. vfCancelPictMove = FALSE;
  129. if (!FStartPMS(FALSE))
  130. return;
  131. GetCursorClientPos( &pt );
  132. while (TRUE)
  133. {
  134. /*
  135. * If the main window proc was sent a kill focus message,
  136. * then we should cancel this move.
  137. */
  138. if (vfCancelPictMove)
  139. {
  140. fPictModified = FALSE;
  141. goto SkipChange;
  142. }
  143. /*
  144. * Otherwise, continue normal processing for a picture move.
  145. */
  146. if (!PeekMessage( (LPMSG) &msg, (HWND) NULL, 0, 0, PM_NOREMOVE ))
  147. { /* No message waiting -- scroll if we're above or below window */
  148. mdIcon &= ~mdIconSetCursor;
  149. goto MoveFrame;
  150. }
  151. else
  152. { /* Absorb all messages, only process: left & right arrows,
  153. RETURN and ESC, mouse move & mouse down (left button) */
  154. GetMessage( (LPMSG) &msg, (HWND) NULL, 0, 0 );
  155. switch (msg.message) {
  156. default:
  157. break;
  158. case WM_KEYDOWN:
  159. mdIcon |= mdIconSetCursor;
  160. GetCursorClientPos( &pt );
  161. pt.y = rcInverted.top +
  162. (unsigned)(rcInverted.bottom - rcInverted.top) / 2;
  163. switch (msg.wParam) {
  164. case VK_RETURN:
  165. goto MakeChange;
  166. case VK_ESCAPE:
  167. goto SkipChange;
  168. case VK_LEFT:
  169. pt.x -= dxpKeyMove;
  170. goto MoveFrame;
  171. case VK_RIGHT:
  172. pt.x += dxpKeyMove;
  173. goto MoveFrame;
  174. }
  175. break;
  176. case WM_MOUSEMOVE:
  177. mdIcon &= ~mdIconSetCursor;
  178. pt = MAKEPOINT( msg.lParam );
  179. MoveFrame:
  180. DrawPMSFrameIcon( mdIcon, pt );
  181. break;
  182. case WM_LBUTTONDOWN:
  183. goto MakeChange;
  184. break;
  185. }
  186. } /* end else */
  187. } /* end while */
  188. MakeChange:
  189. ModifyPicInfoDxp( rcInverted.left - xpSelBar + wwdCurrentDoc.xpMin, -1, -1,
  190. -1, -1 );
  191. SkipChange:
  192. EndPMS();
  193. }
  194. fnSizePicture()
  195. { /* Handle the "Size Picture" command in the EDIT dropdown. */
  196. MSG msg;
  197. int mdIcon=mdIconCenterFloat;
  198. POINT pt;
  199. int fFirstMouse=TRUE; /* A workaround hack bug fix */
  200. vfCancelPictMove = FALSE;
  201. if (!FStartPMS(TRUE))
  202. return;
  203. ShowPictMultipliers();
  204. GetCursorClientPos( &pt );
  205. while (TRUE)
  206. {
  207. /*
  208. * If the main window proc was sent a killfocus message,
  209. * then we should cancel this sizing.
  210. */
  211. if (vfCancelPictMove)
  212. {
  213. fPictModified = FALSE;
  214. goto SkipChange;
  215. }
  216. /*
  217. * Otherwise, continue normal processing for a picture size.
  218. */
  219. if (!PeekMessage( (LPMSG) &msg, (HWND) NULL, 0, 0, PM_NOREMOVE ))
  220. { /* No message waiting -- scroll if we're above or below window */
  221. mdIcon &= ~mdIconSetCursor;
  222. goto MoveFrame;
  223. }
  224. else
  225. { /* Absorb all messages, only process: left & right arrows,
  226. RETURN and ESC, mouse move & mouse down (left button) */
  227. GetMessage( (LPMSG) &msg, (HWND) NULL, 0, 0 );
  228. switch (msg.message) {
  229. default:
  230. break;
  231. case WM_KEYDOWN:
  232. GetCursorClientPos( &pt );
  233. mdIcon |= mdIconSetCursor;
  234. switch (msg.wParam) {
  235. case VK_RETURN:
  236. goto MakeChange;
  237. case VK_ESCAPE:
  238. goto SkipChange;
  239. case VK_RIGHT:
  240. switch (mdIcon & mdIconXMask) {
  241. default:
  242. pt.x = rcInverted.right;
  243. mdIcon |= mdIconRight;
  244. break;
  245. case mdIconRight:
  246. case mdIconLeft:
  247. pt.x += dxpKeyMove;
  248. break;
  249. }
  250. goto MoveFrame;
  251. case VK_LEFT:
  252. switch (mdIcon & mdIconXMask) {
  253. default:
  254. pt.x = rcInverted.left;
  255. mdIcon |= mdIconRight;
  256. break;
  257. case mdIconRight:
  258. case mdIconLeft:
  259. pt.x -= dxpKeyMove;
  260. break;
  261. }
  262. goto MoveFrame;
  263. case VK_UP:
  264. if ( mdIcon & mdIconBottom )
  265. pt.y -= dypKeyMove;
  266. else
  267. {
  268. pt.y = rcInverted.bottom;
  269. mdIcon |= mdIconBottom;
  270. }
  271. goto MoveFrame;
  272. case VK_DOWN:
  273. if ( mdIcon & mdIconBottom )
  274. pt.y += dypKeyMove;
  275. else
  276. {
  277. pt.y = rcInverted.bottom;
  278. mdIcon |= mdIconBottom;
  279. }
  280. goto MoveFrame;
  281. }
  282. break;
  283. case WM_MOUSEMOVE:
  284. mdIcon &= ~mdIconSetCursor;
  285. if (fFirstMouse)
  286. { /* We sometimes get 1 bogus mouse message, so skip it */
  287. fFirstMouse = FALSE;
  288. break;
  289. }
  290. pt = MAKEPOINT( msg.lParam );
  291. /* Trap "breaking through" a border with a mouse */
  292. if ( !(mdIcon & mdIconXMask) )
  293. { /* Haven't broken through left or right */
  294. if (pt.x >= rcInverted.right)
  295. mdIcon |= mdIconRight;
  296. else if (pt.x <= rcInverted.left)
  297. mdIcon |= mdIconLeft;
  298. }
  299. if ( !(mdIcon & mdIconBottom) )
  300. { /* Haven't broken through bottom */
  301. if (pt.y >= rcInverted.bottom)
  302. mdIcon |= mdIconBottom;
  303. }
  304. MoveFrame:
  305. /* Trap border crossings */
  306. switch (mdIcon & mdIconXMask) {
  307. default:
  308. break;
  309. case mdIconLeft:
  310. if (pt.x >= rcInverted.right)
  311. { /* Moving left icon right, crossed right border */
  312. mdIcon = (mdIcon & ~mdIconXMask) | mdIconRight;
  313. goto WholePic;
  314. }
  315. break;
  316. case mdIconRight:
  317. if (pt.x <= rcInverted.left)
  318. { /* Moving right icon left, crossed border */
  319. mdIcon = (mdIcon & ~mdIconXMask) | mdIconLeft;
  320. WholePic:
  321. if (fIsRcInverted)
  322. InvertPMSFrame();
  323. rcInverted = rcPicture;
  324. }
  325. break;
  326. }
  327. DrawPMSFrameIcon( mdIcon, pt );
  328. break;
  329. case WM_LBUTTONDOWN:
  330. goto MakeChange;
  331. break;
  332. }
  333. } /* end else */
  334. } /* end while */
  335. MakeChange:
  336. {
  337. unsigned NEAR MxRoundMx( unsigned );
  338. /* Round multipliers if near an even multiple */
  339. unsigned mx = MxRoundMx( mxCurrent );
  340. unsigned my = MxRoundMx( myCurrent );
  341. /* Assert must be true for above call to work for an my */
  342. Assert( mxMultByOne == myMultByOne );
  343. ModifyPicInfoDxp( rcInverted.left - xpSelBar + wwdCurrentDoc.xpMin,
  344. rcInverted.right - rcInverted.left,
  345. rcInverted.bottom - rcInverted.top,
  346. mx, my );
  347. }
  348. SkipChange:
  349. EndPMS();
  350. }
  351. unsigned NEAR MxRoundMx( mx )
  352. unsigned mx;
  353. { /* If mx is near an "interesting" multiple, round it to be exactly that
  354. multiple. Interesting multiples are:
  355. 1 (m=mxMultByOne), 2 (m=2 * mxMultByOne), 3 , ...
  356. 0.5 (m = .5 * mxMultByOne)
  357. This routine works for my, too, as long as mxMultByOne == myMultByOne */
  358. /* This means close enough to round (1 decimal place accuracy) */
  359. #define dmxRound (mxMultByOne / 20)
  360. unsigned mxRemainder;
  361. if (mx >= mxMultByOne - dmxRound)
  362. { /* Multiplier > 1 -- look for rounding to integer multiple */
  363. if ((mxRemainder = mx % mxMultByOne) < dmxRound)
  364. mx -= mxRemainder;
  365. else if (mxRemainder >= mxMultByOne - dmxRound)
  366. mx += (mxMultByOne - mxRemainder);
  367. }
  368. else
  369. { /* Multiplier < 1 -- look for multiplication by 1/2 */
  370. if ((mxRemainder = mx % (mxMultByOne >> 1)) < dmxRound)
  371. mx -= mxRemainder;
  372. else if (mxRemainder >= ((mxMultByOne >> 1) - dmxRound))
  373. mx += (mxMultByOne >> 1) - mxRemainder;
  374. }
  375. return mx;
  376. }
  377. int NEAR FStartPMS( fSize )
  378. int fSize;
  379. { /* Initialization for Picture Move/Size */
  380. extern HCURSOR vhcHourGlass;
  381. extern HWND hParentWw;
  382. extern struct SEP vsepAbs;
  383. extern struct SEP vsepPage;
  384. extern HDC vhDCPrinter;
  385. struct PICINFOX picInfo;
  386. struct EDL *pedl;
  387. RECT rc;
  388. HDC hdcT;
  389. POINT pt;
  390. Assert(vhDCPrinter);
  391. fSizing = fSize;
  392. UpdateWw( wwCur, FALSE ); /* Screen must be up-to-date */
  393. /* Set the rect that defines our display area */
  394. SetRect( (LPRECT) &rcClip, xpSelBar, wwdCurrentDoc.ypMin,
  395. wwdCurrentDoc.xpMac, wwdCurrentDoc.ypMac );
  396. GetPicInfo( selCur.cpFirst, selCur.cpLim, docCur, &picInfo );
  397. if (fSize)
  398. {
  399. if (BStructMember( PICINFOX, my ) >= picInfo.cbHeader )
  400. { /* OLD file format (no multipliers), scaling not supported */
  401. return FALSE;
  402. }
  403. }
  404. /* Set multiplier factor used by the printer (will be { 1, 1 } if
  405. the printer is not a scaling device; greater if it is.)
  406. This info is used for the 64K limit test of picture growth. */
  407. if (!(GetDeviceCaps( vhDCPrinter, RASTERCAPS ) & RC_BITMAP64))
  408. /* doesn't support > 64K bitmaps */
  409. {
  410. if (GetDeviceCaps( vhDCPrinter, RASTERCAPS ) & RC_SCALING)
  411. {
  412. POINT pt;
  413. pt.x = pt.y = 0; /* Just in case */
  414. Escape( vhDCPrinter, GETSCALINGFACTOR, 0, (LPSTR) NULL,
  415. (LPSTR) (LPPOINT) &pt );
  416. cxpPrinterPixel = 1 << pt.x;
  417. cypPrinterPixel = 1 << pt.y;
  418. }
  419. else
  420. {
  421. cxpPrinterPixel = cypPrinterPixel = 1;
  422. }
  423. }
  424. else
  425. {
  426. cxpPrinterPixel = cypPrinterPixel = 0xFFFF;
  427. }
  428. /* Compute picture's original (when pasted) size in
  429. screen pixels {dxpOrig, dypOrig}.
  430. These numbers are the bases for computing the multiplier. */
  431. switch(picInfo.mfp.mm)
  432. {
  433. case MM_BITMAP:
  434. GetBitmapSize( &dxpOrig, &dypOrig, &picInfo, FALSE );
  435. /* Compensate for effects of existing multipliers */
  436. dxpOrig = MultDiv( dxpOrig, mxMultByOne, picInfo.mx );
  437. dypOrig = MultDiv( dypOrig, myMultByOne, picInfo.my );
  438. break;
  439. default: // OLE and META
  440. {
  441. int dxa, dya;
  442. if (!FComputePictSize( &picInfo.mfp, &dxa, &dya ))
  443. return FALSE;
  444. dxpOrig = DxpFromDxa( dxa, FALSE );
  445. dypOrig = DypFromDya( dya, FALSE );
  446. }
  447. break;
  448. }
  449. if (!FGetPictPedl( &pedl ))
  450. /* Picture must be on the screen */
  451. return FALSE;
  452. ComputePictRect( &rcPicture, &picInfo, pedl, wwCur );
  453. rcInverted = rcPicture; /* Initial grey box is the size of the picture */
  454. vfPMS = TRUE; /* So ToggleSel knows not to invert the pict */
  455. fPictModified = FALSE;
  456. /* Amt to move for arrow keys is derived from size of fixed font */
  457. if ( ((hdcT=GetDC( hParentWw ))!=NULL) &&
  458. (SelectObject( hdcT, GetStockObject( ANSI_FIXED_FONT ) )!=0))
  459. {
  460. TEXTMETRIC tm;
  461. GetTextMetrics( hdcT, (LPTEXTMETRIC) &tm );
  462. ReleaseDC( hParentWw, hdcT );
  463. dxpKeyMove = tm.tmAveCharWidth;
  464. dypKeyMove = (tm.tmHeight + tm.tmExternalLeading) / 2;
  465. }
  466. SetupDCForPMS(); /* Save DC and select in a grey brush for border drawing */
  467. /* Assure that the "size box" mouse cursor is loaded */
  468. if (vhcPMS == NULL)
  469. {
  470. extern HANDLE hMmwModInstance;
  471. extern CHAR szPmsCur[];
  472. vhcPMS = LoadCursor( hMmwModInstance, (LPSTR) szPmsCur );
  473. }
  474. /* Compute maximum allowable area for picture to roam
  475. (relative to para left edge, picture top) */
  476. CacheSectPic( docCur, selCur.cpFirst );
  477. dxpPicMac = imax(
  478. DxpFromDxa( vsepAbs.dxaText, FALSE ),
  479. rcPicture.right - xpSelBar + wwdCurrentDoc.xpMin );
  480. dypPicMac = DypFromDya( vsepAbs.yaMac, FALSE );
  481. /* Since the picture is selected, need to un-invert it */
  482. InvertRect( wwdCurrentDoc.hDC, (LPRECT) &rcPicture );
  483. SetCapture( wwdCurrentDoc.wwptr ); /* Hog all mouse actions */
  484. /* Draw initial size box icon in the center of the picture */
  485. pt.x = rcInverted.left + (unsigned)(rcInverted.right - rcInverted.left)/2;
  486. pt.y = rcInverted.top + (unsigned)(rcInverted.bottom - rcInverted.top)/2;
  487. DrawPMSFrameIcon( mdIconCenterFix | mdIconSetCursor, pt );
  488. SetCursor( vhcPMS ); /* Make the mouse cursor a size box */
  489. ShowCursor( TRUE ); /* So cursor appears even on mouseless systems */
  490. return TRUE;
  491. }
  492. void NEAR SetupDCForPMS()
  493. { /* Save current document DC & set it up for picture move/sizing:
  494. - A gray background brush for drawing the border
  495. - A drawing area resricted to rcClip */
  496. ilevelPMS = SaveDC( wwdCurrentDoc.hDC );
  497. SelectObject( wwdCurrentDoc.hDC, GetStockObject( GRAY_BRUSH ) );
  498. IntersectClipRect( wwdCurrentDoc.hDC,
  499. rcClip.left, rcClip.top, rcClip.right, rcClip.bottom );
  500. }
  501. void NEAR EndPMS()
  502. { /* Leaving Picture Move/Size */
  503. extern int docMode;
  504. struct PICINFOX picInfo;
  505. vfPMS = FALSE;
  506. ReleaseCapture(); /* Allow other windows to receive mouse events */
  507. SetCursor( NULL );
  508. docMode = docNil;
  509. CheckMode(); /* Compensate for multiplier display */
  510. if (fIsRcInverted)
  511. InvertPMSFrame();
  512. if (!fPictModified && !vfCancelPictMove)
  513. { /* Picture did not change, restore inversion to show selection */
  514. /* Must do this BEFORE RestoreDC so excess above ypMin is clipped */
  515. InvertRect( wwdCurrentDoc.hDC, (LPRECT) &rcPicture );
  516. }
  517. RestoreDC( wwdCurrentDoc.hDC, ilevelPMS );
  518. ShowCursor( FALSE ); /* Decrement cursor ref cnt (blanks if no mouse) */
  519. /* Since we've been ignoring messages, make sure our key flags are OK */
  520. SetShiftFlags();
  521. }
  522. void NEAR DrawPMSFrameIcon( mdIcon, pt )
  523. int mdIcon;
  524. POINT pt;
  525. { /* Draw Picture Move/Size frame and icon, with the icon at position
  526. pt. The icon type is given by mdIcon.
  527. Scrolls the correct part of the picture into view if necessary.
  528. Uses statics: rcPicture, rcClip, rcInverted, fIsRcInverted
  529. */
  530. #define FEqualRect( r1, r2 ) ((r1.left==r2.left)&&(r1.right==r2.right)&&\
  531. (r1.top==r2.top)&&(r1.bottom==r2.bottom))
  532. extern int vfAwfulNoise;
  533. int xpCntr;
  534. int dxpCntr = ((unsigned)(rcInverted.right - rcInverted.left)) / 2;
  535. RECT rcT;
  536. rcT = rcInverted;
  537. /* Set pt.y so it does not exceed limits */
  538. if (mdIcon & mdIconBottom)
  539. {
  540. if (pt.y - rcInverted.top > dypPicMac)
  541. {
  542. pt.y = rcInverted.top + dypPicMac; /* max y-size is 1 page */
  543. }
  544. else if (pt.y < rcInverted.top + 1)
  545. pt.y = rcInverted.top + 1; /* min y-size is 1 pixel */
  546. /* Restrict pt.x as necessary to keep printer bitmap < 64K */
  547. if ((pt.y > rcInverted.bottom) && (cxpPrinterPixel < 0xFFFF) && (cypPrinterPixel < 0xFFFF))
  548. { /* Really sizing in y */
  549. unsigned dxpScreen = imax (imax(pt.x,rcInverted.right)-rcInverted.left,
  550. dxpPicSizeMin);
  551. unsigned dxpPrinter = DxpFromDxa(DxaFromDxp( dxpScreen, FALSE ), TRUE);
  552. unsigned dypLast = 0xFFFF / (dxpPrinter / 8);
  553. unsigned dyp = DypFromDya( DyaFromDyp( pt.y - rcInverted.top , FALSE),
  554. TRUE );
  555. if (dyp / (cxpPrinterPixel * cypPrinterPixel) > dypLast )
  556. { /* Bitmap would overflow 64K boundary */
  557. pt.y = rcInverted.top +
  558. DypFromDya( DyaFromDyp( dypLast, TRUE ), FALSE );
  559. }
  560. }
  561. }
  562. else if (pt.y < rcInverted.top)
  563. pt.y = rcInverted.top; /* Can't go above picture top */
  564. else if (pt.y > rcInverted.bottom)
  565. pt.y = rcInverted.bottom; /* Necessary? */
  566. /* Set pt.x so it does not execeed limits */
  567. switch (mdIcon & mdIconXMask) {
  568. case mdIconCenterFloat:
  569. case mdIconRight:
  570. /* Restrict pt.x as necessary to keep printer bitmap < 64K */
  571. if ((cxpPrinterPixel < 0xFFFF) && (cypPrinterPixel < 0xFFFF))
  572. {
  573. unsigned dyp = DypFromDya( DyaFromDyp( imax( pt.y - rcInverted.top,
  574. dypPicSizeMin), FALSE ), TRUE );
  575. unsigned dxpLast = 0xFFFF / (dyp / 8);
  576. unsigned dxp = DxpFromDxa( DxaFromDxp( pt.x - rcInverted.left,
  577. FALSE ), TRUE );
  578. if (dxp / (cxpPrinterPixel * cypPrinterPixel) > dxpLast )
  579. { /* Printer bitmap would overflow 64K boundary */
  580. pt.x = rcInverted.left +
  581. DxpFromDxa( DxaFromDxp( dxpLast, TRUE ), FALSE );
  582. }
  583. }
  584. default:
  585. break;
  586. case mdIconLeft:
  587. if ((pt.x < rcClip.left) && (wwdCurrentDoc.xpMin == 0))
  588. pt.x = rcClip.left; /* Reached left scroll limit */
  589. break;
  590. case mdIconCenterFix:
  591. if ( (pt.x - dxpCntr < rcClip.left) && (wwdCurrentDoc.xpMin == 0))
  592. pt.x = rcClip.left + dxpCntr; /* Reached left scroll limit */
  593. else if (pt.x - xpSelBar + wwdCurrentDoc.xpMin + dxpCntr > dxpPicMac)
  594. /* Move Picture only: can't move past margins */
  595. pt.x = dxpPicMac + xpSelBar - wwdCurrentDoc.xpMin - dxpCntr;
  596. break;
  597. }
  598. /* Check for pt outside of clip rectangle; scroll/bail out as needed */
  599. if (!PtInRect( (LPRECT)&rcClip, pt ))
  600. {
  601. int dxpHalfWidth = (unsigned)(rcClip.right - rcClip.left) / 2;
  602. int dypHalfHeight = (unsigned)(rcClip.bottom - rcClip.top) / 2;
  603. int dxpScroll=0;
  604. int dypScroll=0;
  605. if (pt.x < rcClip.left)
  606. {
  607. if (wwdCurrentDoc.xpMin == 0)
  608. {
  609. _beep(); /* Reached left-hand scroll limit */
  610. pt.x = rcClip.left;
  611. }
  612. else
  613. { /* SCROLL LEFT */
  614. dxpScroll = imax( -wwdCurrentDoc.xpMin,
  615. imin( -dxpHalfWidth, pt.x - rcClip.left ) );
  616. }
  617. }
  618. else if (pt.x > rcClip.right)
  619. {
  620. if (wwdCurrentDoc.xpMin + rcClip.right - rcClip.left >= xpRightLim )
  621. {
  622. _beep();
  623. pt.x = rcClip.right; /* Reached right-hand scroll limit */
  624. }
  625. else
  626. { /* SCROLL RIGHT */
  627. dxpScroll = imin( xpRightLim - wwdCurrentDoc.xpMin +
  628. rcClip.right - rcClip.left,
  629. imax( dxpHalfWidth, pt.x - rcClip.right ) );
  630. }
  631. }
  632. if (pt.y < rcClip.top)
  633. {
  634. struct EDL *pedl = &(**wwdCurrentDoc.hdndl)[wwdCurrentDoc.dlMac - 1];
  635. if ( (rcInverted.top >= rcClip.top) ||
  636. /* May not scroll all of the original picture off the screen */
  637. (wwdCurrentDoc.dlMac <= 1) ||
  638. ( (pedl->cpMin == selCur.cpFirst) &&
  639. ( ((pedl-1)->cpMin != pedl->cpMin) || !(pedl-1)->fGraphics)))
  640. {
  641. _beep();
  642. pt.y = rcClip.top;
  643. }
  644. else
  645. { /* SCROLL UP */
  646. dypScroll = rcInverted.top - rcClip.top;
  647. }
  648. }
  649. else if (pt.y > rcClip.bottom)
  650. {
  651. struct EDL *pedl=&(**wwdCurrentDoc.hdndl)[0];
  652. /* May not scroll all of the original picture off the screen */
  653. if ( (wwdCurrentDoc.dlMac <= 1) ||
  654. ( (pedl->cpMin == selCur.cpFirst) &&
  655. ( ((pedl+1)->ichCpMin == 0) || !(pedl+1)->fGraphics) ))
  656. {
  657. _beep(); /* Reached downward scroll limit */
  658. pt.y = rcClip.bottom; /* Must have at least 1 picture dl visible */
  659. }
  660. else
  661. dypScroll = 1; /* SCROLL DOWN */
  662. }
  663. if (dxpScroll || dypScroll)
  664. { /* SCROLL */
  665. struct EDL *pedl;
  666. struct PICINFOX picInfo;
  667. int xpMinT = wwdCurrentDoc.xpMin;
  668. int ypTopT = rcPicture.top;
  669. int dxpAdjust, dypAdjust;
  670. if (dxpScroll && dypScroll)
  671. /* Did not need to truncate coordinates; re-enable beep */
  672. vfAwfulNoise = FALSE;
  673. if (fIsRcInverted)
  674. InvertPMSFrame();
  675. /* Scroll by the appropriate amount:
  676. dxpScroll in x-direction; one line in y-direction */
  677. RestoreDC( wwdCurrentDoc.hDC, ilevelPMS ); /* Use orig DC props */
  678. if (dxpScroll)
  679. AdjWwHoriz( dxpScroll );
  680. if (dypScroll > 0)
  681. ScrollDownCtr( 1 );
  682. else if (dypScroll < 0)
  683. ScrollUpCtr( 1 );
  684. UpdateWw( wwCur, FALSE );
  685. SetupDCForPMS(); /* Compensate for RestoreDC */
  686. /* Update rcPicture to reflect new scroll position */
  687. GetPicInfo( selCur.cpFirst, selCur.cpLim, docCur, &picInfo );
  688. if (!FGetPictPedl( &pedl ))
  689. {
  690. Assert (FALSE); /* If we get here, we're in trouble */
  691. _beep();
  692. return;
  693. }
  694. ComputePictRect( &rcPicture, &picInfo, pedl, wwCur );
  695. /* Adjust rcT, pt relative to the amount we actually scrolled */
  696. dxpAdjust = xpMinT - wwdCurrentDoc.xpMin;
  697. dypAdjust = rcPicture.top - ypTopT;
  698. OffsetRect( (LPRECT) &rcT, dxpAdjust, dypAdjust );
  699. pt.x += dxpAdjust;
  700. pt.y += dypAdjust;
  701. goto Display; /* Dont let rcInverted be edited until we have
  702. scrolled the icon into view */
  703. }
  704. }
  705. /* Compute effect of new icon position and/or type on rcInverted */
  706. switch (mdIcon & mdIconXMask) {
  707. case mdIconCenterFix:
  708. if (!fSizing)
  709. {
  710. xpCntr = rcInverted.left + dxpCntr;
  711. OffsetRect( (LPRECT) &rcT, pt.x - xpCntr, 0 );
  712. }
  713. break;
  714. case mdIconLeft:
  715. rcT.left = pt.x;
  716. goto ComputeY;
  717. case mdIconRight:
  718. rcT.right = pt.x;
  719. default:
  720. case mdIconCenterFloat:
  721. ComputeY:
  722. if (mdIcon & mdIconBottom)
  723. rcT.bottom = pt.y;
  724. break;
  725. }
  726. Display:
  727. /* If redrawing the border is necessary, do it */
  728. if (!FEqualRect( rcT, rcInverted ) || (mdIcon & mdIconSetCursor))
  729. {
  730. if (fIsRcInverted)
  731. InvertPMSFrame();
  732. rcInverted = rcT;
  733. InvertPMSFrame();
  734. }
  735. if (mdIcon & mdIconSetCursor)
  736. {
  737. SetCursorClientPos( pt );
  738. SetCursor( vhcPMS );
  739. }
  740. /* If the multipliers have changed, redisplay them */
  741. if (fSizing)
  742. {
  743. unsigned mx, my;
  744. mx = MultDiv( rcInverted.right - rcInverted.left, mxMultByOne, dxpOrig );
  745. my = MultDiv( rcInverted.bottom - rcInverted.top, myMultByOne, dypOrig );
  746. if (mx != mxCurrent || my != myCurrent)
  747. { /* Multipliers have changed */
  748. mxCurrent = mx;
  749. myCurrent = my;
  750. ShowPictMultipliers();
  751. }
  752. }
  753. }
  754. void NEAR InvertPMSFrame()
  755. { /* Draw a frame for rcInverted in XOR mode, update fIsRcInverted */
  756. int dxpSize=rcInverted.right - rcInverted.left - 1;
  757. int dypSize=rcInverted.bottom - rcInverted.top - 1;
  758. PatBlt( wwdCurrentDoc.hDC, rcInverted.left, rcInverted.top,
  759. dxpSize, 1, PATINVERT );
  760. PatBlt( wwdCurrentDoc.hDC, rcInverted.right - 1, rcInverted.top,
  761. 1, dypSize, PATINVERT );
  762. PatBlt( wwdCurrentDoc.hDC, rcInverted.left + 1, rcInverted.bottom - 1,
  763. dxpSize, 1, PATINVERT );
  764. PatBlt( wwdCurrentDoc.hDC, rcInverted.left, rcInverted.top + 1,
  765. 1, dypSize, PATINVERT );
  766. fIsRcInverted ^= -1;
  767. }
  768. void NEAR GetCursorClientPos( ppt )
  769. POINT *ppt;
  770. { /* Get current mouse cursor coordinates (window-relative) */
  771. GetCursorPos( (LPPOINT) ppt );
  772. ScreenToClient( wwdCurrentDoc.wwptr, (LPPOINT) ppt );
  773. }
  774. void NEAR SetCursorClientPos( pt )
  775. POINT pt;
  776. { /* Set current mouse cursor coordinates (window-relative) */
  777. ClientToScreen( wwdCurrentDoc.wwptr, (LPPOINT) &pt );
  778. SetCursorPos( pt.x, pt.y );
  779. }
  780. STATIC NEAR ModifyPicInfoDxp( xpOffset, xpSize, ypSize, mx, my )
  781. int xpOffset, xpSize, ypSize;
  782. unsigned mx, my;
  783. { /* Modify the currently selected picture by adjusting its offset and
  784. size to the pixel values specified. Negative values mean don't
  785. set that value.
  786. Added 9/23/85: mx and my parms give the multiplier, redundant
  787. info used for scaling bitmaps. */
  788. int xaOffset, xaSize, yaSize;
  789. xaOffset = xaSize = yaSize = -1;
  790. if (xpSize >= 0)
  791. xaSize = DxaFromDxp( umax( xpSize, dxpPicSizeMin ), FALSE );
  792. if (ypSize >= 0)
  793. yaSize = DyaFromDyp( umax( ypSize, dypPicSizeMin ), FALSE );
  794. if (xpOffset >= 0)
  795. xaOffset = DxaFromDxp( xpOffset, FALSE );
  796. ModifyPicInfoDxa( xaOffset, xaSize, yaSize, mx, my, TRUE );
  797. }
  798. /* M O D I F Y P I C I N F O D X A */
  799. STATIC NEAR ModifyPicInfoDxa( xaOffset, xaSize, yaSize, mx, my, fSetUndo )
  800. int xaOffset, xaSize, yaSize;
  801. unsigned mx, my;
  802. BOOL fSetUndo;
  803. { /* Modify the currently selected picture by adjusting its offset and
  804. size to the twip values specified. Negative values mean don't
  805. set that value.
  806. Added 9/23/85: mx, my are size "multipliers", used for
  807. bitmaps only */
  808. typeFC fcT;
  809. struct PICINFOX picInfo;
  810. typeCP cp = selCur.cpFirst;
  811. int dyaSizeOld;
  812. int fBitmap,fObj;
  813. fPictModified = TRUE;
  814. FreeBitmapCache();
  815. GetPicInfo(cp, cpMacCur, docCur, &picInfo);
  816. fBitmap = (picInfo.mfp.mm == MM_BITMAP);
  817. fObj = (picInfo.mfp.mm == MM_OLE);
  818. dyaSizeOld = picInfo.dyaSize;
  819. if (fBitmap || fObj)
  820. {
  821. if ((int)mx > 0 && (int)my > 0)
  822. {
  823. picInfo.mx = mx;
  824. picInfo.my = my;
  825. }
  826. }
  827. else
  828. {
  829. if (xaSize >= 0)
  830. picInfo.dxaSize = xaSize;
  831. if (yaSize >= 0)
  832. picInfo.dyaSize = yaSize;
  833. }
  834. if (xaOffset >= 0)
  835. picInfo.dxaOffset = xaOffset;
  836. if (picInfo.cbHeader > cchOldPICINFO)
  837. /* Extended picture format, set extended format bit */
  838. picInfo.mfp.mm |= MM_EXTENDED;
  839. if (!fObj)
  840. fcT = FcWScratch( &picInfo, picInfo.cbHeader );
  841. picInfo.mfp.mm &= ~MM_EXTENDED;
  842. /* Right or center justify becomes invalid if the picture is moved
  843. without being sized */
  844. CachePara(docCur, cp);
  845. if ( (xaSize < 0 && yaSize < 0) &&
  846. (vpapAbs.jc == jcRight || vpapAbs.jc == jcCenter))
  847. {
  848. CHAR rgb[2];
  849. if (fSetUndo)
  850. SetUndo(uacPictSel, docCur, cp, selCur.cpLim - selCur.cpFirst,
  851. docNil, cpNil, cpNil, 0);
  852. TrashCache();
  853. rgb[0] = sprmPJc;
  854. rgb[1] = jcLeft;
  855. AddSprm(&rgb[0]);
  856. }
  857. else
  858. {
  859. if (fSetUndo)
  860. SetUndo( uacPictSel, docCur, cp, (typeCP) picInfo.cbHeader,
  861. docNil, cpNil, cpNil, 0);
  862. }
  863. if (fObj)
  864. ObjSetPicInfo(&picInfo, docCur, cp);
  865. else
  866. Replace( docCur, cp, (typeCP) picInfo.cbHeader,
  867. fnScratch, fcT, (typeFC) picInfo.cbHeader);
  868. if ( ((fBitmap || fObj) && (my > myMultByOne)) ||
  869. (!fBitmap && (dyaSizeOld < picInfo.dyaSize)))
  870. { /* If the picture height was increased, make sure proper EDLs are
  871. invalidated. */
  872. typeCP dcp = cpMacCur - cp + (typeCP) 1;
  873. AdjustCp(docCur, cp, dcp, dcp);
  874. }
  875. }
  876. STATIC NEAR ShowPictMultipliers( )
  877. { /* Display the current multipliers (mxCurrent, myCurrent) in the page info
  878. window in the form "n.nX/n.nY". */
  879. CHAR *PchCvtMx( unsigned, CHAR * );
  880. extern CHAR szMode[];
  881. CHAR *pch = szMode;
  882. pch = PchCvtMx( mxCurrent, pch );
  883. *(pch++) = 'X';
  884. *(pch++) = '/';
  885. Assert( mxMultByOne == myMultByOne ); /* Necessary for below to work w/ my */
  886. pch = PchCvtMx( myCurrent, pch );
  887. *(pch++) = 'Y';
  888. *pch = '\0';
  889. DrawMode();
  890. }
  891. CHAR *PchCvtMx( mx, pch )
  892. CHAR *pch;
  893. unsigned mx;
  894. { /* Convert the passed multiplier word to a string representation.
  895. Number is based on a mxMultByOne === 1 scale
  896. (e.g. mx == .9 * mxMultByOne yields "0.9")
  897. String always has at least one digit before the decimal point,
  898. and exactly one after.
  899. Examples of return strings: "10.5", "0.0", "5.5" */
  900. int nTenths;
  901. int nWholes;
  902. int cch;
  903. extern CHAR vchDecimal;
  904. extern BOOL vbLZero;
  905. extern int viDigits;
  906. /* Round up to nearest single decimal place */
  907. if (mx % (mxMultByOne / 10) >= mxMultByOne / 20)
  908. mx += mxMultByOne / 20;
  909. /* Write digit(s) before decimal place */
  910. if (((nWholes = mx / mxMultByOne) == 0) && vbLZero)
  911. *(pch++) = '0';
  912. else
  913. ncvtu( nWholes, &pch );
  914. /* Write Decimal Point and following digit */
  915. *(pch++) = vchDecimal;
  916. if (viDigits > 0)
  917. *(pch++) = ((mx % mxMultByOne) / (mxMultByOne / 10)) + '0';
  918. *pch = '\0';
  919. return pch;
  920. }