1 /*
2 * Wordpad implementation - Printing and print preview functions
3 *
4 * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winreg.h>
25 #include <wingdi.h>
26 #include <winuser.h>
27 #include <richedit.h>
28 #include <commctrl.h>
29 #include <commdlg.h>
30
31 #include "wordpad.h"
32
33 typedef struct _previewinfo
34 {
35 int page;
36 int pages_shown;
37 int saved_pages_shown;
38 int *pageEnds, pageCapacity;
39 int textlength;
40 HDC hdc;
41 HDC hdc2;
42 RECT window;
43 RECT rcPage;
44 SIZE bmSize;
45 SIZE bmScaledSize;
46 SIZE spacing;
47 float zoomratio;
48 int zoomlevel;
49 LPWSTR wszFileName;
50 } previewinfo, *ppreviewinfo;
51
52 static HGLOBAL devMode;
53 static HGLOBAL devNames;
54
55 static RECT margins;
56 static previewinfo preview;
57
58 extern const WCHAR wszPreviewWndClass[];
59
60 static const WCHAR var_pagemargin[] = {'P','a','g','e','M','a','r','g','i','n',0};
61 static const WCHAR var_previewpages[] = {'P','r','e','v','i','e','w','P','a','g','e','s',0};
62
get_print_file_filter(HWND hMainWnd)63 static LPWSTR get_print_file_filter(HWND hMainWnd)
64 {
65 static WCHAR wszPrintFilter[MAX_STRING_LEN*2+6+4+1];
66 const WCHAR files_prn[] = {'*','.','P','R','N',0};
67 const WCHAR files_all[] = {'*','.','*','\0'};
68 LPWSTR p;
69 HINSTANCE hInstance = GetModuleHandleW(0);
70
71 p = wszPrintFilter;
72 LoadStringW(hInstance, STRING_PRINTER_FILES_PRN, p, MAX_STRING_LEN);
73 p += lstrlenW(p) + 1;
74 lstrcpyW(p, files_prn);
75 p += lstrlenW(p) + 1;
76 LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
77 p += lstrlenW(p) + 1;
78 lstrcpyW(p, files_all);
79 p += lstrlenW(p) + 1;
80 *p = 0;
81
82 return wszPrintFilter;
83 }
84
registry_set_pagemargins(HKEY hKey)85 void registry_set_pagemargins(HKEY hKey)
86 {
87 RegSetValueExW(hKey, var_pagemargin, 0, REG_BINARY, (LPBYTE)&margins, sizeof(RECT));
88 }
89
registry_read_pagemargins(HKEY hKey)90 void registry_read_pagemargins(HKEY hKey)
91 {
92 DWORD size = sizeof(RECT);
93
94 if(!hKey || RegQueryValueExW(hKey, var_pagemargin, 0, NULL, (LPBYTE)&margins,
95 &size) != ERROR_SUCCESS || size != sizeof(RECT))
96 SetRect(&margins, 1757, 1417, 1757, 1417);
97 }
98
registry_set_previewpages(HKEY hKey)99 void registry_set_previewpages(HKEY hKey)
100 {
101 RegSetValueExW(hKey, var_previewpages, 0, REG_DWORD,
102 (LPBYTE)&preview.pages_shown, sizeof(DWORD));
103 }
104
registry_read_previewpages(HKEY hKey)105 void registry_read_previewpages(HKEY hKey)
106 {
107 DWORD size = sizeof(DWORD);
108 if(!hKey ||
109 RegQueryValueExW(hKey, var_previewpages, 0, NULL,
110 (LPBYTE)&preview.pages_shown, &size) != ERROR_SUCCESS ||
111 size != sizeof(DWORD))
112 {
113 preview.pages_shown = 1;
114 } else {
115 if (preview.pages_shown < 1) preview.pages_shown = 1;
116 else if (preview.pages_shown > 2) preview.pages_shown = 2;
117 }
118 }
119
120
AddTextButton(HWND hRebarWnd,UINT string,UINT command,UINT id)121 static void AddTextButton(HWND hRebarWnd, UINT string, UINT command, UINT id)
122 {
123 REBARBANDINFOW rb;
124 HINSTANCE hInstance = GetModuleHandleW(0);
125 WCHAR text[MAX_STRING_LEN];
126 HWND hButton;
127
128 LoadStringW(hInstance, string, text, MAX_STRING_LEN);
129 hButton = CreateWindowW(WC_BUTTONW, text,
130 WS_VISIBLE | WS_CHILD, 5, 5, 100, 15,
131 hRebarWnd, ULongToHandle(command), hInstance, NULL);
132
133 rb.cbSize = REBARBANDINFOW_V6_SIZE;
134 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID;
135 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT;
136 rb.hwndChild = hButton;
137 rb.cyChild = rb.cyMinChild = 22;
138 rb.cx = rb.cxMinChild = 90;
139 rb.cxIdeal = 100;
140 rb.wID = id;
141
142 SendMessageW(hRebarWnd, RB_INSERTBANDW, -1, (LPARAM)&rb);
143 }
144
make_dc(void)145 static HDC make_dc(void)
146 {
147 if(devNames && devMode)
148 {
149 LPDEVNAMES dn = GlobalLock(devNames);
150 LPDEVMODEW dm = GlobalLock(devMode);
151 HDC ret;
152
153 ret = CreateDCW((LPWSTR)dn + dn->wDriverOffset,
154 (LPWSTR)dn + dn->wDeviceOffset, 0, dm);
155
156 GlobalUnlock(dn);
157 GlobalUnlock(dm);
158
159 return ret;
160 } else
161 {
162 return 0;
163 }
164 }
165
twips_to_centmm(int twips)166 static LONG twips_to_centmm(int twips)
167 {
168 return MulDiv(twips, CENTMM_PER_INCH, TWIPS_PER_INCH);
169 }
170
centmm_to_twips(int mm)171 static LONG centmm_to_twips(int mm)
172 {
173 return MulDiv(mm, TWIPS_PER_INCH, CENTMM_PER_INCH);
174 }
175
twips_to_pixels(int twips,int dpi)176 static LONG twips_to_pixels(int twips, int dpi)
177 {
178 return MulDiv(twips, dpi, TWIPS_PER_INCH);
179 }
180
devunits_to_twips(int units,int dpi)181 static LONG devunits_to_twips(int units, int dpi)
182 {
183 return MulDiv(units, TWIPS_PER_INCH, dpi);
184 }
185
186
get_print_rect(HDC hdc)187 static RECT get_print_rect(HDC hdc)
188 {
189 RECT rc;
190 int width, height;
191
192 if(hdc)
193 {
194 int dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
195 int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
196 width = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALWIDTH), dpiX);
197 height = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALHEIGHT), dpiY);
198 } else
199 {
200 width = centmm_to_twips(18500);
201 height = centmm_to_twips(27000);
202 }
203
204 SetRect(&rc, margins.left, margins.top, width - margins.right, height - margins.bottom);
205
206 return rc;
207 }
208
target_device(HWND hMainWnd,DWORD wordWrap)209 void target_device(HWND hMainWnd, DWORD wordWrap)
210 {
211 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
212
213 if(wordWrap == ID_WORDWRAP_MARGIN)
214 {
215 int width = 0;
216 LRESULT result;
217 HDC hdc = make_dc();
218 RECT rc = get_print_rect(hdc);
219
220 width = rc.right - rc.left;
221 if(!hdc)
222 {
223 HDC hMaindc = GetDC(hMainWnd);
224 hdc = CreateCompatibleDC(hMaindc);
225 ReleaseDC(hMainWnd, hMaindc);
226 }
227 result = SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, (WPARAM)hdc, width);
228 DeleteDC(hdc);
229 if (result)
230 return;
231 /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping
232 * to window using the NULL DC. */
233 }
234
235 if (wordWrap != ID_WORDWRAP_NONE) {
236 SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 0);
237 } else {
238 SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 1);
239 }
240
241 }
242
dialog_print_to_file(HWND hMainWnd)243 static LPWSTR dialog_print_to_file(HWND hMainWnd)
244 {
245 OPENFILENAMEW ofn;
246 static WCHAR file[MAX_PATH] = {'O','U','T','P','U','T','.','P','R','N',0};
247 static const WCHAR defExt[] = {'P','R','N',0};
248 static LPWSTR file_filter;
249
250 if(!file_filter)
251 file_filter = get_print_file_filter(hMainWnd);
252
253 ZeroMemory(&ofn, sizeof(ofn));
254
255 ofn.lStructSize = sizeof(ofn);
256 ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
257 ofn.hwndOwner = hMainWnd;
258 ofn.lpstrFilter = file_filter;
259 ofn.lpstrFile = file;
260 ofn.nMaxFile = MAX_PATH;
261 ofn.lpstrDefExt = defExt;
262
263 if(GetSaveFileNameW(&ofn))
264 return file;
265 else
266 return FALSE;
267 }
268
char_from_pagenum(HWND hEditorWnd,FORMATRANGE * fr,int page)269 static void char_from_pagenum(HWND hEditorWnd, FORMATRANGE *fr, int page)
270 {
271 int i;
272
273 fr->chrg.cpMin = 0;
274
275 for(i = 1; i < page; i++)
276 {
277 int bottom = fr->rc.bottom;
278 fr->chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, (LPARAM)fr);
279 fr->rc.bottom = bottom;
280 }
281 }
282
get_ruler_wnd(HWND hMainWnd)283 static HWND get_ruler_wnd(HWND hMainWnd)
284 {
285 return GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
286 }
287
redraw_ruler(HWND hRulerWnd)288 void redraw_ruler(HWND hRulerWnd)
289 {
290 RECT rc;
291
292 GetClientRect(hRulerWnd, &rc);
293 InvalidateRect(hRulerWnd, &rc, TRUE);
294 }
295
update_ruler(HWND hRulerWnd)296 static void update_ruler(HWND hRulerWnd)
297 {
298 SendMessageW(hRulerWnd, WM_USER, 0, 0);
299 redraw_ruler(hRulerWnd);
300 }
301
add_ruler_units(HDC hdcRuler,RECT * drawRect,BOOL NewMetrics,LONG EditLeftmost)302 static void add_ruler_units(HDC hdcRuler, RECT* drawRect, BOOL NewMetrics, LONG EditLeftmost)
303 {
304 static HDC hdc;
305
306 if(NewMetrics)
307 {
308 static HBITMAP hBitmap;
309 int i, x, y, RulerTextEnd;
310 int CmPixels;
311 int QuarterCmPixels;
312 HFONT hFont;
313 WCHAR FontName[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
314
315 if(hdc)
316 {
317 DeleteDC(hdc);
318 DeleteObject(hBitmap);
319 }
320
321 hdc = CreateCompatibleDC(0);
322
323 CmPixels = twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc, LOGPIXELSX));
324 QuarterCmPixels = (int)((float)CmPixels / 4.0);
325
326 hBitmap = CreateCompatibleBitmap(hdc, drawRect->right, drawRect->bottom);
327 SelectObject(hdc, hBitmap);
328 FillRect(hdc, drawRect, GetStockObject(WHITE_BRUSH));
329
330 hFont = CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName);
331
332 SelectObject(hdc, hFont);
333 SetBkMode(hdc, TRANSPARENT);
334 SetTextAlign(hdc, TA_CENTER);
335 y = (int)(((float)drawRect->bottom - (float)drawRect->top) / 2.0) + 1;
336 RulerTextEnd = drawRect->right - EditLeftmost + 1;
337 for(i = 1, x = EditLeftmost; x < (drawRect->right - EditLeftmost + 1); i ++)
338 {
339 WCHAR str[3];
340 WCHAR format[] = {'%','d',0};
341 int x2 = x;
342
343 x2 += QuarterCmPixels;
344 if(x2 > RulerTextEnd)
345 break;
346
347 MoveToEx(hdc, x2, y, NULL);
348 LineTo(hdc, x2, y+2);
349
350 x2 += QuarterCmPixels;
351 if(x2 > RulerTextEnd)
352 break;
353
354 MoveToEx(hdc, x2, y - 3, NULL);
355 LineTo(hdc, x2, y + 3);
356
357 x2 += QuarterCmPixels;
358 if(x2 > RulerTextEnd)
359 break;
360
361 MoveToEx(hdc, x2, y, NULL);
362 LineTo(hdc, x2, y+2);
363
364 x += CmPixels;
365 if(x > RulerTextEnd)
366 break;
367
368 wsprintfW(str, format, i);
369 TextOutW(hdc, x, 5, str, lstrlenW(str));
370 }
371 DeleteObject(hFont);
372 }
373
374 BitBlt(hdcRuler, 0, 0, drawRect->right, drawRect->bottom, hdc, 0, 0, SRCAND);
375 }
376
paint_ruler(HWND hWnd,LONG EditLeftmost,BOOL NewMetrics)377 static void paint_ruler(HWND hWnd, LONG EditLeftmost, BOOL NewMetrics)
378 {
379 PAINTSTRUCT ps;
380 HDC hdc = BeginPaint(hWnd, &ps);
381 HDC hdcPrint = make_dc();
382 RECT printRect = get_print_rect(hdcPrint);
383 RECT drawRect;
384
385 GetClientRect(hWnd, &drawRect);
386 FillRect(hdc, &drawRect, GetSysColorBrush(COLOR_MENU));
387
388 InflateRect(&drawRect, 0, -3);
389 drawRect.left = EditLeftmost;
390 drawRect.right = twips_to_pixels(printRect.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
391 FillRect(hdc, &drawRect, GetStockObject(WHITE_BRUSH));
392
393 drawRect.top--;
394 drawRect.bottom++;
395 DrawEdge(hdc, &drawRect, EDGE_SUNKEN, BF_RECT);
396
397 drawRect.left = drawRect.right - 1;
398 drawRect.right = twips_to_pixels(printRect.right + margins.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
399 DrawEdge(hdc, &drawRect, EDGE_ETCHED, BF_RECT);
400
401 drawRect.left = 0;
402 drawRect.top = 0;
403 add_ruler_units(hdc, &drawRect, NewMetrics, EditLeftmost);
404
405 SelectObject(hdc, GetStockObject(BLACK_BRUSH));
406 DeleteDC(hdcPrint);
407 EndPaint(hWnd, &ps);
408 }
409
ruler_proc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)410 LRESULT CALLBACK ruler_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
411 {
412 static WNDPROC pPrevRulerProc;
413 static LONG EditLeftmost;
414 static BOOL NewMetrics;
415
416 switch(msg)
417 {
418 case WM_USER:
419 if(wParam)
420 {
421 EditLeftmost = ((POINTL*)wParam)->x;
422 pPrevRulerProc = (WNDPROC)lParam;
423 }
424 NewMetrics = TRUE;
425 break;
426
427 case WM_PAINT:
428 paint_ruler(hWnd, EditLeftmost, NewMetrics);
429 break;
430
431 default:
432 return CallWindowProcW(pPrevRulerProc, hWnd, msg, wParam, lParam);
433 }
434
435 return 0;
436 }
437
print(LPPRINTDLGW pd,LPWSTR wszFileName)438 static void print(LPPRINTDLGW pd, LPWSTR wszFileName)
439 {
440 FORMATRANGE fr;
441 DOCINFOW di;
442 HWND hEditorWnd = GetDlgItem(pd->hwndOwner, IDC_EDITOR);
443 int printedPages = 0;
444
445 fr.hdc = pd->hDC;
446 fr.hdcTarget = pd->hDC;
447
448 fr.rc = get_print_rect(fr.hdc);
449 SetRect(&fr.rcPage, 0, 0, fr.rc.right + margins.right, fr.rc.bottom + margins.bottom);
450
451 ZeroMemory(&di, sizeof(di));
452 di.cbSize = sizeof(di);
453 di.lpszDocName = wszFileName;
454
455 if(pd->Flags & PD_PRINTTOFILE)
456 {
457 di.lpszOutput = dialog_print_to_file(pd->hwndOwner);
458 if(!di.lpszOutput)
459 return;
460 }
461
462 if(pd->Flags & PD_SELECTION)
463 {
464 SendMessageW(hEditorWnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg);
465 } else
466 {
467 GETTEXTLENGTHEX gt;
468 gt.flags = GTL_DEFAULT;
469 gt.codepage = 1200;
470 fr.chrg.cpMin = 0;
471 fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0);
472
473 if(pd->Flags & PD_PAGENUMS)
474 char_from_pagenum(hEditorWnd, &fr, pd->nToPage);
475 }
476
477 StartDocW(fr.hdc, &di);
478 do
479 {
480 if(StartPage(fr.hdc) <= 0)
481 break;
482
483 fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
484
485 if(EndPage(fr.hdc) <= 0)
486 break;
487
488 printedPages++;
489 if((pd->Flags & PD_PAGENUMS) && (printedPages > (pd->nToPage - pd->nFromPage)))
490 break;
491 }
492 while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax);
493
494 EndDoc(fr.hdc);
495 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
496 }
497
dialog_printsetup(HWND hMainWnd)498 void dialog_printsetup(HWND hMainWnd)
499 {
500 PAGESETUPDLGW ps;
501
502 ZeroMemory(&ps, sizeof(ps));
503 ps.lStructSize = sizeof(ps);
504 ps.hwndOwner = hMainWnd;
505 ps.Flags = PSD_INHUNDREDTHSOFMILLIMETERS | PSD_MARGINS;
506 SetRect(&ps.rtMargin, twips_to_centmm(margins.left), twips_to_centmm(margins.top),
507 twips_to_centmm(margins.right), twips_to_centmm(margins.bottom));
508 ps.hDevMode = devMode;
509 ps.hDevNames = devNames;
510
511 if(PageSetupDlgW(&ps))
512 {
513 SetRect(&margins, centmm_to_twips(ps.rtMargin.left), centmm_to_twips(ps.rtMargin.top),
514 centmm_to_twips(ps.rtMargin.right), centmm_to_twips(ps.rtMargin.bottom));
515 devMode = ps.hDevMode;
516 devNames = ps.hDevNames;
517 update_ruler(get_ruler_wnd(hMainWnd));
518 }
519 }
520
get_default_printer_opts(void)521 void get_default_printer_opts(void)
522 {
523 PRINTDLGW pd;
524 ZeroMemory(&pd, sizeof(pd));
525
526 ZeroMemory(&pd, sizeof(pd));
527 pd.lStructSize = sizeof(pd);
528 pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
529 pd.hDevMode = devMode;
530
531 PrintDlgW(&pd);
532
533 devMode = pd.hDevMode;
534 devNames = pd.hDevNames;
535 }
536
print_quick(HWND hMainWnd,LPWSTR wszFileName)537 void print_quick(HWND hMainWnd, LPWSTR wszFileName)
538 {
539 PRINTDLGW pd;
540
541 ZeroMemory(&pd, sizeof(pd));
542 pd.hwndOwner = hMainWnd;
543 pd.hDC = make_dc();
544
545 print(&pd, wszFileName);
546 DeleteDC(pd.hDC);
547 }
548
dialog_print(HWND hMainWnd,LPWSTR wszFileName)549 void dialog_print(HWND hMainWnd, LPWSTR wszFileName)
550 {
551 PRINTDLGW pd;
552 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
553 int from = 0;
554 int to = 0;
555
556 ZeroMemory(&pd, sizeof(pd));
557 pd.lStructSize = sizeof(pd);
558 pd.hwndOwner = hMainWnd;
559 pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
560 pd.nMinPage = 1;
561 pd.nMaxPage = -1;
562 pd.hDevMode = devMode;
563 pd.hDevNames = devNames;
564
565 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
566 if(from == to)
567 pd.Flags |= PD_NOSELECTION;
568
569 if(PrintDlgW(&pd))
570 {
571 devMode = pd.hDevMode;
572 devNames = pd.hDevNames;
573 print(&pd, wszFileName);
574 update_ruler(get_ruler_wnd(hMainWnd));
575 }
576 }
577
preview_bar_show(HWND hMainWnd,BOOL show)578 static void preview_bar_show(HWND hMainWnd, BOOL show)
579 {
580 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
581 int i;
582
583 if(show)
584 {
585 REBARBANDINFOW rb;
586 HWND hStatic;
587 UINT num_pages_string = preview.pages_shown > 1 ? STRING_PREVIEW_ONEPAGE :
588 STRING_PREVIEW_TWOPAGES;
589
590 AddTextButton(hReBar, STRING_PREVIEW_PRINT, ID_PRINT, BANDID_PREVIEW_BTN1);
591 AddTextButton(hReBar, STRING_PREVIEW_NEXTPAGE, ID_PREVIEW_NEXTPAGE, BANDID_PREVIEW_BTN2);
592 AddTextButton(hReBar, STRING_PREVIEW_PREVPAGE, ID_PREVIEW_PREVPAGE, BANDID_PREVIEW_BTN3);
593 AddTextButton(hReBar, num_pages_string, ID_PREVIEW_NUMPAGES, BANDID_PREVIEW_BTN4);
594 AddTextButton(hReBar, STRING_PREVIEW_ZOOMIN, ID_PREVIEW_ZOOMIN, BANDID_PREVIEW_BTN5);
595 AddTextButton(hReBar, STRING_PREVIEW_ZOOMOUT, ID_PREVIEW_ZOOMOUT, BANDID_PREVIEW_BTN6);
596 AddTextButton(hReBar, STRING_PREVIEW_CLOSE, ID_FILE_EXIT, BANDID_PREVIEW_BTN7);
597
598 hStatic = CreateWindowW(WC_STATICW, NULL,
599 WS_VISIBLE | WS_CHILD, 0, 0, 0, 0,
600 hReBar, NULL, NULL, NULL);
601
602 rb.cbSize = REBARBANDINFOW_V6_SIZE;
603 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID;
604 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT;
605 rb.hwndChild = hStatic;
606 rb.cyChild = rb.cyMinChild = 22;
607 rb.cx = rb.cxMinChild = 90;
608 rb.cxIdeal = 100;
609 rb.wID = BANDID_PREVIEW_BUFFER;
610
611 SendMessageW(hReBar, RB_INSERTBANDW, -1, (LPARAM)&rb);
612 } else
613 {
614 for(i = 0; i <= PREVIEW_BUTTONS; i++)
615 SendMessageW(hReBar, RB_DELETEBAND, SendMessageW(hReBar, RB_IDTOINDEX, BANDID_PREVIEW_BTN1+i, 0), 0);
616 }
617 }
618
619 static const int min_spacing = 10;
620
update_preview_scrollbars(HWND hwndPreview,RECT * window)621 static void update_preview_scrollbars(HWND hwndPreview, RECT *window)
622 {
623 SCROLLINFO sbi;
624 sbi.cbSize = sizeof(sbi);
625 sbi.fMask = SIF_PAGE|SIF_RANGE;
626 sbi.nMin = 0;
627 if (preview.zoomlevel == 0)
628 {
629 /* Hide scrollbars when zoomed out. */
630 sbi.nMax = 0;
631 sbi.nPage = window->right;
632 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE);
633 sbi.nPage = window->bottom;
634 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE);
635 } else {
636 sbi.nMax = preview.bmScaledSize.cx * preview.pages_shown +
637 min_spacing * (preview.pages_shown + 1);
638 sbi.nPage = window->right;
639 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE);
640 /* Change in the horizontal scrollbar visibility affects the
641 * client rect, so update the client rect. */
642 GetClientRect(hwndPreview, window);
643 sbi.nMax = preview.bmScaledSize.cy + min_spacing * 2;
644 sbi.nPage = window->bottom;
645 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE);
646 }
647 }
648
update_preview_sizes(HWND hwndPreview,BOOL zoomLevelUpdated)649 static void update_preview_sizes(HWND hwndPreview, BOOL zoomLevelUpdated)
650 {
651 RECT window;
652
653 GetClientRect(hwndPreview, &window);
654
655 /* The zoom ratio isn't updated for partial zoom because of resizing the window. */
656 if (zoomLevelUpdated || preview.zoomlevel != 1)
657 {
658 float ratio, ratioHeight, ratioWidth;
659 if (preview.zoomlevel == 2)
660 {
661 ratio = 1.0;
662 } else {
663 ratioHeight = (window.bottom - min_spacing * 2) / (float)preview.bmSize.cy;
664
665 ratioWidth = (float)(window.right -
666 min_spacing * (preview.pages_shown + 1)) /
667 (preview.pages_shown * preview.bmSize.cx);
668
669 if(ratioWidth > ratioHeight)
670 ratio = ratioHeight;
671 else
672 ratio = ratioWidth;
673
674 if (preview.zoomlevel == 1)
675 ratio += (1.0 - ratio) / 2;
676 }
677 preview.zoomratio = ratio;
678 }
679
680 preview.bmScaledSize.cx = preview.bmSize.cx * preview.zoomratio;
681 preview.bmScaledSize.cy = preview.bmSize.cy * preview.zoomratio;
682
683 preview.spacing.cy = max(min_spacing, (window.bottom - preview.bmScaledSize.cy) / 2);
684
685 preview.spacing.cx = (window.right -
686 preview.bmScaledSize.cx * preview.pages_shown) /
687 (preview.pages_shown + 1);
688 if (preview.spacing.cx < min_spacing)
689 preview.spacing.cx = min_spacing;
690
691 update_preview_scrollbars(hwndPreview, &window);
692 }
693
draw_margin_lines(HDC hdc,int x,int y,float ratio)694 static void draw_margin_lines(HDC hdc, int x, int y, float ratio)
695 {
696 HPEN hPen, oldPen;
697 SIZE dpi;
698 RECT page_margin = preview.rcPage;
699
700 dpi.cx = GetDeviceCaps(hdc, LOGPIXELSX);
701 dpi.cy = GetDeviceCaps(hdc, LOGPIXELSY);
702
703 SetRect(&page_margin, preview.rcPage.left + margins.left, preview.rcPage.top + margins.top,
704 preview.rcPage.right - margins.right, preview.rcPage.bottom - margins.bottom);
705
706 page_margin.left = (int)((float)twips_to_pixels(page_margin.left, dpi.cx) * ratio);
707 page_margin.top = (int)((float)twips_to_pixels(page_margin.top, dpi.cy) * ratio);
708 page_margin.bottom = (int)((float)twips_to_pixels(page_margin.bottom, dpi.cy) * ratio);
709 page_margin.right = (int)((float)twips_to_pixels(page_margin.right, dpi.cx) * ratio);
710
711 OffsetRect(&page_margin, x, y);
712
713 hPen = CreatePen(PS_DOT, 1, RGB(0,0,0));
714 oldPen = SelectObject(hdc, hPen);
715
716 MoveToEx(hdc, x, page_margin.top, NULL);
717 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.top);
718 MoveToEx(hdc, x, page_margin.bottom, NULL);
719 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.bottom);
720
721 MoveToEx(hdc, page_margin.left, y, NULL);
722 LineTo(hdc, page_margin.left, y + preview.bmScaledSize.cy);
723 MoveToEx(hdc, page_margin.right, y, NULL);
724 LineTo(hdc, page_margin.right, y + preview.bmScaledSize.cy);
725
726 SelectObject(hdc, oldPen);
727 DeleteObject(hPen);
728 }
729
is_last_preview_page(int page)730 static BOOL is_last_preview_page(int page)
731 {
732 return preview.pageEnds[page - 1] >= preview.textlength;
733 }
734
init_preview(HWND hMainWnd,LPWSTR wszFileName)735 void init_preview(HWND hMainWnd, LPWSTR wszFileName)
736 {
737 HINSTANCE hInstance = GetModuleHandleW(0);
738 preview.page = 1;
739 preview.hdc = 0;
740 preview.hdc2 = 0;
741 preview.wszFileName = wszFileName;
742 preview.zoomratio = 0;
743 preview.zoomlevel = 0;
744 preview_bar_show(hMainWnd, TRUE);
745
746 CreateWindowExW(0, wszPreviewWndClass, NULL,
747 WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL,
748 0, 0, 200, 10, hMainWnd, (HMENU)IDC_PREVIEW, hInstance, NULL);
749 }
750
close_preview(HWND hMainWnd)751 void close_preview(HWND hMainWnd)
752 {
753 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW);
754 preview.window.right = 0;
755 preview.window.bottom = 0;
756 preview.page = 0;
757 HeapFree(GetProcessHeap(), 0, preview.pageEnds);
758 preview.pageEnds = NULL;
759 preview.pageCapacity = 0;
760 if (preview.zoomlevel > 0)
761 preview.pages_shown = preview.saved_pages_shown;
762 if(preview.hdc) {
763 HBITMAP oldbm = GetCurrentObject(preview.hdc, OBJ_BITMAP);
764 DeleteDC(preview.hdc);
765 DeleteObject(oldbm);
766 preview.hdc = NULL;
767 }
768 if(preview.hdc2) {
769 HBITMAP oldbm = GetCurrentObject(preview.hdc2, OBJ_BITMAP);
770 DeleteDC(preview.hdc2);
771 DeleteObject(oldbm);
772 preview.hdc2 = NULL;
773 }
774
775 preview_bar_show(hMainWnd, FALSE);
776 DestroyWindow(hwndPreview);
777 }
778
preview_isactive(void)779 BOOL preview_isactive(void)
780 {
781 return preview.page != 0;
782 }
783
draw_preview(HWND hEditorWnd,FORMATRANGE * lpFr,RECT * paper,int page)784 static void draw_preview(HWND hEditorWnd, FORMATRANGE* lpFr, RECT* paper, int page)
785 {
786 int bottom;
787
788 if (!preview.pageEnds)
789 {
790 preview.pageCapacity = 32;
791 preview.pageEnds = HeapAlloc(GetProcessHeap(), 0,
792 sizeof(int) * preview.pageCapacity);
793 if (!preview.pageEnds) return;
794 } else if (page >= preview.pageCapacity) {
795 int *new_buffer;
796 new_buffer = HeapReAlloc(GetProcessHeap(), 0, preview.pageEnds,
797 sizeof(int) * preview.pageCapacity * 2);
798 if (!new_buffer) return;
799 preview.pageCapacity *= 2;
800 preview.pageEnds = new_buffer;
801 }
802
803 FillRect(lpFr->hdc, paper, GetStockObject(WHITE_BRUSH));
804 if (page > 1 && is_last_preview_page(page - 1)) return;
805 lpFr->chrg.cpMin = page <= 1 ? 0 : preview.pageEnds[page-2];
806 bottom = lpFr->rc.bottom;
807 preview.pageEnds[page-1] = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)lpFr);
808
809 /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in,
810 * but we want to keep the original for drawing margins */
811 lpFr->rc.bottom = bottom;
812 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
813 }
814
update_preview_buttons(HWND hMainWnd)815 static void update_preview_buttons(HWND hMainWnd)
816 {
817 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
818 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_PREVPAGE), preview.page > 1);
819 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NEXTPAGE),
820 !is_last_preview_page(preview.page) &&
821 !is_last_preview_page(preview.page + preview.pages_shown - 1));
822 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES),
823 preview.pages_shown > 1 ||
824 (!is_last_preview_page(1) && preview.zoomlevel == 0));
825 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMIN), preview.zoomlevel < 2);
826 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMOUT), preview.zoomlevel > 0);
827 }
828
print_preview(HWND hwndPreview)829 static LRESULT print_preview(HWND hwndPreview)
830 {
831 HPEN hPen, oldPen;
832 HDC hdc;
833 HRGN back_rgn, excl_rgn;
834 RECT window, background;
835 PAINTSTRUCT ps;
836 int x, y;
837
838 hdc = BeginPaint(hwndPreview, &ps);
839 GetClientRect(hwndPreview, &window);
840 back_rgn = CreateRectRgnIndirect(&window);
841
842 x = preview.spacing.cx - GetScrollPos(hwndPreview, SB_HORZ);
843 y = preview.spacing.cy - GetScrollPos(hwndPreview, SB_VERT);
844
845 /* draw page outlines */
846 hPen = CreatePen(PS_SOLID|PS_INSIDEFRAME, 2, RGB(0,0,0));
847 oldPen = SelectObject(hdc, hPen);
848 SetRect(&background, x - 2, y - 2, x + preview.bmScaledSize.cx + 2,
849 y + preview.bmScaledSize.cy + 2);
850 Rectangle(hdc, background.left, background.top,
851 background.right, background.bottom);
852 excl_rgn = CreateRectRgnIndirect(&background);
853 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF);
854 if(preview.pages_shown > 1)
855 {
856 background.left += preview.bmScaledSize.cx + preview.spacing.cx;
857 background.right += preview.bmScaledSize.cx + preview.spacing.cx;
858 Rectangle(hdc, background.left, background.top,
859 background.right, background.bottom);
860 SetRectRgn(excl_rgn, background.left, background.top,
861 background.right, background.bottom);
862 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF);
863 }
864 SelectObject(hdc, oldPen);
865 DeleteObject(hPen);
866 FillRgn(hdc, back_rgn, GetStockObject(GRAY_BRUSH));
867 DeleteObject(excl_rgn);
868 DeleteObject(back_rgn);
869
870 StretchBlt(hdc, x, y, preview.bmScaledSize.cx, preview.bmScaledSize.cy,
871 preview.hdc, 0, 0, preview.bmSize.cx, preview.bmSize.cy, SRCCOPY);
872
873 draw_margin_lines(hdc, x, y, preview.zoomratio);
874
875 if(preview.pages_shown > 1)
876 {
877 if (!is_last_preview_page(preview.page)) {
878 x += preview.spacing.cx + preview.bmScaledSize.cx;
879 StretchBlt(hdc, x, y,
880 preview.bmScaledSize.cx, preview.bmScaledSize.cy,
881 preview.hdc2, 0, 0,
882 preview.bmSize.cx, preview.bmSize.cy, SRCCOPY);
883
884 draw_margin_lines(hdc, x, y, preview.zoomratio);
885 } else {
886 InflateRect(&background, -2, -2);
887 FillRect(hdc, &background, GetStockObject(WHITE_BRUSH));
888 }
889 }
890
891 preview.window = window;
892
893 EndPaint(hwndPreview, &ps);
894
895 return 0;
896 }
897
update_preview_statusbar(HWND hMainWnd)898 static void update_preview_statusbar(HWND hMainWnd)
899 {
900 HWND hStatusbar = GetDlgItem(hMainWnd, IDC_STATUSBAR);
901 HINSTANCE hInst = GetModuleHandleW(0);
902 WCHAR *p;
903 WCHAR wstr[MAX_STRING_LEN];
904
905 p = wstr;
906 if (preview.pages_shown < 2 || is_last_preview_page(preview.page))
907 {
908 static const WCHAR fmt[] = {' ','%','d','\0'};
909 p += LoadStringW(hInst, STRING_PREVIEW_PAGE, wstr, MAX_STRING_LEN);
910 wsprintfW(p, fmt, preview.page);
911 } else {
912 static const WCHAR fmt[] = {' ','%','d','-','%','d','\0'};
913 p += LoadStringW(hInst, STRING_PREVIEW_PAGES, wstr, MAX_STRING_LEN);
914 wsprintfW(p, fmt, preview.page, preview.page + 1);
915 }
916 SetWindowTextW(hStatusbar, wstr);
917 }
918
919 /* Update for page changes. */
update_preview(HWND hMainWnd)920 static void update_preview(HWND hMainWnd)
921 {
922 RECT paper;
923 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
924 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW);
925 HBITMAP hBitmapCapture;
926 FORMATRANGE fr;
927 HDC hdc = GetDC(hwndPreview);
928
929 fr.hdcTarget = make_dc();
930 fr.rc = fr.rcPage = preview.rcPage;
931 fr.rc.left += margins.left;
932 fr.rc.top += margins.top;
933 fr.rc.bottom -= margins.bottom;
934 fr.rc.right -= margins.right;
935
936 fr.chrg.cpMin = 0;
937 fr.chrg.cpMax = preview.textlength;
938
939 SetRect(&paper, 0, 0, preview.bmSize.cx, preview.bmSize.cy);
940
941 if (!preview.hdc) {
942 preview.hdc = CreateCompatibleDC(hdc);
943 hBitmapCapture = CreateCompatibleBitmap(hdc, preview.bmSize.cx, preview.bmSize.cy);
944 SelectObject(preview.hdc, hBitmapCapture);
945 }
946
947 fr.hdc = preview.hdc;
948 draw_preview(hEditorWnd, &fr, &paper, preview.page);
949
950 if(preview.pages_shown > 1)
951 {
952 if (!preview.hdc2)
953 {
954 preview.hdc2 = CreateCompatibleDC(hdc);
955 hBitmapCapture = CreateCompatibleBitmap(hdc,
956 preview.bmSize.cx,
957 preview.bmSize.cy);
958 SelectObject(preview.hdc2, hBitmapCapture);
959 }
960
961 fr.hdc = preview.hdc2;
962 draw_preview(hEditorWnd, &fr, &fr.rcPage, preview.page + 1);
963 }
964 DeleteDC(fr.hdcTarget);
965 ReleaseDC(hwndPreview, hdc);
966
967 InvalidateRect(hwndPreview, NULL, FALSE);
968 update_preview_buttons(hMainWnd);
969 update_preview_statusbar(hMainWnd);
970 }
971
toggle_num_pages(HWND hMainWnd)972 static void toggle_num_pages(HWND hMainWnd)
973 {
974 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
975 WCHAR name[MAX_STRING_LEN];
976 HINSTANCE hInst = GetModuleHandleW(0);
977 int nPreviewPages;
978
979 preview.pages_shown = preview.pages_shown > 1 ? 1 : 2;
980
981 nPreviewPages = preview.zoomlevel > 0 ? preview.saved_pages_shown :
982 preview.pages_shown;
983
984 LoadStringW(hInst, nPreviewPages > 1 ? STRING_PREVIEW_ONEPAGE :
985 STRING_PREVIEW_TWOPAGES,
986 name, MAX_STRING_LEN);
987
988 SetWindowTextW(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), name);
989 update_preview_sizes(GetDlgItem(hMainWnd, IDC_PREVIEW), TRUE);
990 update_preview(hMainWnd);
991 }
992
993 /* Returns the page shown that the point is in (1 or 2) or 0 if the point
994 * isn't inside either page */
preview_page_hittest(POINT pt)995 static int preview_page_hittest(POINT pt)
996 {
997 RECT rc;
998 rc.left = preview.spacing.cx;
999 rc.right = rc.left + preview.bmScaledSize.cx;
1000 rc.top = preview.spacing.cy;
1001 rc.bottom = rc.top + preview.bmScaledSize.cy;
1002 if (PtInRect(&rc, pt))
1003 return 1;
1004
1005 if (preview.pages_shown <= 1)
1006 return 0;
1007
1008 rc.left += preview.bmScaledSize.cx + preview.spacing.cx;
1009 rc.right += preview.bmScaledSize.cx + preview.spacing.cx;
1010 if (PtInRect(&rc, pt))
1011 return is_last_preview_page(preview.page) ? 1 : 2;
1012
1013 return 0;
1014 }
1015
preview_proc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)1016 LRESULT CALLBACK preview_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1017 {
1018 switch(msg)
1019 {
1020 case WM_CREATE:
1021 {
1022 HWND hMainWnd = GetParent(hWnd);
1023 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
1024 FORMATRANGE fr;
1025 GETTEXTLENGTHEX gt = {GTL_DEFAULT, 1200};
1026 HDC hdc = GetDC(hWnd);
1027 HDC hdcTarget = make_dc();
1028
1029 fr.rc = preview.rcPage = get_print_rect(hdcTarget);
1030 preview.rcPage.bottom += margins.bottom;
1031 preview.rcPage.right += margins.right;
1032 preview.rcPage.top = preview.rcPage.left = 0;
1033 fr.rcPage = preview.rcPage;
1034
1035 preview.bmSize.cx = twips_to_pixels(preview.rcPage.right, GetDeviceCaps(hdc, LOGPIXELSX));
1036 preview.bmSize.cy = twips_to_pixels(preview.rcPage.bottom, GetDeviceCaps(hdc, LOGPIXELSY));
1037
1038 preview.textlength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0);
1039
1040 fr.hdc = CreateCompatibleDC(hdc);
1041 fr.hdcTarget = hdcTarget;
1042 fr.chrg.cpMin = 0;
1043 fr.chrg.cpMax = preview.textlength;
1044 DeleteDC(fr.hdc);
1045 DeleteDC(hdcTarget);
1046 ReleaseDC(hWnd, hdc);
1047
1048 update_preview_sizes(hWnd, TRUE);
1049 update_preview(hMainWnd);
1050 break;
1051 }
1052
1053 case WM_PAINT:
1054 return print_preview(hWnd);
1055
1056 case WM_SIZE:
1057 {
1058 update_preview_sizes(hWnd, FALSE);
1059 InvalidateRect(hWnd, NULL, FALSE);
1060 break;
1061 }
1062
1063 case WM_VSCROLL:
1064 case WM_HSCROLL:
1065 {
1066 SCROLLINFO si;
1067 RECT rc;
1068 int nBar = (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ;
1069 int origPos;
1070
1071 GetClientRect(hWnd, &rc);
1072 si.cbSize = sizeof(si);
1073 si.fMask = SIF_ALL;
1074 GetScrollInfo(hWnd, nBar, &si);
1075 origPos = si.nPos;
1076 switch(LOWORD(wParam))
1077 {
1078 case SB_TOP: /* == SB_LEFT */
1079 si.nPos = si.nMin;
1080 break;
1081 case SB_BOTTOM: /* == SB_RIGHT */
1082 si.nPos = si.nMax;
1083 break;
1084 case SB_LINEUP: /* == SB_LINELEFT */
1085 si.nPos -= si.nPage / 10;
1086 break;
1087 case SB_LINEDOWN: /* == SB_LINERIGHT */
1088 si.nPos += si.nPage / 10;
1089 break;
1090 case SB_PAGEUP: /* == SB_PAGELEFT */
1091 si.nPos -= si.nPage;
1092 break;
1093 case SB_PAGEDOWN: /* SB_PAGERIGHT */
1094 si.nPos += si.nPage;
1095 break;
1096 case SB_THUMBTRACK:
1097 si.nPos = si.nTrackPos;
1098 break;
1099 }
1100 si.fMask = SIF_POS;
1101 SetScrollInfo(hWnd, nBar, &si, TRUE);
1102 GetScrollInfo(hWnd, nBar, &si);
1103 if (si.nPos != origPos)
1104 {
1105 int amount = origPos - si.nPos;
1106 if (msg == WM_VSCROLL)
1107 ScrollWindow(hWnd, 0, amount, NULL, NULL);
1108 else
1109 ScrollWindow(hWnd, amount, 0, NULL, NULL);
1110 }
1111 return 0;
1112 }
1113
1114 case WM_SETCURSOR:
1115 {
1116 POINT pt;
1117 RECT rc;
1118 int bHittest = 0;
1119 DWORD messagePos = GetMessagePos();
1120 pt.x = (short)LOWORD(messagePos);
1121 pt.y = (short)HIWORD(messagePos);
1122 ScreenToClient(hWnd, &pt);
1123
1124 GetClientRect(hWnd, &rc);
1125 if (PtInRect(&rc, pt))
1126 {
1127 pt.x += GetScrollPos(hWnd, SB_HORZ);
1128 pt.y += GetScrollPos(hWnd, SB_VERT);
1129 bHittest = preview_page_hittest(pt);
1130 }
1131
1132 if (bHittest)
1133 SetCursor(LoadCursorW(GetModuleHandleW(0),
1134 MAKEINTRESOURCEW(IDC_ZOOM)));
1135 else
1136 SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW));
1137
1138 return TRUE;
1139 }
1140
1141 case WM_LBUTTONDOWN:
1142 {
1143 int page;
1144 POINT pt;
1145 pt.x = (short)LOWORD(lParam) + GetScrollPos(hWnd, SB_HORZ);
1146 pt.y = (short)HIWORD(lParam) + GetScrollPos(hWnd, SB_VERT);
1147 if ((page = preview_page_hittest(pt)) > 0)
1148 {
1149 HWND hMainWnd = GetParent(hWnd);
1150
1151 /* Convert point from client coordinate to unzoomed page
1152 * coordinate. */
1153 pt.x -= preview.spacing.cx;
1154 if (page > 1)
1155 pt.x -= preview.bmScaledSize.cx + preview.spacing.cx;
1156 pt.y -= preview.spacing.cy;
1157 pt.x /= preview.zoomratio;
1158 pt.y /= preview.zoomratio;
1159
1160 if (preview.zoomlevel == 0)
1161 preview.saved_pages_shown = preview.pages_shown;
1162 preview.zoomlevel = (preview.zoomlevel + 1) % 3;
1163 preview.zoomratio = 0;
1164 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1)
1165 {
1166 toggle_num_pages(hMainWnd);
1167 } else if (preview.pages_shown > 1) {
1168 if (page >= 2) preview.page++;
1169 toggle_num_pages(hMainWnd);
1170 } else {
1171 update_preview_sizes(hWnd, TRUE);
1172 InvalidateRect(hWnd, NULL, FALSE);
1173 update_preview_buttons(hMainWnd);
1174 }
1175
1176 if (preview.zoomlevel > 0) {
1177 SCROLLINFO si;
1178 /* Convert the coordinate back to client coordinate. */
1179 pt.x *= preview.zoomratio;
1180 pt.y *= preview.zoomratio;
1181 pt.x += preview.spacing.cx;
1182 pt.y += preview.spacing.cy;
1183 /* Scroll to center view at that point on the page */
1184 si.cbSize = sizeof(si);
1185 si.fMask = SIF_PAGE;
1186 GetScrollInfo(hWnd, SB_HORZ, &si);
1187 pt.x -= si.nPage / 2;
1188 SetScrollPos(hWnd, SB_HORZ, pt.x, TRUE);
1189 GetScrollInfo(hWnd, SB_VERT, &si);
1190 pt.y -= si.nPage / 2;
1191 SetScrollPos(hWnd, SB_VERT, pt.y, TRUE);
1192 }
1193 }
1194 }
1195
1196 default:
1197 return DefWindowProcW(hWnd, msg, wParam, lParam);
1198 }
1199
1200 return 0;
1201 }
1202
preview_command(HWND hWnd,WPARAM wParam)1203 LRESULT preview_command(HWND hWnd, WPARAM wParam)
1204 {
1205 switch(LOWORD(wParam))
1206 {
1207 case ID_FILE_EXIT:
1208 PostMessageW(hWnd, WM_CLOSE, 0, 0);
1209 break;
1210
1211 case ID_PREVIEW_NEXTPAGE:
1212 case ID_PREVIEW_PREVPAGE:
1213 {
1214 if(LOWORD(wParam) == ID_PREVIEW_NEXTPAGE)
1215 preview.page++;
1216 else
1217 preview.page--;
1218
1219 update_preview(hWnd);
1220 }
1221 break;
1222
1223 case ID_PREVIEW_NUMPAGES:
1224 toggle_num_pages(hWnd);
1225 break;
1226
1227 case ID_PREVIEW_ZOOMIN:
1228 if (preview.zoomlevel < 2)
1229 {
1230 if (preview.zoomlevel == 0)
1231 preview.saved_pages_shown = preview.pages_shown;
1232 preview.zoomlevel++;
1233 preview.zoomratio = 0;
1234 if (preview.pages_shown > 1)
1235 {
1236 /* Forced switch to one page when zooming in. */
1237 toggle_num_pages(hWnd);
1238 } else {
1239 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW);
1240 update_preview_sizes(hwndPreview, TRUE);
1241 InvalidateRect(hwndPreview, NULL, FALSE);
1242 update_preview_buttons(hWnd);
1243 }
1244 }
1245 break;
1246
1247 case ID_PREVIEW_ZOOMOUT:
1248 if (preview.zoomlevel > 0)
1249 {
1250 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW);
1251 preview.zoomlevel--;
1252 preview.zoomratio = 0;
1253 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1) {
1254 toggle_num_pages(hWnd);
1255 } else {
1256 update_preview_sizes(hwndPreview, TRUE);
1257 InvalidateRect(hwndPreview, NULL, FALSE);
1258 update_preview_buttons(hWnd);
1259 }
1260 }
1261 break;
1262
1263 case ID_PRINT:
1264 dialog_print(hWnd, preview.wszFileName);
1265 SendMessageW(hWnd, WM_CLOSE, 0, 0);
1266 break;
1267 }
1268
1269 return 0;
1270 }
1271