/*++ Copyright (c) 1992 Microsoft Corporation Module Name: preview.c Abstract: This module contains the code for console preview window Author: Therese Stowell (thereses) Feb-3-1992 (swiped from Win3.1) Revision History: --*/ #include "shellprv.h" #pragma hdrstop #include "lnkcon.h" /* ----- Equates ----- */ LONG CnslAspectScale( LONG n1, LONG n2, LONG m ); void CnslAspectPoint( CONSOLEPROP_DATA * pcpd, RECT* rectPreview, POINT* pt); VOID UpdatePreviewRect( CONSOLEPROP_DATA * pcpd ) /*++ Update the global window size and dimensions --*/ { POINT MinSize; POINT MaxSize; POINT WindowSize; FONT_INFO *lpFont; HMONITOR hMonitor; MONITORINFO mi; /* * Get the font pointer */ lpFont = &pcpd->FontInfo[pcpd->CurrentFontIndex]; /* * Get the window size */ MinSize.x = (GetSystemMetrics(SM_CXMIN)-pcpd->NonClientSize.x) / lpFont->Size.X; MinSize.y = (GetSystemMetrics(SM_CYMIN)-pcpd->NonClientSize.y) / lpFont->Size.Y; MaxSize.x = GetSystemMetrics(SM_CXFULLSCREEN) / lpFont->Size.X; MaxSize.y = GetSystemMetrics(SM_CYFULLSCREEN) / lpFont->Size.Y; WindowSize.x = max(MinSize.x, min(MaxSize.x, pcpd->lpConsole->dwWindowSize.X)); WindowSize.y = max(MinSize.y, min(MaxSize.y, pcpd->lpConsole->dwWindowSize.Y)); /* * Get the window rectangle, making sure it's at least twice the * size of the non-client area. */ pcpd->WindowRect.left = pcpd->lpConsole->dwWindowOrigin.X; pcpd->WindowRect.top = pcpd->lpConsole->dwWindowOrigin.Y; pcpd->WindowRect.right = WindowSize.x * lpFont->Size.X + pcpd->NonClientSize.x; if (pcpd->WindowRect.right < pcpd->NonClientSize.x * 2) { pcpd->WindowRect.right = pcpd->NonClientSize.x * 2; } pcpd->WindowRect.right += pcpd->WindowRect.left; pcpd->WindowRect.bottom = WindowSize.y * lpFont->Size.Y + pcpd->NonClientSize.y; if (pcpd->WindowRect.bottom < pcpd->NonClientSize.y * 2) { pcpd->WindowRect.bottom = pcpd->NonClientSize.y * 2; } pcpd->WindowRect.bottom += pcpd->WindowRect.top; /* * Get information about the monitor we're on */ hMonitor = MonitorFromRect(&pcpd->WindowRect, MONITOR_DEFAULTTONEAREST); mi.cbSize = sizeof(mi); GetMonitorInfo(hMonitor, &mi); pcpd->xScreen = mi.rcWork.right - mi.rcWork.left; pcpd->yScreen = mi.rcWork.bottom - mi.rcWork.top; /* * Convert window rectangle to monitor relative coordinates */ pcpd->WindowRect.right -= pcpd->WindowRect.left; pcpd->WindowRect.left -= mi.rcWork.left; pcpd->WindowRect.bottom -= pcpd->WindowRect.top; pcpd->WindowRect.top -= mi.rcWork.top; /* * Update the display flags */ if (WindowSize.x < pcpd->lpConsole->dwScreenBufferSize.X) { pcpd->PreviewFlags |= PREVIEW_HSCROLL; } else { pcpd->PreviewFlags &= ~PREVIEW_HSCROLL; } if (WindowSize.y < pcpd->lpConsole->dwScreenBufferSize.Y) { pcpd->PreviewFlags |= PREVIEW_VSCROLL; } else { pcpd->PreviewFlags &= ~PREVIEW_VSCROLL; } } VOID InvalidatePreviewRect(HWND hWnd, CONSOLEPROP_DATA * pcpd) /*++ Invalidate the area covered by the preview "window" --*/ { RECT rectWin; RECT rectPreview; /* * Get the size of the preview "screen" */ GetClientRect(hWnd, &rectPreview); /* * Get the dimensions of the preview "window" and scale it to the * preview "screen" */ rectWin.left = pcpd->WindowRect.left; rectWin.top = pcpd->WindowRect.top; rectWin.right = pcpd->WindowRect.left + pcpd->WindowRect.right; rectWin.bottom = pcpd->WindowRect.top + pcpd->WindowRect.bottom; CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.left); CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.right); /* * Invalidate the area covered by the preview "window" */ InvalidateRect(hWnd, &rectWin, FALSE); } VOID PreviewPaint( PAINTSTRUCT* pPS, HWND hWnd, CONSOLEPROP_DATA * pcpd ) /*++ Paints the font preview. This is called inside the paint message handler for the preview window --*/ { RECT rectWin; RECT rectPreview; HBRUSH hbrFrame; HBRUSH hbrTitle; HBRUSH hbrOld; HBRUSH hbrClient; HBRUSH hbrBorder; HBRUSH hbrButton; HBRUSH hbrScroll; HBRUSH hbrDesktop; POINT ptButton; POINT ptScroll; HDC hDC; HBITMAP hBitmap; HBITMAP hBitmapOld; COLORREF rgbClient; /* * Get the size of the preview "screen" */ GetClientRect(hWnd, &rectPreview); /* * Get the dimensions of the preview "window" and scale it to the * preview "screen" */ rectWin = pcpd->WindowRect; CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.left); CnslAspectPoint( pcpd, &rectPreview, (POINT*)&rectWin.right); /* * Compute the dimensions of some other window components */ ptButton.x = GetSystemMetrics(SM_CXSIZE); ptButton.y = GetSystemMetrics(SM_CYSIZE); CnslAspectPoint( pcpd, &rectPreview, &ptButton); ptButton.y *= 2; /* Double the computed size for "looks" */ ptScroll.x = GetSystemMetrics(SM_CXVSCROLL); ptScroll.y = GetSystemMetrics(SM_CYHSCROLL); CnslAspectPoint( pcpd, &rectPreview, &ptScroll); /* * Create the memory device context */ hDC = CreateCompatibleDC(pPS->hdc); hBitmap = CreateCompatibleBitmap(pPS->hdc, rectPreview.right, rectPreview.bottom); hBitmapOld = SelectObject(hDC, hBitmap); /* * Create the brushes */ hbrBorder = CreateSolidBrush(GetSysColor(COLOR_ACTIVEBORDER)); hbrTitle = CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION)); hbrFrame = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME)); hbrButton = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); hbrScroll = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR)); hbrDesktop = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND)); rgbClient = GetNearestColor(hDC, ScreenBkColor(pcpd)); hbrClient = CreateSolidBrush(rgbClient); /* * Erase the clipping area */ FillRect(hDC, &(pPS->rcPaint), hbrDesktop); /* * Fill in the whole window with the client brush */ hbrOld = SelectObject(hDC, hbrClient); PatBlt(hDC, rectWin.left, rectWin.top, rectWin.right - 1, rectWin.bottom - 1, PATCOPY); /* * Fill in the caption bar */ SelectObject(hDC, hbrTitle); PatBlt(hDC, rectWin.left + 3, rectWin.top + 3, rectWin.right - 7, ptButton.y - 2, PATCOPY); /* * Draw the "buttons" */ SelectObject(hDC, hbrButton); PatBlt(hDC, rectWin.left + 3, rectWin.top + 3, ptButton.x, ptButton.y - 2, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptButton.x, rectWin.top + 3, ptButton.x, ptButton.y - 2, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 4 - 2 * ptButton.x - 1, rectWin.top + 3, ptButton.x, ptButton.y - 2, PATCOPY); SelectObject(hDC, hbrFrame); PatBlt(hDC, rectWin.left + 3 + ptButton.x, rectWin.top + 3, 1, ptButton.y - 2, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptButton.x - 1, rectWin.top + 3, 1, ptButton.y - 2, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 4 - 2 * ptButton.x - 2, rectWin.top + 3, 1, ptButton.y - 2, PATCOPY); /* * Draw the scrollbars */ SelectObject(hDC, hbrScroll); if (pcpd->PreviewFlags & PREVIEW_HSCROLL) { PatBlt(hDC, rectWin.left + 3, rectWin.top + rectWin.bottom - 4 - ptScroll.y, rectWin.right - 7, ptScroll.y, PATCOPY); } if (pcpd->PreviewFlags & PREVIEW_VSCROLL) { PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptScroll.x, rectWin.top + 1 + ptButton.y + 1, ptScroll.x, rectWin.bottom - 6 - ptButton.y, PATCOPY); if (pcpd->PreviewFlags & PREVIEW_HSCROLL) { SelectObject(hDC, hbrFrame); PatBlt(hDC, rectWin.left + rectWin.right - 5 - ptScroll.x, rectWin.top + rectWin.bottom - 4 - ptScroll.y, 1, ptScroll.y, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 4 - ptScroll.x, rectWin.top + rectWin.bottom - 5 - ptScroll.y, ptScroll.x, 1, PATCOPY); } } /* * Draw the interior window frame and caption frame */ SelectObject(hDC, hbrFrame); PatBlt(hDC, rectWin.left + 2, rectWin.top + 2, 1, rectWin.bottom - 5, PATCOPY); PatBlt(hDC, rectWin.left + 2, rectWin.top + 2, rectWin.right - 5, 1, PATCOPY); PatBlt(hDC, rectWin.left + 2, rectWin.top + rectWin.bottom - 4, rectWin.right - 5, 1, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 4, rectWin.top + 2, 1, rectWin.bottom - 5, PATCOPY); PatBlt(hDC, rectWin.left + 2, rectWin.top + 1 + ptButton.y, rectWin.right - 5, 1, PATCOPY); /* * Draw the border */ SelectObject(hDC, hbrBorder); PatBlt(hDC, rectWin.left + 1, rectWin.top + 1, 1, rectWin.bottom - 3, PATCOPY); PatBlt(hDC, rectWin.left + 1, rectWin.top + 1, rectWin.right - 3, 1, PATCOPY); PatBlt(hDC, rectWin.left + 1, rectWin.top + rectWin.bottom - 3, rectWin.right - 3, 1, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 3, rectWin.top + 1, 1, rectWin.bottom - 3, PATCOPY); /* * Draw the exterior window frame */ SelectObject(hDC, hbrFrame); PatBlt(hDC, rectWin.left, rectWin.top, 1, rectWin.bottom - 1, PATCOPY); PatBlt(hDC, rectWin.left, rectWin.top, rectWin.right - 1, 1, PATCOPY); PatBlt(hDC, rectWin.left, rectWin.top + rectWin.bottom - 2, rectWin.right - 1, 1, PATCOPY); PatBlt(hDC, rectWin.left + rectWin.right - 2, rectWin.top, 1, rectWin.bottom - 1, PATCOPY); /* * Copy the memory device context to the screen device context */ BitBlt(pPS->hdc, 0, 0, rectPreview.right, rectPreview.bottom, hDC, 0, 0, SRCCOPY); /* * Clean up everything */ SelectObject(hDC, hbrOld); SelectObject(hDC, hBitmapOld); DeleteObject(hbrBorder); DeleteObject(hbrFrame); DeleteObject(hbrTitle); DeleteObject(hbrClient); DeleteObject(hbrButton); DeleteObject(hbrScroll); DeleteObject(hbrDesktop); DeleteObject(hBitmap); DeleteDC(hDC); } #define LPCS_INDEX 0 #define PCPD_INDEX sizeof(PVOID) LRESULT PreviewWndProc( HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam ) /* * PreviewWndProc * Handles the preview window */ { PAINTSTRUCT ps; LPCREATESTRUCT lpcs; RECT rcWindow; CONSOLEPROP_DATA * pcpd; int cx; int cy; switch (wMessage) { case WM_CREATE: lpcs = (LPCREATESTRUCT)LocalAlloc( LPTR, SIZEOF( CREATESTRUCT ) ); if (lpcs) { CopyMemory( (PVOID)lpcs, (PVOID)lParam, SIZEOF( CREATESTRUCT ) ); SetWindowLongPtr( hWnd, LPCS_INDEX, (LONG_PTR)lpcs ); } else return 0; break; case CM_PREVIEW_INIT: pcpd = (CONSOLEPROP_DATA *)lParam; SetWindowLongPtr( hWnd, PCPD_INDEX, (LONG_PTR)pcpd ); /* * Figure out space used by non-client area */ SetRect(&rcWindow, 0, 0, 50, 50); AdjustWindowRect(&rcWindow, WS_OVERLAPPEDWINDOW, FALSE); pcpd->NonClientSize.x = rcWindow.right - rcWindow.left - 50; pcpd->NonClientSize.y = rcWindow.bottom - rcWindow.top - 50; /* * Compute the size of the preview "window" */ UpdatePreviewRect( pcpd ); /* * Scale the window so it has the same aspect ratio as the screen */ lpcs = (LPCREATESTRUCT)GetWindowLongPtr( hWnd, LPCS_INDEX ); cx = lpcs->cx; cy = CnslAspectScale( pcpd->yScreen, pcpd->xScreen, cx); if (cy > lpcs->cy) { cy = lpcs->cy; cx = CnslAspectScale(pcpd->xScreen, pcpd->yScreen, cy); } MoveWindow(hWnd, lpcs->x, lpcs->y, cx, cy, TRUE); break; case WM_PAINT: pcpd = (CONSOLEPROP_DATA *)GetWindowLongPtr( hWnd, PCPD_INDEX ); BeginPaint(hWnd, &ps); if (pcpd) PreviewPaint(&ps, hWnd, pcpd); EndPaint(hWnd, &ps); break; case CM_PREVIEW_UPDATE: pcpd = (CONSOLEPROP_DATA *)GetWindowLongPtr( hWnd, PCPD_INDEX ); if (pcpd) { InvalidatePreviewRect(hWnd, pcpd); UpdatePreviewRect( pcpd ); /* * Make sure the preview "screen" has the correct aspect ratio */ GetWindowRect(hWnd, &rcWindow); cx = rcWindow.right - rcWindow.left; cy = CnslAspectScale(pcpd->yScreen, pcpd->xScreen, cx); if (cy != rcWindow.bottom - rcWindow.top) { SetWindowPos(hWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); } InvalidatePreviewRect(hWnd, pcpd); } break; case WM_DESTROY: lpcs = (LPCREATESTRUCT)GetWindowLongPtr( hWnd, LPCS_INDEX ); if (lpcs) LocalFree( lpcs ); break; default: return DefWindowProc(hWnd, wMessage, wParam, lParam); } return 0L; } /* CnslAspectScale * Performs the following calculation in LONG arithmetic to avoid * overflow: * return = n1 * m / n2 * This can be used to make an aspect ration calculation where n1/n2 * is the aspect ratio and m is a known value. The return value will * be the value that corresponds to m with the correct apsect ratio. */ LONG CnslAspectScale( LONG n1, LONG n2, LONG m) { LONG Temp; Temp = n1 * m + (n2 >> 1); return Temp / n2; } /* CnslAspectPoint * Scales a point to be preview-sized instead of screen-sized. */ void CnslAspectPoint( CONSOLEPROP_DATA * pcpd, RECT* rectPreview, POINT* pt ) { pt->x = CnslAspectScale(rectPreview->right, pcpd->xScreen, pt->x); pt->y = CnslAspectScale(rectPreview->bottom, pcpd->yScreen, pt->y); }