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
28 typedef struct _previewinfo
32 int saved_pages_shown
;
33 int *pageEnds
, pageCapacity
;
45 } previewinfo
, *ppreviewinfo
;
47 static HGLOBAL devMode
;
48 static HGLOBAL devNames
;
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'};
64 HINSTANCE hInstance
= GetModuleHandleW(0);
67 LoadStringW(hInstance
, STRING_PRINTER_FILES_PRN
, p
, MAX_STRING_LEN
);
69 lstrcpyW(p
, files_prn
);
71 LoadStringW(hInstance
, STRING_ALL_FILES
, p
, MAX_STRING_LEN
);
73 lstrcpyW(p
, files_all
);
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
))
91 SetRect(&margins
, 1757, 1417, 1757, 1417);
94 void registry_set_previewpages(HKEY hKey
)
96 RegSetValueExW(hKey
, var_previewpages
, 0, REG_DWORD
,
97 (LPBYTE
)&preview
.pages_shown
, sizeof(DWORD
));
100 void registry_read_previewpages(HKEY hKey
)
102 DWORD size
= sizeof(DWORD
);
104 RegQueryValueExW(hKey
, var_previewpages
, 0, NULL
,
105 (LPBYTE
)&preview
.pages_shown
, &size
) != ERROR_SUCCESS
||
106 size
!= sizeof(DWORD
))
108 preview
.pages_shown
= 1;
110 if (preview
.pages_shown
< 1) preview
.pages_shown
= 1;
111 else if (preview
.pages_shown
> 2) preview
.pages_shown
= 2;
116 static void AddTextButton(HWND hRebarWnd
, UINT string
, UINT command
, UINT id
)
119 HINSTANCE hInstance
= GetModuleHandleW(0);
120 WCHAR text
[MAX_STRING_LEN
];
123 LoadStringW(hInstance
, string
, text
, MAX_STRING_LEN
);
124 hButton
= CreateWindowW(WC_BUTTONW
, text
,
125 WS_VISIBLE
| WS_CHILD
, 5, 5, 100, 15,
126 hRebarWnd
, ULongToHandle(command
), hInstance
, NULL
);
128 rb
.cbSize
= REBARBANDINFOW_V6_SIZE
;
129 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
130 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
131 rb
.hwndChild
= hButton
;
132 rb
.cyChild
= rb
.cyMinChild
= 22;
133 rb
.cx
= rb
.cxMinChild
= 90;
137 SendMessageW(hRebarWnd
, RB_INSERTBANDW
, -1, (LPARAM
)&rb
);
140 static HDC
make_dc(void)
142 if(devNames
&& devMode
)
144 LPDEVNAMES dn
= GlobalLock(devNames
);
145 LPDEVMODEW dm
= GlobalLock(devMode
);
148 ret
= CreateDCW((LPWSTR
)dn
+ dn
->wDriverOffset
,
149 (LPWSTR
)dn
+ dn
->wDeviceOffset
, 0, dm
);
161 static LONG
twips_to_centmm(int twips
)
163 return MulDiv(twips
, CENTMM_PER_INCH
, TWIPS_PER_INCH
);
166 static LONG
centmm_to_twips(int mm
)
168 return MulDiv(mm
, TWIPS_PER_INCH
, CENTMM_PER_INCH
);
171 static LONG
twips_to_pixels(int twips
, int dpi
)
173 return MulDiv(twips
, dpi
, TWIPS_PER_INCH
);
176 static LONG
devunits_to_twips(int units
, int dpi
)
178 return MulDiv(units
, TWIPS_PER_INCH
, dpi
);
182 static RECT
get_print_rect(HDC hdc
)
189 int dpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
190 int dpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
191 width
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALWIDTH
), dpiX
);
192 height
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALHEIGHT
), dpiY
);
195 width
= centmm_to_twips(18500);
196 height
= centmm_to_twips(27000);
199 SetRect(&rc
, margins
.left
, margins
.top
, width
- margins
.right
, height
- margins
.bottom
);
204 void target_device(HWND hMainWnd
, DWORD wordWrap
)
206 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
208 if(wordWrap
== ID_WORDWRAP_MARGIN
)
213 RECT rc
= get_print_rect(hdc
);
215 width
= rc
.right
- rc
.left
;
218 HDC hMaindc
= GetDC(hMainWnd
);
219 hdc
= CreateCompatibleDC(hMaindc
);
220 ReleaseDC(hMainWnd
, hMaindc
);
222 result
= SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, (WPARAM
)hdc
, width
);
226 /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping
227 * to window using the NULL DC. */
230 if (wordWrap
!= ID_WORDWRAP_NONE
) {
231 SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, 0, 0);
233 SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, 0, 1);
238 static LPWSTR
dialog_print_to_file(HWND hMainWnd
)
241 static WCHAR file
[MAX_PATH
] = {'O','U','T','P','U','T','.','P','R','N',0};
242 static const WCHAR defExt
[] = {'P','R','N',0};
243 static LPWSTR file_filter
;
246 file_filter
= get_print_file_filter(hMainWnd
);
248 ZeroMemory(&ofn
, sizeof(ofn
));
250 ofn
.lStructSize
= sizeof(ofn
);
251 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
| OFN_OVERWRITEPROMPT
;
252 ofn
.hwndOwner
= hMainWnd
;
253 ofn
.lpstrFilter
= file_filter
;
254 ofn
.lpstrFile
= file
;
255 ofn
.nMaxFile
= MAX_PATH
;
256 ofn
.lpstrDefExt
= defExt
;
258 if(GetSaveFileNameW(&ofn
))
264 static void char_from_pagenum(HWND hEditorWnd
, FORMATRANGE
*fr
, int page
)
270 for(i
= 1; i
< page
; i
++)
272 int bottom
= fr
->rc
.bottom
;
273 fr
->chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, (LPARAM
)fr
);
274 fr
->rc
.bottom
= bottom
;
278 static HWND
get_ruler_wnd(HWND hMainWnd
)
280 return GetDlgItem(GetDlgItem(hMainWnd
, IDC_REBAR
), IDC_RULER
);
283 void redraw_ruler(HWND hRulerWnd
)
287 GetClientRect(hRulerWnd
, &rc
);
288 InvalidateRect(hRulerWnd
, &rc
, TRUE
);
291 static void update_ruler(HWND hRulerWnd
)
293 SendMessageW(hRulerWnd
, WM_USER
, 0, 0);
294 redraw_ruler(hRulerWnd
);
297 static void add_ruler_units(HDC hdcRuler
, RECT
* drawRect
, BOOL NewMetrics
, LONG EditLeftmost
)
303 static HBITMAP hBitmap
;
304 int i
, x
, y
, RulerTextEnd
;
308 WCHAR FontName
[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
313 DeleteObject(hBitmap
);
316 hdc
= CreateCompatibleDC(0);
318 CmPixels
= twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc
, LOGPIXELSX
));
319 QuarterCmPixels
= (int)((float)CmPixels
/ 4.0);
321 hBitmap
= CreateCompatibleBitmap(hdc
, drawRect
->right
, drawRect
->bottom
);
322 SelectObject(hdc
, hBitmap
);
323 FillRect(hdc
, drawRect
, GetStockObject(WHITE_BRUSH
));
325 hFont
= CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName
);
327 SelectObject(hdc
, hFont
);
328 SetBkMode(hdc
, TRANSPARENT
);
329 SetTextAlign(hdc
, TA_CENTER
);
330 y
= (int)(((float)drawRect
->bottom
- (float)drawRect
->top
) / 2.0) + 1;
331 RulerTextEnd
= drawRect
->right
- EditLeftmost
+ 1;
332 for(i
= 1, x
= EditLeftmost
; x
< (drawRect
->right
- EditLeftmost
+ 1); i
++)
335 WCHAR format
[] = {'%','d',0};
338 x2
+= QuarterCmPixels
;
339 if(x2
> RulerTextEnd
)
342 MoveToEx(hdc
, x2
, y
, NULL
);
343 LineTo(hdc
, x2
, y
+2);
345 x2
+= QuarterCmPixels
;
346 if(x2
> RulerTextEnd
)
349 MoveToEx(hdc
, x2
, y
- 3, NULL
);
350 LineTo(hdc
, x2
, y
+ 3);
352 x2
+= QuarterCmPixels
;
353 if(x2
> RulerTextEnd
)
356 MoveToEx(hdc
, x2
, y
, NULL
);
357 LineTo(hdc
, x2
, y
+2);
363 wsprintfW(str
, format
, i
);
364 TextOutW(hdc
, x
, 5, str
, lstrlenW(str
));
369 BitBlt(hdcRuler
, 0, 0, drawRect
->right
, drawRect
->bottom
, hdc
, 0, 0, SRCAND
);
372 static void paint_ruler(HWND hWnd
, LONG EditLeftmost
, BOOL NewMetrics
)
375 HDC hdc
= BeginPaint(hWnd
, &ps
);
376 HDC hdcPrint
= make_dc();
377 RECT printRect
= get_print_rect(hdcPrint
);
379 HBRUSH hBrush
= CreateSolidBrush(GetSysColor(COLOR_MENU
));
381 GetClientRect(hWnd
, &drawRect
);
382 FillRect(hdc
, &drawRect
, hBrush
);
384 InflateRect(&drawRect
, 0, -3);
385 drawRect
.left
= EditLeftmost
;
386 drawRect
.right
= twips_to_pixels(printRect
.right
- margins
.left
, GetDeviceCaps(hdc
, LOGPIXELSX
));
387 FillRect(hdc
, &drawRect
, GetStockObject(WHITE_BRUSH
));
391 DrawEdge(hdc
, &drawRect
, EDGE_SUNKEN
, BF_RECT
);
393 drawRect
.left
= drawRect
.right
- 1;
394 drawRect
.right
= twips_to_pixels(printRect
.right
+ margins
.right
- margins
.left
, GetDeviceCaps(hdc
, LOGPIXELSX
));
395 DrawEdge(hdc
, &drawRect
, EDGE_ETCHED
, BF_RECT
);
399 add_ruler_units(hdc
, &drawRect
, NewMetrics
, EditLeftmost
);
401 SelectObject(hdc
, GetStockObject(BLACK_BRUSH
));
402 DeleteObject(hBrush
);
407 LRESULT CALLBACK
ruler_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
409 static WNDPROC pPrevRulerProc
;
410 static LONG EditLeftmost
;
411 static BOOL NewMetrics
;
418 EditLeftmost
= ((POINTL
*)wParam
)->x
;
419 pPrevRulerProc
= (WNDPROC
)lParam
;
425 paint_ruler(hWnd
, EditLeftmost
, NewMetrics
);
429 return CallWindowProcW(pPrevRulerProc
, hWnd
, msg
, wParam
, lParam
);
435 static void print(LPPRINTDLGW pd
, LPWSTR wszFileName
)
439 HWND hEditorWnd
= GetDlgItem(pd
->hwndOwner
, IDC_EDITOR
);
440 int printedPages
= 0;
443 fr
.hdcTarget
= pd
->hDC
;
445 fr
.rc
= get_print_rect(fr
.hdc
);
446 SetRect(&fr
.rcPage
, 0, 0, fr
.rc
.right
+ margins
.right
, fr
.rc
.bottom
+ margins
.bottom
);
448 ZeroMemory(&di
, sizeof(di
));
449 di
.cbSize
= sizeof(di
);
450 di
.lpszDocName
= wszFileName
;
452 if(pd
->Flags
& PD_PRINTTOFILE
)
454 di
.lpszOutput
= dialog_print_to_file(pd
->hwndOwner
);
459 if(pd
->Flags
& PD_SELECTION
)
461 SendMessageW(hEditorWnd
, EM_EXGETSEL
, 0, (LPARAM
)&fr
.chrg
);
465 gt
.flags
= GTL_DEFAULT
;
468 fr
.chrg
.cpMax
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
470 if(pd
->Flags
& PD_PAGENUMS
)
471 char_from_pagenum(hEditorWnd
, &fr
, pd
->nToPage
);
474 StartDocW(fr
.hdc
, &di
);
477 if(StartPage(fr
.hdc
) <= 0)
480 fr
.chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
482 if(EndPage(fr
.hdc
) <= 0)
486 if((pd
->Flags
& PD_PAGENUMS
) && (printedPages
> (pd
->nToPage
- pd
->nFromPage
)))
489 while(fr
.chrg
.cpMin
&& fr
.chrg
.cpMin
< fr
.chrg
.cpMax
);
492 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
495 void dialog_printsetup(HWND hMainWnd
)
499 ZeroMemory(&ps
, sizeof(ps
));
500 ps
.lStructSize
= sizeof(ps
);
501 ps
.hwndOwner
= hMainWnd
;
502 ps
.Flags
= PSD_INHUNDREDTHSOFMILLIMETERS
| PSD_MARGINS
;
503 SetRect(&ps
.rtMargin
, twips_to_centmm(margins
.left
), twips_to_centmm(margins
.top
),
504 twips_to_centmm(margins
.right
), twips_to_centmm(margins
.bottom
));
505 ps
.hDevMode
= devMode
;
506 ps
.hDevNames
= devNames
;
508 if(PageSetupDlgW(&ps
))
510 SetRect(&margins
, centmm_to_twips(ps
.rtMargin
.left
), centmm_to_twips(ps
.rtMargin
.top
),
511 centmm_to_twips(ps
.rtMargin
.right
), centmm_to_twips(ps
.rtMargin
.bottom
));
512 devMode
= ps
.hDevMode
;
513 devNames
= ps
.hDevNames
;
514 update_ruler(get_ruler_wnd(hMainWnd
));
518 void get_default_printer_opts(void)
521 ZeroMemory(&pd
, sizeof(pd
));
523 ZeroMemory(&pd
, sizeof(pd
));
524 pd
.lStructSize
= sizeof(pd
);
525 pd
.Flags
= PD_RETURNDC
| PD_RETURNDEFAULT
;
526 pd
.hDevMode
= devMode
;
530 devMode
= pd
.hDevMode
;
531 devNames
= pd
.hDevNames
;
534 void print_quick(HWND hMainWnd
, LPWSTR wszFileName
)
538 ZeroMemory(&pd
, sizeof(pd
));
539 pd
.hwndOwner
= hMainWnd
;
542 print(&pd
, wszFileName
);
546 void dialog_print(HWND hMainWnd
, LPWSTR wszFileName
)
549 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
553 ZeroMemory(&pd
, sizeof(pd
));
554 pd
.lStructSize
= sizeof(pd
);
555 pd
.hwndOwner
= hMainWnd
;
556 pd
.Flags
= PD_RETURNDC
| PD_USEDEVMODECOPIESANDCOLLATE
;
559 pd
.hDevMode
= devMode
;
560 pd
.hDevNames
= devNames
;
562 SendMessageW(hEditorWnd
, EM_GETSEL
, (WPARAM
)&from
, (LPARAM
)&to
);
564 pd
.Flags
|= PD_NOSELECTION
;
568 devMode
= pd
.hDevMode
;
569 devNames
= pd
.hDevNames
;
570 print(&pd
, wszFileName
);
571 update_ruler(get_ruler_wnd(hMainWnd
));
575 static void preview_bar_show(HWND hMainWnd
, BOOL show
)
577 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
584 UINT num_pages_string
= preview
.pages_shown
> 1 ? STRING_PREVIEW_ONEPAGE
:
585 STRING_PREVIEW_TWOPAGES
;
587 AddTextButton(hReBar
, STRING_PREVIEW_PRINT
, ID_PRINT
, BANDID_PREVIEW_BTN1
);
588 AddTextButton(hReBar
, STRING_PREVIEW_NEXTPAGE
, ID_PREVIEW_NEXTPAGE
, BANDID_PREVIEW_BTN2
);
589 AddTextButton(hReBar
, STRING_PREVIEW_PREVPAGE
, ID_PREVIEW_PREVPAGE
, BANDID_PREVIEW_BTN3
);
590 AddTextButton(hReBar
, num_pages_string
, ID_PREVIEW_NUMPAGES
, BANDID_PREVIEW_BTN4
);
591 AddTextButton(hReBar
, STRING_PREVIEW_ZOOMIN
, ID_PREVIEW_ZOOMIN
, BANDID_PREVIEW_BTN5
);
592 AddTextButton(hReBar
, STRING_PREVIEW_ZOOMOUT
, ID_PREVIEW_ZOOMOUT
, BANDID_PREVIEW_BTN6
);
593 AddTextButton(hReBar
, STRING_PREVIEW_CLOSE
, ID_FILE_EXIT
, BANDID_PREVIEW_BTN7
);
595 hStatic
= CreateWindowW(WC_STATICW
, NULL
,
596 WS_VISIBLE
| WS_CHILD
, 0, 0, 0, 0,
597 hReBar
, NULL
, NULL
, NULL
);
599 rb
.cbSize
= REBARBANDINFOW_V6_SIZE
;
600 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
601 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
602 rb
.hwndChild
= hStatic
;
603 rb
.cyChild
= rb
.cyMinChild
= 22;
604 rb
.cx
= rb
.cxMinChild
= 90;
606 rb
.wID
= BANDID_PREVIEW_BUFFER
;
608 SendMessageW(hReBar
, RB_INSERTBANDW
, -1, (LPARAM
)&rb
);
611 for(i
= 0; i
<= PREVIEW_BUTTONS
; i
++)
612 SendMessageW(hReBar
, RB_DELETEBAND
, SendMessageW(hReBar
, RB_IDTOINDEX
, BANDID_PREVIEW_BTN1
+i
, 0), 0);
616 static const int min_spacing
= 10;
618 static void update_preview_scrollbars(HWND hwndPreview
, RECT
*window
)
621 sbi
.cbSize
= sizeof(sbi
);
622 sbi
.fMask
= SIF_PAGE
|SIF_RANGE
;
624 if (preview
.zoomlevel
== 0)
626 /* Hide scrollbars when zoomed out. */
628 sbi
.nPage
= window
->right
;
629 SetScrollInfo(hwndPreview
, SB_HORZ
, &sbi
, TRUE
);
630 sbi
.nPage
= window
->bottom
;
631 SetScrollInfo(hwndPreview
, SB_VERT
, &sbi
, TRUE
);
633 sbi
.nMax
= preview
.bmScaledSize
.cx
* preview
.pages_shown
+
634 min_spacing
* (preview
.pages_shown
+ 1);
635 sbi
.nPage
= window
->right
;
636 SetScrollInfo(hwndPreview
, SB_HORZ
, &sbi
, TRUE
);
637 /* Change in the horizontal scrollbar visibility affects the
638 * client rect, so update the client rect. */
639 GetClientRect(hwndPreview
, window
);
640 sbi
.nMax
= preview
.bmScaledSize
.cy
+ min_spacing
* 2;
641 sbi
.nPage
= window
->bottom
;
642 SetScrollInfo(hwndPreview
, SB_VERT
, &sbi
, TRUE
);
646 static void update_preview_sizes(HWND hwndPreview
, BOOL zoomLevelUpdated
)
650 GetClientRect(hwndPreview
, &window
);
652 /* The zoom ratio isn't updated for partial zoom because of resizing the window. */
653 if (zoomLevelUpdated
|| preview
.zoomlevel
!= 1)
655 float ratio
, ratioHeight
, ratioWidth
;
656 if (preview
.zoomlevel
== 2)
660 ratioHeight
= (window
.bottom
- min_spacing
* 2) / (float)preview
.bmSize
.cy
;
662 ratioWidth
= (float)(window
.right
-
663 min_spacing
* (preview
.pages_shown
+ 1)) /
664 (preview
.pages_shown
* preview
.bmSize
.cx
);
666 if(ratioWidth
> ratioHeight
)
671 if (preview
.zoomlevel
== 1)
672 ratio
+= (1.0 - ratio
) / 2;
674 preview
.zoomratio
= ratio
;
677 preview
.bmScaledSize
.cx
= preview
.bmSize
.cx
* preview
.zoomratio
;
678 preview
.bmScaledSize
.cy
= preview
.bmSize
.cy
* preview
.zoomratio
;
680 preview
.spacing
.cy
= max(min_spacing
, (window
.bottom
- preview
.bmScaledSize
.cy
) / 2);
682 preview
.spacing
.cx
= (window
.right
-
683 preview
.bmScaledSize
.cx
* preview
.pages_shown
) /
684 (preview
.pages_shown
+ 1);
685 if (preview
.spacing
.cx
< min_spacing
)
686 preview
.spacing
.cx
= min_spacing
;
688 update_preview_scrollbars(hwndPreview
, &window
);
691 static void draw_margin_lines(HDC hdc
, int x
, int y
, float ratio
)
695 RECT page_margin
= preview
.rcPage
;
697 dpi
.cx
= GetDeviceCaps(hdc
, LOGPIXELSX
);
698 dpi
.cy
= GetDeviceCaps(hdc
, LOGPIXELSY
);
700 SetRect(&page_margin
, preview
.rcPage
.left
+ margins
.left
, preview
.rcPage
.top
+ margins
.top
,
701 preview
.rcPage
.right
- margins
.right
, preview
.rcPage
.bottom
- margins
.bottom
);
703 page_margin
.left
= (int)((float)twips_to_pixels(page_margin
.left
, dpi
.cx
) * ratio
);
704 page_margin
.top
= (int)((float)twips_to_pixels(page_margin
.top
, dpi
.cy
) * ratio
);
705 page_margin
.bottom
= (int)((float)twips_to_pixels(page_margin
.bottom
, dpi
.cy
) * ratio
);
706 page_margin
.right
= (int)((float)twips_to_pixels(page_margin
.right
, dpi
.cx
) * ratio
);
708 OffsetRect(&page_margin
, x
, y
);
710 hPen
= CreatePen(PS_DOT
, 1, RGB(0,0,0));
711 oldPen
= SelectObject(hdc
, hPen
);
713 MoveToEx(hdc
, x
, page_margin
.top
, NULL
);
714 LineTo(hdc
, x
+ preview
.bmScaledSize
.cx
, page_margin
.top
);
715 MoveToEx(hdc
, x
, page_margin
.bottom
, NULL
);
716 LineTo(hdc
, x
+ preview
.bmScaledSize
.cx
, page_margin
.bottom
);
718 MoveToEx(hdc
, page_margin
.left
, y
, NULL
);
719 LineTo(hdc
, page_margin
.left
, y
+ preview
.bmScaledSize
.cy
);
720 MoveToEx(hdc
, page_margin
.right
, y
, NULL
);
721 LineTo(hdc
, page_margin
.right
, y
+ preview
.bmScaledSize
.cy
);
723 SelectObject(hdc
, oldPen
);
727 static BOOL
is_last_preview_page(int page
)
729 return preview
.pageEnds
[page
- 1] >= preview
.textlength
;
732 void init_preview(HWND hMainWnd
, LPWSTR wszFileName
)
734 HINSTANCE hInstance
= GetModuleHandleW(0);
738 preview
.wszFileName
= wszFileName
;
739 preview
.zoomratio
= 0;
740 preview
.zoomlevel
= 0;
741 preview_bar_show(hMainWnd
, TRUE
);
743 CreateWindowExW(0, wszPreviewWndClass
, NULL
,
744 WS_VISIBLE
| WS_CHILD
| WS_VSCROLL
| WS_HSCROLL
,
745 0, 0, 200, 10, hMainWnd
, (HMENU
)IDC_PREVIEW
, hInstance
, NULL
);
748 void close_preview(HWND hMainWnd
)
750 HWND hwndPreview
= GetDlgItem(hMainWnd
, IDC_PREVIEW
);
751 preview
.window
.right
= 0;
752 preview
.window
.bottom
= 0;
754 HeapFree(GetProcessHeap(), 0, preview
.pageEnds
);
755 preview
.pageEnds
= NULL
;
756 preview
.pageCapacity
= 0;
757 if (preview
.zoomlevel
> 0)
758 preview
.pages_shown
= preview
.saved_pages_shown
;
760 HBITMAP oldbm
= GetCurrentObject(preview
.hdc
, OBJ_BITMAP
);
761 DeleteDC(preview
.hdc
);
766 HBITMAP oldbm
= GetCurrentObject(preview
.hdc2
, OBJ_BITMAP
);
767 DeleteDC(preview
.hdc2
);
772 preview_bar_show(hMainWnd
, FALSE
);
773 DestroyWindow(hwndPreview
);
776 BOOL
preview_isactive(void)
778 return preview
.page
!= 0;
781 static void draw_preview(HWND hEditorWnd
, FORMATRANGE
* lpFr
, RECT
* paper
, int page
)
785 if (!preview
.pageEnds
)
787 preview
.pageCapacity
= 32;
788 preview
.pageEnds
= HeapAlloc(GetProcessHeap(), 0,
789 sizeof(int) * preview
.pageCapacity
);
790 if (!preview
.pageEnds
) return;
791 } else if (page
>= preview
.pageCapacity
) {
793 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, preview
.pageEnds
,
794 sizeof(int) * preview
.pageCapacity
* 2);
795 if (!new_buffer
) return;
796 preview
.pageCapacity
*= 2;
797 preview
.pageEnds
= new_buffer
;
800 FillRect(lpFr
->hdc
, paper
, GetStockObject(WHITE_BRUSH
));
801 if (page
> 1 && is_last_preview_page(page
- 1)) return;
802 lpFr
->chrg
.cpMin
= page
<= 1 ? 0 : preview
.pageEnds
[page
-2];
803 bottom
= lpFr
->rc
.bottom
;
804 preview
.pageEnds
[page
-1] = SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)lpFr
);
806 /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in,
807 * but we want to keep the original for drawing margins */
808 lpFr
->rc
.bottom
= bottom
;
809 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
812 static void update_preview_buttons(HWND hMainWnd
)
814 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
815 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_PREVPAGE
), preview
.page
> 1);
816 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_NEXTPAGE
),
817 !is_last_preview_page(preview
.page
) &&
818 !is_last_preview_page(preview
.page
+ preview
.pages_shown
- 1));
819 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_NUMPAGES
),
820 preview
.pages_shown
> 1 ||
821 (!is_last_preview_page(1) && preview
.zoomlevel
== 0));
822 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_ZOOMIN
), preview
.zoomlevel
< 2);
823 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_ZOOMOUT
), preview
.zoomlevel
> 0);
826 static LRESULT
print_preview(HWND hwndPreview
)
830 HRGN back_rgn
, excl_rgn
;
831 RECT window
, background
;
835 hdc
= BeginPaint(hwndPreview
, &ps
);
836 GetClientRect(hwndPreview
, &window
);
837 back_rgn
= CreateRectRgnIndirect(&window
);
839 x
= preview
.spacing
.cx
- GetScrollPos(hwndPreview
, SB_HORZ
);
840 y
= preview
.spacing
.cy
- GetScrollPos(hwndPreview
, SB_VERT
);
842 /* draw page outlines */
843 hPen
= CreatePen(PS_SOLID
|PS_INSIDEFRAME
, 2, RGB(0,0,0));
844 oldPen
= SelectObject(hdc
, hPen
);
845 SetRect(&background
, x
- 2, y
- 2, x
+ preview
.bmScaledSize
.cx
+ 2,
846 y
+ preview
.bmScaledSize
.cy
+ 2);
847 Rectangle(hdc
, background
.left
, background
.top
,
848 background
.right
, background
.bottom
);
849 excl_rgn
= CreateRectRgnIndirect(&background
);
850 CombineRgn(back_rgn
, back_rgn
, excl_rgn
, RGN_DIFF
);
851 if(preview
.pages_shown
> 1)
853 background
.left
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
854 background
.right
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
855 Rectangle(hdc
, background
.left
, background
.top
,
856 background
.right
, background
.bottom
);
857 SetRectRgn(excl_rgn
, background
.left
, background
.top
,
858 background
.right
, background
.bottom
);
859 CombineRgn(back_rgn
, back_rgn
, excl_rgn
, RGN_DIFF
);
861 SelectObject(hdc
, oldPen
);
863 FillRgn(hdc
, back_rgn
, GetStockObject(GRAY_BRUSH
));
864 DeleteObject(excl_rgn
);
865 DeleteObject(back_rgn
);
867 StretchBlt(hdc
, x
, y
, preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
868 preview
.hdc
, 0, 0, preview
.bmSize
.cx
, preview
.bmSize
.cy
, SRCCOPY
);
870 draw_margin_lines(hdc
, x
, y
, preview
.zoomratio
);
872 if(preview
.pages_shown
> 1)
874 if (!is_last_preview_page(preview
.page
)) {
875 x
+= preview
.spacing
.cx
+ preview
.bmScaledSize
.cx
;
876 StretchBlt(hdc
, x
, y
,
877 preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
879 preview
.bmSize
.cx
, preview
.bmSize
.cy
, SRCCOPY
);
881 draw_margin_lines(hdc
, x
, y
, preview
.zoomratio
);
883 InflateRect(&background
, -2, -2);
884 FillRect(hdc
, &background
, GetStockObject(WHITE_BRUSH
));
888 preview
.window
= window
;
890 EndPaint(hwndPreview
, &ps
);
895 static void update_preview_statusbar(HWND hMainWnd
)
897 HWND hStatusbar
= GetDlgItem(hMainWnd
, IDC_STATUSBAR
);
898 HINSTANCE hInst
= GetModuleHandleW(0);
900 WCHAR wstr
[MAX_STRING_LEN
];
903 if (preview
.pages_shown
< 2 || is_last_preview_page(preview
.page
))
905 static const WCHAR fmt
[] = {' ','%','d','\0'};
906 p
+= LoadStringW(hInst
, STRING_PREVIEW_PAGE
, wstr
, MAX_STRING_LEN
);
907 wsprintfW(p
, fmt
, preview
.page
);
909 static const WCHAR fmt
[] = {' ','%','d','-','%','d','\0'};
910 p
+= LoadStringW(hInst
, STRING_PREVIEW_PAGES
, wstr
, MAX_STRING_LEN
);
911 wsprintfW(p
, fmt
, preview
.page
, preview
.page
+ 1);
913 SetWindowTextW(hStatusbar
, wstr
);
916 /* Update for page changes. */
917 static void update_preview(HWND hMainWnd
)
920 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
921 HWND hwndPreview
= GetDlgItem(hMainWnd
, IDC_PREVIEW
);
922 HBITMAP hBitmapCapture
;
924 HDC hdc
= GetDC(hwndPreview
);
926 fr
.hdcTarget
= make_dc();
927 fr
.rc
= fr
.rcPage
= preview
.rcPage
;
928 fr
.rc
.left
+= margins
.left
;
929 fr
.rc
.top
+= margins
.top
;
930 fr
.rc
.bottom
-= margins
.bottom
;
931 fr
.rc
.right
-= margins
.right
;
934 fr
.chrg
.cpMax
= preview
.textlength
;
936 SetRect(&paper
, 0, 0, preview
.bmSize
.cx
, preview
.bmSize
.cy
);
939 preview
.hdc
= CreateCompatibleDC(hdc
);
940 hBitmapCapture
= CreateCompatibleBitmap(hdc
, preview
.bmSize
.cx
, preview
.bmSize
.cy
);
941 SelectObject(preview
.hdc
, hBitmapCapture
);
944 fr
.hdc
= preview
.hdc
;
945 draw_preview(hEditorWnd
, &fr
, &paper
, preview
.page
);
947 if(preview
.pages_shown
> 1)
951 preview
.hdc2
= CreateCompatibleDC(hdc
);
952 hBitmapCapture
= CreateCompatibleBitmap(hdc
,
955 SelectObject(preview
.hdc2
, hBitmapCapture
);
958 fr
.hdc
= preview
.hdc2
;
959 draw_preview(hEditorWnd
, &fr
, &fr
.rcPage
, preview
.page
+ 1);
961 DeleteDC(fr
.hdcTarget
);
962 ReleaseDC(hwndPreview
, hdc
);
964 InvalidateRect(hwndPreview
, NULL
, FALSE
);
965 update_preview_buttons(hMainWnd
);
966 update_preview_statusbar(hMainWnd
);
969 static void toggle_num_pages(HWND hMainWnd
)
971 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
972 WCHAR name
[MAX_STRING_LEN
];
973 HINSTANCE hInst
= GetModuleHandleW(0);
976 preview
.pages_shown
= preview
.pages_shown
> 1 ? 1 : 2;
978 nPreviewPages
= preview
.zoomlevel
> 0 ? preview
.saved_pages_shown
:
981 LoadStringW(hInst
, nPreviewPages
> 1 ? STRING_PREVIEW_ONEPAGE
:
982 STRING_PREVIEW_TWOPAGES
,
983 name
, MAX_STRING_LEN
);
985 SetWindowTextW(GetDlgItem(hReBar
, ID_PREVIEW_NUMPAGES
), name
);
986 update_preview_sizes(GetDlgItem(hMainWnd
, IDC_PREVIEW
), TRUE
);
987 update_preview(hMainWnd
);
990 /* Returns the page shown that the point is in (1 or 2) or 0 if the point
991 * isn't inside either page */
992 static int preview_page_hittest(POINT pt
)
995 rc
.left
= preview
.spacing
.cx
;
996 rc
.right
= rc
.left
+ preview
.bmScaledSize
.cx
;
997 rc
.top
= preview
.spacing
.cy
;
998 rc
.bottom
= rc
.top
+ preview
.bmScaledSize
.cy
;
999 if (PtInRect(&rc
, pt
))
1002 if (preview
.pages_shown
<= 1)
1005 rc
.left
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
1006 rc
.right
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
1007 if (PtInRect(&rc
, pt
))
1008 return is_last_preview_page(preview
.page
) ? 1 : 2;
1013 LRESULT CALLBACK
preview_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1019 HWND hMainWnd
= GetParent(hWnd
);
1020 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
1022 GETTEXTLENGTHEX gt
= {GTL_DEFAULT
, 1200};
1023 HDC hdc
= GetDC(hWnd
);
1024 HDC hdcTarget
= make_dc();
1026 fr
.rc
= preview
.rcPage
= get_print_rect(hdcTarget
);
1027 preview
.rcPage
.bottom
+= margins
.bottom
;
1028 preview
.rcPage
.right
+= margins
.right
;
1029 preview
.rcPage
.top
= preview
.rcPage
.left
= 0;
1030 fr
.rcPage
= preview
.rcPage
;
1032 preview
.bmSize
.cx
= twips_to_pixels(preview
.rcPage
.right
, GetDeviceCaps(hdc
, LOGPIXELSX
));
1033 preview
.bmSize
.cy
= twips_to_pixels(preview
.rcPage
.bottom
, GetDeviceCaps(hdc
, LOGPIXELSY
));
1035 preview
.textlength
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
1037 fr
.hdc
= CreateCompatibleDC(hdc
);
1038 fr
.hdcTarget
= hdcTarget
;
1040 fr
.chrg
.cpMax
= preview
.textlength
;
1042 DeleteDC(hdcTarget
);
1043 ReleaseDC(hWnd
, hdc
);
1045 update_preview_sizes(hWnd
, TRUE
);
1046 update_preview(hMainWnd
);
1051 return print_preview(hWnd
);
1055 update_preview_sizes(hWnd
, FALSE
);
1056 InvalidateRect(hWnd
, NULL
, FALSE
);
1065 int nBar
= (msg
== WM_VSCROLL
) ? SB_VERT
: SB_HORZ
;
1068 GetClientRect(hWnd
, &rc
);
1069 si
.cbSize
= sizeof(si
);
1071 GetScrollInfo(hWnd
, nBar
, &si
);
1073 switch(LOWORD(wParam
))
1075 case SB_TOP
: /* == SB_LEFT */
1078 case SB_BOTTOM
: /* == SB_RIGHT */
1081 case SB_LINEUP
: /* == SB_LINELEFT */
1082 si
.nPos
-= si
.nPage
/ 10;
1084 case SB_LINEDOWN
: /* == SB_LINERIGHT */
1085 si
.nPos
+= si
.nPage
/ 10;
1087 case SB_PAGEUP
: /* == SB_PAGELEFT */
1088 si
.nPos
-= si
.nPage
;
1090 case SB_PAGEDOWN
: /* SB_PAGERIGHT */
1091 si
.nPos
+= si
.nPage
;
1094 si
.nPos
= si
.nTrackPos
;
1098 SetScrollInfo(hWnd
, nBar
, &si
, TRUE
);
1099 GetScrollInfo(hWnd
, nBar
, &si
);
1100 if (si
.nPos
!= origPos
)
1102 int amount
= origPos
- si
.nPos
;
1103 if (msg
== WM_VSCROLL
)
1104 ScrollWindow(hWnd
, 0, amount
, NULL
, NULL
);
1106 ScrollWindow(hWnd
, amount
, 0, NULL
, NULL
);
1116 DWORD messagePos
= GetMessagePos();
1117 pt
.x
= (short)LOWORD(messagePos
);
1118 pt
.y
= (short)HIWORD(messagePos
);
1119 ScreenToClient(hWnd
, &pt
);
1121 GetClientRect(hWnd
, &rc
);
1122 if (PtInRect(&rc
, pt
))
1124 pt
.x
+= GetScrollPos(hWnd
, SB_HORZ
);
1125 pt
.y
+= GetScrollPos(hWnd
, SB_VERT
);
1126 bHittest
= preview_page_hittest(pt
);
1130 SetCursor(LoadCursorW(GetModuleHandleW(0),
1131 MAKEINTRESOURCEW(IDC_ZOOM
)));
1133 SetCursor(LoadCursorW(NULL
, (WCHAR
*)IDC_ARROW
));
1138 case WM_LBUTTONDOWN
:
1142 pt
.x
= (short)LOWORD(lParam
) + GetScrollPos(hWnd
, SB_HORZ
);
1143 pt
.y
= (short)HIWORD(lParam
) + GetScrollPos(hWnd
, SB_VERT
);
1144 if ((page
= preview_page_hittest(pt
)) > 0)
1146 HWND hMainWnd
= GetParent(hWnd
);
1148 /* Convert point from client coordinate to unzoomed page
1150 pt
.x
-= preview
.spacing
.cx
;
1152 pt
.x
-= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
1153 pt
.y
-= preview
.spacing
.cy
;
1154 pt
.x
/= preview
.zoomratio
;
1155 pt
.y
/= preview
.zoomratio
;
1157 if (preview
.zoomlevel
== 0)
1158 preview
.saved_pages_shown
= preview
.pages_shown
;
1159 preview
.zoomlevel
= (preview
.zoomlevel
+ 1) % 3;
1160 preview
.zoomratio
= 0;
1161 if (preview
.zoomlevel
== 0 && preview
.saved_pages_shown
> 1)
1163 toggle_num_pages(hMainWnd
);
1164 } else if (preview
.pages_shown
> 1) {
1165 if (page
>= 2) preview
.page
++;
1166 toggle_num_pages(hMainWnd
);
1168 update_preview_sizes(hWnd
, TRUE
);
1169 InvalidateRect(hWnd
, NULL
, FALSE
);
1170 update_preview_buttons(hMainWnd
);
1173 if (preview
.zoomlevel
> 0) {
1175 /* Convert the coordinate back to client coordinate. */
1176 pt
.x
*= preview
.zoomratio
;
1177 pt
.y
*= preview
.zoomratio
;
1178 pt
.x
+= preview
.spacing
.cx
;
1179 pt
.y
+= preview
.spacing
.cy
;
1180 /* Scroll to center view at that point on the page */
1181 si
.cbSize
= sizeof(si
);
1182 si
.fMask
= SIF_PAGE
;
1183 GetScrollInfo(hWnd
, SB_HORZ
, &si
);
1184 pt
.x
-= si
.nPage
/ 2;
1185 SetScrollPos(hWnd
, SB_HORZ
, pt
.x
, TRUE
);
1186 GetScrollInfo(hWnd
, SB_VERT
, &si
);
1187 pt
.y
-= si
.nPage
/ 2;
1188 SetScrollPos(hWnd
, SB_VERT
, pt
.y
, TRUE
);
1194 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1200 LRESULT
preview_command(HWND hWnd
, WPARAM wParam
)
1202 switch(LOWORD(wParam
))
1205 PostMessageW(hWnd
, WM_CLOSE
, 0, 0);
1208 case ID_PREVIEW_NEXTPAGE
:
1209 case ID_PREVIEW_PREVPAGE
:
1211 if(LOWORD(wParam
) == ID_PREVIEW_NEXTPAGE
)
1216 update_preview(hWnd
);
1220 case ID_PREVIEW_NUMPAGES
:
1221 toggle_num_pages(hWnd
);
1224 case ID_PREVIEW_ZOOMIN
:
1225 if (preview
.zoomlevel
< 2)
1227 if (preview
.zoomlevel
== 0)
1228 preview
.saved_pages_shown
= preview
.pages_shown
;
1229 preview
.zoomlevel
++;
1230 preview
.zoomratio
= 0;
1231 if (preview
.pages_shown
> 1)
1233 /* Forced switch to one page when zooming in. */
1234 toggle_num_pages(hWnd
);
1236 HWND hwndPreview
= GetDlgItem(hWnd
, IDC_PREVIEW
);
1237 update_preview_sizes(hwndPreview
, TRUE
);
1238 InvalidateRect(hwndPreview
, NULL
, FALSE
);
1239 update_preview_buttons(hWnd
);
1244 case ID_PREVIEW_ZOOMOUT
:
1245 if (preview
.zoomlevel
> 0)
1247 HWND hwndPreview
= GetDlgItem(hWnd
, IDC_PREVIEW
);
1248 preview
.zoomlevel
--;
1249 preview
.zoomratio
= 0;
1250 if (preview
.zoomlevel
== 0 && preview
.saved_pages_shown
> 1) {
1251 toggle_num_pages(hWnd
);
1253 update_preview_sizes(hwndPreview
, TRUE
);
1254 InvalidateRect(hwndPreview
, NULL
, FALSE
);
1255 update_preview_buttons(hWnd
);
1261 dialog_print(hWnd
, preview
.wszFileName
);
1262 SendMessageW(hWnd
, WM_CLOSE
, 0, 0);