//// TEXTWND.CPP // // Maintains the text display panel #include "precomp.hxx" #include "global.h" #include "winspool.h" #include //// 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; }