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