481 lines
13 KiB
C
481 lines
13 KiB
C
|
/*++
|
||
|
|
||
|
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 "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
|
||
|
/* ----- Equates ----- */
|
||
|
#define PREVIEW_HSCROLL 0x01
|
||
|
#define PREVIEW_VSCROLL 0x02
|
||
|
|
||
|
|
||
|
/* ----- Prototypes ----- */
|
||
|
|
||
|
void AspectPoint(
|
||
|
RECT* rectPreview,
|
||
|
POINT* pt);
|
||
|
|
||
|
LONG AspectScale(
|
||
|
LONG n1,
|
||
|
LONG n2,
|
||
|
LONG m);
|
||
|
|
||
|
|
||
|
/* ----- Globals ----- */
|
||
|
|
||
|
POINT NonClientSize;
|
||
|
RECT WindowRect;
|
||
|
DWORD PreviewFlags;
|
||
|
|
||
|
|
||
|
VOID
|
||
|
UpdatePreviewRect(VOID)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Update the global window size and dimensions
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
POINT MinSize;
|
||
|
POINT MaxSize;
|
||
|
POINT WindowSize;
|
||
|
PFONT_INFO lpFont;
|
||
|
HMONITOR hMonitor;
|
||
|
MONITORINFO mi;
|
||
|
|
||
|
/*
|
||
|
* Get the font pointer
|
||
|
*/
|
||
|
lpFont = &FontInfo[CurrentFontIndex];
|
||
|
|
||
|
/*
|
||
|
* Get the window size
|
||
|
*/
|
||
|
MinSize.x = (GetSystemMetrics(SM_CXMIN)-NonClientSize.x) / lpFont->Size.X;
|
||
|
MinSize.y = (GetSystemMetrics(SM_CYMIN)-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, gpStateInfo->WindowSize.X));
|
||
|
WindowSize.y = max(MinSize.y, min(MaxSize.y, gpStateInfo->WindowSize.Y));
|
||
|
|
||
|
/*
|
||
|
* Get the window rectangle, making sure it's at least twice the
|
||
|
* size of the non-client area.
|
||
|
*/
|
||
|
WindowRect.left = gpStateInfo->WindowPosX;
|
||
|
WindowRect.top = gpStateInfo->WindowPosY;
|
||
|
WindowRect.right = WindowSize.x * lpFont->Size.X + NonClientSize.x;
|
||
|
if (WindowRect.right < NonClientSize.x * 2) {
|
||
|
WindowRect.right = NonClientSize.x * 2;
|
||
|
}
|
||
|
WindowRect.right += WindowRect.left;
|
||
|
WindowRect.bottom = WindowSize.y * lpFont->Size.Y + NonClientSize.y;
|
||
|
if (WindowRect.bottom < NonClientSize.y * 2) {
|
||
|
WindowRect.bottom = NonClientSize.y * 2;
|
||
|
}
|
||
|
WindowRect.bottom += WindowRect.top;
|
||
|
|
||
|
/*
|
||
|
* Get information about the monitor we're on
|
||
|
*/
|
||
|
hMonitor = MonitorFromRect(&WindowRect, MONITOR_DEFAULTTONEAREST);
|
||
|
mi.cbSize = sizeof(mi);
|
||
|
GetMonitorInfo(hMonitor, &mi);
|
||
|
gcxScreen = mi.rcWork.right - mi.rcWork.left;
|
||
|
gcyScreen = mi.rcWork.bottom - mi.rcWork.top;
|
||
|
|
||
|
/*
|
||
|
* Convert window rectangle to monitor relative coordinates
|
||
|
*/
|
||
|
WindowRect.right -= WindowRect.left;
|
||
|
WindowRect.left -= mi.rcWork.left;
|
||
|
WindowRect.bottom -= WindowRect.top;
|
||
|
WindowRect.top -= mi.rcWork.top;
|
||
|
|
||
|
/*
|
||
|
* Update the display flags
|
||
|
*/
|
||
|
if (WindowSize.x < gpStateInfo->ScreenBufferSize.X) {
|
||
|
PreviewFlags |= PREVIEW_HSCROLL;
|
||
|
} else {
|
||
|
PreviewFlags &= ~PREVIEW_HSCROLL;
|
||
|
}
|
||
|
if (WindowSize.y < gpStateInfo->ScreenBufferSize.Y) {
|
||
|
PreviewFlags |= PREVIEW_VSCROLL;
|
||
|
} else {
|
||
|
PreviewFlags &= ~PREVIEW_VSCROLL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
InvalidatePreviewRect(HWND hWnd)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
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 = WindowRect.left;
|
||
|
rectWin.top = WindowRect.top;
|
||
|
rectWin.right = WindowRect.left + WindowRect.right;
|
||
|
rectWin.bottom = WindowRect.top + WindowRect.bottom;
|
||
|
AspectPoint(&rectPreview, (POINT*)&rectWin.left);
|
||
|
AspectPoint(&rectPreview, (POINT*)&rectWin.right);
|
||
|
|
||
|
/*
|
||
|
* Invalidate the area covered by the preview "window"
|
||
|
*/
|
||
|
InvalidateRect(hWnd, &rectWin, FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PreviewPaint(
|
||
|
PAINTSTRUCT* pPS,
|
||
|
HWND hWnd
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
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 = WindowRect;
|
||
|
AspectPoint(&rectPreview, (POINT*)&rectWin.left);
|
||
|
AspectPoint(&rectPreview, (POINT*)&rectWin.right);
|
||
|
|
||
|
/*
|
||
|
* Compute the dimensions of some other window components
|
||
|
*/
|
||
|
ptButton.x = GetSystemMetrics(SM_CXSIZE);
|
||
|
ptButton.y = GetSystemMetrics(SM_CYSIZE);
|
||
|
AspectPoint(&rectPreview, &ptButton);
|
||
|
ptButton.y *= 2; /* Double the computed size for "looks" */
|
||
|
ptScroll.x = GetSystemMetrics(SM_CXVSCROLL);
|
||
|
ptScroll.y = GetSystemMetrics(SM_CYHSCROLL);
|
||
|
AspectPoint(&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(gpStateInfo));
|
||
|
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 (PreviewFlags & PREVIEW_HSCROLL) {
|
||
|
PatBlt(hDC, rectWin.left + 3,
|
||
|
rectWin.top + rectWin.bottom - 4 - ptScroll.y,
|
||
|
rectWin.right - 7, ptScroll.y, PATCOPY);
|
||
|
}
|
||
|
if (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 (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);
|
||
|
}
|
||
|
|
||
|
|
||
|
LRESULT
|
||
|
PreviewWndProc(
|
||
|
HWND hWnd,
|
||
|
UINT wMessage,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
|
||
|
/*
|
||
|
* PreviewWndProc
|
||
|
* Handles the preview window
|
||
|
*/
|
||
|
|
||
|
{
|
||
|
PAINTSTRUCT ps;
|
||
|
LPCREATESTRUCT lpcs;
|
||
|
RECT rcWindow;
|
||
|
int cx;
|
||
|
int cy;
|
||
|
|
||
|
switch (wMessage) {
|
||
|
case WM_CREATE:
|
||
|
/*
|
||
|
* Figure out space used by non-client area
|
||
|
*/
|
||
|
SetRect(&rcWindow, 0, 0, 50, 50);
|
||
|
AdjustWindowRect(&rcWindow, WS_OVERLAPPEDWINDOW, FALSE);
|
||
|
NonClientSize.x = rcWindow.right - rcWindow.left - 50;
|
||
|
NonClientSize.y = rcWindow.bottom - rcWindow.top - 50;
|
||
|
|
||
|
/*
|
||
|
* Compute the size of the preview "window"
|
||
|
*/
|
||
|
UpdatePreviewRect();
|
||
|
|
||
|
/*
|
||
|
* Scale the window so it has the same aspect ratio as the screen
|
||
|
*/
|
||
|
lpcs = (LPCREATESTRUCT)lParam;
|
||
|
cx = lpcs->cx;
|
||
|
cy = AspectScale(gcyScreen, gcxScreen, cx);
|
||
|
if (cy > lpcs->cy) {
|
||
|
cy = lpcs->cy;
|
||
|
cx = AspectScale(gcxScreen, gcyScreen, cy);
|
||
|
}
|
||
|
MoveWindow(hWnd, lpcs->x, lpcs->y, cx, cy, TRUE);
|
||
|
break;
|
||
|
|
||
|
case WM_PAINT:
|
||
|
BeginPaint(hWnd, &ps);
|
||
|
PreviewPaint(&ps, hWnd);
|
||
|
EndPaint(hWnd, &ps);
|
||
|
break;
|
||
|
|
||
|
case CM_PREVIEW_UPDATE:
|
||
|
InvalidatePreviewRect(hWnd);
|
||
|
UpdatePreviewRect();
|
||
|
|
||
|
/*
|
||
|
* Make sure the preview "screen" has the correct aspect ratio
|
||
|
*/
|
||
|
GetWindowRect(hWnd, &rcWindow);
|
||
|
cx = rcWindow.right - rcWindow.left;
|
||
|
cy = AspectScale(gcyScreen, gcxScreen, cx);
|
||
|
if (cy != rcWindow.bottom - rcWindow.top) {
|
||
|
SetWindowPos(hWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
||
|
}
|
||
|
|
||
|
InvalidatePreviewRect(hWnd);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return DefWindowProc(hWnd, wMessage, wParam, lParam);
|
||
|
}
|
||
|
return 0L;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* AspectScale
|
||
|
* 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 AspectScale(
|
||
|
LONG n1,
|
||
|
LONG n2,
|
||
|
LONG m)
|
||
|
{
|
||
|
LONG Temp;
|
||
|
|
||
|
Temp = n1 * m + (n2 >> 1);
|
||
|
return Temp / n2;
|
||
|
}
|
||
|
|
||
|
/* AspectPoint
|
||
|
* Scales a point to be preview-sized instead of screen-sized.
|
||
|
*/
|
||
|
|
||
|
void AspectPoint(
|
||
|
RECT* rectPreview,
|
||
|
POINT* pt)
|
||
|
{
|
||
|
pt->x = AspectScale(rectPreview->right, gcxScreen, pt->x);
|
||
|
pt->y = AspectScale(rectPreview->bottom, gcyScreen, pt->y);
|
||
|
}
|