terminal/src/propsheet/preview.cpp
pi1024e 9f95b54f2c
Change NULL to nullptr since they are pointers (#4960)
Some functions and variables are having NULL assigned to them when they are in fact pointers, so nullptr might be more accurate here.
2020-03-20 20:35:12 +00:00

451 lines
13 KiB
C++

/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
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 = { 0 };
/*
* Get the font pointer
*/
lpFont = &FontInfo[g_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 = std::max(MinSize.x, std::min<LONG>(MaxSize.x, gpStateInfo->WindowSize.X));
WindowSize.y = std::max(MinSize.y, std::min<LONG>(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 = (HBITMAP)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 = (HBRUSH)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);
}
[[nodiscard]] LRESULT
CALLBACK
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, nullptr, 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);
}