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