Sync with trunk head (part 1 or 2)
[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:
6 * COPYRIGHT: Copyright 2007 Marc Piulachs <marc.piulachs@codexchange.net>
7 *
8 */
9
10 #include <windows.h>
11 #include <shellapi.h>
12 #include "magnifier.h"
13 #include "resource.h"
14
15 const TCHAR szWindowClass[] = TEXT("MAGNIFIER");
16
17 #define MAX_LOADSTRING 100
18
19 // Global Variables:
20 HINSTANCE hInst; // current instance
21 HWND hMainWnd;
22
23 TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
24
25 #define REPAINT_SPEED 100
26
27 HWND hDesktopWindow = NULL;
28
29 //Current magnified area
30 POINT cp;
31
32 //Last positions
33 POINT pMouse;
34 POINT pCaret;
35 POINT pFocus;
36
37 // Forward declarations of functions included in this code module:
38 ATOM MyRegisterClass(HINSTANCE hInstance);
39 BOOL InitInstance(HINSTANCE, int);
40 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
41 INT_PTR CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
42 INT_PTR CALLBACK OptionsProc(HWND, UINT, WPARAM, LPARAM);
43 INT_PTR CALLBACK WarningProc(HWND, UINT, WPARAM, LPARAM);
44
45 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
46 {
47 // TODO: Place code here.
48 MSG msg;
49 HACCEL hAccelTable;
50
51 UNREFERENCED_PARAMETER(hPrevInstance);
52 UNREFERENCED_PARAMETER(lpCmdLine);
53
54 // Initialize global strings
55 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
56 MyRegisterClass(hInstance);
57
58 // Perform application initialization:
59 if (!InitInstance (hInstance, nCmdShow))
60 {
61 return FALSE;
62 }
63
64 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MAGNIFIER));
65
66 // Main message loop:
67 while (GetMessage(&msg, NULL, 0, 0))
68 {
69 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
70 {
71 TranslateMessage(&msg);
72 DispatchMessage(&msg);
73 }
74 }
75
76 return (int) msg.wParam;
77 }
78
79
80
81 //
82 // FUNCTION: MyRegisterClass()
83 //
84 // PURPOSE: Registers the window class.
85 //
86 // COMMENTS:
87 //
88 // This function and its usage are only necessary if you want this code
89 // to be compatible with Win32 systems prior to the 'RegisterClassEx'
90 // function that was added to Windows 95. It is important to call this function
91 // so that the application will get 'well formed' small icons associated
92 // with it.
93 //
94 ATOM MyRegisterClass(HINSTANCE hInstance)
95 {
96 WNDCLASS wc;
97
98 wc.style = CS_HREDRAW | CS_VREDRAW;
99 wc.lpfnWndProc = WndProc;
100 wc.cbClsExtra = 0;
101 wc.cbWndExtra = 0;
102 wc.hInstance = hInstance;
103 wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
104 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
105 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
106 wc.lpszMenuName = MAKEINTRESOURCE(IDC_MAGNIFIER);
107 wc.lpszClassName = szWindowClass;
108
109 return RegisterClass(&wc);
110 }
111
112 //
113 // FUNCTION: InitInstance(HINSTANCE, int)
114 //
115 // PURPOSE: Saves instance handle and creates main window
116 //
117 // COMMENTS:
118 //
119 // In this function, we save the instance handle in a global variable and
120 // create and display the main program window.
121 //
122 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
123 {
124 hInst = hInstance; // Store instance handle in our global variable
125
126 // Create the Window
127 hMainWnd = CreateWindowEx(
128 WS_EX_TOPMOST,
129 szWindowClass,
130 szTitle,
131 WS_OVERLAPPEDWINDOW,
132 CW_USEDEFAULT,
133 CW_USEDEFAULT,
134 CW_USEDEFAULT,
135 CW_USEDEFAULT,
136 NULL,
137 NULL,
138 hInstance,
139 NULL);
140
141 if (!hMainWnd)
142 {
143 return FALSE;
144 }
145
146 ShowWindow(hMainWnd, (bStartMinimized) ? SW_MINIMIZE : nCmdShow);
147 UpdateWindow(hMainWnd);
148
149 if (bShowWarning)
150 {
151 DialogBox (hInstance, MAKEINTRESOURCE(IDD_WARNINGDIALOG), hMainWnd, (DLGPROC)WarningProc);
152 }
153
154 return TRUE;
155 }
156
157 void Refresh ()
158 {
159 if (!IsIconic(hMainWnd))
160 {
161 // Invalidate the client area forcing a WM_PAINT message
162 InvalidateRgn(hMainWnd, NULL, TRUE);
163 }
164 }
165
166 void Draw(HDC aDc)
167 {
168 HDC desktopHdc = NULL;
169 HDC HdcStrech;
170 HANDLE hOld;
171 HBITMAP HbmpStrech;
172
173 RECT R;
174 RECT appRect;
175 DWORD rop = SRCCOPY;
176 CURSORINFO cinfo;
177 ICONINFO iinfo;
178
179 int Width, Height, AppWidth, AppHeight;
180 LONG blitAreaWidth, blitAreaHeight, blitAreaX, blitAreaY;
181
182 desktopHdc = GetWindowDC (hDesktopWindow);
183
184 GetClientRect(hMainWnd, &appRect);
185 GetWindowRect(hDesktopWindow, &R);
186
187 ZeroMemory(&cinfo, sizeof(CURSORINFO));
188 ZeroMemory(&iinfo, sizeof(ICONINFO));
189 cinfo.cbSize = sizeof(cinfo);
190 GetCursorInfo(&cinfo);
191 GetIconInfo(cinfo.hCursor, &iinfo);
192
193 /* Create a memory DC compatible with client area DC.*/
194 HdcStrech = CreateCompatibleDC(desktopHdc);
195
196 /* Create a bitmap compatible with the client area DC.*/
197 HbmpStrech = CreateCompatibleBitmap(
198 desktopHdc,
199 R.right,
200 R.bottom);
201
202 /* Select our bitmap in memory DC and save the old one.*/
203 hOld = SelectObject (HdcStrech , HbmpStrech);
204
205 /* Paint the screen bitmap to our in memory DC */
206 BitBlt(
207 HdcStrech,
208 0,
209 0,
210 R.right,
211 R.bottom,
212 desktopHdc,
213 0,
214 0,
215 SRCCOPY);
216
217 /* Draw the mouse pointer in the right position */
218 DrawIcon(
219 HdcStrech ,
220 pMouse.x - iinfo.xHotspot, // - 10,
221 pMouse.y - iinfo.yHotspot, // - 10,
222 cinfo.hCursor);
223
224 Width = (R.right - R.left);
225 Height = (R.bottom - R.top);
226
227 AppWidth = (appRect.right - appRect.left);
228 AppHeight = (appRect.bottom - appRect.top);
229
230 blitAreaWidth = AppWidth / iZoom;
231 blitAreaHeight = AppHeight / iZoom;
232
233 blitAreaX = (cp.x) - (blitAreaWidth /2);
234 blitAreaY = (cp.y) - (blitAreaHeight /2);
235
236 if (blitAreaX < 0)
237 {
238 blitAreaX = 0;
239 }
240
241 if (blitAreaY < 0)
242 {
243 blitAreaY = 0;
244 }
245
246 if (blitAreaX > (Width - blitAreaWidth))
247 {
248 blitAreaX = (Width - blitAreaWidth);
249 }
250
251 if (blitAreaY > (Height - blitAreaHeight))
252 {
253 blitAreaY = (Height - blitAreaHeight);
254 }
255
256 if (bInvertColors)
257 {
258 rop = NOTSRCCOPY;
259 }
260
261 /* Blast the stretched image from memory DC to window DC.*/
262 StretchBlt(
263 aDc,
264 0,
265 0,
266 AppWidth,
267 AppHeight,
268 HdcStrech,
269 blitAreaX,
270 blitAreaY,
271 blitAreaWidth,
272 blitAreaHeight,
273 rop);
274
275 /* Cleanup.*/
276 if (iinfo.hbmMask)
277 DeleteObject(iinfo.hbmMask);
278 if (iinfo.hbmColor)
279 DeleteObject(iinfo.hbmColor);
280 SelectObject (HdcStrech, hOld);
281 DeleteObject (HbmpStrech);
282 DeleteDC (HdcStrech);
283 ReleaseDC(hDesktopWindow, desktopHdc);
284 }
285
286 //
287 // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
288 //
289 // PURPOSE: Processes messages for the main window.
290 //
291 // WM_COMMAND - process the application menu
292 // WM_PAINT - Paint the main window
293 // WM_DESTROY - post a quit message and return
294 //
295 //
296 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
297 {
298 int wmId, wmEvent;
299
300 switch (message)
301 {
302 case WM_TIMER:
303 {
304 POINT pNewMouse;
305 POINT pNewCaret;
306 POINT pNewFocus;
307 HWND hwnd1, hwnd2, hwnd3;
308 DWORD a, b;
309 RECT controlRect;
310
311 //Get current mouse position
312 GetCursorPos (&pNewMouse);
313
314 //Get caret position
315 hwnd1 = GetForegroundWindow ();
316 a = GetWindowThreadProcessId(hwnd1, NULL);
317 b = GetCurrentThreadId();
318 AttachThreadInput (a, b, TRUE);
319 hwnd2 = GetFocus();
320
321 GetCaretPos( &pNewCaret);
322 ClientToScreen (hwnd2, (LPPOINT) &pNewCaret);
323 AttachThreadInput (a, b, FALSE);
324
325 //Get current control focus
326 hwnd3 = GetFocus ();
327 GetWindowRect (hwnd3 , &controlRect);
328 pNewFocus.x = controlRect.left;
329 pNewFocus.y = controlRect.top;
330
331 //If mouse has moved ....
332 if (((pMouse.x != pNewMouse.x) || (pMouse.y != pNewMouse.y)) && bFollowMouse)
333 {
334 //Update to new position
335 pMouse = pNewMouse;
336 cp = pNewMouse;
337 Refresh();
338 }
339 else if (((pCaret.x != pNewCaret.x) || (pCaret.y != pNewCaret.y)) && bFollowCaret)
340 {
341 //Update to new position
342 pCaret = pNewCaret;
343 cp = pNewCaret;
344 Refresh();
345 }
346 else if (((pFocus.x != pNewFocus.x) || (pFocus.y != pNewFocus.y)) && bFollowFocus)
347 {
348 //Update to new position
349 pFocus = pNewFocus;
350 cp = pNewFocus;
351 Refresh();
352 }
353 }
354 break;
355 case WM_COMMAND:
356 wmId = LOWORD(wParam);
357 wmEvent = HIWORD(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 }