[CSRSRV]
[reactos.git] / base / applications / magnify / magnifier.c
1 /*
2 * PROJECT: ReactOS Magnify
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/magnify/magnifier.c
5 * PURPOSE: Magnification of parts of the screen.
6 * COPYRIGHT: Copyright 2007 Marc Piulachs <marc.piulachs@codexchange.net>
7 *
8 */
9
10 /* TODO: AppBar */
11 #include "magnifier.h"
12
13 const TCHAR szWindowClass[] = TEXT("MAGNIFIER");
14
15 #define MAX_LOADSTRING 100
16
17 // Global Variables:
18 HINSTANCE hInst; // current instance
19 HWND hMainWnd;
20
21 TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
22
23 #define REPAINT_SPEED 100
24
25 HWND hDesktopWindow = NULL;
26
27 //Current magnified area
28 POINT cp;
29
30 //Last positions
31 POINT pMouse;
32 POINT pCaret;
33 POINT pFocus;
34
35 // Forward declarations of functions included in this code module:
36 ATOM MyRegisterClass(HINSTANCE hInstance);
37 BOOL InitInstance(HINSTANCE, int);
38 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
39 INT_PTR CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
40 INT_PTR CALLBACK OptionsProc(HWND, UINT, WPARAM, LPARAM);
41 INT_PTR CALLBACK WarningProc(HWND, UINT, WPARAM, LPARAM);
42
43 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
44 {
45 // TODO: Place code here.
46 MSG msg;
47 HACCEL hAccelTable;
48
49 UNREFERENCED_PARAMETER(hPrevInstance);
50 UNREFERENCED_PARAMETER(lpCmdLine);
51
52 // Initialize global strings
53 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
54 MyRegisterClass(hInstance);
55
56 // Perform application initialization:
57 if (!InitInstance (hInstance, nCmdShow))
58 {
59 return FALSE;
60 }
61
62 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MAGNIFIER));
63
64 // Main message loop:
65 while (GetMessage(&msg, NULL, 0, 0))
66 {
67 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
68 {
69 TranslateMessage(&msg);
70 DispatchMessage(&msg);
71 }
72 }
73
74 return (int) msg.wParam;
75 }
76
77
78
79 /*
80 * FUNCTION: MyRegisterClass()
81 *
82 * PURPOSE: Registers the window class.
83 *
84 * COMMENTS:
85 *
86 * This function and its usage are only necessary if you want this code
87 * to be compatible with Win32 systems prior to the 'RegisterClassEx'
88 * function that was added to Windows 95. It is important to call this function
89 * so that the application will get 'well formed' small icons associated
90 * with it.
91 */
92 ATOM MyRegisterClass(HINSTANCE hInstance)
93 {
94 WNDCLASS wc;
95
96 wc.style = CS_HREDRAW | CS_VREDRAW;
97 wc.lpfnWndProc = WndProc;
98 wc.cbClsExtra = 0;
99 wc.cbWndExtra = 0;
100 wc.hInstance = hInstance;
101 wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
102 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
103 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
104 wc.lpszMenuName = MAKEINTRESOURCE(IDC_MAGNIFIER);
105 wc.lpszClassName = szWindowClass;
106
107 return RegisterClass(&wc);
108 }
109
110 /*
111 * FUNCTION: InitInstance(HINSTANCE, int)
112 *
113 * PURPOSE: Saves instance handle and creates main window
114 *
115 * COMMENTS:
116 *
117 * In this function, we save the instance handle in a global variable and
118 * create and display the main program window.
119 */
120 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
121 {
122 RECT rcWorkArea;
123 hInst = hInstance; // Store instance handle in our global variable
124
125 SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
126
127 /* Create the Window */
128 hMainWnd = CreateWindowEx(
129 WS_EX_TOPMOST | WS_EX_PALETTEWINDOW,
130 szWindowClass,
131 szTitle,
132 WS_OVERLAPPEDWINDOW,
133 CW_USEDEFAULT,
134 CW_USEDEFAULT,
135 (rcWorkArea.right - rcWorkArea.left) * 2 / 3,
136 200,
137 NULL,
138 NULL,
139 hInstance,
140 NULL);
141
142 if (!hMainWnd)
143 {
144 return FALSE;
145 }
146
147 ShowWindow(hMainWnd, (bStartMinimized) ? SW_MINIMIZE : nCmdShow);
148 UpdateWindow(hMainWnd);
149
150 if (bShowWarning)
151 {
152 DialogBox (hInstance, MAKEINTRESOURCE(IDD_WARNINGDIALOG), hMainWnd, (DLGPROC)WarningProc);
153 }
154
155 return TRUE;
156 }
157
158 void Refresh ()
159 {
160 if (!IsIconic(hMainWnd))
161 {
162 // Invalidate the client area forcing a WM_PAINT message
163 InvalidateRgn(hMainWnd, NULL, TRUE);
164 }
165 }
166
167 void Draw(HDC aDc)
168 {
169 HDC desktopHdc = NULL;
170 HDC HdcStrech;
171 HANDLE hOld;
172 HBITMAP HbmpStrech;
173
174 RECT R;
175 RECT appRect;
176 DWORD rop = SRCCOPY;
177 CURSORINFO cinfo;
178 ICONINFO iinfo;
179
180 int Width, Height, AppWidth, AppHeight;
181 LONG blitAreaWidth, blitAreaHeight, blitAreaX, blitAreaY;
182
183 desktopHdc = GetWindowDC (hDesktopWindow);
184
185 GetClientRect(hMainWnd, &appRect);
186 GetWindowRect(hDesktopWindow, &R);
187
188 ZeroMemory(&cinfo, sizeof(CURSORINFO));
189 ZeroMemory(&iinfo, sizeof(ICONINFO));
190 cinfo.cbSize = sizeof(cinfo);
191 GetCursorInfo(&cinfo);
192 GetIconInfo(cinfo.hCursor, &iinfo);
193
194 /* Create a memory DC compatible with client area DC.*/
195 HdcStrech = CreateCompatibleDC(desktopHdc);
196
197 /* Create a bitmap compatible with the client area DC.*/
198 HbmpStrech = CreateCompatibleBitmap(
199 desktopHdc,
200 R.right,
201 R.bottom);
202
203 /* Select our bitmap in memory DC and save the old one.*/
204 hOld = SelectObject (HdcStrech , HbmpStrech);
205
206 /* Paint the screen bitmap to our in memory DC */
207 BitBlt(
208 HdcStrech,
209 0,
210 0,
211 R.right,
212 R.bottom,
213 desktopHdc,
214 0,
215 0,
216 SRCCOPY);
217
218 /* Draw the mouse pointer in the right position */
219 DrawIcon(
220 HdcStrech ,
221 pMouse.x - iinfo.xHotspot, // - 10,
222 pMouse.y - iinfo.yHotspot, // - 10,
223 cinfo.hCursor);
224
225 Width = (R.right - R.left);
226 Height = (R.bottom - R.top);
227
228 AppWidth = (appRect.right - appRect.left);
229 AppHeight = (appRect.bottom - appRect.top);
230
231 blitAreaWidth = AppWidth / iZoom;
232 blitAreaHeight = AppHeight / iZoom;
233
234 blitAreaX = (cp.x) - (blitAreaWidth /2);
235 blitAreaY = (cp.y) - (blitAreaHeight /2);
236
237 if (blitAreaX < 0)
238 {
239 blitAreaX = 0;
240 }
241
242 if (blitAreaY < 0)
243 {
244 blitAreaY = 0;
245 }
246
247 if (blitAreaX > (Width - blitAreaWidth))
248 {
249 blitAreaX = (Width - blitAreaWidth);
250 }
251
252 if (blitAreaY > (Height - blitAreaHeight))
253 {
254 blitAreaY = (Height - blitAreaHeight);
255 }
256
257 if (bInvertColors)
258 {
259 rop = NOTSRCCOPY;
260 }
261
262 /* Blast the stretched image from memory DC to window DC.*/
263 StretchBlt(
264 aDc,
265 0,
266 0,
267 AppWidth,
268 AppHeight,
269 HdcStrech,
270 blitAreaX,
271 blitAreaY,
272 blitAreaWidth,
273 blitAreaHeight,
274 rop);
275
276 /* Cleanup.*/
277 if (iinfo.hbmMask)
278 DeleteObject(iinfo.hbmMask);
279 if (iinfo.hbmColor)
280 DeleteObject(iinfo.hbmColor);
281 SelectObject (HdcStrech, hOld);
282 DeleteObject (HbmpStrech);
283 DeleteDC (HdcStrech);
284 ReleaseDC(hDesktopWindow, desktopHdc);
285 }
286
287 /*
288 * FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
289 *
290 * PURPOSE: Processes messages for the main window.
291 *
292 * WM_COMMAND - process the application menu
293 * WM_PAINT - Paint the main window
294 * WM_DESTROY - post a quit message and return
295 *
296 */
297 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
298 {
299 int wmId;
300
301 switch (message)
302 {
303 case WM_TIMER:
304 {
305 POINT pNewMouse;
306 POINT pNewCaret;
307 POINT pNewFocus;
308 HWND hwnd1, hwnd2, hwnd3;
309 DWORD a, b;
310 RECT controlRect;
311
312 //Get current mouse position
313 GetCursorPos (&pNewMouse);
314
315 //Get caret position
316 hwnd1 = GetForegroundWindow ();
317 a = GetWindowThreadProcessId(hwnd1, NULL);
318 b = GetCurrentThreadId();
319 AttachThreadInput (a, b, TRUE);
320 hwnd2 = GetFocus();
321
322 GetCaretPos( &pNewCaret);
323 ClientToScreen (hwnd2, (LPPOINT) &pNewCaret);
324 AttachThreadInput (a, b, FALSE);
325
326 //Get current control focus
327 hwnd3 = GetFocus ();
328 GetWindowRect (hwnd3 , &controlRect);
329 pNewFocus.x = controlRect.left;
330 pNewFocus.y = controlRect.top;
331
332 //If mouse has moved ....
333 if (((pMouse.x != pNewMouse.x) || (pMouse.y != pNewMouse.y)) && bFollowMouse)
334 {
335 //Update to new position
336 pMouse = pNewMouse;
337 cp = pNewMouse;
338 Refresh();
339 }
340 else if (((pCaret.x != pNewCaret.x) || (pCaret.y != pNewCaret.y)) && bFollowCaret)
341 {
342 //Update to new position
343 pCaret = pNewCaret;
344 cp = pNewCaret;
345 Refresh();
346 }
347 else if (((pFocus.x != pNewFocus.x) || (pFocus.y != pNewFocus.y)) && bFollowFocus)
348 {
349 //Update to new position
350 pFocus = pNewFocus;
351 cp = pNewFocus;
352 Refresh();
353 }
354 }
355 break;
356 case WM_COMMAND:
357 wmId = LOWORD(wParam);
358 // Parse the menu selections:
359 switch (wmId)
360 {
361 case IDM_OPTIONS:
362 DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOGOPTIONS), hWnd, (DLGPROC)OptionsProc);
363 break;
364 case IDM_ABOUT:
365 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC)AboutProc);
366 break;
367 case IDM_EXIT:
368 DestroyWindow(hWnd);
369 break;
370 default:
371 return DefWindowProc(hWnd, message, wParam, lParam);
372 }
373 break;
374 case WM_PAINT:
375 {
376 PAINTSTRUCT PaintStruct;
377 HDC dc;
378 dc = BeginPaint(hWnd, &PaintStruct);
379 Draw(dc);
380 EndPaint(hWnd, &PaintStruct);
381 }
382 break;
383 case WM_ERASEBKGND:
384 //handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
385 break;
386 case WM_DESTROY:
387 //Save settings to registry
388 SaveSettings ();
389 KillTimer (hWnd , 1);
390 PostQuitMessage(0);
391 break;
392 case WM_CREATE:
393 //Load settings from registry
394 LoadSettings ();
395
396 //Get the desktop window
397 hDesktopWindow = GetDesktopWindow();
398
399 //Set the timer
400 SetTimer (hWnd , 1, REPAINT_SPEED , NULL);
401 break;
402 default:
403 return DefWindowProc(hWnd, message, wParam, lParam);
404 }
405 return 0;
406 }
407
408 // Message handler for about box.
409 INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
410 {
411 UNREFERENCED_PARAMETER(lParam);
412 switch (message)
413 {
414 case WM_INITDIALOG:
415 return (INT_PTR)TRUE;
416
417 case WM_COMMAND:
418 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
419 {
420 EndDialog(hDlg, LOWORD(wParam));
421 return (INT_PTR)TRUE;
422 }
423 break;
424 }
425 return (INT_PTR)FALSE;
426 }
427
428 // Message handler for options box.
429 INT_PTR CALLBACK OptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
430 {
431 UNREFERENCED_PARAMETER(lParam);
432 switch (message)
433 {
434 case WM_INITDIALOG:
435 {
436 //Add the zoom items....
437 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("1"));
438 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("2"));
439 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("3"));
440 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("4"));
441 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("5"));
442 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("6"));
443 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("7"));
444 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("8"));
445
446 //
447 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_SETCURSEL, iZoom - 1, 0);
448
449 if (bFollowMouse)
450 SendDlgItemMessage(hDlg,IDC_FOLLOWMOUSECHECK,BM_SETCHECK , wParam ,0);
451
452 if (bFollowFocus)
453 SendDlgItemMessage(hDlg,IDC_FOLLOWKEYBOARDCHECK,BM_SETCHECK , wParam ,0);
454
455 if (bFollowCaret)
456 SendDlgItemMessage(hDlg,IDC_FOLLOWTEXTEDITINGCHECK,BM_SETCHECK , wParam ,0);
457
458 if (bInvertColors)
459 SendDlgItemMessage(hDlg,IDC_INVERTCOLORSCHECK,BM_SETCHECK , wParam ,0);
460
461 if (bStartMinimized)
462 SendDlgItemMessage(hDlg,IDC_STARTMINIMIZEDCHECK,BM_SETCHECK , wParam ,0);
463
464 if (bShowMagnifier)
465 SendDlgItemMessage(hDlg,IDC_SHOWMAGNIFIERCHECK,BM_SETCHECK , wParam ,0);
466
467 return (INT_PTR)TRUE;
468 }
469 case WM_COMMAND:
470 switch(LOWORD(wParam))
471 {
472 case IDOK:
473 case IDCANCEL:
474 EndDialog(hDlg, LOWORD(wParam));
475 return (INT_PTR)TRUE;
476
477 case IDC_BUTTON_HELP:
478 /* unimplemented */
479 MessageBox(hDlg , TEXT("Magnifier help not available yet!") , TEXT("Help") , MB_OK);
480 break;
481 case IDC_ZOOM:
482 if(HIWORD(wParam) == CBN_SELCHANGE)
483 {
484 HWND hCombo = GetDlgItem(hDlg,IDC_ZOOM);
485
486 /* Get index of current selection and the text of that selection. */
487 iZoom = SendMessage( hCombo, CB_GETCURSEL, (WPARAM) wParam, (LPARAM) lParam ) + 1;
488
489 //Update the magnigier UI
490 Refresh ();
491 }
492 break;
493 case IDC_INVERTCOLORSCHECK:
494 bInvertColors = IsDlgButtonChecked (hDlg, IDC_INVERTCOLORSCHECK);
495 Refresh ();
496 break;
497 case IDC_FOLLOWMOUSECHECK:
498 bFollowMouse = IsDlgButtonChecked (hDlg, IDC_FOLLOWMOUSECHECK);
499 break;
500 case IDC_FOLLOWKEYBOARDCHECK:
501 bFollowFocus = IsDlgButtonChecked (hDlg, IDC_FOLLOWKEYBOARDCHECK);
502 break;
503 case IDC_FOLLOWTEXTEDITINGCHECK:
504 bFollowCaret = IsDlgButtonChecked (hDlg, IDC_FOLLOWTEXTEDITINGCHECK);
505 break;
506 case IDC_STARTMINIMIZEDCHECK:
507 bStartMinimized = IsDlgButtonChecked (hDlg, IDC_STARTMINIMIZEDCHECK);
508 break;
509 case IDC_SHOWMAGNIFIER:
510 bShowMagnifier = IsDlgButtonChecked (hDlg, IDC_SHOWMAGNIFIERCHECK);
511 if (bShowMagnifier){
512 ShowWindow (hMainWnd , SW_SHOW);
513 }else{
514 ShowWindow (hMainWnd , SW_HIDE);
515 }
516 break;
517 }
518 }
519 return (INT_PTR)FALSE;
520 }
521
522 // Message handler for warning box.
523 INT_PTR CALLBACK WarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
524 {
525 UNREFERENCED_PARAMETER(lParam);
526
527 switch (message)
528 {
529 case WM_INITDIALOG:
530 return (INT_PTR)TRUE;
531 case WM_COMMAND:
532 switch(LOWORD(wParam))
533 {
534 case IDC_SHOWWARNINGCHECK:
535 bShowWarning = !IsDlgButtonChecked (hDlg, IDC_SHOWWARNINGCHECK);
536 break;
537 }
538 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
539 {
540 EndDialog(hDlg, LOWORD(wParam));
541 return (INT_PTR)TRUE;
542 }
543 break;
544 }
545 return (INT_PTR)FALSE;
546 }