wgl: We were already advertising GL_EXT_framebuffer_sRGB but not the corresponding...
[wine.git] / programs / wordpad / print.c
blobc0cd182d17e020a06c8eef80b581169ac041aa67
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>
25 #include "wordpad.h"
27 typedef struct _previewinfo
29 int page;
30 int pages;
31 HDC hdc;
32 HDC hdc2;
33 HDC hdcSized;
34 HDC hdcSized2;
35 RECT window;
36 LPWSTR wszFileName;
37 } previewinfo, *ppreviewinfo;
39 static HGLOBAL devMode;
40 static HGLOBAL devNames;
42 static RECT margins;
43 static previewinfo preview;
45 static const WCHAR var_pagemargin[] = {'P','a','g','e','M','a','r','g','i','n',0};
47 static LPWSTR get_print_file_filter(HWND hMainWnd)
49 static WCHAR wszPrintFilter[MAX_STRING_LEN*2+6+4+1];
50 const WCHAR files_prn[] = {'*','.','P','R','N',0};
51 const WCHAR files_all[] = {'*','.','*','\0'};
52 LPWSTR p;
53 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE);
55 p = wszPrintFilter;
56 LoadStringW(hInstance, STRING_PRINTER_FILES_PRN, p, MAX_STRING_LEN);
57 p += lstrlenW(p) + 1;
58 lstrcpyW(p, files_prn);
59 p += lstrlenW(p) + 1;
60 LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN);
61 p += lstrlenW(p) + 1;
62 lstrcpyW(p, files_all);
63 p += lstrlenW(p) + 1;
64 *p = 0;
66 return wszPrintFilter;
69 void registry_set_pagemargins(HKEY hKey)
71 RegSetValueExW(hKey, var_pagemargin, 0, REG_BINARY, (LPBYTE)&margins, sizeof(RECT));
74 void registry_read_pagemargins(HKEY hKey)
76 DWORD size = sizeof(RECT);
78 if(!hKey || RegQueryValueExW(hKey, var_pagemargin, 0, NULL, (LPBYTE)&margins,
79 &size) != ERROR_SUCCESS || size != sizeof(RECT))
81 margins.top = 1417;
82 margins.bottom = 1417;
83 margins.left = 1757;
84 margins.right = 1757;
88 static void AddTextButton(HWND hRebarWnd, UINT string, UINT command, UINT id)
90 REBARBANDINFOW rb;
91 HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hRebarWnd, GWLP_HINSTANCE);
92 WCHAR text[MAX_STRING_LEN];
93 HWND hButton;
95 LoadStringW(hInstance, string, text, MAX_STRING_LEN);
96 hButton = CreateWindowW(WC_BUTTONW, text,
97 WS_VISIBLE | WS_CHILD, 5, 5, 100, 15,
98 hRebarWnd, (HMENU)ULongToHandle(command), hInstance, NULL);
100 rb.cbSize = sizeof(rb);
101 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID;
102 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT;
103 rb.hwndChild = hButton;
104 rb.cyChild = rb.cyMinChild = 22;
105 rb.cx = rb.cxMinChild = 90;
106 rb.cxIdeal = 100;
107 rb.wID = id;
109 SendMessageW(hRebarWnd, RB_INSERTBAND, -1, (LPARAM)&rb);
112 static HDC make_dc(void)
114 if(devNames && devMode)
116 LPDEVNAMES dn = GlobalLock(devNames);
117 LPDEVMODEW dm = GlobalLock(devMode);
118 HDC ret;
120 ret = CreateDCW((LPWSTR)dn + dn->wDriverOffset,
121 (LPWSTR)dn + dn->wDeviceOffset, 0, dm);
123 GlobalUnlock(dn);
124 GlobalUnlock(dm);
126 return ret;
127 } else
129 return 0;
133 static LONG twips_to_centmm(int twips)
135 return MulDiv(twips, 1000, TWIPS_PER_CM);
138 LONG centmm_to_twips(int mm)
140 return MulDiv(mm, TWIPS_PER_CM, 1000);
143 static LONG twips_to_pixels(int twips, int dpi)
145 float ret = ((float)twips / ((float)TWIPS_PER_CM * 2.54)) * (float)dpi;
146 return (LONG)ret;
149 static LONG devunits_to_twips(int units, int dpi)
151 float ret = ((float)units / (float)dpi) * (float)TWIPS_PER_CM * 2.54;
152 return (LONG)ret;
156 static RECT get_print_rect(HDC hdc)
158 RECT rc;
159 int width, height;
161 if(hdc)
163 int dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
164 int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
165 width = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALWIDTH), dpiX);
166 height = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALHEIGHT), dpiY);
167 } else
169 width = centmm_to_twips(18500);
170 height = centmm_to_twips(27000);
173 rc.left = margins.left;
174 rc.right = width - margins.right;
175 rc.top = margins.top;
176 rc.bottom = height - margins.bottom;
178 return rc;
181 void target_device(HWND hMainWnd, DWORD wordWrap)
183 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
184 HDC hdc = make_dc();
185 int width = 0;
187 if(wordWrap == ID_WORDWRAP_MARGIN)
189 RECT rc = get_print_rect(hdc);
190 width = rc.right - rc.left;
193 if(!hdc)
195 HDC hMaindc = GetDC(hMainWnd);
196 hdc = CreateCompatibleDC(hMaindc);
197 ReleaseDC(hMainWnd, hMaindc);
200 SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, (WPARAM)hdc, width);
202 DeleteDC(hdc);
205 static LPWSTR dialog_print_to_file(HWND hMainWnd)
207 OPENFILENAMEW ofn;
208 static WCHAR file[MAX_PATH] = {'O','U','T','P','U','T','.','P','R','N',0};
209 static const WCHAR defExt[] = {'P','R','N',0};
210 static LPWSTR file_filter;
212 if(!file_filter)
213 file_filter = get_print_file_filter(hMainWnd);
215 ZeroMemory(&ofn, sizeof(ofn));
217 ofn.lStructSize = sizeof(ofn);
218 ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
219 ofn.hwndOwner = hMainWnd;
220 ofn.lpstrFilter = file_filter;
221 ofn.lpstrFile = (LPWSTR)file;
222 ofn.nMaxFile = MAX_PATH;
223 ofn.lpstrDefExt = (LPWSTR)defExt;
225 if(GetSaveFileNameW(&ofn))
226 return (LPWSTR)file;
227 else
228 return FALSE;
231 static int get_num_pages(HWND hEditorWnd, FORMATRANGE fr)
233 int page = 0;
234 fr.chrg.cpMin = 0;
238 page++;
239 fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE,
240 (LPARAM)&fr);
242 while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax);
244 return page;
247 static void char_from_pagenum(HWND hEditorWnd, FORMATRANGE *fr, int page)
249 int i;
251 fr->chrg.cpMin = 0;
253 for(i = 1; i < page; i++)
255 fr->chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)fr);
259 static HWND get_ruler_wnd(HWND hMainWnd)
261 return GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER);
264 void redraw_ruler(HWND hRulerWnd)
266 RECT rc;
268 GetClientRect(hRulerWnd, &rc);
269 InvalidateRect(hRulerWnd, &rc, TRUE);
272 static void update_ruler(HWND hRulerWnd)
274 SendMessageW(hRulerWnd, WM_USER, 0, 0);
275 redraw_ruler(hRulerWnd);
278 static void print(LPPRINTDLGW pd, LPWSTR wszFileName)
280 FORMATRANGE fr;
281 DOCINFOW di;
282 HWND hEditorWnd = GetDlgItem(pd->hwndOwner, IDC_EDITOR);
283 int printedPages = 0;
285 fr.hdc = pd->hDC;
286 fr.hdcTarget = pd->hDC;
288 fr.rc = get_print_rect(fr.hdc);
289 fr.rcPage.left = 0;
290 fr.rcPage.right = fr.rc.right + margins.right;
291 fr.rcPage.top = 0;
292 fr.rcPage.bottom = fr.rc.bottom + margins.bottom;
294 ZeroMemory(&di, sizeof(di));
295 di.cbSize = sizeof(di);
296 di.lpszDocName = wszFileName;
298 if(pd->Flags & PD_PRINTTOFILE)
300 di.lpszOutput = dialog_print_to_file(pd->hwndOwner);
301 if(!di.lpszOutput)
302 return;
305 if(pd->Flags & PD_SELECTION)
307 SendMessageW(hEditorWnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg);
308 } else
310 GETTEXTLENGTHEX gt;
311 gt.flags = GTL_DEFAULT;
312 gt.codepage = 1200;
313 fr.chrg.cpMin = 0;
314 fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
316 if(pd->Flags & PD_PAGENUMS)
317 char_from_pagenum(hEditorWnd, &fr, pd->nToPage);
320 StartDocW(fr.hdc, &di);
323 if(StartPage(fr.hdc) <= 0)
324 break;
326 fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
328 if(EndPage(fr.hdc) <= 0)
329 break;
331 printedPages++;
332 if((pd->Flags & PD_PAGENUMS) && (printedPages > (pd->nToPage - pd->nFromPage)))
333 break;
335 while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax);
337 EndDoc(fr.hdc);
338 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
341 void dialog_printsetup(HWND hMainWnd)
343 PAGESETUPDLGW ps;
345 ZeroMemory(&ps, sizeof(ps));
346 ps.lStructSize = sizeof(ps);
347 ps.hwndOwner = hMainWnd;
348 ps.Flags = PSD_INHUNDREDTHSOFMILLIMETERS | PSD_MARGINS;
349 ps.rtMargin.left = twips_to_centmm(margins.left);
350 ps.rtMargin.right = twips_to_centmm(margins.right);
351 ps.rtMargin.top = twips_to_centmm(margins.top);
352 ps.rtMargin.bottom = twips_to_centmm(margins.bottom);
353 ps.hDevMode = devMode;
354 ps.hDevNames = devNames;
356 if(PageSetupDlgW(&ps))
358 margins.left = centmm_to_twips(ps.rtMargin.left);
359 margins.right = centmm_to_twips(ps.rtMargin.right);
360 margins.top = centmm_to_twips(ps.rtMargin.top);
361 margins.bottom = centmm_to_twips(ps.rtMargin.bottom);
362 devMode = ps.hDevMode;
363 devNames = ps.hDevNames;
364 update_ruler(get_ruler_wnd(hMainWnd));
368 void get_default_printer_opts(void)
370 PRINTDLGW pd;
371 ZeroMemory(&pd, sizeof(pd));
373 ZeroMemory(&pd, sizeof(pd));
374 pd.lStructSize = sizeof(pd);
375 pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
376 pd.hDevMode = devMode;
378 PrintDlgW(&pd);
380 devMode = pd.hDevMode;
381 devNames = pd.hDevNames;
384 void print_quick(LPWSTR wszFileName)
386 PRINTDLGW pd;
388 ZeroMemory(&pd, sizeof(pd));
389 pd.hDC = make_dc();
391 print(&pd, wszFileName);
394 void dialog_print(HWND hMainWnd, LPWSTR wszFileName)
396 PRINTDLGW pd;
397 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
398 int from = 0;
399 int to = 0;
401 ZeroMemory(&pd, sizeof(pd));
402 pd.lStructSize = sizeof(pd);
403 pd.hwndOwner = hMainWnd;
404 pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
405 pd.nMinPage = 1;
406 pd.nMaxPage = -1;
407 pd.hDevMode = devMode;
408 pd.hDevNames = devNames;
410 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to);
411 if(from == to)
412 pd.Flags |= PD_NOSELECTION;
414 if(PrintDlgW(&pd))
416 devMode = pd.hDevMode;
417 devNames = pd.hDevNames;
418 print(&pd, wszFileName);
419 update_ruler(get_ruler_wnd(hMainWnd));
423 static void preview_bar_show(HWND hMainWnd, BOOL show)
425 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
426 int i;
428 if(show)
430 REBARBANDINFOW rb;
431 HWND hStatic;
433 AddTextButton(hReBar, STRING_PREVIEW_PRINT, ID_PRINT, BANDID_PREVIEW_BTN1);
434 AddTextButton(hReBar, STRING_PREVIEW_NEXTPAGE, ID_PREVIEW_NEXTPAGE, BANDID_PREVIEW_BTN2);
435 AddTextButton(hReBar, STRING_PREVIEW_PREVPAGE, ID_PREVIEW_PREVPAGE, BANDID_PREVIEW_BTN3);
436 AddTextButton(hReBar, STRING_PREVIEW_TWOPAGES, ID_PREVIEW_NUMPAGES, BANDID_PREVIEW_BTN4);
437 AddTextButton(hReBar, STRING_PREVIEW_CLOSE, ID_FILE_EXIT, BANDID_PREVIEW_BTN5);
439 hStatic = CreateWindowW(WC_STATICW, NULL,
440 WS_VISIBLE | WS_CHILD, 0, 0, 0, 0,
441 hReBar, NULL, NULL, NULL);
443 rb.cbSize = sizeof(rb);
444 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID;
445 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT;
446 rb.hwndChild = hStatic;
447 rb.cyChild = rb.cyMinChild = 22;
448 rb.cx = rb.cxMinChild = 90;
449 rb.cxIdeal = 100;
450 rb.wID = BANDID_PREVIEW_BUFFER;
452 SendMessageW(hReBar, RB_INSERTBAND, -1, (LPARAM)&rb);
453 } else
455 for(i = 0; i <= PREVIEW_BUTTONS; i++)
456 SendMessageW(hReBar, RB_DELETEBAND, SendMessageW(hReBar, RB_IDTOINDEX, BANDID_PREVIEW_BTN1+i, 0), 0);
460 void init_preview(HWND hMainWnd, LPWSTR wszFileName)
462 preview.page = 1;
463 preview.hdc = 0;
464 preview.hdc2 = 0;
465 preview.wszFileName = wszFileName;
466 preview_bar_show(hMainWnd, TRUE);
469 void close_preview(HWND hMainWnd)
471 preview.window.right = 0;
472 preview.window.bottom = 0;
473 preview.page = 0;
474 preview.pages = 0;
476 preview_bar_show(hMainWnd, FALSE);
479 BOOL preview_isactive(void)
481 return preview.page != 0;
484 static void add_ruler_units(HDC hdcRuler, RECT* drawRect, BOOL NewMetrics, long EditLeftmost)
486 static HDC hdc;
488 if(NewMetrics)
490 static HBITMAP hBitmap;
491 int i, x, y, RulerTextEnd;
492 int CmPixels;
493 int QuarterCmPixels;
494 HFONT hFont;
495 WCHAR FontName[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
497 if(hdc)
499 DeleteDC(hdc);
500 DeleteObject(hBitmap);
503 hdc = CreateCompatibleDC(0);
505 CmPixels = twips_to_pixels(TWIPS_PER_CM, GetDeviceCaps(hdc, LOGPIXELSX));
506 QuarterCmPixels = (int)((float)CmPixels / 4.0);
508 hBitmap = CreateCompatibleBitmap(hdc, drawRect->right, drawRect->bottom);
509 SelectObject(hdc, hBitmap);
510 FillRect(hdc, drawRect, GetStockObject(WHITE_BRUSH));
512 hFont = CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName);
514 SelectObject(hdc, hFont);
515 SetBkMode(hdc, TRANSPARENT);
516 SetTextAlign(hdc, TA_CENTER);
517 y = (int)(((float)drawRect->bottom - (float)drawRect->top) / 2.0) + 1;
518 RulerTextEnd = drawRect->right - EditLeftmost + 1;
519 for(i = 1, x = EditLeftmost; x < (drawRect->right - EditLeftmost + 1); i ++)
521 WCHAR str[3];
522 WCHAR format[] = {'%','d',0};
523 int x2 = x;
525 x2 += QuarterCmPixels;
526 if(x2 > RulerTextEnd)
527 break;
529 MoveToEx(hdc, x2, y, NULL);
530 LineTo(hdc, x2, y+2);
532 x2 += QuarterCmPixels;
533 if(x2 > RulerTextEnd)
534 break;
536 MoveToEx(hdc, x2, y - 3, NULL);
537 LineTo(hdc, x2, y + 3);
539 x2 += QuarterCmPixels;
540 if(x2 > RulerTextEnd)
541 break;
543 MoveToEx(hdc, x2, y, NULL);
544 LineTo(hdc, x2, y+2);
546 x += CmPixels;
547 if(x > RulerTextEnd)
548 break;
550 wsprintfW(str, format, i);
551 TextOutW(hdc, x, 5, str, lstrlenW(str));
553 DeleteObject(hFont);
556 BitBlt(hdcRuler, 0, 0, drawRect->right, drawRect->bottom, hdc, 0, 0, SRCAND);
559 static void paint_ruler(HWND hWnd, long EditLeftmost, BOOL NewMetrics)
561 PAINTSTRUCT ps;
562 HDC hdc = BeginPaint(hWnd, &ps);
563 HDC hdcPrint = make_dc();
564 RECT printRect = get_print_rect(hdcPrint);
565 RECT drawRect;
566 HBRUSH hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
568 GetClientRect(hWnd, &drawRect);
569 FillRect(hdc, &drawRect, hBrush);
571 drawRect.top += 3;
572 drawRect.bottom -= 3;
573 drawRect.left = EditLeftmost;
574 drawRect.right = twips_to_pixels(printRect.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
575 FillRect(hdc, &drawRect, GetStockObject(WHITE_BRUSH));
577 drawRect.top--;
578 drawRect.bottom++;
579 DrawEdge(hdc, &drawRect, EDGE_SUNKEN, BF_RECT);
581 drawRect.left = drawRect.right - 1;
582 drawRect.right = twips_to_pixels(printRect.right + margins.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX));
583 DrawEdge(hdc, &drawRect, EDGE_ETCHED, BF_RECT);
585 drawRect.left = 0;
586 drawRect.top = 0;
587 add_ruler_units(hdc, &drawRect, NewMetrics, EditLeftmost);
589 SelectObject(hdc, GetStockObject(BLACK_BRUSH));
590 DeleteObject(hBrush);
591 DeleteDC(hdcPrint);
592 EndPaint(hWnd, &ps);
595 LRESULT CALLBACK ruler_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
597 static WNDPROC pPrevRulerProc;
598 static long EditLeftmost;
599 static BOOL NewMetrics;
601 switch(msg)
603 case WM_USER:
604 if(wParam)
606 EditLeftmost = ((POINTL*)wParam)->x;
607 pPrevRulerProc = (WNDPROC)lParam;
609 NewMetrics = TRUE;
610 break;
612 case WM_PAINT:
613 paint_ruler(hWnd, EditLeftmost, NewMetrics);
614 break;
616 default:
617 return CallWindowProcW(pPrevRulerProc, hWnd, msg, wParam, lParam);
620 return 0;
623 void draw_preview_page(HDC hdc, HDC* hdcSized, FORMATRANGE* lpFr, float ratio, int bmNewWidth, int bmNewHeight, int bmWidth, int bmHeight)
625 HBITMAP hBitmapScaled = CreateCompatibleBitmap(hdc, bmNewWidth, bmNewHeight);
626 HPEN hPen;
627 int TopMargin = (int)((float)twips_to_pixels(lpFr->rc.top, GetDeviceCaps(hdc, LOGPIXELSX)) * ratio);
628 int BottomMargin = (int)((float)twips_to_pixels(lpFr->rc.bottom, GetDeviceCaps(hdc, LOGPIXELSX)) * ratio);
629 int LeftMargin = (int)((float)twips_to_pixels(lpFr->rc.left, GetDeviceCaps(hdc, LOGPIXELSY)) * ratio);
630 int RightMargin = (int)((float)twips_to_pixels(lpFr->rc.right, GetDeviceCaps(hdc, LOGPIXELSY)) * ratio);
632 if(*hdcSized)
633 DeleteDC(*hdcSized);
634 *hdcSized = CreateCompatibleDC(hdc);
635 SelectObject(*hdcSized, hBitmapScaled);
637 StretchBlt(*hdcSized, 0, 0, bmNewWidth, bmNewHeight, hdc, 0, 0, bmWidth, bmHeight, SRCCOPY);
639 /* Draw margin lines */
640 hPen = CreatePen(PS_DOT, 1, RGB(0,0,0));
641 SelectObject(*hdcSized, hPen);
643 MoveToEx(*hdcSized, 0, TopMargin, NULL);
644 LineTo(*hdcSized, bmNewWidth, TopMargin);
645 MoveToEx(*hdcSized, 0, BottomMargin, NULL);
646 LineTo(*hdcSized, bmNewWidth, BottomMargin);
648 MoveToEx(*hdcSized, LeftMargin, 0, NULL);
649 LineTo(*hdcSized, LeftMargin, bmNewHeight);
650 MoveToEx(*hdcSized, RightMargin, 0, NULL);
651 LineTo(*hdcSized, RightMargin, bmNewHeight);
655 static void draw_preview(HWND hEditorWnd, FORMATRANGE* lpFr, int bmWidth, int bmHeight, RECT* paper, int page)
657 HBITMAP hBitmapCapture = CreateCompatibleBitmap(lpFr->hdc, bmWidth, bmHeight);
659 char_from_pagenum(hEditorWnd, lpFr, page);
660 SelectObject(lpFr->hdc, hBitmapCapture);
661 FillRect(lpFr->hdc, paper, GetStockObject(WHITE_BRUSH));
662 SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)lpFr);
663 /* EM_FORMATRANGE sets fr.rc to indicate the area printed in, but we want to
664 keep the original for drawing margins */
665 lpFr->rc = get_print_rect(lpFr->hdcTarget);
666 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0);
669 LRESULT print_preview(HWND hMainWnd)
671 FORMATRANGE fr;
672 GETTEXTLENGTHEX gt;
673 HDC hdc;
674 RECT window, background;
675 int bmWidth, bmHeight, bmNewWidth, bmNewHeight;
676 float ratioWidth, ratioHeight, ratio;
677 int xOffset, yOffset;
678 int barheight;
679 float spacing = 20.0;
680 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR);
681 PAINTSTRUCT ps;
683 hdc = BeginPaint(hMainWnd, &ps);
684 GetClientRect(hMainWnd, &window);
686 fr.hdcTarget = make_dc();
687 fr.rc = get_print_rect(fr.hdcTarget);
688 fr.rcPage.left = 0;
689 fr.rcPage.top = 0;
690 fr.rcPage.bottom = fr.rc.bottom + margins.bottom;
691 fr.rcPage.right = fr.rc.right + margins.right;
693 bmWidth = twips_to_pixels(fr.rcPage.right, GetDeviceCaps(hdc, LOGPIXELSX));
694 bmHeight = twips_to_pixels(fr.rcPage.bottom, GetDeviceCaps(hdc, LOGPIXELSY));
696 if(!preview.hdc)
698 RECT paper;
699 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR);
701 preview.hdc = CreateCompatibleDC(hdc);
703 if(preview.hdc2)
705 if(preview.hdc2 != (HDC)-1)
706 DeleteDC(preview.hdc2);
707 preview.hdc2 = CreateCompatibleDC(hdc);
710 fr.hdc = preview.hdc;
711 gt.flags = GTL_DEFAULT;
712 gt.codepage = 1200;
713 fr.chrg.cpMin = 0;
714 fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, 0);
716 paper.left = 0;
717 paper.right = bmWidth;
718 paper.top = 0;
719 paper.bottom = bmHeight;
721 if(!preview.pages)
722 preview.pages = get_num_pages(hEditorWnd, fr);
724 fr.hdc = preview.hdc;
725 draw_preview(hEditorWnd, &fr, bmWidth, bmHeight, &paper, preview.page);
727 if(preview.hdc2)
729 fr.hdc = preview.hdc2;
730 draw_preview(hEditorWnd, &fr, bmWidth, bmHeight, &paper, preview.page + 1);
733 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_PREVPAGE), preview.page > 1);
734 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NEXTPAGE), preview.hdc2 ?
735 (preview.page + 1) < preview.pages :
736 preview.page < preview.pages);
737 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), preview.pages > 1);
740 barheight = SendMessageW(hReBar, RB_GETBARHEIGHT, 0, 0);
741 ratioHeight = ((float)window.bottom - spacing - (float)barheight) / (float)bmHeight;
743 if(preview.hdc2)
744 ratioWidth = ((float)window.right / 2.0 - spacing * 2.0) / (float)bmWidth;
745 else
746 ratioWidth = ((float)window.right - spacing * 3.0) / (float)bmWidth;
748 if(ratioWidth > ratioHeight)
749 ratio = ratioHeight;
750 else
751 ratio = ratioWidth;
753 bmNewWidth = (int)((float)bmWidth * ratio);
754 bmNewHeight = (int)((float)bmHeight * ratio);
756 yOffset = ((window.bottom - bmNewHeight + barheight) / 2);
758 if(!preview.hdc2)
759 xOffset = (window.right - bmNewWidth) / 2;
760 else
761 xOffset = (window.right - bmNewWidth * 2) / 2;
763 window.top = barheight;
764 FillRect(hdc, &window, GetStockObject(GRAY_BRUSH));
766 background.left = xOffset - 2;
767 background.right = xOffset + bmNewWidth + 2;
768 background.top = yOffset - 2;
769 background.bottom = yOffset + bmNewHeight + 2;
771 FillRect(hdc, &background, GetStockObject(BLACK_BRUSH));
773 if(window.right != preview.window.right || window.bottom != preview.window.bottom)
775 draw_preview_page(preview.hdc, &preview.hdcSized, &fr, ratio, bmNewWidth, bmNewHeight, bmWidth, bmHeight);
777 if(preview.hdc2)
779 background.left += bmNewWidth + spacing;
780 background.right += bmNewWidth + spacing;
782 FillRect(hdc, &background, GetStockObject(BLACK_BRUSH));
784 draw_preview_page(preview.hdc2, &preview.hdcSized2, &fr, ratio, bmNewWidth, bmNewHeight, bmWidth, bmHeight);
788 BitBlt(hdc, xOffset, yOffset, bmNewWidth, bmNewHeight, preview.hdcSized, 0, 0, SRCCOPY);
790 if(preview.hdc2)
792 BitBlt(hdc, xOffset + bmNewWidth + spacing, yOffset, bmNewWidth, bmNewHeight, preview.hdcSized2, 0, 0, SRCCOPY);
795 DeleteDC(fr.hdcTarget);
796 preview.window = window;
798 EndPaint(hMainWnd, &ps);
800 return 0;
803 void update_preview(HWND hWnd)
805 RECT rc;
807 DeleteDC(preview.hdc);
808 preview.hdc = 0;
810 preview.window.right = 0;
812 GetClientRect(hWnd, &rc);
813 rc.top += SendMessageW(GetDlgItem(hWnd, IDC_REBAR), RB_GETBARHEIGHT, 0, 0);
814 InvalidateRect(hWnd, &rc, TRUE);
817 LRESULT preview_command(HWND hWnd, WPARAM wParam, LPARAM lParam)
819 switch(LOWORD(wParam))
821 case ID_FILE_EXIT:
822 PostMessageW(hWnd, WM_CLOSE, 0, 0);
823 break;
825 case ID_PREVIEW_NEXTPAGE:
826 case ID_PREVIEW_PREVPAGE:
828 if(LOWORD(wParam) == ID_PREVIEW_NEXTPAGE)
829 preview.page++;
830 else
831 preview.page--;
833 update_preview(hWnd);
835 break;
837 case ID_PREVIEW_NUMPAGES:
839 HWND hReBar = GetDlgItem(hWnd, IDC_REBAR);
840 WCHAR name[MAX_STRING_LEN];
841 HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE);
843 if(preview.hdc2)
845 DeleteDC(preview.hdc2);
846 preview.hdc2 = 0;
847 } else
849 if(preview.page == preview.pages)
850 preview.page--;
851 preview.hdc2 = (HDC)-1;
854 LoadStringW(hInst, preview.hdc2 ? STRING_PREVIEW_ONEPAGE : STRING_PREVIEW_TWOPAGES,
855 name, MAX_STRING_LEN);
857 SetWindowTextW(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), name);
858 update_preview(hWnd);
860 break;
862 case ID_PRINT:
863 dialog_print(hWnd, preview.wszFileName);
864 SendMessageW(hWnd, WM_CLOSE, 0, 0);
865 break;
868 return 0;