1 /*--------------------------------------------- 2 CHECKER4.C -- Mouse Hit-Test Demo Program No.4 3 (c) Charles Petzold, 1998 4 --------------------------------------------*/ 5 6 #include <Windows.h> 7 8 #define DIVISIONS 5 9 10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 11 LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM); 12 13 int idFocus = 0; 14 TCHAR szChildClass[] = TEXT("Checker4_Child"); 15 16 int WINAPI WinMain( __in HINSTANCE hInstance 17 , __in_opt HINSTANCE hPrevInstance 18 , __in LPSTR lpCmdLine 19 , __in int nShowCmd ) 20 { 21 static TCHAR szAppName[] = TEXT("Checker4"); 22 HWND hwnd; 23 MSG msg; 24 WNDCLASS wndclass; 25 26 wndclass.style = CS_HREDRAW | CS_VREDRAW; 27 wndclass.lpfnWndProc = WndProc; 28 wndclass.cbClsExtra = 0; 29 wndclass.cbWndExtra = 0; 30 wndclass.hInstance = hInstance; 31 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 32 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 33 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 34 wndclass.lpszMenuName = NULL; 35 wndclass.lpszClassName = szAppName; 36 37 if (!RegisterClass(&wndclass)) 38 { 39 MessageBox(NULL, TEXT("Program requires Windows NT!") 40 , szAppName, MB_ICONERROR); 41 return 0; 42 } 43 44 wndclass.lpfnWndProc = ChildWndProc; 45 wndclass.cbWndExtra = sizeof(long); 46 wndclass.hIcon = NULL; 47 wndclass.lpszClassName = szChildClass; 48 49 RegisterClass(&wndclass); 50 51 hwnd = CreateWindow(szAppName, TEXT("Checker4 Mouse Hit-Test Demo") 52 , WS_OVERLAPPEDWINDOW 53 , CW_USEDEFAULT, CW_USEDEFAULT 54 , CW_USEDEFAULT, CW_USEDEFAULT 55 , NULL, NULL, hInstance, NULL); 56 57 ShowWindow(hwnd, nShowCmd); 58 UpdateWindow(hwnd); 59 60 while (GetMessage(&msg, NULL, 0, 0)) 61 { 62 TranslateMessage(&msg); 63 DispatchMessage(&msg); 64 } 65 66 return msg.wParam; 67 } 68 69 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 70 { 71 static HWND hwndChild[DIVISIONS][DIVISIONS]; 72 int cxBlock, cyBlock, x, y; 73 74 switch (message) 75 { 76 case WM_CREATE: 77 for (x = 0; x != DIVISIONS; ++x) 78 for (y = 0; y != DIVISIONS; ++y) 79 { 80 hwndChild[x][y] = CreateWindow(szChildClass, NULL 81 , WS_CHILDWINDOW | WS_VISIBLE 82 , 0, 0, 0, 0 83 , hwnd, (HMENU)(y << 8 | x) 84 , (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL); 85 } 86 return 0; 87 88 case WM_SIZE: 89 cxBlock = LOWORD(lParam) / DIVISIONS; 90 cyBlock = HIWORD(lParam) / DIVISIONS; 91 92 for (x = 0; x != DIVISIONS; ++x) 93 for (y = 0; y != DIVISIONS; ++y) 94 { 95 MoveWindow(hwndChild[x][y] 96 , x * cxBlock, y * cyBlock 97 , cxBlock, cyBlock, TRUE); 98 } 99 return 0; 100 101 case WM_LBUTTONDOWN: 102 MessageBeep(0); 103 return 0; 104 105 //on set-focus message, set focus to child window 106 case WM_SETFOCUS: 107 SetFocus(GetDlgItem(hwnd, idFocus)); 108 return 0; 109 110 //on key-down message, possibly change the focus window 111 case WM_KEYDOWN: 112 x = idFocus & 0xff; 113 y = idFocus >> 8; 114 115 switch (wParam) 116 { 117 case VK_UP: 118 --y; 119 break; 120 121 case VK_DOWN: 122 ++y; 123 break; 124 125 case VK_LEFT: 126 --x; 127 break; 128 129 case VK_RIGHT: 130 ++x; 131 break; 132 133 case VK_HOME: 134 x = y = 0; 135 break; 136 137 case VK_END: 138 x = y = DIVISIONS - 1; 139 break; 140 141 default: 142 return 0; 143 } 144 145 x = (x + DIVISIONS) % DIVISIONS; 146 y = (y + DIVISIONS) % DIVISIONS; 147 148 idFocus = y << 8 | x; 149 SetFocus(GetDlgItem(hwnd, idFocus)); 150 return 0; 151 152 case WM_DESTROY: 153 PostQuitMessage(0); 154 return 0; 155 } 156 157 return DefWindowProc(hwnd, message, wParam, lParam); 158 } 159 160 LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 161 { 162 HDC hdc; 163 PAINTSTRUCT ps; 164 RECT rect; 165 166 switch (message) 167 { 168 case WM_CREATE: 169 SetWindowLong(hwnd, DWL_MSGRESULT, 0); // on/off flag 170 return 0; 171 172 case WM_KEYDOWN: 173 //send most key press to the parent window 174 if (wParam != VK_RETURN && wParam != VK_SPACE) 175 { 176 SendMessage(GetParent(hwnd), message, wParam, lParam); 177 return 0; 178 } 179 180 //for Return and Space, fall through to toggle the square 181 case WM_LBUTTONDOWN: 182 SetWindowLong(hwnd, DWL_MSGRESULT, 1 ^ GetWindowLong(hwnd, DWL_MSGRESULT)); 183 SetFocus(hwnd); 184 InvalidateRect(hwnd, &rect, FALSE); 185 return 0; 186 187 //for focus message, invalidate the window for repaint 188 case WM_SETFOCUS: 189 idFocus = GetWindowLong(hwnd, GWL_ID); 190 191 //fall through 192 case WM_KILLFOCUS: 193 InvalidateRect(hwnd, NULL, TRUE); 194 return 0; 195 196 case WM_PAINT: 197 hdc = BeginPaint(hwnd, &ps); 198 199 GetClientRect(hwnd, &rect); 200 Rectangle(hdc, 0, 0, rect.right, rect.bottom); 201 202 //draw the "x" mark 203 if (GetWindowLong(hwnd, DWL_MSGRESULT)) 204 { 205 MoveToEx(hdc, 0, 0, NULL); 206 LineTo(hdc, rect.right, rect.bottom); 207 MoveToEx(hdc, 0, rect.bottom, NULL); 208 LineTo(hdc, rect.right, 0); 209 } 210 211 //draw the "focus" rectangle 212 if (hwnd == GetFocus()) 213 { 214 rect.left += rect.right / 10; 215 rect.right -= rect.left; 216 rect.top += rect.bottom / 10; 217 rect.bottom -= rect.top; 218 219 SelectObject(hdc, GetStockObject(NULL_BRUSH)); 220 SelectObject(hdc, CreatePen(PS_DASH, 0, 0)); 221 Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom); 222 DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN))); 223 } 224 225 EndPaint(hwnd, &ps); 226 return 0; 227 } 228 229 return DefWindowProc(hwnd, message, wParam, lParam); 230 }