reactos/modules/rostests/win32/user32/biditext/biditext.c
Baruch Rutman 1fc041c91a
[BIDITEXT] Add more demo code. (#842)
Add code that demonstrates the use of the lpOrder and lpCaretPos struct members of GCP_RESULTS w/ and  w/o GCP_REORDER flag.
Changed demo string literals to arrays containing character unicode values.
2018-09-09 18:03:48 +02:00

346 lines
11 KiB
C

/*
* PROJECT: ReactOS Tests
* FILE: rostests/win32/user32/biditext/biditext.c
* PURPOSE: Demonstrates how ExtTextOut and GetCharacterPlacement
* handle bidirectional text strings via certain selection
* of flags provided to them.
*
* PROGRAMMER: Program skeleton: https://github.com/TransmissionZero/MinGW-Win32-Application
* Test code by Baruch Rutman
*/
#include "biditext.h"
/* Prototypes */
DWORD WINAPI LpkGetCharacterPlacement(HDC hdc, LPCWSTR lpString, INT uCount, INT nMaxExtent,
GCP_RESULTSW *lpResults, DWORD dwFlags, DWORD dwUnused);
BOOL WINAPI LpkExtTextOut(HDC hdc, int x, int y,
UINT fuOptions, const RECT *lprc, LPCWSTR lpString,
UINT uCount , const INT *lpDx, INT unknown);
/* Global instance handle */
HINSTANCE g_hInstance = NULL;
/* Our application entry point */
int WINAPI
wWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpszCmdLine,
int nCmdShow)
{
INITCOMMONCONTROLSEX icc;
HWND hWnd;
HACCEL hAccelerators;
MSG msg;
/* Assign global HINSTANCE */
g_hInstance = hInstance;
/* Initialise common controls */
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icc);
/* Register our main window class, or error */
if (!RegisterMainWindowClass())
{
MessageBox(NULL, TEXT("Error registering main window class."), TEXT("Error"), MB_ICONERROR | MB_OK);
return 0;
}
/* Create our main window, or error */
if (!(hWnd = CreateMainWindow()))
{
MessageBox(NULL, TEXT("Error creating main window."), TEXT("Error"), MB_ICONERROR | MB_OK);
return 0;
}
/* Load accelerators */
hAccelerators = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR));
/* Show main window and force a paint */
ShowWindow(hWnd, nCmdShow | SW_MAXIMIZE);
UpdateWindow(hWnd);
/* Main message loop */
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
if (!TranslateAccelerator(hWnd, hAccelerators, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
/* Dialog procedure for our "about" dialog */
INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
{
WORD id = LOWORD(wParam);
switch (id)
{
case IDOK:
case IDCANCEL:
{
EndDialog(hwndDlg, (INT_PTR)id);
return (INT_PTR)TRUE;
}
}
break;
}
case WM_INITDIALOG:
{
return (INT_PTR)TRUE;
}
}
return (INT_PTR)FALSE;
}
/* Show our "about" dialog */
void ShowAboutDialog(HWND owner)
{
DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ABOUTDIALOG), owner, &AboutDialogProc);
}
/* Main window class and title */
static LPCTSTR MainWndClass = TEXT("BiDi Test");
/* Window procedure for our main window */
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
{
WORD id = LOWORD(wParam);
switch (id)
{
case ID_HELP_ABOUT:
{
ShowAboutDialog(hWnd);
return 0;
}
case ID_FILE_EXIT:
{
DestroyWindow(hWnd);
return 0;
}
}
break;
}
case WM_GETMINMAXINFO:
{
/* Prevent our window from being sized too small */
MINMAXINFO *minMax = (MINMAXINFO*)lParam;
minMax->ptMinTrackSize.x = 220;
minMax->ptMinTrackSize.y = 110;
return 0;
}
/* Item from system menu has been invoked */
case WM_SYSCOMMAND:
{
WORD id = LOWORD(wParam);
switch (id)
{
/* Show "about" dialog on about system menu item */
case ID_HELP_ABOUT:
{
ShowAboutDialog(hWnd);
return 0;
}
}
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
enum
{
ALEF = 0x5D0,
BET,
GIMEL,
DALET,
HEY,
VAV,
ZAYIN,
HET,
TET,
YUD
};
const WCHAR szString[] = {ALEF, BET, GIMEL, DALET, HEY, 'A', 'B', 'C', 'D', VAV, ZAYIN, HET, TET, YUD, 0};
const WCHAR szReversedString[] = {HEY, DALET, GIMEL, BET, ALEF, 'A', 'B', 'C', 'D', YUD, TET, HET, ZAYIN, VAV, 0};
int Len = wcslen(szString);
int i, xpos, tempLength;
WCHAR tempString[20] = { 0 };
WCHAR Glyphs[100] = { 0 };
WCHAR OutString[100] = { 0 };
INT lpCaretPos[100] = { 0 };
UINT lpOrder[100] = { 0 };
GCP_RESULTSW Results = { 0 };
Results.lStructSize = sizeof(Results);
Results.lpOutString = OutString;
Results.lpGlyphs = Glyphs;
Results.nGlyphs = 100;
Results.lpCaretPos = lpCaretPos;
Results.lpOrder = lpOrder;
SetBkMode(hdc, TRANSPARENT);
TextOutW(hdc, 10, 10, L"Proper (string being used):", 27);
TextOutW(hdc, 200, 10, szString, 14);
TextOutW(hdc, 10, 30, L"Reversed (example):", 19);
TextOutW(hdc, 200, 30, szReversedString, 14);
TextOutW(hdc, 10, 50, L"String with NULL LpkETO call (not reversed):", 44);
LpkExtTextOut(hdc, 10, 70, 0, NULL, szString, Len, NULL, 0);
TextOutW(hdc, 10, 90, L"String with ETO_IGNORELANGUAGE LpkETO call (not reversed):", 58);
LpkExtTextOut(hdc, 10, 110, ETO_IGNORELANGUAGE, NULL, szString, Len, NULL, 0);
TextOutW(hdc, 10, 130, L"String with GCP_REORDER and ETO_GLYPH_INDEX LpkGCP call (not reversed):", 71);
LpkGetCharacterPlacement(hdc, szString, Len, 0, &Results, GCP_REORDER, 0);
LpkExtTextOut(hdc, 10, 150, ETO_GLYPH_INDEX, NULL, Glyphs, Results.nGlyphs, NULL, 0);
TextOutW(hdc, 10, 170, L"String with GCP_REORDER and ETO_IGNORELANGUAGE LpkGCP call (not reversed, lpOutString):", 87);
ExtTextOutW(hdc, 10, 190, ETO_IGNORELANGUAGE, NULL, OutString, Results.nGlyphs, NULL);
TextOutW(hdc, 10, 210, L"String without GCP_REORDER and ETO_GLYPH_INDEX LpkGCP call (reversed):", 70);
LpkGetCharacterPlacement(hdc, szString, Len, 0, &Results, 0, 0);
LpkExtTextOut(hdc, 10, 230, ETO_GLYPH_INDEX, NULL, Glyphs, Results.nGlyphs, NULL, 0);
TextOutW(hdc, 10, 250, L"String without GCP_REORDER and ETO_IGNORELANGUAGE LpkGCP call (reversed, lpOutString):", 86);
ExtTextOutW(hdc, 10, 270, ETO_IGNORELANGUAGE, NULL, OutString, Len, NULL);
TextOutW(hdc, 10, 290, L"String with ETO_IGNORELANGUAGE ETO call (reversed, not Lpk direct call!):", 73);
ExtTextOutW(hdc, 10, 310, ETO_IGNORELANGUAGE, NULL, szString, Len, NULL);
TextOutW(hdc, 10, 330, L"String with ETO_RTLREADING LpkETO call (slight order change)", 60);
LpkExtTextOut(hdc, 10, 350, ETO_RTLREADING, NULL, szString, Len, NULL, 0);
TextOutW(hdc, 10, 370, L"String with ETO_RTLREADING ETO call (slight order change)", 57);
ExtTextOutW(hdc, 10, 390, ETO_RTLREADING, NULL, szString, Len, NULL);
GetCharacterPlacementW(hdc, szString, Len, 0, &Results, GCP_REORDER);
TextOutW(hdc, 10, 410, L"Glyph positions with GCP_REORDER flag", 37);
/* Prints per column the location of the character in the string, reordered location, its position and the character itself */
for (i = 0, xpos = 10; i < Len; i++, xpos += 30)
{
StringCchPrintfW(tempString, 20, L"%d", i);
tempLength = wcslen(tempString);
TextOutW(hdc, xpos, 430, tempString, tempLength);
StringCchPrintfW(tempString, 20, L"%d", lpOrder[i]);
tempLength = wcslen(tempString);
TextOutW(hdc, xpos, 450, tempString, tempLength);
StringCchPrintfW(tempString, 20, L"%d", lpCaretPos[i]);
tempLength = wcslen(tempString);
TextOutW(hdc, xpos, 470, tempString, tempLength);
TextOutW(hdc, xpos, 490, &szString[i], 1);
}
TextOutW(hdc, xpos, 430, L"Character location", 18);
TextOutW(hdc, xpos, 450, L"lpOrder[i]", 10);
TextOutW(hdc, xpos, 470, L"lpCaretPos[i]", 13);
TextOutW(hdc, xpos, 490, L"String[i]", 9);
GetCharacterPlacementW(hdc, szString, Len, 0, &Results, 0);
TextOutW(hdc, 10, 510, L"Glyph positions without GCP_REORDER flag", 40);
for (i = 0, xpos = 10; i < Len; i++, xpos += 30)
{
StringCchPrintfW(tempString, 20, L"%d", i);
tempLength = wcslen(tempString);
TextOutW(hdc, xpos, 530, tempString, tempLength);
StringCchPrintfW(tempString, 20, L"%d", lpOrder[i]);
tempLength = wcslen(tempString);
TextOutW(hdc, xpos, 550, tempString, tempLength);
StringCchPrintfW(tempString, 20, L"%d", lpCaretPos[i]);
tempLength = wcslen(tempString);
TextOutW(hdc, xpos, 570, tempString, tempLength);
TextOutW(hdc, xpos, 590, &szString[i], 1);
}
TextOutW(hdc, xpos, 530, L"Character location", 18);
TextOutW(hdc, xpos, 550, L"lpOrder[i]", 10);
TextOutW(hdc, xpos, 570, L"lpCaretPos[i]", 13);
TextOutW(hdc, xpos, 590, L"String[i]", 9);
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
/* Register a class for our main window */
BOOL RegisterMainWindowClass()
{
WNDCLASSEX wc;
/* Class for our main window */
wc.cbSize = sizeof(wc);
wc.style = 0;
wc.lpfnWndProc = &MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInstance;
wc.hIcon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE |
LR_DEFAULTCOLOR | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
wc.lpszClassName = MainWndClass;
wc.hIconSm = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
return (RegisterClassEx(&wc)) ? TRUE : FALSE;
}
/* Create an instance of our main window */
HWND CreateMainWindow()
{
/* Create instance of main window */
HWND hWnd = CreateWindowEx(0, MainWndClass, MainWndClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
NULL, NULL, g_hInstance, NULL);
if (hWnd)
{
/* Add "about" to the system menu */
HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
InsertMenu(hSysMenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
InsertMenu(hSysMenu, 6, MF_BYPOSITION, ID_HELP_ABOUT, TEXT("About"));
}
return hWnd;
}