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.
646 lines
16 KiB
646 lines
16 KiB
//// TEXTWND.CPP
|
|
//
|
|
// Maintains the text display panel
|
|
|
|
|
|
|
|
#include "precomp.hxx"
|
|
#include "global.h"
|
|
#include "winspool.h"
|
|
#include <Tchar.h>
|
|
|
|
|
|
|
|
|
|
//// InvalidateText - Force redisplay
|
|
//
|
|
//
|
|
|
|
void InvalidateText() {
|
|
RECT rc;
|
|
rc.left = g_fPresentation ? 0 : g_iSettingsWidth;
|
|
rc.top = 0;
|
|
rc.right = 10000;
|
|
rc.bottom = 10000;
|
|
InvalidateRect(g_hTextWnd, &rc, TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// Header - draw a simple header for each text section
|
|
//
|
|
// Used to distinguish logical, plaintext and formatted text sections of
|
|
// text window.
|
|
//
|
|
// Advances SEPARATORHEIGHT drawing a horizontal line 2/5ths of the way
|
|
// down, and displays a title below the line.
|
|
//
|
|
// At the top of the page displays only the title.
|
|
|
|
void Header(HDC hdc, char* str, RECT *prc, int *piY) {
|
|
|
|
HFONT hf;
|
|
HFONT hfold;
|
|
RECT rcClear;
|
|
|
|
int iLinePos;
|
|
int iTextPos;
|
|
int iFontEmHeight;
|
|
int iHeight;
|
|
|
|
int separatorHeight = (prc->bottom - prc->top) / 20;
|
|
|
|
iFontEmHeight = separatorHeight*40/100;
|
|
|
|
if (*piY <= prc->top)
|
|
{
|
|
// Prepare settings for title only, at top of window
|
|
iLinePos = -1;
|
|
iTextPos = 0;
|
|
iHeight = separatorHeight*60/100;
|
|
|
|
}
|
|
else
|
|
{
|
|
// Prepare settings for 40% white space, a line, 10% whitespace, text and 3% whitespace
|
|
iLinePos = separatorHeight*30/100;
|
|
iTextPos = separatorHeight*40/100;
|
|
iHeight = separatorHeight;
|
|
}
|
|
|
|
|
|
rcClear = *prc;
|
|
rcClear.top = *piY;
|
|
rcClear.bottom = *piY + iHeight;
|
|
FillRect(hdc, &rcClear, (HBRUSH) GetStockObject(WHITE_BRUSH));
|
|
|
|
|
|
if (*piY > prc->top) {
|
|
|
|
// Separate from previous output with double pixel line
|
|
|
|
MoveToEx(hdc, prc->left, *piY+iLinePos, NULL);
|
|
LineTo (hdc, prc->right, *piY+iLinePos);
|
|
MoveToEx(hdc, prc->left, *piY+iLinePos+1, NULL);
|
|
LineTo (hdc, prc->right, *piY+iLinePos+1);
|
|
}
|
|
|
|
|
|
hf = CreateFontA(-iFontEmHeight, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, "Tahoma");
|
|
hfold = (HFONT) SelectObject(hdc, hf);
|
|
ExtTextOutA(hdc, prc->left, *piY + iTextPos, 0, prc, str, strlen(str), NULL);
|
|
|
|
*piY += iHeight;
|
|
|
|
SelectObject(hdc, hfold);
|
|
DeleteObject(hf);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// ResetCaret - used during paint by each DSP*.CPP
|
|
//
|
|
//
|
|
|
|
|
|
void ResetCaret(int iX, int iY, int iHeight) {
|
|
|
|
g_iCaretX = iX;
|
|
g_iCaretY = iY;
|
|
|
|
if (g_iCaretHeight != iHeight) {
|
|
g_iCaretHeight = iHeight;
|
|
HideCaret(g_hTextWnd);
|
|
DestroyCaret();
|
|
CreateCaret(g_hTextWnd, NULL, 0, g_iCaretHeight);
|
|
SetCaretPos(g_iCaretX, g_iCaretY);
|
|
ShowCaret(g_hTextWnd);
|
|
} else {
|
|
SetCaretPos(g_iCaretX, g_iCaretY);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
///// PaintDC - display all selected tests, either on screen
|
|
// or on printer.
|
|
|
|
void PaintDC(HDC hdc, BOOL presentation, RECT &rcText, INT &iY)
|
|
{
|
|
int iPos;
|
|
int iLineHeight;
|
|
|
|
iY = rcText.top;
|
|
|
|
if (presentation) {
|
|
iLineHeight = rcText.bottom*9/20;
|
|
} else {
|
|
iLineHeight = 40;
|
|
}
|
|
|
|
|
|
if (g_ShowGDI) {
|
|
if (!presentation) {
|
|
Header(hdc, "GDI", &rcText, &iY);
|
|
}
|
|
PaintGDI(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
if (g_ShowFamilies) {
|
|
if (!presentation) {
|
|
Header(hdc, "Font families", &rcText, &iY);
|
|
}
|
|
PaintFamilies(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
|
|
if (g_ShowLogical) {
|
|
if (!presentation) {
|
|
Header(hdc, "Logical characters (ScriptGetCmap, ExtTextOut(ETO_GLYPHINDEX))", &rcText, &iY);
|
|
}
|
|
PaintLogical(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
|
|
if (g_ShowGlyphs) {
|
|
if (!presentation) {
|
|
Header(hdc, "DrawGlyphs", &rcText, &iY);
|
|
}
|
|
PaintGlyphs(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
|
|
if (g_ShowDrawString) {
|
|
if (!presentation) {
|
|
Header(hdc, "DrawString", &rcText, &iY);
|
|
}
|
|
PaintDrawString(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
|
|
if (g_ShowDriver) {
|
|
if (!presentation) {
|
|
Header(hdc, "DrawDriverString", &rcText, &iY);
|
|
}
|
|
PaintDrawDriverString(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
|
|
if (g_ShowPath) {
|
|
if (!presentation) {
|
|
Header(hdc, "Path", &rcText, &iY);
|
|
}
|
|
PaintPath(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
if (g_ShowMetric) {
|
|
if (!presentation) {
|
|
Header(hdc, "Metrics", &rcText, &iY);
|
|
}
|
|
PaintMetrics(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
if (g_ShowPerformance) {
|
|
if (!presentation) {
|
|
Header(hdc, "Performance", &rcText, &iY);
|
|
}
|
|
PaintPerformance(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
if (g_ShowScaling) {
|
|
if (!presentation) {
|
|
Header(hdc, "Scaling", &rcText, &iY);
|
|
}
|
|
PaintScaling(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
|
|
|
|
/*
|
|
if (g_fShowFancyText && !presentation) {
|
|
Header(hdc, "Formatted text (ScriptItemize, ScriptLayout, ScriptShape, ScriptPlace, ScriptTextOut)", &rcText, &iY);
|
|
PaintFormattedText(hdc, &iY, &rcText, iLineHeight);
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//// Paint - redraw part or all of client area
|
|
//
|
|
//
|
|
|
|
|
|
void PaintWindow(HWND hWnd) {
|
|
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
RECT rcText;
|
|
RECT rcClear;
|
|
int iY;
|
|
|
|
hdc = BeginPaint(hWnd, &ps);
|
|
|
|
// Remove the settings dialog from the repaint rectangle
|
|
|
|
|
|
if (ps.fErase) {
|
|
|
|
// Clear below the settings dialog
|
|
|
|
if (!g_fPresentation) {
|
|
|
|
rcClear = ps.rcPaint;
|
|
if (rcClear.right > g_iSettingsWidth) {
|
|
rcClear.right = g_iSettingsWidth;
|
|
}
|
|
if (rcClear.top < g_iSettingsHeight) {
|
|
rcClear.top = g_iSettingsHeight;
|
|
}
|
|
|
|
FillRect(ps.hdc, &rcClear, (HBRUSH) GetStockObject(WHITE_BRUSH));
|
|
}
|
|
}
|
|
|
|
|
|
// Clear top and left margin
|
|
|
|
GetClientRect(hWnd, &rcText);
|
|
|
|
// Left margin
|
|
|
|
rcClear = rcText;
|
|
rcClear.left = g_fPresentation ? 0 : g_iSettingsWidth;
|
|
rcClear.right = rcClear.left + 10;
|
|
FillRect(ps.hdc, &rcClear, (HBRUSH) GetStockObject(WHITE_BRUSH));
|
|
|
|
|
|
// Top margin
|
|
|
|
rcClear = rcText;
|
|
rcClear.left = g_fPresentation ? 0 : g_iSettingsWidth;
|
|
rcClear.top = 0;
|
|
rcClear.bottom = 8;
|
|
FillRect(ps.hdc, &rcClear, (HBRUSH) GetStockObject(WHITE_BRUSH));
|
|
|
|
rcText.left = g_fPresentation ? 10 : g_iSettingsWidth + 10;
|
|
rcText.top = 8;
|
|
|
|
|
|
if (!g_Offscreen)
|
|
{
|
|
PaintDC(hdc, g_fPresentation, rcText, iY);
|
|
}
|
|
else
|
|
{
|
|
// Render everything to an offscreen buffer instead of
|
|
// directly to the display surface...
|
|
HBITMAP hbmpOffscreen = NULL;
|
|
HDC hdcOffscreen = NULL;
|
|
RECT rectOffscreen;
|
|
|
|
rectOffscreen.left = 0;
|
|
rectOffscreen.top = 0;
|
|
rectOffscreen.right = rcText.right - rcText.left;
|
|
rectOffscreen.bottom = rcText.bottom - rcText.top;
|
|
|
|
hbmpOffscreen = CreateCompatibleBitmap(hdc, rectOffscreen.right, rectOffscreen.bottom);
|
|
|
|
if (hbmpOffscreen)
|
|
{
|
|
hdcOffscreen = CreateCompatibleDC(hdc);
|
|
|
|
if (hdcOffscreen)
|
|
{
|
|
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcOffscreen, hbmpOffscreen);
|
|
|
|
PaintDC(hdcOffscreen, g_fPresentation, rectOffscreen, iY);
|
|
|
|
StretchBlt(
|
|
hdc,
|
|
rcText.left,
|
|
rcText.top,
|
|
rectOffscreen.right,
|
|
rectOffscreen.bottom,
|
|
hdcOffscreen,
|
|
0,
|
|
0,
|
|
rectOffscreen.right,
|
|
rectOffscreen.bottom,
|
|
SRCCOPY);
|
|
|
|
SelectObject(hdcOffscreen, (HGDIOBJ)hbmpOld);
|
|
|
|
DeleteDC(hdcOffscreen);
|
|
}
|
|
|
|
DeleteObject(hbmpOffscreen);
|
|
}
|
|
}
|
|
|
|
// Clear any remaining space below the text
|
|
|
|
if ( ps.fErase
|
|
&& iY < rcText.bottom) {
|
|
|
|
rcClear = rcText;
|
|
rcClear.top = iY;
|
|
FillRect(ps.hdc, &rcClear, (HBRUSH) GetStockObject(WHITE_BRUSH));
|
|
}
|
|
|
|
|
|
EndPaint(hWnd, &ps);
|
|
}
|
|
|
|
|
|
|
|
void PrintPage()
|
|
{
|
|
PRINTDLG printDialog;
|
|
|
|
memset(&printDialog, 0, sizeof(printDialog));
|
|
|
|
printDialog.lStructSize = sizeof(printDialog);
|
|
printDialog.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION ;
|
|
|
|
if (PrintDlg(&printDialog))
|
|
{
|
|
HDC dc = printDialog.hDC;
|
|
|
|
if (dc != NULL)
|
|
{
|
|
DOCINFO documentInfo;
|
|
documentInfo.cbSize = sizeof(documentInfo);
|
|
documentInfo.lpszDocName = _T("TextTest");
|
|
documentInfo.lpszOutput = NULL;
|
|
documentInfo.lpszDatatype = NULL;
|
|
documentInfo.fwType = 0;
|
|
|
|
if (StartDoc(dc, &documentInfo))
|
|
{
|
|
if (StartPage(dc) > 0)
|
|
{
|
|
RECT rcText;
|
|
INT iY;
|
|
|
|
rcText.left = 0;
|
|
rcText.top = 0;
|
|
rcText.right = GetDeviceCaps(dc, HORZRES);
|
|
rcText.bottom = GetDeviceCaps(dc, VERTRES);
|
|
|
|
PaintDC(dc, FALSE, rcText, iY);
|
|
EndPage(dc);
|
|
}
|
|
|
|
EndDoc(dc);
|
|
}
|
|
|
|
DeleteDC(dc);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//// TextWndProc - Main window message handler and dispatcher
|
|
//
|
|
//
|
|
|
|
|
|
LRESULT CALLBACK TextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
|
|
HDC hdc;
|
|
|
|
switch (message) {
|
|
|
|
case WM_CREATE:
|
|
hdc = GetDC(hWnd);
|
|
g_iLogPixelsY = GetDeviceCaps(hdc, LOGPIXELSY);
|
|
ReleaseDC(hWnd, hdc);
|
|
break;
|
|
|
|
|
|
case WM_ERASEBKGND:
|
|
return 0; // Leave Paint to erase the background
|
|
|
|
|
|
case WM_CHAR:
|
|
|
|
if (!g_bUnicodeWnd) {
|
|
|
|
// Convert ANSI keyboard data to Unicode
|
|
|
|
int iCP;
|
|
|
|
switch (PRIMARYLANGID(LOWORD(GetKeyboardLayout(NULL)))) {
|
|
case LANG_ARABIC: iCP = 1256; break;
|
|
case LANG_HEBREW: iCP = 1255; break;
|
|
case LANG_THAI: iCP = 874; break;
|
|
default: iCP = 1252; break;
|
|
}
|
|
|
|
MultiByteToWideChar(iCP, 0, (char*)&wParam, 1, (WCHAR*)&wParam, 1);
|
|
}
|
|
|
|
if (LOWORD(wParam) == 0x1B) {
|
|
|
|
// Exit presentation mode
|
|
|
|
g_fPresentation = FALSE;
|
|
ShowWindow(g_hSettingsDlg, SW_SHOW);
|
|
UpdateWindow(g_hSettingsDlg);
|
|
InvalidateText();
|
|
|
|
} else {
|
|
|
|
EditChar(LOWORD(wParam));
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case WM_KEYDOWN:
|
|
EditKeyDown(LOWORD(wParam));
|
|
break;
|
|
|
|
|
|
case WM_KEYUP:
|
|
|
|
if (wParam != VK_ESCAPE) {
|
|
goto DefaultWindowProcedure;
|
|
}
|
|
// Eat all escape key processing
|
|
break;
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
g_iMouseDownX = LOWORD(lParam); // horizontal position of cursor
|
|
g_iMouseDownY = HIWORD(lParam); // vertical position of cursor
|
|
g_fMouseDown = TRUE;
|
|
SetFocus(hWnd);
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
// Treat movement like lbuttonup while lbutton is down,
|
|
// so the selection tracks the cursor movement.
|
|
if (wParam & MK_LBUTTON) {
|
|
g_iMouseUpX = LOWORD(lParam); // horizontal position of cursor
|
|
g_iMouseUpY = HIWORD(lParam); // vertical position of cursor
|
|
g_fMouseUp = TRUE;
|
|
InvalidateText();
|
|
SetActiveWindow(hWnd);
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_LBUTTONUP:
|
|
g_iMouseUpX = LOWORD(lParam); // horizontal position of cursor
|
|
g_iMouseUpY = HIWORD(lParam); // vertical position of cursor
|
|
g_fMouseUp = TRUE;
|
|
InvalidateText();
|
|
SetActiveWindow(hWnd);
|
|
break;
|
|
|
|
|
|
case WM_SETFOCUS:
|
|
CreateCaret(hWnd, NULL, 0, g_iCaretHeight);
|
|
SetCaretPos(g_iCaretX, g_iCaretY);
|
|
ShowCaret(hWnd);
|
|
break;
|
|
|
|
|
|
case WM_KILLFOCUS:
|
|
DestroyCaret();
|
|
break;
|
|
|
|
|
|
case WM_GETMINMAXINFO:
|
|
|
|
// Don't let text window size drop too low
|
|
|
|
((LPMINMAXINFO)lParam)->ptMinTrackSize.x = g_fPresentation ? 10 : g_iMinWidth;
|
|
((LPMINMAXINFO)lParam)->ptMinTrackSize.y = g_fPresentation ? 10 : g_iMinHeight;
|
|
return 0;
|
|
|
|
|
|
case WM_PAINT:
|
|
PaintWindow(hWnd);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
if (g_textBrush)
|
|
delete g_textBrush;
|
|
|
|
if (g_textBackBrush)
|
|
delete g_textBackBrush;
|
|
|
|
DestroyWindow(g_hSettingsDlg);
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
|
|
default:
|
|
DefaultWindowProcedure:
|
|
if (g_bUnicodeWnd) {
|
|
return DefWindowProcW(hWnd, message, wParam, lParam);
|
|
} else {
|
|
return DefWindowProcA(hWnd, message, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// CreateTextWindow - create window class and window
|
|
//
|
|
// Attempts to use a Unicode window, if this fails uses an ANSI
|
|
// window.
|
|
//
|
|
// For example the Unicode window will succeed on Windows NT and
|
|
// Windows CE, but fail on Windows 9x.
|
|
|
|
|
|
HWND CreateTextWindow() {
|
|
|
|
WNDCLASSA wcA;
|
|
WNDCLASSW wcW;
|
|
HWND hWnd;
|
|
|
|
// Try registering as a Unicode window
|
|
|
|
wcW.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcW.lpfnWndProc = TextWndProc;
|
|
wcW.cbClsExtra = 0;
|
|
wcW.cbWndExtra = 0;
|
|
wcW.hInstance = g_hInstance;
|
|
wcW.hIcon = LoadIconW(g_hInstance, APPNAMEW);
|
|
wcW.hCursor = LoadCursorW(NULL, (WCHAR*)IDC_ARROW);
|
|
wcW.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
|
wcW.lpszMenuName = APPNAMEW;
|
|
wcW.lpszClassName = APPNAMEW;
|
|
|
|
if (RegisterClassW(&wcW)) {
|
|
|
|
// Use a Unicode window
|
|
|
|
g_bUnicodeWnd = TRUE;
|
|
|
|
hWnd = CreateWindowW(
|
|
APPNAMEW, APPTITLEW,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, 0,
|
|
CW_USEDEFAULT, 0,
|
|
NULL, NULL,
|
|
g_hInstance,
|
|
NULL);
|
|
|
|
|
|
return hWnd;
|
|
|
|
} else {
|
|
|
|
// Must use an ANSI window.
|
|
|
|
wcA.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcA.lpfnWndProc = TextWndProc;
|
|
wcA.cbClsExtra = 0;
|
|
wcA.cbWndExtra = 0;
|
|
wcA.hInstance = g_hInstance;
|
|
wcA.hIcon = LoadIconA(g_hInstance, APPNAMEA);
|
|
wcA.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcA.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
|
wcA.lpszMenuName = APPNAMEA;
|
|
wcA.lpszClassName = APPNAMEA;
|
|
|
|
if (!RegisterClassA(&wcA)) {
|
|
return NULL;
|
|
}
|
|
|
|
g_bUnicodeWnd = FALSE;
|
|
|
|
hWnd = CreateWindowA(
|
|
APPNAMEA, APPTITLEA,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, 0,
|
|
CW_USEDEFAULT, 0,
|
|
NULL, NULL,
|
|
g_hInstance,
|
|
NULL);
|
|
};
|
|
|
|
|
|
return hWnd;
|
|
}
|