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.

503 lines
14 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. preview.c
  5. Abstract:
  6. This module contains the code for console preview window
  7. Author:
  8. Therese Stowell (thereses) Feb-3-1992 (swiped from Win3.1)
  9. Revision History:
  10. --*/
  11. #include "shellprv.h"
  12. #pragma hdrstop
  13. #include "lnkcon.h"
  14. /* ----- Equates ----- */
  15. LONG CnslAspectScale( LONG n1, LONG n2, LONG m );
  16. void CnslAspectPoint( CONSOLEPROP_DATA * pcpd, RECT* rectPreview, POINT* pt);
  17. VOID
  18. UpdatePreviewRect( CONSOLEPROP_DATA * pcpd )
  19. /*++
  20. Update the global window size and dimensions
  21. --*/
  22. {
  23. POINT MinSize;
  24. POINT MaxSize;
  25. POINT WindowSize;
  26. FONT_INFO *lpFont;
  27. HMONITOR hMonitor;
  28. MONITORINFO mi;
  29. /*
  30. * Get the font pointer
  31. */
  32. lpFont = &pcpd->FontInfo[pcpd->CurrentFontIndex];
  33. /*
  34. * Get the window size
  35. */
  36. MinSize.x = (GetSystemMetrics(SM_CXMIN)-pcpd->NonClientSize.x) / lpFont->Size.X;
  37. MinSize.y = (GetSystemMetrics(SM_CYMIN)-pcpd->NonClientSize.y) / lpFont->Size.Y;
  38. MaxSize.x = GetSystemMetrics(SM_CXFULLSCREEN) / lpFont->Size.X;
  39. MaxSize.y = GetSystemMetrics(SM_CYFULLSCREEN) / lpFont->Size.Y;
  40. WindowSize.x = max(MinSize.x, min(MaxSize.x, pcpd->lpConsole->dwWindowSize.X));
  41. WindowSize.y = max(MinSize.y, min(MaxSize.y, pcpd->lpConsole->dwWindowSize.Y));
  42. /*
  43. * Get the window rectangle, making sure it's at least twice the
  44. * size of the non-client area.
  45. */
  46. pcpd->WindowRect.left = pcpd->lpConsole->dwWindowOrigin.X;
  47. pcpd->WindowRect.top = pcpd->lpConsole->dwWindowOrigin.Y;
  48. pcpd->WindowRect.right = WindowSize.x * lpFont->Size.X + pcpd->NonClientSize.x;
  49. if (pcpd->WindowRect.right < pcpd->NonClientSize.x * 2) {
  50. pcpd->WindowRect.right = pcpd->NonClientSize.x * 2;
  51. }
  52. pcpd->WindowRect.right += pcpd->WindowRect.left;
  53. pcpd->WindowRect.bottom = WindowSize.y * lpFont->Size.Y + pcpd->NonClientSize.y;
  54. if (pcpd->WindowRect.bottom < pcpd->NonClientSize.y * 2) {
  55. pcpd->WindowRect.bottom = pcpd->NonClientSize.y * 2;
  56. }
  57. pcpd->WindowRect.bottom += pcpd->WindowRect.top;
  58. /*
  59. * Get information about the monitor we're on
  60. */
  61. hMonitor = MonitorFromRect(&pcpd->WindowRect, MONITOR_DEFAULTTONEAREST);
  62. mi.cbSize = sizeof(mi);
  63. GetMonitorInfo(hMonitor, &mi);
  64. pcpd->xScreen = mi.rcWork.right - mi.rcWork.left;
  65. pcpd->yScreen = mi.rcWork.bottom - mi.rcWork.top;
  66. /*
  67. * Convert window rectangle to monitor relative coordinates
  68. */
  69. pcpd->WindowRect.right -= pcpd->WindowRect.left;
  70. pcpd->WindowRect.left -= mi.rcWork.left;
  71. pcpd->WindowRect.bottom -= pcpd->WindowRect.top;
  72. pcpd->WindowRect.top -= mi.rcWork.top;
  73. /*
  74. * Update the display flags
  75. */
  76. if (WindowSize.x < pcpd->lpConsole->dwScreenBufferSize.X) {
  77. pcpd->PreviewFlags |= PREVIEW_HSCROLL;
  78. } else {
  79. pcpd->PreviewFlags &= ~PREVIEW_HSCROLL;
  80. }
  81. if (WindowSize.y < pcpd->lpConsole->dwScreenBufferSize.Y) {
  82. pcpd->PreviewFlags |= PREVIEW_VSCROLL;
  83. } else {
  84. pcpd->PreviewFlags &= ~PREVIEW_VSCROLL;
  85. }
  86. }
  87. VOID
  88. InvalidatePreviewRect(HWND hWnd, CONSOLEPROP_DATA * pcpd)
  89. /*++
  90. Invalidate the area covered by the preview "window"
  91. --*/
  92. {
  93. RECT rectWin;
  94. RECT rectPreview;
  95. /*
  96. * Get the size of the preview "screen"
  97. */
  98. GetClientRect(hWnd, &rectPreview);
  99. /*
  100. * Get the dimensions of the preview "window" and scale it to the
  101. * preview "screen"
  102. */
  103. rectWin.left = pcpd->WindowRect.left;
  104. rectWin.top = pcpd->WindowRect.top;
  105. rectWin.right = pcpd->WindowRect.left + pcpd->WindowRect.right;
  106. rectWin.bottom = pcpd->WindowRect.top + pcpd->WindowRect.bottom;
  107. CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.left);
  108. CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.right);
  109. /*
  110. * Invalidate the area covered by the preview "window"
  111. */
  112. InvalidateRect(hWnd, &rectWin, FALSE);
  113. }
  114. VOID
  115. PreviewPaint(
  116. PAINTSTRUCT* pPS,
  117. HWND hWnd,
  118. CONSOLEPROP_DATA * pcpd
  119. )
  120. /*++
  121. Paints the font preview. This is called inside the paint message
  122. handler for the preview window
  123. --*/
  124. {
  125. RECT rectWin;
  126. RECT rectPreview;
  127. HBRUSH hbrFrame;
  128. HBRUSH hbrTitle;
  129. HBRUSH hbrOld;
  130. HBRUSH hbrClient;
  131. HBRUSH hbrBorder;
  132. HBRUSH hbrButton;
  133. HBRUSH hbrScroll;
  134. HBRUSH hbrDesktop;
  135. POINT ptButton;
  136. POINT ptScroll;
  137. HDC hDC;
  138. HBITMAP hBitmap;
  139. HBITMAP hBitmapOld;
  140. COLORREF rgbClient;
  141. /*
  142. * Get the size of the preview "screen"
  143. */
  144. GetClientRect(hWnd, &rectPreview);
  145. /*
  146. * Get the dimensions of the preview "window" and scale it to the
  147. * preview "screen"
  148. */
  149. rectWin = pcpd->WindowRect;
  150. CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.left);
  151. CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.right);
  152. /*
  153. * Compute the dimensions of some other window components
  154. */
  155. ptButton.x = GetSystemMetrics(SM_CXSIZE);
  156. ptButton.y = GetSystemMetrics(SM_CYSIZE);
  157. CnslAspectPoint( pcpd, &rectPreview, &ptButton);
  158. ptButton.y *= 2; /* Double the computed size for "looks" */
  159. ptScroll.x = GetSystemMetrics(SM_CXVSCROLL);
  160. ptScroll.y = GetSystemMetrics(SM_CYHSCROLL);
  161. CnslAspectPoint( pcpd, &rectPreview, &ptScroll);
  162. /*
  163. * Create the memory device context
  164. */
  165. hDC = CreateCompatibleDC(pPS->hdc);
  166. hBitmap = CreateCompatibleBitmap(pPS->hdc,
  167. rectPreview.right,
  168. rectPreview.bottom);
  169. hBitmapOld = SelectObject(hDC, hBitmap);
  170. /*
  171. * Create the brushes
  172. */
  173. hbrBorder = CreateSolidBrush(GetSysColor(COLOR_ACTIVEBORDER));
  174. hbrTitle = CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
  175. hbrFrame = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME));
  176. hbrButton = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  177. hbrScroll = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR));
  178. hbrDesktop = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
  179. rgbClient = GetNearestColor(hDC, ScreenBkColor(pcpd));
  180. hbrClient = CreateSolidBrush(rgbClient);
  181. /*
  182. * Erase the clipping area
  183. */
  184. FillRect(hDC, &(pPS->rcPaint), hbrDesktop);
  185. /*
  186. * Fill in the whole window with the client brush
  187. */
  188. hbrOld = SelectObject(hDC, hbrClient);
  189. PatBlt(hDC, rectWin.left, rectWin.top,
  190. rectWin.right - 1, rectWin.bottom - 1, PATCOPY);
  191. /*
  192. * Fill in the caption bar
  193. */
  194. SelectObject(hDC, hbrTitle);
  195. PatBlt(hDC, rectWin.left + 3, rectWin.top + 3,
  196. rectWin.right - 7, ptButton.y - 2, PATCOPY);
  197. /*
  198. * Draw the "buttons"
  199. */
  200. SelectObject(hDC, hbrButton);
  201. PatBlt(hDC, rectWin.left + 3, rectWin.top + 3,
  202. ptButton.x, ptButton.y - 2, PATCOPY);
  203. PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptButton.x,
  204. rectWin.top + 3,
  205. ptButton.x, ptButton.y - 2, PATCOPY);
  206. PatBlt(hDC, rectWin.left + rectWin.right - 4 - 2 * ptButton.x - 1,
  207. rectWin.top + 3,
  208. ptButton.x, ptButton.y - 2, PATCOPY);
  209. SelectObject(hDC, hbrFrame);
  210. PatBlt(hDC, rectWin.left + 3 + ptButton.x, rectWin.top + 3,
  211. 1, ptButton.y - 2, PATCOPY);
  212. PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptButton.x - 1,
  213. rectWin.top + 3,
  214. 1, ptButton.y - 2, PATCOPY);
  215. PatBlt(hDC, rectWin.left + rectWin.right - 4 - 2 * ptButton.x - 2,
  216. rectWin.top + 3,
  217. 1, ptButton.y - 2, PATCOPY);
  218. /*
  219. * Draw the scrollbars
  220. */
  221. SelectObject(hDC, hbrScroll);
  222. if (pcpd->PreviewFlags & PREVIEW_HSCROLL) {
  223. PatBlt(hDC, rectWin.left + 3,
  224. rectWin.top + rectWin.bottom - 4 - ptScroll.y,
  225. rectWin.right - 7, ptScroll.y, PATCOPY);
  226. }
  227. if (pcpd->PreviewFlags & PREVIEW_VSCROLL) {
  228. PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptScroll.x,
  229. rectWin.top + 1 + ptButton.y + 1,
  230. ptScroll.x, rectWin.bottom - 6 - ptButton.y, PATCOPY);
  231. if (pcpd->PreviewFlags & PREVIEW_HSCROLL) {
  232. SelectObject(hDC, hbrFrame);
  233. PatBlt(hDC, rectWin.left + rectWin.right - 5 - ptScroll.x,
  234. rectWin.top + rectWin.bottom - 4 - ptScroll.y,
  235. 1, ptScroll.y, PATCOPY);
  236. PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptScroll.x,
  237. rectWin.top + rectWin.bottom - 5 - ptScroll.y,
  238. ptScroll.x, 1, PATCOPY);
  239. }
  240. }
  241. /*
  242. * Draw the interior window frame and caption frame
  243. */
  244. SelectObject(hDC, hbrFrame);
  245. PatBlt(hDC, rectWin.left + 2, rectWin.top + 2,
  246. 1, rectWin.bottom - 5, PATCOPY);
  247. PatBlt(hDC, rectWin.left + 2, rectWin.top + 2,
  248. rectWin.right - 5, 1, PATCOPY);
  249. PatBlt(hDC, rectWin.left + 2, rectWin.top + rectWin.bottom - 4,
  250. rectWin.right - 5, 1, PATCOPY);
  251. PatBlt(hDC, rectWin.left + rectWin.right - 4, rectWin.top + 2,
  252. 1, rectWin.bottom - 5, PATCOPY);
  253. PatBlt(hDC, rectWin.left + 2, rectWin.top + 1 + ptButton.y,
  254. rectWin.right - 5, 1, PATCOPY);
  255. /*
  256. * Draw the border
  257. */
  258. SelectObject(hDC, hbrBorder);
  259. PatBlt(hDC, rectWin.left + 1, rectWin.top + 1,
  260. 1, rectWin.bottom - 3, PATCOPY);
  261. PatBlt(hDC, rectWin.left + 1, rectWin.top + 1,
  262. rectWin.right - 3, 1, PATCOPY);
  263. PatBlt(hDC, rectWin.left + 1, rectWin.top + rectWin.bottom - 3,
  264. rectWin.right - 3, 1, PATCOPY);
  265. PatBlt(hDC, rectWin.left + rectWin.right - 3, rectWin.top + 1,
  266. 1, rectWin.bottom - 3, PATCOPY);
  267. /*
  268. * Draw the exterior window frame
  269. */
  270. SelectObject(hDC, hbrFrame);
  271. PatBlt(hDC, rectWin.left, rectWin.top,
  272. 1, rectWin.bottom - 1, PATCOPY);
  273. PatBlt(hDC, rectWin.left, rectWin.top,
  274. rectWin.right - 1, 1, PATCOPY);
  275. PatBlt(hDC, rectWin.left, rectWin.top + rectWin.bottom - 2,
  276. rectWin.right - 1, 1, PATCOPY);
  277. PatBlt(hDC, rectWin.left + rectWin.right - 2, rectWin.top,
  278. 1, rectWin.bottom - 1, PATCOPY);
  279. /*
  280. * Copy the memory device context to the screen device context
  281. */
  282. BitBlt(pPS->hdc, 0, 0, rectPreview.right, rectPreview.bottom,
  283. hDC, 0, 0, SRCCOPY);
  284. /*
  285. * Clean up everything
  286. */
  287. SelectObject(hDC, hbrOld);
  288. SelectObject(hDC, hBitmapOld);
  289. DeleteObject(hbrBorder);
  290. DeleteObject(hbrFrame);
  291. DeleteObject(hbrTitle);
  292. DeleteObject(hbrClient);
  293. DeleteObject(hbrButton);
  294. DeleteObject(hbrScroll);
  295. DeleteObject(hbrDesktop);
  296. DeleteObject(hBitmap);
  297. DeleteDC(hDC);
  298. }
  299. #define LPCS_INDEX 0
  300. #define PCPD_INDEX sizeof(PVOID)
  301. LRESULT
  302. PreviewWndProc(
  303. HWND hWnd,
  304. UINT wMessage,
  305. WPARAM wParam,
  306. LPARAM lParam
  307. )
  308. /*
  309. * PreviewWndProc
  310. * Handles the preview window
  311. */
  312. {
  313. PAINTSTRUCT ps;
  314. LPCREATESTRUCT lpcs;
  315. RECT rcWindow;
  316. CONSOLEPROP_DATA * pcpd;
  317. int cx;
  318. int cy;
  319. switch (wMessage) {
  320. case WM_CREATE:
  321. lpcs = (LPCREATESTRUCT)LocalAlloc( LPTR, SIZEOF( CREATESTRUCT ) );
  322. if (lpcs)
  323. {
  324. CopyMemory( (PVOID)lpcs, (PVOID)lParam, SIZEOF( CREATESTRUCT ) );
  325. SetWindowLongPtr( hWnd, LPCS_INDEX, (LONG_PTR)lpcs );
  326. }
  327. else
  328. return 0;
  329. break;
  330. case CM_PREVIEW_INIT:
  331. pcpd = (CONSOLEPROP_DATA *)lParam;
  332. SetWindowLongPtr( hWnd, PCPD_INDEX, (LONG_PTR)pcpd );
  333. /*
  334. * Figure out space used by non-client area
  335. */
  336. SetRect(&rcWindow, 0, 0, 50, 50);
  337. AdjustWindowRect(&rcWindow, WS_OVERLAPPEDWINDOW, FALSE);
  338. pcpd->NonClientSize.x = rcWindow.right - rcWindow.left - 50;
  339. pcpd->NonClientSize.y = rcWindow.bottom - rcWindow.top - 50;
  340. /*
  341. * Compute the size of the preview "window"
  342. */
  343. UpdatePreviewRect( pcpd );
  344. /*
  345. * Scale the window so it has the same aspect ratio as the screen
  346. */
  347. lpcs = (LPCREATESTRUCT)GetWindowLongPtr( hWnd, LPCS_INDEX );
  348. cx = lpcs->cx;
  349. cy = CnslAspectScale( pcpd->yScreen, pcpd->xScreen, cx);
  350. if (cy > lpcs->cy) {
  351. cy = lpcs->cy;
  352. cx = CnslAspectScale(pcpd->xScreen, pcpd->yScreen, cy);
  353. }
  354. MoveWindow(hWnd, lpcs->x, lpcs->y, cx, cy, TRUE);
  355. break;
  356. case WM_PAINT:
  357. pcpd = (CONSOLEPROP_DATA *)GetWindowLongPtr( hWnd, PCPD_INDEX );
  358. BeginPaint(hWnd, &ps);
  359. if (pcpd)
  360. PreviewPaint(&ps, hWnd, pcpd);
  361. EndPaint(hWnd, &ps);
  362. break;
  363. case CM_PREVIEW_UPDATE:
  364. pcpd = (CONSOLEPROP_DATA *)GetWindowLongPtr( hWnd, PCPD_INDEX );
  365. if (pcpd)
  366. {
  367. InvalidatePreviewRect(hWnd, pcpd);
  368. UpdatePreviewRect( pcpd );
  369. /*
  370. * Make sure the preview "screen" has the correct aspect ratio
  371. */
  372. GetWindowRect(hWnd, &rcWindow);
  373. cx = rcWindow.right - rcWindow.left;
  374. cy = CnslAspectScale(pcpd->yScreen, pcpd->xScreen, cx);
  375. if (cy != rcWindow.bottom - rcWindow.top) {
  376. SetWindowPos(hWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  377. }
  378. InvalidatePreviewRect(hWnd, pcpd);
  379. }
  380. break;
  381. case WM_DESTROY:
  382. lpcs = (LPCREATESTRUCT)GetWindowLongPtr( hWnd, LPCS_INDEX );
  383. if (lpcs)
  384. LocalFree( lpcs );
  385. break;
  386. default:
  387. return DefWindowProc(hWnd, wMessage, wParam, lParam);
  388. }
  389. return 0L;
  390. }
  391. /* CnslAspectScale
  392. * Performs the following calculation in LONG arithmetic to avoid
  393. * overflow:
  394. * return = n1 * m / n2
  395. * This can be used to make an aspect ration calculation where n1/n2
  396. * is the aspect ratio and m is a known value. The return value will
  397. * be the value that corresponds to m with the correct apsect ratio.
  398. */
  399. LONG
  400. CnslAspectScale(
  401. LONG n1,
  402. LONG n2,
  403. LONG m)
  404. {
  405. LONG Temp;
  406. Temp = n1 * m + (n2 >> 1);
  407. return Temp / n2;
  408. }
  409. /* CnslAspectPoint
  410. * Scales a point to be preview-sized instead of screen-sized.
  411. */
  412. void
  413. CnslAspectPoint(
  414. CONSOLEPROP_DATA * pcpd,
  415. RECT* rectPreview,
  416. POINT* pt
  417. )
  418. {
  419. pt->x = CnslAspectScale(rectPreview->right, pcpd->xScreen, pt->x);
  420. pt->y = CnslAspectScale(rectPreview->bottom, pcpd->yScreen, pt->y);
  421. }