[MAGNIFY]
[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 #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 }
357 else if (((pCaret.x != pNewCaret.x) || (pCaret.y != pNewCaret.y)) && bFollowCaret)
358 {
359 //Update to new position
360 pCaret = pNewCaret;
361 cp = pNewCaret;
362 }
363 else if (((pFocus.x != pNewFocus.x) || (pFocus.y != pNewFocus.y)) && bFollowFocus)
364 {
365 //Update to new position
366 pFocus = pNewFocus;
367 cp = pNewFocus;
368 }
369 Refresh();
370 }
371 break;
372 case WM_COMMAND:
373 wmId = LOWORD(wParam);
374 // Parse the menu selections:
375 switch (wmId)
376 {
377 case IDM_OPTIONS:
378 DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOGOPTIONS), hWnd, (DLGPROC)OptionsProc);
379 break;
380 case IDM_ABOUT:
381 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC)AboutProc);
382 break;
383 case IDM_EXIT:
384 DestroyWindow(hWnd);
385 break;
386 default:
387 return DefWindowProc(hWnd, message, wParam, lParam);
388 }
389 break;
390 case WM_PAINT:
391 {
392 PAINTSTRUCT PaintStruct;
393 HDC dc;
394 dc = BeginPaint(hWnd, &PaintStruct);
395 Draw(dc);
396 EndPaint(hWnd, &PaintStruct);
397 }
398 break;
399 case WM_ERASEBKGND:
400 //handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
401 break;
402 case WM_DESTROY:
403 //Save settings to registry
404 SaveSettings ();
405 KillTimer (hWnd , 1);
406 PostQuitMessage(0);
407 break;
408 case WM_CREATE:
409 //Load settings from registry
410 LoadSettings ();
411
412 //Get the desktop window
413 hDesktopWindow = GetDesktopWindow();
414
415 //Set the timer
416 SetTimer (hWnd , 1, REPAINT_SPEED , NULL);
417 break;
418 default:
419 return DefWindowProc(hWnd, message, wParam, lParam);
420 }
421 return 0;
422 }
423
424 // Message handler for about box.
425 INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
426 {
427 UNREFERENCED_PARAMETER(lParam);
428 switch (message)
429 {
430 case WM_INITDIALOG:
431 return (INT_PTR)TRUE;
432
433 case WM_COMMAND:
434 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
435 {
436 EndDialog(hDlg, LOWORD(wParam));
437 return (INT_PTR)TRUE;
438 }
439 break;
440 }
441 return (INT_PTR)FALSE;
442 }
443
444 // Message handler for options box.
445 INT_PTR CALLBACK OptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
446 {
447 UNREFERENCED_PARAMETER(lParam);
448 switch (message)
449 {
450 case WM_INITDIALOG:
451 {
452 //Add the zoom items....
453 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("1"));
454 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("2"));
455 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("3"));
456 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("4"));
457 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("5"));
458 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("6"));
459 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("7"));
460 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("8"));
461
462 //
463 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_SETCURSEL, iZoom - 1, 0);
464
465 if (bFollowMouse)
466 SendDlgItemMessage(hDlg,IDC_FOLLOWMOUSECHECK,BM_SETCHECK , wParam ,0);
467
468 if (bFollowFocus)
469 SendDlgItemMessage(hDlg,IDC_FOLLOWKEYBOARDCHECK,BM_SETCHECK , wParam ,0);
470
471 if (bFollowCaret)
472 SendDlgItemMessage(hDlg,IDC_FOLLOWTEXTEDITINGCHECK,BM_SETCHECK , wParam ,0);
473
474 if (bInvertColors)
475 SendDlgItemMessage(hDlg,IDC_INVERTCOLORSCHECK,BM_SETCHECK , wParam ,0);
476
477 if (bStartMinimized)
478 SendDlgItemMessage(hDlg,IDC_STARTMINIMIZEDCHECK,BM_SETCHECK , wParam ,0);
479
480 if (bShowMagnifier)
481 SendDlgItemMessage(hDlg,IDC_SHOWMAGNIFIERCHECK,BM_SETCHECK , wParam ,0);
482
483 return (INT_PTR)TRUE;
484 }
485 case WM_COMMAND:
486 switch(LOWORD(wParam))
487 {
488 case IDOK:
489 case IDCANCEL:
490 EndDialog(hDlg, LOWORD(wParam));
491 return (INT_PTR)TRUE;
492
493 case IDC_BUTTON_HELP:
494 /* unimplemented */
495 MessageBox(hDlg , TEXT("Magnifier help not available yet!") , TEXT("Help") , MB_OK);
496 break;
497 case IDC_ZOOM:
498 if(HIWORD(wParam) == CBN_SELCHANGE)
499 {
500 HWND hCombo = GetDlgItem(hDlg,IDC_ZOOM);
501
502 /* Get index of current selection and the text of that selection. */
503 iZoom = SendMessage( hCombo, CB_GETCURSEL, (WPARAM) wParam, (LPARAM) lParam ) + 1;
504
505 //Update the magnigier UI
506 Refresh ();
507 }
508 break;
509 case IDC_INVERTCOLORSCHECK:
510 bInvertColors = IsDlgButtonChecked (hDlg, IDC_INVERTCOLORSCHECK);
511 Refresh ();
512 break;
513 case IDC_FOLLOWMOUSECHECK:
514 bFollowMouse = IsDlgButtonChecked (hDlg, IDC_FOLLOWMOUSECHECK);
515 break;
516 case IDC_FOLLOWKEYBOARDCHECK:
517 bFollowFocus = IsDlgButtonChecked (hDlg, IDC_FOLLOWKEYBOARDCHECK);
518 break;
519 case IDC_FOLLOWTEXTEDITINGCHECK:
520 bFollowCaret = IsDlgButtonChecked (hDlg, IDC_FOLLOWTEXTEDITINGCHECK);
521 break;
522 case IDC_STARTMINIMIZEDCHECK:
523 bStartMinimized = IsDlgButtonChecked (hDlg, IDC_STARTMINIMIZEDCHECK);
524 break;
525 case IDC_SHOWMAGNIFIER:
526 bShowMagnifier = IsDlgButtonChecked (hDlg, IDC_SHOWMAGNIFIERCHECK);
527 if (bShowMagnifier){
528 ShowWindow (hMainWnd , SW_SHOW);
529 }else{
530 ShowWindow (hMainWnd , SW_HIDE);
531 }
532 break;
533 }
534 }
535 return (INT_PTR)FALSE;
536 }
537
538 // Message handler for warning box.
539 INT_PTR CALLBACK WarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
540 {
541 UNREFERENCED_PARAMETER(lParam);
542
543 switch (message)
544 {
545 case WM_INITDIALOG:
546 return (INT_PTR)TRUE;
547 case WM_COMMAND:
548 switch(LOWORD(wParam))
549 {
550 case IDC_SHOWWARNINGCHECK:
551 bShowWarning = !IsDlgButtonChecked (hDlg, IDC_SHOWWARNINGCHECK);
552 break;
553 }
554 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
555 {
556 EndDialog(hDlg, LOWORD(wParam));
557 return (INT_PTR)TRUE;
558 }
559 break;
560 }
561 return (INT_PTR)FALSE;
562 }