Carlo Bramini (carlo DOT bramix AT libero DOT it):
[reactos.git] / rosapps / 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 memset(&cinfo, 0, sizeof(cinfo));
188 cinfo.cbSize = sizeof(cinfo);
189 GetCursorInfo(&cinfo);
190 GetIconInfo(cinfo.hCursor, &iinfo);
191
192 /* Create a memory DC compatible with client area DC.*/
193 HdcStrech = CreateCompatibleDC(desktopHdc);
194
195 /* Create a bitmap compatible with the client area DC.*/
196 HbmpStrech = CreateCompatibleBitmap(
197 desktopHdc,
198 R.right,
199 R.bottom);
200
201 /* Select our bitmap in memory DC and save the old one.*/
202 hOld = SelectObject (HdcStrech , HbmpStrech);
203
204 /* Paint the screen bitmap to our in memory DC */
205 BitBlt(
206 HdcStrech,
207 0,
208 0,
209 R.right,
210 R.bottom,
211 desktopHdc,
212 0,
213 0,
214 SRCCOPY);
215
216 /* Draw the mouse pointer in the right position */
217 DrawIcon(
218 HdcStrech ,
219 pMouse.x - iinfo.xHotspot, // - 10,
220 pMouse.y - iinfo.yHotspot, // - 10,
221 cinfo.hCursor);
222
223 Width = (R.right - R.left);
224 Height = (R.bottom - R.top);
225
226 AppWidth = (appRect.right - appRect.left);
227 AppHeight = (appRect.bottom - appRect.top);
228
229 blitAreaWidth = AppWidth / iZoom;
230 blitAreaHeight = AppHeight / iZoom;
231
232 blitAreaX = (cp.x) - (blitAreaWidth /2);
233 blitAreaY = (cp.y) - (blitAreaHeight /2);
234
235 if (blitAreaX < 0)
236 {
237 blitAreaX = 0;
238 }
239
240 if (blitAreaY < 0)
241 {
242 blitAreaY = 0;
243 }
244
245 if (blitAreaX > (Width - blitAreaWidth))
246 {
247 blitAreaX = (Width - blitAreaWidth);
248 }
249
250 if (blitAreaY > (Height - blitAreaHeight))
251 {
252 blitAreaY = (Height - blitAreaHeight);
253 }
254
255 if (bInvertColors)
256 {
257 rop = NOTSRCCOPY;
258 }
259
260 /* Blast the stretched image from memory DC to window DC.*/
261 StretchBlt(
262 aDc,
263 0,
264 0,
265 AppWidth,
266 AppHeight,
267 HdcStrech,
268 blitAreaX,
269 blitAreaY,
270 blitAreaWidth,
271 blitAreaHeight,
272 rop);
273
274 /* Cleanup.*/
275 SelectObject (HdcStrech, hOld);
276 DeleteObject (HbmpStrech);
277 DeleteDC (HdcStrech);
278 ReleaseDC(hDesktopWindow, desktopHdc);
279 }
280
281 //
282 // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
283 //
284 // PURPOSE: Processes messages for the main window.
285 //
286 // WM_COMMAND - process the application menu
287 // WM_PAINT - Paint the main window
288 // WM_DESTROY - post a quit message and return
289 //
290 //
291 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
292 {
293 int wmId, wmEvent;
294
295 switch (message)
296 {
297 case WM_TIMER:
298 {
299 POINT pNewMouse;
300 POINT pNewCaret;
301 POINT pNewFocus;
302 HWND hwnd1, hwnd2, hwnd3;
303 DWORD a, b;
304 RECT controlRect;
305
306 //Get current mouse position
307 GetCursorPos (&pNewMouse);
308
309 //Get caret position
310 hwnd1 = GetForegroundWindow ();
311 a = GetWindowThreadProcessId(hwnd1, NULL);
312 b = GetCurrentThreadId();
313 AttachThreadInput (a, b, TRUE);
314 hwnd2 = GetFocus();
315
316 GetCaretPos( &pNewCaret);
317 ClientToScreen (hwnd2, (LPPOINT) &pNewCaret);
318 AttachThreadInput (a, b, FALSE);
319
320 //Get current control focus
321 hwnd3 = GetFocus ();
322 GetWindowRect (hwnd3 , &controlRect);
323 pNewFocus.x = controlRect.left;
324 pNewFocus.y = controlRect.top;
325
326 //If mouse has moved ....
327 if (((pMouse.x != pNewMouse.x) || (pMouse.y != pNewMouse.y)) && bFollowMouse)
328 {
329 //Update to new position
330 pMouse = pNewMouse;
331 cp = pNewMouse;
332 Refresh();
333 }
334 else if (((pCaret.x != pNewCaret.x) || (pCaret.y != pNewCaret.y)) && bFollowCaret)
335 {
336 //Update to new position
337 pCaret = pNewCaret;
338 cp = pNewCaret;
339 Refresh();
340 }
341 else if (((pFocus.x != pNewFocus.x) || (pFocus.y != pNewFocus.y)) && bFollowFocus)
342 {
343 //Update to new position
344 pFocus = pNewFocus;
345 cp = pNewFocus;
346 Refresh();
347 }
348 }
349 break;
350 case WM_COMMAND:
351 wmId = LOWORD(wParam);
352 wmEvent = HIWORD(wParam);
353 // Parse the menu selections:
354 switch (wmId)
355 {
356 case IDM_OPTIONS:
357 DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOGOPTIONS), hWnd, (DLGPROC)OptionsProc);
358 break;
359 case IDM_ABOUT:
360 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC)AboutProc);
361 break;
362 case IDM_EXIT:
363 DestroyWindow(hWnd);
364 break;
365 default:
366 return DefWindowProc(hWnd, message, wParam, lParam);
367 }
368 break;
369 case WM_PAINT:
370 {
371 PAINTSTRUCT PaintStruct;
372 HDC dc;
373 dc = BeginPaint(hWnd, &PaintStruct);
374 Draw(dc);
375 EndPaint(hWnd, &PaintStruct);
376 }
377 break;
378 case WM_ERASEBKGND:
379 //handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
380 break;
381 case WM_DESTROY:
382 //Save settings to registry
383 SaveSettings ();
384 KillTimer (hWnd , 1);
385 PostQuitMessage(0);
386 break;
387 case WM_CREATE:
388 //Load settings from registry
389 LoadSettings ();
390
391 //Get the desktop window
392 hDesktopWindow = GetDesktopWindow();
393
394 //Set the timer
395 SetTimer (hWnd , 1, REPAINT_SPEED , NULL);
396 break;
397 default:
398 return DefWindowProc(hWnd, message, wParam, lParam);
399 }
400 return 0;
401 }
402
403 // Message handler for about box.
404 INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
405 {
406 UNREFERENCED_PARAMETER(lParam);
407 switch (message)
408 {
409 case WM_INITDIALOG:
410 return (INT_PTR)TRUE;
411
412 case WM_COMMAND:
413 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
414 {
415 EndDialog(hDlg, LOWORD(wParam));
416 return (INT_PTR)TRUE;
417 }
418 break;
419 }
420 return (INT_PTR)FALSE;
421 }
422
423 // Message handler for options box.
424 INT_PTR CALLBACK OptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
425 {
426 UNREFERENCED_PARAMETER(lParam);
427 switch (message)
428 {
429 case WM_INITDIALOG:
430 {
431 //Add the zoom items....
432 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("1"));
433 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("2"));
434 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("3"));
435 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("4"));
436 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("5"));
437 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("6"));
438 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("7"));
439 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("8"));
440
441 //
442 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_SETCURSEL, iZoom - 1, 0);
443
444 if (bFollowMouse)
445 SendDlgItemMessage(hDlg,IDC_FOLLOWMOUSECHECK,BM_SETCHECK , wParam ,0);
446
447 if (bFollowFocus)
448 SendDlgItemMessage(hDlg,IDC_FOLLOWKEYBOARDCHECK,BM_SETCHECK , wParam ,0);
449
450 if (bFollowCaret)
451 SendDlgItemMessage(hDlg,IDC_FOLLOWTEXTEDITINGCHECK,BM_SETCHECK , wParam ,0);
452
453 if (bInvertColors)
454 SendDlgItemMessage(hDlg,IDC_INVERTCOLORSCHECK,BM_SETCHECK , wParam ,0);
455
456 if (bStartMinimized)
457 SendDlgItemMessage(hDlg,IDC_STARTMINIMIZEDCHECK,BM_SETCHECK , wParam ,0);
458
459 if (bShowMagnifier)
460 SendDlgItemMessage(hDlg,IDC_SHOWMAGNIFIERCHECK,BM_SETCHECK , wParam ,0);
461
462 return (INT_PTR)TRUE;
463 }
464 case WM_COMMAND:
465 switch(LOWORD(wParam))
466 {
467 case IDOK:
468 case IDCANCEL:
469 EndDialog(hDlg, LOWORD(wParam));
470 return (INT_PTR)TRUE;
471
472 case IDC_BUTTON_HELP:
473 /* unimplemented */
474 MessageBox(hDlg , TEXT("Magnifier help not available yet!") , TEXT("Help") , MB_OK);
475 break;
476 case IDC_ZOOM:
477 if(HIWORD(wParam) == CBN_SELCHANGE)
478 {
479 HWND hCombo = GetDlgItem(hDlg,IDC_ZOOM);
480
481 /* Get index of current selection and the text of that selection. */
482 iZoom = SendMessage( hCombo, CB_GETCURSEL, (WPARAM) wParam, (LPARAM) lParam ) + 1;
483
484 //Update the magnigier UI
485 Refresh ();
486 }
487 break;
488 case IDC_INVERTCOLORSCHECK:
489 bInvertColors = IsDlgButtonChecked (hDlg, IDC_INVERTCOLORSCHECK);
490 Refresh ();
491 break;
492 case IDC_FOLLOWMOUSECHECK:
493 bFollowMouse = IsDlgButtonChecked (hDlg, IDC_FOLLOWMOUSECHECK);
494 break;
495 case IDC_FOLLOWKEYBOARDCHECK:
496 bFollowFocus = IsDlgButtonChecked (hDlg, IDC_FOLLOWKEYBOARDCHECK);
497 break;
498 case IDC_FOLLOWTEXTEDITINGCHECK:
499 bFollowCaret = IsDlgButtonChecked (hDlg, IDC_FOLLOWTEXTEDITINGCHECK);
500 break;
501 case IDC_STARTMINIMIZEDCHECK:
502 bStartMinimized = IsDlgButtonChecked (hDlg, IDC_STARTMINIMIZEDCHECK);
503 break;
504 case IDC_SHOWMAGNIFIER:
505 bShowMagnifier = IsDlgButtonChecked (hDlg, IDC_SHOWMAGNIFIERCHECK);
506 if (bShowMagnifier){
507 ShowWindow (hMainWnd , SW_SHOW);
508 }else{
509 ShowWindow (hMainWnd , SW_HIDE);
510 }
511 break;
512 }
513 }
514 return (INT_PTR)FALSE;
515 }
516
517 // Message handler for warning box.
518 INT_PTR CALLBACK WarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
519 {
520 UNREFERENCED_PARAMETER(lParam);
521
522 switch (message)
523 {
524 case WM_INITDIALOG:
525 return (INT_PTR)TRUE;
526 case WM_COMMAND:
527 switch(LOWORD(wParam))
528 {
529 case IDC_SHOWWARNINGCHECK:
530 bShowWarning = !IsDlgButtonChecked (hDlg, IDC_SHOWWARNINGCHECK);
531 break;
532 }
533 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
534 {
535 EndDialog(hDlg, LOWORD(wParam));
536 return (INT_PTR)TRUE;
537 }
538 break;
539 }
540 return (INT_PTR)FALSE;
541 }