mmdevapi/tests: Avoid %ll printf format.
[wine.git] / programs / wordpad / print.c
blob9021989df66e541f040e717b9ae4f416f8a6bd36
1 /*
2 * Wordpad implementation - Printing and print preview functions
4 * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com>
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.
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.
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
21 #include <windows.h>
22 #include <richedit.h>
23 #include <commctrl.h>
24 #include <commdlg.h>
26 #include "wordpad.h"
28 typedef struct _previewinfo
30 int page;
31 int pages_shown;
32 int saved_pages_shown;
33 int *pageEnds, pageCapacity;
34 int textlength;
35 HDC hdc;
36 HDC hdc2;
37 RECT window;
38 RECT rcPage;
39 SIZE bmSize;
40 SIZE bmScaledSize;
41 SIZE spacing;
42 float zoomratio;
43 int zoomlevel;
44 LPWSTR wszFileName;
45 } previewinfo, *ppreviewinfo;
47 static HGLOBAL devMode;
48 static HGLOBAL devNames;
50 static RECT margins;
51 static previewinfo preview;
53 extern const WCHAR wszPreviewWndClass[];
55 static const WCHAR var_pagemargin[] = {'P','a','g','e','M','a','r','g','i','n',0};
56 static const WCHAR var_previewpages[] = {'P','r','e','v','i','e','w','P','a','g','e','s',0};
58 static LPWSTR get_print_file_filter(HWND hMainWnd)
60 static WCHAR wszPrintFilter[MAX_STRING_LEN*2+6+4+1];
61 const WCHAR files_prn[] = {'*','.','P','R','N',0};
62 const WCHAR files_all[] = {'*','.','*','\0'};
63 LPWSTR p;
64 HINSTANCE hInstance = GetModuleHandleW(0);
66 p = wszPrintFilter;
67 LoadStringW(hInstance, STRING_PRINTER_FILES_PRN, p, MAX_STRING_LEN);
68 p += lstrlenW(p) + 1;
69 lstrcpyW(p, files_prn);
70 p += lstrlenW(p) + 1;
71 LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
72 p += lstrlenW(p) + 1;
73 lstrcpyW(p, files_all);
74 p += lstrlenW(p) + 1;
75 *p = 0;
77 return wszPrintFilter;
80 void registry_set_pagemargins(HKEY hKey)
82 RegSetValueExW(hKey, var_pagemargin, 0, REG_BINARY, (LPBYTE)&margins, sizeof(RECT));
85 void registry_read_pagemargins(HKEY hKey)
87 DWORD size = sizeof(RECT);
89 if(!hKey || RegQueryValueExW(hKey, var_pagemargin, 0, NULL, (LPBYTE)&margins,
90 &size) != ERROR_SUCCESS || size != sizeof(RECT))
92 margins.top = 1417;
93 margins.bottom = 1417;
94 margins.left = 1757;
95 margins.right = 1757;
99 void registry_set_previewpages(HKEY hKey)
101 RegSetValueExW(hKey, var_previewpages, 0, REG_DWORD,
102 (LPBYTE)&preview.pages_shown, sizeof(DWORD));
105 void registry_read_previewpages(HKEY hKey)
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))
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;
121 static void AddTextButton(HWND hRebarWnd, UINT string, UINT command, UINT id)
123 REBARBANDINFOW rb;
124 HINSTANCE hInstance = GetModuleHandleW(0);
125 WCHAR text[MAX_STRING_LEN];
126 HWND hButton;
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);
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;
142 SendMessageW(hRebarWnd, RB_INSERTBANDW, -1, (LPARAM)&rb);
145 static HDC make_dc(void)
147 if(devNames && devMode)
149 LPDEVNAMES dn = GlobalLock(devNames);
150 LPDEVMODEW dm = GlobalLock(devMode);
151 HDC ret;
153 ret = CreateDCW((LPWSTR)dn + dn->wDriverOffset,
154 (LPWSTR)dn + dn->wDeviceOffset, 0, dm);
156 GlobalUnlock(dn);
157 GlobalUnlock(dm);
159 return ret;
160 } else
162 return 0;
166 static LONG twips_to_centmm(int twips)
168 return MulDiv(twips, CENTMM_PER_INCH, TWIPS_PER_INCH);
171 static LONG centmm_to_twips(int mm)
173 return MulDiv(mm, TWIPS_PER_INCH, CENTMM_PER_INCH);
176 static LONG twips_to_pixels(int twips, int dpi)
178 return MulDiv(twips, dpi, TWIPS_PER_INCH);
181 static LONG devunits_to_twips(int units, int dpi)
183 return MulDiv(units, TWIPS_PER_INCH, dpi);
187 static RECT get_print_rect(HDC hdc)
189 RECT rc;
190 int width, height;
192 if(hdc)
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
200 width = centmm_to_twips(18500);
201 height = centmm_to_twips(27000);
204 rc.left = margins.left;
205 rc.right = width - margins.right;
206 rc.top = margins.top;
207 rc.bottom = height - margins.bottom;
209 return rc;
212 void target_device(HWND hMainWnd, DWORD wordWrap)
214 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
216 if(wordWrap == ID_WORDWRAP_MARGIN)
218 int width = 0;
219 LRESULT result;
220 HDC hdc = make_dc();
221 RECT rc = get_print_rect(hdc);
223 width = rc.right - rc.left;
224 if(!hdc)
226 HDC hMaindc = GetDC(hMainWnd);
227 hdc = CreateCompatibleDC(hMaindc);
228 ReleaseDC(hMainWnd, hMaindc);
230 result = SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, (WPARAM)hdc, width);
231 DeleteDC(hdc);
232 if (result)
233 return;
234 /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping
235 * to window using the NULL DC. */
238 if (wordWrap != ID_WORDWRAP_NONE) {
239 SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 0);
240 } else {
241 SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 1);
246 static LPWSTR dialog_print_to_file(HWND hMainWnd)
248 OPENFILENAMEW ofn;
249 static WCHAR file[MAX_PATH] = {'O','U','T','P','U','T','.','P','R','N',0};
250 static const WCHAR defExt[] = {'P','R','N',0};
251 static LPWSTR file_filter;
253 if(!file_filter)
254 file_filter = get_print_file_filter(hMainWnd);
256 ZeroMemory(&ofn, sizeof(ofn));
258 ofn.lStructSize = sizeof(ofn);
259 ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
260 ofn.hwndOwner = hMainWnd;
261 ofn.lpstrFilter = file_filter;
262 ofn.lpstrFile = file;
263 ofn.nMaxFile = MAX_PATH;
264 ofn.lpstrDefExt = defExt;
266 if(GetSaveFileNameW(&ofn))
267 return file;
268 else
269 return FALSE;
272 static void char_from_pagenum(HWND hEditorWnd, FORMATRANGE *fr, int page)
274 int i;
276 fr->chrg.cpMin = 0;
278 for(i = 1; i < page; i++)
280 int bottom = fr->rc.bottom;
281 fr->chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, (LPARAM)fr);
282 fr->rc.bottom = bottom;
286 static HWND get_ruler_wnd(HWND hMainWnd)
288 return GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
291 void redraw_ruler(HWND hRulerWnd)
293 RECT rc;
295 GetClientRect(hRulerWnd, &rc);
296 InvalidateRect(hRulerWnd, &rc, TRUE);
299 static void update_ruler(HWND hRulerWnd)
301 SendMessageW(hRulerWnd, WM_USER, 0, 0);
302 redraw_ruler(hRulerWnd);
305 static void add_ruler_units(HDC hdcRuler, RECT* drawRect, BOOL NewMetrics, LONG EditLeftmost)
307 static HDC hdc;
309 if(NewMetrics)
311 static HBITMAP hBitmap;
312 int i, x, y, RulerTextEnd;
313 int CmPixels;
314 int QuarterCmPixels;
315 HFONT hFont;
316 WCHAR FontName[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
318 if(hdc)
320 DeleteDC(hdc);
321 DeleteObject(hBitmap);
324 hdc = CreateCompatibleDC(0);
326 CmPixels = twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc, LOGPIXELSX));
327 QuarterCmPixels = (int)((float)CmPixels / 4.0);
329 hBitmap = CreateCompatibleBitmap(hdc, drawRect->right, drawRect->bottom);
330 SelectObject(hdc, hBitmap);
331 FillRect(hdc, drawRect, GetStockObject(WHITE_BRUSH));
333 hFont = CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName);
335 SelectObject(hdc, hFont);
336 SetBkMode(hdc, TRANSPARENT);
337 SetTextAlign(hdc, TA_CENTER);
338 y = (int)(((float)drawRect->bottom - (float)drawRect->top) / 2.0) + 1;
339 RulerTextEnd = drawRect->right - EditLeftmost + 1;
340 for(i = 1, x = EditLeftmost; x < (drawRect->right - EditLeftmost + 1); i ++)
342 WCHAR str[3];
343 WCHAR format[] = {'%','d',0};
344 int x2 = x;
346 x2 += QuarterCmPixels;
347 if(x2 > RulerTextEnd)
348 break;
350 MoveToEx(hdc, x2, y, NULL);
351 LineTo(hdc, x2, y+2);
353 x2 += QuarterCmPixels;
354 if(x2 > RulerTextEnd)
355 break;
357 MoveToEx(hdc, x2, y - 3, NULL);
358 LineTo(hdc, x2, y + 3);
360 x2 += QuarterCmPixels;
361 if(x2 > RulerTextEnd)
362 break;
364 MoveToEx(hdc, x2, y, NULL);
365 LineTo(hdc, x2, y+2);
367 x += CmPixels;
368 if(x > RulerTextEnd)
369 break;
371 wsprintfW(str, format, i);
372 TextOutW(hdc, x, 5, str, lstrlenW(str));
374 DeleteObject(hFont);
377 BitBlt(hdcRuler, 0, 0, drawRect->right, drawRect->bottom, hdc, 0, 0, SRCAND);
380 static void paint_ruler(HWND hWnd, LONG EditLeftmost, BOOL NewMetrics)
382 PAINTSTRUCT ps;
383 HDC hdc = BeginPaint(hWnd, &ps);
384 HDC hdcPrint = make_dc();
385 RECT printRect = get_print_rect(hdcPrint);
386 RECT drawRect;
387 HBRUSH hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
389 GetClientRect(hWnd, &drawRect);
390 FillRect(hdc, &drawRect, hBrush);
392 drawRect.top += 3;
393 drawRect.bottom -= 3;
394 drawRect.left = EditLeftmost;
395 drawRect.right = twips_to_pixels(printRect.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
396 FillRect(hdc, &drawRect, GetStockObject(WHITE_BRUSH));
398 drawRect.top--;
399 drawRect.bottom++;
400 DrawEdge(hdc, &drawRect, EDGE_SUNKEN, BF_RECT);
402 drawRect.left = drawRect.right - 1;
403 drawRect.right = twips_to_pixels(printRect.right + margins.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
404 DrawEdge(hdc, &drawRect, EDGE_ETCHED, BF_RECT);
406 drawRect.left = 0;
407 drawRect.top = 0;
408 add_ruler_units(hdc, &drawRect, NewMetrics, EditLeftmost);
410 SelectObject(hdc, GetStockObject(BLACK_BRUSH));
411 DeleteObject(hBrush);
412 DeleteDC(hdcPrint);
413 EndPaint(hWnd, &ps);
416 LRESULT CALLBACK ruler_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
418 static WNDPROC pPrevRulerProc;
419 static LONG EditLeftmost;
420 static BOOL NewMetrics;
422 switch(msg)
424 case WM_USER:
425 if(wParam)
427 EditLeftmost = ((POINTL*)wParam)->x;
428 pPrevRulerProc = (WNDPROC)lParam;
430 NewMetrics = TRUE;
431 break;
433 case WM_PAINT:
434 paint_ruler(hWnd, EditLeftmost, NewMetrics);
435 break;
437 default:
438 return CallWindowProcW(pPrevRulerProc, hWnd, msg, wParam, lParam);
441 return 0;
444 static void print(LPPRINTDLGW pd, LPWSTR wszFileName)
446 FORMATRANGE fr;
447 DOCINFOW di;
448 HWND hEditorWnd = GetDlgItem(pd->hwndOwner, IDC_EDITOR);
449 int printedPages = 0;
451 fr.hdc = pd->hDC;
452 fr.hdcTarget = pd->hDC;
454 fr.rc = get_print_rect(fr.hdc);
455 fr.rcPage.left = 0;
456 fr.rcPage.right = fr.rc.right + margins.right;
457 fr.rcPage.top = 0;
458 fr.rcPage.bottom = fr.rc.bottom + margins.bottom;
460 ZeroMemory(&di, sizeof(di));
461 di.cbSize = sizeof(di);
462 di.lpszDocName = wszFileName;
464 if(pd->Flags & PD_PRINTTOFILE)
466 di.lpszOutput = dialog_print_to_file(pd->hwndOwner);
467 if(!di.lpszOutput)
468 return;
471 if(pd->Flags & PD_SELECTION)
473 SendMessageW(hEditorWnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg);
474 } else
476 GETTEXTLENGTHEX gt;
477 gt.flags = GTL_DEFAULT;
478 gt.codepage = 1200;
479 fr.chrg.cpMin = 0;
480 fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
482 if(pd->Flags & PD_PAGENUMS)
483 char_from_pagenum(hEditorWnd, &fr, pd->nToPage);
486 StartDocW(fr.hdc, &di);
489 if(StartPage(fr.hdc) <= 0)
490 break;
492 fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
494 if(EndPage(fr.hdc) <= 0)
495 break;
497 printedPages++;
498 if((pd->Flags & PD_PAGENUMS) && (printedPages > (pd->nToPage - pd->nFromPage)))
499 break;
501 while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax);
503 EndDoc(fr.hdc);
504 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
507 void dialog_printsetup(HWND hMainWnd)
509 PAGESETUPDLGW ps;
511 ZeroMemory(&ps, sizeof(ps));
512 ps.lStructSize = sizeof(ps);
513 ps.hwndOwner = hMainWnd;
514 ps.Flags = PSD_INHUNDREDTHSOFMILLIMETERS | PSD_MARGINS;
515 ps.rtMargin.left = twips_to_centmm(margins.left);
516 ps.rtMargin.right = twips_to_centmm(margins.right);
517 ps.rtMargin.top = twips_to_centmm(margins.top);
518 ps.rtMargin.bottom = twips_to_centmm(margins.bottom);
519 ps.hDevMode = devMode;
520 ps.hDevNames = devNames;
522 if(PageSetupDlgW(&ps))
524 margins.left = centmm_to_twips(ps.rtMargin.left);
525 margins.right = centmm_to_twips(ps.rtMargin.right);
526 margins.top = centmm_to_twips(ps.rtMargin.top);
527 margins.bottom = centmm_to_twips(ps.rtMargin.bottom);
528 devMode = ps.hDevMode;
529 devNames = ps.hDevNames;
530 update_ruler(get_ruler_wnd(hMainWnd));
534 void get_default_printer_opts(void)
536 PRINTDLGW pd;
537 ZeroMemory(&pd, sizeof(pd));
539 ZeroMemory(&pd, sizeof(pd));
540 pd.lStructSize = sizeof(pd);
541 pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
542 pd.hDevMode = devMode;
544 PrintDlgW(&pd);
546 devMode = pd.hDevMode;
547 devNames = pd.hDevNames;
550 void print_quick(HWND hMainWnd, LPWSTR wszFileName)
552 PRINTDLGW pd;
554 ZeroMemory(&pd, sizeof(pd));
555 pd.hwndOwner = hMainWnd;
556 pd.hDC = make_dc();
558 print(&pd, wszFileName);
559 DeleteDC(pd.hDC);
562 void dialog_print(HWND hMainWnd, LPWSTR wszFileName)
564 PRINTDLGW pd;
565 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
566 int from = 0;
567 int to = 0;
569 ZeroMemory(&pd, sizeof(pd));
570 pd.lStructSize = sizeof(pd);
571 pd.hwndOwner = hMainWnd;
572 pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
573 pd.nMinPage = 1;
574 pd.nMaxPage = -1;
575 pd.hDevMode = devMode;
576 pd.hDevNames = devNames;
578 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
579 if(from == to)
580 pd.Flags |= PD_NOSELECTION;
582 if(PrintDlgW(&pd))
584 devMode = pd.hDevMode;
585 devNames = pd.hDevNames;
586 print(&pd, wszFileName);
587 update_ruler(get_ruler_wnd(hMainWnd));
591 static void preview_bar_show(HWND hMainWnd, BOOL show)
593 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
594 int i;
596 if(show)
598 REBARBANDINFOW rb;
599 HWND hStatic;
600 UINT num_pages_string = preview.pages_shown > 1 ? STRING_PREVIEW_ONEPAGE :
601 STRING_PREVIEW_TWOPAGES;
603 AddTextButton(hReBar, STRING_PREVIEW_PRINT, ID_PRINT, BANDID_PREVIEW_BTN1);
604 AddTextButton(hReBar, STRING_PREVIEW_NEXTPAGE, ID_PREVIEW_NEXTPAGE, BANDID_PREVIEW_BTN2);
605 AddTextButton(hReBar, STRING_PREVIEW_PREVPAGE, ID_PREVIEW_PREVPAGE, BANDID_PREVIEW_BTN3);
606 AddTextButton(hReBar, num_pages_string, ID_PREVIEW_NUMPAGES, BANDID_PREVIEW_BTN4);
607 AddTextButton(hReBar, STRING_PREVIEW_ZOOMIN, ID_PREVIEW_ZOOMIN, BANDID_PREVIEW_BTN5);
608 AddTextButton(hReBar, STRING_PREVIEW_ZOOMOUT, ID_PREVIEW_ZOOMOUT, BANDID_PREVIEW_BTN6);
609 AddTextButton(hReBar, STRING_PREVIEW_CLOSE, ID_FILE_EXIT, BANDID_PREVIEW_BTN7);
611 hStatic = CreateWindowW(WC_STATICW, NULL,
612 WS_VISIBLE | WS_CHILD, 0, 0, 0, 0,
613 hReBar, NULL, NULL, NULL);
615 rb.cbSize = REBARBANDINFOW_V6_SIZE;
616 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID;
617 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT;
618 rb.hwndChild = hStatic;
619 rb.cyChild = rb.cyMinChild = 22;
620 rb.cx = rb.cxMinChild = 90;
621 rb.cxIdeal = 100;
622 rb.wID = BANDID_PREVIEW_BUFFER;
624 SendMessageW(hReBar, RB_INSERTBANDW, -1, (LPARAM)&rb);
625 } else
627 for(i = 0; i <= PREVIEW_BUTTONS; i++)
628 SendMessageW(hReBar, RB_DELETEBAND, SendMessageW(hReBar, RB_IDTOINDEX, BANDID_PREVIEW_BTN1+i, 0), 0);
632 static const int min_spacing = 10;
634 static void update_preview_scrollbars(HWND hwndPreview, RECT *window)
636 SCROLLINFO sbi;
637 sbi.cbSize = sizeof(sbi);
638 sbi.fMask = SIF_PAGE|SIF_RANGE;
639 sbi.nMin = 0;
640 if (preview.zoomlevel == 0)
642 /* Hide scrollbars when zoomed out. */
643 sbi.nMax = 0;
644 sbi.nPage = window->right;
645 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE);
646 sbi.nPage = window->bottom;
647 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE);
648 } else {
649 sbi.nMax = preview.bmScaledSize.cx * preview.pages_shown +
650 min_spacing * (preview.pages_shown + 1);
651 sbi.nPage = window->right;
652 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE);
653 /* Change in the horizontal scrollbar visibility affects the
654 * client rect, so update the client rect. */
655 GetClientRect(hwndPreview, window);
656 sbi.nMax = preview.bmScaledSize.cy + min_spacing * 2;
657 sbi.nPage = window->bottom;
658 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE);
662 static void update_preview_sizes(HWND hwndPreview, BOOL zoomLevelUpdated)
664 RECT window;
666 GetClientRect(hwndPreview, &window);
668 /* The zoom ratio isn't updated for partial zoom because of resizing the window. */
669 if (zoomLevelUpdated || preview.zoomlevel != 1)
671 float ratio, ratioHeight, ratioWidth;
672 if (preview.zoomlevel == 2)
674 ratio = 1.0;
675 } else {
676 ratioHeight = (window.bottom - min_spacing * 2) / (float)preview.bmSize.cy;
678 ratioWidth = (float)(window.right -
679 min_spacing * (preview.pages_shown + 1)) /
680 (preview.pages_shown * preview.bmSize.cx);
682 if(ratioWidth > ratioHeight)
683 ratio = ratioHeight;
684 else
685 ratio = ratioWidth;
687 if (preview.zoomlevel == 1)
688 ratio += (1.0 - ratio) / 2;
690 preview.zoomratio = ratio;
693 preview.bmScaledSize.cx = preview.bmSize.cx * preview.zoomratio;
694 preview.bmScaledSize.cy = preview.bmSize.cy * preview.zoomratio;
696 preview.spacing.cy = max(min_spacing, (window.bottom - preview.bmScaledSize.cy) / 2);
698 preview.spacing.cx = (window.right -
699 preview.bmScaledSize.cx * preview.pages_shown) /
700 (preview.pages_shown + 1);
701 if (preview.spacing.cx < min_spacing)
702 preview.spacing.cx = min_spacing;
704 update_preview_scrollbars(hwndPreview, &window);
707 static void draw_margin_lines(HDC hdc, int x, int y, float ratio)
709 HPEN hPen, oldPen;
710 SIZE dpi;
711 RECT page_margin = preview.rcPage;
713 dpi.cx = GetDeviceCaps(hdc, LOGPIXELSX);
714 dpi.cy = GetDeviceCaps(hdc, LOGPIXELSY);
716 page_margin.left = preview.rcPage.left + margins.left;
717 page_margin.top = preview.rcPage.top + margins.top;
718 page_margin.bottom = preview.rcPage.bottom - margins.bottom;
719 page_margin.right = preview.rcPage.right - margins.right;
721 page_margin.left = (int)((float)twips_to_pixels(page_margin.left, dpi.cx) * ratio);
722 page_margin.top = (int)((float)twips_to_pixels(page_margin.top, dpi.cy) * ratio);
723 page_margin.bottom = (int)((float)twips_to_pixels(page_margin.bottom, dpi.cy) * ratio);
724 page_margin.right = (int)((float)twips_to_pixels(page_margin.right, dpi.cx) * ratio);
726 page_margin.left += x;
727 page_margin.top += y;
728 page_margin.bottom += y;
729 page_margin.right += x;
731 hPen = CreatePen(PS_DOT, 1, RGB(0,0,0));
732 oldPen = SelectObject(hdc, hPen);
734 MoveToEx(hdc, x, page_margin.top, NULL);
735 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.top);
736 MoveToEx(hdc, x, page_margin.bottom, NULL);
737 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.bottom);
739 MoveToEx(hdc, page_margin.left, y, NULL);
740 LineTo(hdc, page_margin.left, y + preview.bmScaledSize.cy);
741 MoveToEx(hdc, page_margin.right, y, NULL);
742 LineTo(hdc, page_margin.right, y + preview.bmScaledSize.cy);
744 SelectObject(hdc, oldPen);
745 DeleteObject(hPen);
748 static BOOL is_last_preview_page(int page)
750 return preview.pageEnds[page - 1] >= preview.textlength;
753 void init_preview(HWND hMainWnd, LPWSTR wszFileName)
755 HINSTANCE hInstance = GetModuleHandleW(0);
756 preview.page = 1;
757 preview.hdc = 0;
758 preview.hdc2 = 0;
759 preview.wszFileName = wszFileName;
760 preview.zoomratio = 0;
761 preview.zoomlevel = 0;
762 preview_bar_show(hMainWnd, TRUE);
764 CreateWindowExW(0, wszPreviewWndClass, NULL,
765 WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL,
766 0, 0, 200, 10, hMainWnd, (HMENU)IDC_PREVIEW, hInstance, NULL);
769 void close_preview(HWND hMainWnd)
771 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW);
772 preview.window.right = 0;
773 preview.window.bottom = 0;
774 preview.page = 0;
775 HeapFree(GetProcessHeap(), 0, preview.pageEnds);
776 preview.pageEnds = NULL;
777 preview.pageCapacity = 0;
778 if (preview.zoomlevel > 0)
779 preview.pages_shown = preview.saved_pages_shown;
780 if(preview.hdc) {
781 HBITMAP oldbm = GetCurrentObject(preview.hdc, OBJ_BITMAP);
782 DeleteDC(preview.hdc);
783 DeleteObject(oldbm);
784 preview.hdc = NULL;
786 if(preview.hdc2) {
787 HBITMAP oldbm = GetCurrentObject(preview.hdc2, OBJ_BITMAP);
788 DeleteDC(preview.hdc2);
789 DeleteObject(oldbm);
790 preview.hdc2 = NULL;
793 preview_bar_show(hMainWnd, FALSE);
794 DestroyWindow(hwndPreview);
797 BOOL preview_isactive(void)
799 return preview.page != 0;
802 static void draw_preview(HWND hEditorWnd, FORMATRANGE* lpFr, RECT* paper, int page)
804 int bottom;
806 if (!preview.pageEnds)
808 preview.pageCapacity = 32;
809 preview.pageEnds = HeapAlloc(GetProcessHeap(), 0,
810 sizeof(int) * preview.pageCapacity);
811 if (!preview.pageEnds) return;
812 } else if (page >= preview.pageCapacity) {
813 int *new_buffer;
814 new_buffer = HeapReAlloc(GetProcessHeap(), 0, preview.pageEnds,
815 sizeof(int) * preview.pageCapacity * 2);
816 if (!new_buffer) return;
817 preview.pageCapacity *= 2;
818 preview.pageEnds = new_buffer;
821 FillRect(lpFr->hdc, paper, GetStockObject(WHITE_BRUSH));
822 if (page > 1 && is_last_preview_page(page - 1)) return;
823 lpFr->chrg.cpMin = page <= 1 ? 0 : preview.pageEnds[page-2];
824 bottom = lpFr->rc.bottom;
825 preview.pageEnds[page-1] = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)lpFr);
827 /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in,
828 * but we want to keep the original for drawing margins */
829 lpFr->rc.bottom = bottom;
830 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
833 static void update_preview_buttons(HWND hMainWnd)
835 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
836 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_PREVPAGE), preview.page > 1);
837 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NEXTPAGE),
838 !is_last_preview_page(preview.page) &&
839 !is_last_preview_page(preview.page + preview.pages_shown - 1));
840 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES),
841 preview.pages_shown > 1 ||
842 (!is_last_preview_page(1) && preview.zoomlevel == 0));
843 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMIN), preview.zoomlevel < 2);
844 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMOUT), preview.zoomlevel > 0);
847 static LRESULT print_preview(HWND hwndPreview)
849 HPEN hPen, oldPen;
850 HDC hdc;
851 HRGN back_rgn, excl_rgn;
852 RECT window, background;
853 PAINTSTRUCT ps;
854 int x, y;
856 hdc = BeginPaint(hwndPreview, &ps);
857 GetClientRect(hwndPreview, &window);
858 back_rgn = CreateRectRgnIndirect(&window);
860 x = preview.spacing.cx - GetScrollPos(hwndPreview, SB_HORZ);
861 y = preview.spacing.cy - GetScrollPos(hwndPreview, SB_VERT);
863 /* draw page outlines */
864 hPen = CreatePen(PS_SOLID|PS_INSIDEFRAME, 2, RGB(0,0,0));
865 oldPen = SelectObject(hdc, hPen);
866 background.left = x - 2;
867 background.right = x + preview.bmScaledSize.cx + 2;
868 background.top = y - 2;
869 background.bottom = y + preview.bmScaledSize.cy + 2;
870 Rectangle(hdc, background.left, background.top,
871 background.right, background.bottom);
872 excl_rgn = CreateRectRgnIndirect(&background);
873 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF);
874 if(preview.pages_shown > 1)
876 background.left += preview.bmScaledSize.cx + preview.spacing.cx;
877 background.right += preview.bmScaledSize.cx + preview.spacing.cx;
878 Rectangle(hdc, background.left, background.top,
879 background.right, background.bottom);
880 SetRectRgn(excl_rgn, background.left, background.top,
881 background.right, background.bottom);
882 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF);
884 SelectObject(hdc, oldPen);
885 DeleteObject(hPen);
886 FillRgn(hdc, back_rgn, GetStockObject(GRAY_BRUSH));
887 DeleteObject(excl_rgn);
888 DeleteObject(back_rgn);
890 StretchBlt(hdc, x, y, preview.bmScaledSize.cx, preview.bmScaledSize.cy,
891 preview.hdc, 0, 0, preview.bmSize.cx, preview.bmSize.cy, SRCCOPY);
893 draw_margin_lines(hdc, x, y, preview.zoomratio);
895 if(preview.pages_shown > 1)
897 if (!is_last_preview_page(preview.page)) {
898 x += preview.spacing.cx + preview.bmScaledSize.cx;
899 StretchBlt(hdc, x, y,
900 preview.bmScaledSize.cx, preview.bmScaledSize.cy,
901 preview.hdc2, 0, 0,
902 preview.bmSize.cx, preview.bmSize.cy, SRCCOPY);
904 draw_margin_lines(hdc, x, y, preview.zoomratio);
905 } else {
906 background.left += 2;
907 background.right -= 2;
908 background.top += 2;
909 background.bottom -= 2;
910 FillRect(hdc, &background, GetStockObject(WHITE_BRUSH));
914 preview.window = window;
916 EndPaint(hwndPreview, &ps);
918 return 0;
921 static void update_preview_statusbar(HWND hMainWnd)
923 HWND hStatusbar = GetDlgItem(hMainWnd, IDC_STATUSBAR);
924 HINSTANCE hInst = GetModuleHandleW(0);
925 WCHAR *p;
926 WCHAR wstr[MAX_STRING_LEN];
928 p = wstr;
929 if (preview.pages_shown < 2 || is_last_preview_page(preview.page))
931 static const WCHAR fmt[] = {' ','%','d','\0'};
932 p += LoadStringW(hInst, STRING_PREVIEW_PAGE, wstr, MAX_STRING_LEN);
933 wsprintfW(p, fmt, preview.page);
934 } else {
935 static const WCHAR fmt[] = {' ','%','d','-','%','d','\0'};
936 p += LoadStringW(hInst, STRING_PREVIEW_PAGES, wstr, MAX_STRING_LEN);
937 wsprintfW(p, fmt, preview.page, preview.page + 1);
939 SetWindowTextW(hStatusbar, wstr);
942 /* Update for page changes. */
943 static void update_preview(HWND hMainWnd)
945 RECT paper;
946 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
947 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW);
948 HBITMAP hBitmapCapture;
949 FORMATRANGE fr;
950 HDC hdc = GetDC(hwndPreview);
952 fr.hdcTarget = make_dc();
953 fr.rc = fr.rcPage = preview.rcPage;
954 fr.rc.left += margins.left;
955 fr.rc.top += margins.top;
956 fr.rc.bottom -= margins.bottom;
957 fr.rc.right -= margins.right;
959 fr.chrg.cpMin = 0;
960 fr.chrg.cpMax = preview.textlength;
962 paper.left = 0;
963 paper.right = preview.bmSize.cx;
964 paper.top = 0;
965 paper.bottom = preview.bmSize.cy;
967 if (!preview.hdc) {
968 preview.hdc = CreateCompatibleDC(hdc);
969 hBitmapCapture = CreateCompatibleBitmap(hdc, preview.bmSize.cx, preview.bmSize.cy);
970 SelectObject(preview.hdc, hBitmapCapture);
973 fr.hdc = preview.hdc;
974 draw_preview(hEditorWnd, &fr, &paper, preview.page);
976 if(preview.pages_shown > 1)
978 if (!preview.hdc2)
980 preview.hdc2 = CreateCompatibleDC(hdc);
981 hBitmapCapture = CreateCompatibleBitmap(hdc,
982 preview.bmSize.cx,
983 preview.bmSize.cy);
984 SelectObject(preview.hdc2, hBitmapCapture);
987 fr.hdc = preview.hdc2;
988 draw_preview(hEditorWnd, &fr, &fr.rcPage, preview.page + 1);
990 DeleteDC(fr.hdcTarget);
991 ReleaseDC(hwndPreview, hdc);
993 InvalidateRect(hwndPreview, NULL, FALSE);
994 update_preview_buttons(hMainWnd);
995 update_preview_statusbar(hMainWnd);
998 static void toggle_num_pages(HWND hMainWnd)
1000 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
1001 WCHAR name[MAX_STRING_LEN];
1002 HINSTANCE hInst = GetModuleHandleW(0);
1003 int nPreviewPages;
1005 preview.pages_shown = preview.pages_shown > 1 ? 1 : 2;
1007 nPreviewPages = preview.zoomlevel > 0 ? preview.saved_pages_shown :
1008 preview.pages_shown;
1010 LoadStringW(hInst, nPreviewPages > 1 ? STRING_PREVIEW_ONEPAGE :
1011 STRING_PREVIEW_TWOPAGES,
1012 name, MAX_STRING_LEN);
1014 SetWindowTextW(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), name);
1015 update_preview_sizes(GetDlgItem(hMainWnd, IDC_PREVIEW), TRUE);
1016 update_preview(hMainWnd);
1019 /* Returns the page shown that the point is in (1 or 2) or 0 if the point
1020 * isn't inside either page */
1021 static int preview_page_hittest(POINT pt)
1023 RECT rc;
1024 rc.left = preview.spacing.cx;
1025 rc.right = rc.left + preview.bmScaledSize.cx;
1026 rc.top = preview.spacing.cy;
1027 rc.bottom = rc.top + preview.bmScaledSize.cy;
1028 if (PtInRect(&rc, pt))
1029 return 1;
1031 if (preview.pages_shown <= 1)
1032 return 0;
1034 rc.left += preview.bmScaledSize.cx + preview.spacing.cx;
1035 rc.right += preview.bmScaledSize.cx + preview.spacing.cx;
1036 if (PtInRect(&rc, pt))
1037 return is_last_preview_page(preview.page) ? 1 : 2;
1039 return 0;
1042 LRESULT CALLBACK preview_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1044 switch(msg)
1046 case WM_CREATE:
1048 HWND hMainWnd = GetParent(hWnd);
1049 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
1050 FORMATRANGE fr;
1051 GETTEXTLENGTHEX gt = {GTL_DEFAULT, 1200};
1052 HDC hdc = GetDC(hWnd);
1053 HDC hdcTarget = make_dc();
1055 fr.rc = preview.rcPage = get_print_rect(hdcTarget);
1056 preview.rcPage.bottom += margins.bottom;
1057 preview.rcPage.right += margins.right;
1058 preview.rcPage.top = preview.rcPage.left = 0;
1059 fr.rcPage = preview.rcPage;
1061 preview.bmSize.cx = twips_to_pixels(preview.rcPage.right, GetDeviceCaps(hdc, LOGPIXELSX));
1062 preview.bmSize.cy = twips_to_pixels(preview.rcPage.bottom, GetDeviceCaps(hdc, LOGPIXELSY));
1064 preview.textlength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
1066 fr.hdc = CreateCompatibleDC(hdc);
1067 fr.hdcTarget = hdcTarget;
1068 fr.chrg.cpMin = 0;
1069 fr.chrg.cpMax = preview.textlength;
1070 DeleteDC(fr.hdc);
1071 DeleteDC(hdcTarget);
1072 ReleaseDC(hWnd, hdc);
1074 update_preview_sizes(hWnd, TRUE);
1075 update_preview(hMainWnd);
1076 break;
1079 case WM_PAINT:
1080 return print_preview(hWnd);
1082 case WM_SIZE:
1084 update_preview_sizes(hWnd, FALSE);
1085 InvalidateRect(hWnd, NULL, FALSE);
1086 break;
1089 case WM_VSCROLL:
1090 case WM_HSCROLL:
1092 SCROLLINFO si;
1093 RECT rc;
1094 int nBar = (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ;
1095 int origPos;
1097 GetClientRect(hWnd, &rc);
1098 si.cbSize = sizeof(si);
1099 si.fMask = SIF_ALL;
1100 GetScrollInfo(hWnd, nBar, &si);
1101 origPos = si.nPos;
1102 switch(LOWORD(wParam))
1104 case SB_TOP: /* == SB_LEFT */
1105 si.nPos = si.nMin;
1106 break;
1107 case SB_BOTTOM: /* == SB_RIGHT */
1108 si.nPos = si.nMax;
1109 break;
1110 case SB_LINEUP: /* == SB_LINELEFT */
1111 si.nPos -= si.nPage / 10;
1112 break;
1113 case SB_LINEDOWN: /* == SB_LINERIGHT */
1114 si.nPos += si.nPage / 10;
1115 break;
1116 case SB_PAGEUP: /* == SB_PAGELEFT */
1117 si.nPos -= si.nPage;
1118 break;
1119 case SB_PAGEDOWN: /* SB_PAGERIGHT */
1120 si.nPos += si.nPage;
1121 break;
1122 case SB_THUMBTRACK:
1123 si.nPos = si.nTrackPos;
1124 break;
1126 si.fMask = SIF_POS;
1127 SetScrollInfo(hWnd, nBar, &si, TRUE);
1128 GetScrollInfo(hWnd, nBar, &si);
1129 if (si.nPos != origPos)
1131 int amount = origPos - si.nPos;
1132 if (msg == WM_VSCROLL)
1133 ScrollWindow(hWnd, 0, amount, NULL, NULL);
1134 else
1135 ScrollWindow(hWnd, amount, 0, NULL, NULL);
1137 return 0;
1140 case WM_SETCURSOR:
1142 POINT pt;
1143 RECT rc;
1144 int bHittest = 0;
1145 DWORD messagePos = GetMessagePos();
1146 pt.x = (short)LOWORD(messagePos);
1147 pt.y = (short)HIWORD(messagePos);
1148 ScreenToClient(hWnd, &pt);
1150 GetClientRect(hWnd, &rc);
1151 if (PtInRect(&rc, pt))
1153 pt.x += GetScrollPos(hWnd, SB_HORZ);
1154 pt.y += GetScrollPos(hWnd, SB_VERT);
1155 bHittest = preview_page_hittest(pt);
1158 if (bHittest)
1159 SetCursor(LoadCursorW(GetModuleHandleW(0),
1160 MAKEINTRESOURCEW(IDC_ZOOM)));
1161 else
1162 SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW));
1164 return TRUE;
1167 case WM_LBUTTONDOWN:
1169 int page;
1170 POINT pt;
1171 pt.x = (short)LOWORD(lParam) + GetScrollPos(hWnd, SB_HORZ);
1172 pt.y = (short)HIWORD(lParam) + GetScrollPos(hWnd, SB_VERT);
1173 if ((page = preview_page_hittest(pt)) > 0)
1175 HWND hMainWnd = GetParent(hWnd);
1177 /* Convert point from client coordinate to unzoomed page
1178 * coordinate. */
1179 pt.x -= preview.spacing.cx;
1180 if (page > 1)
1181 pt.x -= preview.bmScaledSize.cx + preview.spacing.cx;
1182 pt.y -= preview.spacing.cy;
1183 pt.x /= preview.zoomratio;
1184 pt.y /= preview.zoomratio;
1186 if (preview.zoomlevel == 0)
1187 preview.saved_pages_shown = preview.pages_shown;
1188 preview.zoomlevel = (preview.zoomlevel + 1) % 3;
1189 preview.zoomratio = 0;
1190 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1)
1192 toggle_num_pages(hMainWnd);
1193 } else if (preview.pages_shown > 1) {
1194 if (page >= 2) preview.page++;
1195 toggle_num_pages(hMainWnd);
1196 } else {
1197 update_preview_sizes(hWnd, TRUE);
1198 InvalidateRect(hWnd, NULL, FALSE);
1199 update_preview_buttons(hMainWnd);
1202 if (preview.zoomlevel > 0) {
1203 SCROLLINFO si;
1204 /* Convert the coordinate back to client coordinate. */
1205 pt.x *= preview.zoomratio;
1206 pt.y *= preview.zoomratio;
1207 pt.x += preview.spacing.cx;
1208 pt.y += preview.spacing.cy;
1209 /* Scroll to center view at that point on the page */
1210 si.cbSize = sizeof(si);
1211 si.fMask = SIF_PAGE;
1212 GetScrollInfo(hWnd, SB_HORZ, &si);
1213 pt.x -= si.nPage / 2;
1214 SetScrollPos(hWnd, SB_HORZ, pt.x, TRUE);
1215 GetScrollInfo(hWnd, SB_VERT, &si);
1216 pt.y -= si.nPage / 2;
1217 SetScrollPos(hWnd, SB_VERT, pt.y, TRUE);
1222 default:
1223 return DefWindowProcW(hWnd, msg, wParam, lParam);
1226 return 0;
1229 LRESULT preview_command(HWND hWnd, WPARAM wParam)
1231 switch(LOWORD(wParam))
1233 case ID_FILE_EXIT:
1234 PostMessageW(hWnd, WM_CLOSE, 0, 0);
1235 break;
1237 case ID_PREVIEW_NEXTPAGE:
1238 case ID_PREVIEW_PREVPAGE:
1240 if(LOWORD(wParam) == ID_PREVIEW_NEXTPAGE)
1241 preview.page++;
1242 else
1243 preview.page--;
1245 update_preview(hWnd);
1247 break;
1249 case ID_PREVIEW_NUMPAGES:
1250 toggle_num_pages(hWnd);
1251 break;
1253 case ID_PREVIEW_ZOOMIN:
1254 if (preview.zoomlevel < 2)
1256 if (preview.zoomlevel == 0)
1257 preview.saved_pages_shown = preview.pages_shown;
1258 preview.zoomlevel++;
1259 preview.zoomratio = 0;
1260 if (preview.pages_shown > 1)
1262 /* Forced switch to one page when zooming in. */
1263 toggle_num_pages(hWnd);
1264 } else {
1265 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW);
1266 update_preview_sizes(hwndPreview, TRUE);
1267 InvalidateRect(hwndPreview, NULL, FALSE);
1268 update_preview_buttons(hWnd);
1271 break;
1273 case ID_PREVIEW_ZOOMOUT:
1274 if (preview.zoomlevel > 0)
1276 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW);
1277 preview.zoomlevel--;
1278 preview.zoomratio = 0;
1279 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1) {
1280 toggle_num_pages(hWnd);
1281 } else {
1282 update_preview_sizes(hwndPreview, TRUE);
1283 InvalidateRect(hwndPreview, NULL, FALSE);
1284 update_preview_buttons(hWnd);
1287 break;
1289 case ID_PRINT:
1290 dialog_print(hWnd, preview.wszFileName);
1291 SendMessageW(hWnd, WM_CLOSE, 0, 0);
1292 break;
1295 return 0;