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