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
27 typedef struct _previewinfo
43 } previewinfo
, *ppreviewinfo
;
45 static HGLOBAL devMode
;
46 static HGLOBAL devNames
;
49 static previewinfo preview
;
51 extern const WCHAR wszPreviewWndClass
[];
53 static const WCHAR var_pagemargin
[] = {'P','a','g','e','M','a','r','g','i','n',0};
55 static LPWSTR
get_print_file_filter(HWND hMainWnd
)
57 static WCHAR wszPrintFilter
[MAX_STRING_LEN
*2+6+4+1];
58 const WCHAR files_prn
[] = {'*','.','P','R','N',0};
59 const WCHAR files_all
[] = {'*','.','*','\0'};
61 HINSTANCE hInstance
= GetModuleHandleW(0);
64 LoadStringW(hInstance
, STRING_PRINTER_FILES_PRN
, p
, MAX_STRING_LEN
);
66 lstrcpyW(p
, files_prn
);
68 LoadStringW(hInstance
, STRING_ALL_FILES
, p
, MAX_STRING_LEN
);
70 lstrcpyW(p
, files_all
);
74 return wszPrintFilter
;
77 void registry_set_pagemargins(HKEY hKey
)
79 RegSetValueExW(hKey
, var_pagemargin
, 0, REG_BINARY
, (LPBYTE
)&margins
, sizeof(RECT
));
82 void registry_read_pagemargins(HKEY hKey
)
84 DWORD size
= sizeof(RECT
);
86 if(!hKey
|| RegQueryValueExW(hKey
, var_pagemargin
, 0, NULL
, (LPBYTE
)&margins
,
87 &size
) != ERROR_SUCCESS
|| size
!= sizeof(RECT
))
90 margins
.bottom
= 1417;
96 static void AddTextButton(HWND hRebarWnd
, UINT string
, UINT command
, UINT id
)
99 HINSTANCE hInstance
= GetModuleHandleW(0);
100 WCHAR text
[MAX_STRING_LEN
];
103 LoadStringW(hInstance
, string
, text
, MAX_STRING_LEN
);
104 hButton
= CreateWindowW(WC_BUTTONW
, text
,
105 WS_VISIBLE
| WS_CHILD
, 5, 5, 100, 15,
106 hRebarWnd
, ULongToHandle(command
), hInstance
, NULL
);
108 rb
.cbSize
= REBARBANDINFOW_V6_SIZE
;
109 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
110 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
111 rb
.hwndChild
= hButton
;
112 rb
.cyChild
= rb
.cyMinChild
= 22;
113 rb
.cx
= rb
.cxMinChild
= 90;
117 SendMessageW(hRebarWnd
, RB_INSERTBAND
, -1, (LPARAM
)&rb
);
120 static HDC
make_dc(void)
122 if(devNames
&& devMode
)
124 LPDEVNAMES dn
= GlobalLock(devNames
);
125 LPDEVMODEW dm
= GlobalLock(devMode
);
128 ret
= CreateDCW((LPWSTR
)dn
+ dn
->wDriverOffset
,
129 (LPWSTR
)dn
+ dn
->wDeviceOffset
, 0, dm
);
141 static LONG
twips_to_centmm(int twips
)
143 return MulDiv(twips
, CENTMM_PER_INCH
, TWIPS_PER_INCH
);
146 static LONG
centmm_to_twips(int mm
)
148 return MulDiv(mm
, TWIPS_PER_INCH
, CENTMM_PER_INCH
);
151 static LONG
twips_to_pixels(int twips
, int dpi
)
153 return MulDiv(twips
, dpi
, TWIPS_PER_INCH
);
156 static LONG
devunits_to_twips(int units
, int dpi
)
158 return MulDiv(units
, TWIPS_PER_INCH
, dpi
);
162 static RECT
get_print_rect(HDC hdc
)
169 int dpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
170 int dpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
171 width
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALWIDTH
), dpiX
);
172 height
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALHEIGHT
), dpiY
);
175 width
= centmm_to_twips(18500);
176 height
= centmm_to_twips(27000);
179 rc
.left
= margins
.left
;
180 rc
.right
= width
- margins
.right
;
181 rc
.top
= margins
.top
;
182 rc
.bottom
= height
- margins
.bottom
;
187 void target_device(HWND hMainWnd
, DWORD wordWrap
)
189 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
191 if(wordWrap
== ID_WORDWRAP_MARGIN
)
196 RECT rc
= get_print_rect(hdc
);
198 width
= rc
.right
- rc
.left
;
201 HDC hMaindc
= GetDC(hMainWnd
);
202 hdc
= CreateCompatibleDC(hMaindc
);
203 ReleaseDC(hMainWnd
, hMaindc
);
205 result
= SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, (WPARAM
)hdc
, width
);
209 /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping
210 * to window using the NULL DC. */
213 if (wordWrap
!= ID_WORDWRAP_NONE
) {
214 SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, 0, 0);
216 SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, 0, 1);
221 static LPWSTR
dialog_print_to_file(HWND hMainWnd
)
224 static WCHAR file
[MAX_PATH
] = {'O','U','T','P','U','T','.','P','R','N',0};
225 static const WCHAR defExt
[] = {'P','R','N',0};
226 static LPWSTR file_filter
;
229 file_filter
= get_print_file_filter(hMainWnd
);
231 ZeroMemory(&ofn
, sizeof(ofn
));
233 ofn
.lStructSize
= sizeof(ofn
);
234 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
| OFN_OVERWRITEPROMPT
;
235 ofn
.hwndOwner
= hMainWnd
;
236 ofn
.lpstrFilter
= file_filter
;
237 ofn
.lpstrFile
= file
;
238 ofn
.nMaxFile
= MAX_PATH
;
239 ofn
.lpstrDefExt
= defExt
;
241 if(GetSaveFileNameW(&ofn
))
247 static int get_num_pages(HWND hEditorWnd
, FORMATRANGE fr
)
254 int bottom
= fr
.rc
.bottom
;
256 fr
.chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
,
258 fr
.rc
.bottom
= bottom
;
260 while(fr
.chrg
.cpMin
&& fr
.chrg
.cpMin
< fr
.chrg
.cpMax
);
265 static void char_from_pagenum(HWND hEditorWnd
, FORMATRANGE
*fr
, int page
)
271 for(i
= 1; i
< page
; i
++)
273 int bottom
= fr
->rc
.bottom
;
274 fr
->chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, (LPARAM
)fr
);
275 fr
->rc
.bottom
= bottom
;
279 static HWND
get_ruler_wnd(HWND hMainWnd
)
281 return GetDlgItem(GetDlgItem(hMainWnd
, IDC_REBAR
), IDC_RULER
);
284 void redraw_ruler(HWND hRulerWnd
)
288 GetClientRect(hRulerWnd
, &rc
);
289 InvalidateRect(hRulerWnd
, &rc
, TRUE
);
292 static void update_ruler(HWND hRulerWnd
)
294 SendMessageW(hRulerWnd
, WM_USER
, 0, 0);
295 redraw_ruler(hRulerWnd
);
298 static void print(LPPRINTDLGW pd
, LPWSTR wszFileName
)
302 HWND hEditorWnd
= GetDlgItem(pd
->hwndOwner
, IDC_EDITOR
);
303 int printedPages
= 0;
306 fr
.hdcTarget
= pd
->hDC
;
308 fr
.rc
= get_print_rect(fr
.hdc
);
310 fr
.rcPage
.right
= fr
.rc
.right
+ margins
.right
;
312 fr
.rcPage
.bottom
= fr
.rc
.bottom
+ margins
.bottom
;
314 ZeroMemory(&di
, sizeof(di
));
315 di
.cbSize
= sizeof(di
);
316 di
.lpszDocName
= wszFileName
;
318 if(pd
->Flags
& PD_PRINTTOFILE
)
320 di
.lpszOutput
= dialog_print_to_file(pd
->hwndOwner
);
325 if(pd
->Flags
& PD_SELECTION
)
327 SendMessageW(hEditorWnd
, EM_EXGETSEL
, 0, (LPARAM
)&fr
.chrg
);
331 gt
.flags
= GTL_DEFAULT
;
334 fr
.chrg
.cpMax
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
336 if(pd
->Flags
& PD_PAGENUMS
)
337 char_from_pagenum(hEditorWnd
, &fr
, pd
->nToPage
);
340 StartDocW(fr
.hdc
, &di
);
343 int bottom
= fr
.rc
.bottom
;
344 if(StartPage(fr
.hdc
) <= 0)
347 fr
.chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
349 if(EndPage(fr
.hdc
) <= 0)
351 bottom
= fr
.rc
.bottom
;
354 if((pd
->Flags
& PD_PAGENUMS
) && (printedPages
> (pd
->nToPage
- pd
->nFromPage
)))
357 while(fr
.chrg
.cpMin
&& fr
.chrg
.cpMin
< fr
.chrg
.cpMax
);
360 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
363 void dialog_printsetup(HWND hMainWnd
)
367 ZeroMemory(&ps
, sizeof(ps
));
368 ps
.lStructSize
= sizeof(ps
);
369 ps
.hwndOwner
= hMainWnd
;
370 ps
.Flags
= PSD_INHUNDREDTHSOFMILLIMETERS
| PSD_MARGINS
;
371 ps
.rtMargin
.left
= twips_to_centmm(margins
.left
);
372 ps
.rtMargin
.right
= twips_to_centmm(margins
.right
);
373 ps
.rtMargin
.top
= twips_to_centmm(margins
.top
);
374 ps
.rtMargin
.bottom
= twips_to_centmm(margins
.bottom
);
375 ps
.hDevMode
= devMode
;
376 ps
.hDevNames
= devNames
;
378 if(PageSetupDlgW(&ps
))
380 margins
.left
= centmm_to_twips(ps
.rtMargin
.left
);
381 margins
.right
= centmm_to_twips(ps
.rtMargin
.right
);
382 margins
.top
= centmm_to_twips(ps
.rtMargin
.top
);
383 margins
.bottom
= centmm_to_twips(ps
.rtMargin
.bottom
);
384 devMode
= ps
.hDevMode
;
385 devNames
= ps
.hDevNames
;
386 update_ruler(get_ruler_wnd(hMainWnd
));
390 void get_default_printer_opts(void)
393 ZeroMemory(&pd
, sizeof(pd
));
395 ZeroMemory(&pd
, sizeof(pd
));
396 pd
.lStructSize
= sizeof(pd
);
397 pd
.Flags
= PD_RETURNDC
| PD_RETURNDEFAULT
;
398 pd
.hDevMode
= devMode
;
402 devMode
= pd
.hDevMode
;
403 devNames
= pd
.hDevNames
;
406 void print_quick(HWND hMainWnd
, LPWSTR wszFileName
)
410 ZeroMemory(&pd
, sizeof(pd
));
411 pd
.hwndOwner
= hMainWnd
;
414 print(&pd
, wszFileName
);
417 void dialog_print(HWND hMainWnd
, LPWSTR wszFileName
)
420 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
424 ZeroMemory(&pd
, sizeof(pd
));
425 pd
.lStructSize
= sizeof(pd
);
426 pd
.hwndOwner
= hMainWnd
;
427 pd
.Flags
= PD_RETURNDC
| PD_USEDEVMODECOPIESANDCOLLATE
;
430 pd
.hDevMode
= devMode
;
431 pd
.hDevNames
= devNames
;
433 SendMessageW(hEditorWnd
, EM_GETSEL
, (WPARAM
)&from
, (LPARAM
)&to
);
435 pd
.Flags
|= PD_NOSELECTION
;
439 devMode
= pd
.hDevMode
;
440 devNames
= pd
.hDevNames
;
441 print(&pd
, wszFileName
);
442 update_ruler(get_ruler_wnd(hMainWnd
));
446 static void preview_bar_show(HWND hMainWnd
, BOOL show
)
448 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
456 AddTextButton(hReBar
, STRING_PREVIEW_PRINT
, ID_PRINT
, BANDID_PREVIEW_BTN1
);
457 AddTextButton(hReBar
, STRING_PREVIEW_NEXTPAGE
, ID_PREVIEW_NEXTPAGE
, BANDID_PREVIEW_BTN2
);
458 AddTextButton(hReBar
, STRING_PREVIEW_PREVPAGE
, ID_PREVIEW_PREVPAGE
, BANDID_PREVIEW_BTN3
);
459 AddTextButton(hReBar
, STRING_PREVIEW_TWOPAGES
, ID_PREVIEW_NUMPAGES
, BANDID_PREVIEW_BTN4
);
460 AddTextButton(hReBar
, STRING_PREVIEW_ZOOMIN
, ID_PREVIEW_ZOOMIN
, BANDID_PREVIEW_BTN5
);
461 AddTextButton(hReBar
, STRING_PREVIEW_ZOOMOUT
, ID_PREVIEW_ZOOMOUT
, BANDID_PREVIEW_BTN6
);
462 AddTextButton(hReBar
, STRING_PREVIEW_CLOSE
, ID_FILE_EXIT
, BANDID_PREVIEW_BTN7
);
464 hStatic
= CreateWindowW(WC_STATICW
, NULL
,
465 WS_VISIBLE
| WS_CHILD
, 0, 0, 0, 0,
466 hReBar
, NULL
, NULL
, NULL
);
468 rb
.cbSize
= REBARBANDINFOW_V6_SIZE
;
469 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
470 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
471 rb
.hwndChild
= hStatic
;
472 rb
.cyChild
= rb
.cyMinChild
= 22;
473 rb
.cx
= rb
.cxMinChild
= 90;
475 rb
.wID
= BANDID_PREVIEW_BUFFER
;
477 SendMessageW(hReBar
, RB_INSERTBAND
, -1, (LPARAM
)&rb
);
480 for(i
= 0; i
<= PREVIEW_BUTTONS
; i
++)
481 SendMessageW(hReBar
, RB_DELETEBAND
, SendMessageW(hReBar
, RB_IDTOINDEX
, BANDID_PREVIEW_BTN1
+i
, 0), 0);
485 static const int min_spacing
= 10;
487 static void update_preview_scrollbars(HWND hwndPreview
, RECT
*window
)
490 sbi
.cbSize
= sizeof(sbi
);
491 sbi
.fMask
= SIF_PAGE
|SIF_RANGE
;
493 if (preview
.zoomlevel
== 0)
495 /* Hide scrollbars when zoomed out. */
497 sbi
.nPage
= window
->right
;
498 SetScrollInfo(hwndPreview
, SB_HORZ
, &sbi
, TRUE
);
499 sbi
.nPage
= window
->bottom
;
500 SetScrollInfo(hwndPreview
, SB_VERT
, &sbi
, TRUE
);
503 sbi
.nMax
= preview
.bmScaledSize
.cx
+ min_spacing
* 2;
505 sbi
.nMax
= preview
.bmScaledSize
.cx
* 2 + min_spacing
* 3;
506 sbi
.nPage
= window
->right
;
507 SetScrollInfo(hwndPreview
, SB_HORZ
, &sbi
, TRUE
);
508 /* Change in the horizontal scrollbar visibility affects the
509 * client rect, so update the client rect. */
510 GetClientRect(hwndPreview
, window
);
511 sbi
.nMax
= preview
.bmScaledSize
.cy
+ min_spacing
* 2;
512 sbi
.nPage
= window
->bottom
;
513 SetScrollInfo(hwndPreview
, SB_VERT
, &sbi
, TRUE
);
517 static void update_preview_sizes(HWND hwndPreview
, BOOL zoomLevelUpdated
)
521 GetClientRect(hwndPreview
, &window
);
523 /* The zoom ratio isn't updated for partial zoom because of resizing the window. */
524 if (zoomLevelUpdated
|| preview
.zoomlevel
!= 1)
526 float ratio
, ratioHeight
, ratioWidth
;
527 if (preview
.zoomlevel
== 2)
531 ratioHeight
= (window
.bottom
- min_spacing
* 2) / (float)preview
.bmSize
.cy
;
534 ratioWidth
= ((window
.right
- min_spacing
* 3) / 2.0) / (float)preview
.bmSize
.cx
;
536 ratioWidth
= (window
.right
- min_spacing
* 2) / (float)preview
.bmSize
.cx
;
538 if(ratioWidth
> ratioHeight
)
543 if (preview
.zoomlevel
== 1)
544 ratio
+= (1.0 - ratio
) / 2;
546 preview
.zoomratio
= ratio
;
549 preview
.bmScaledSize
.cx
= preview
.bmSize
.cx
* preview
.zoomratio
;
550 preview
.bmScaledSize
.cy
= preview
.bmSize
.cy
* preview
.zoomratio
;
552 preview
.spacing
.cy
= max(min_spacing
, (window
.bottom
- preview
.bmScaledSize
.cy
) / 2);
555 preview
.spacing
.cx
= (window
.right
- preview
.bmScaledSize
.cx
) / 2;
557 preview
.spacing
.cx
= (window
.right
- preview
.bmScaledSize
.cx
* 2) / 3;
558 if (preview
.spacing
.cx
< min_spacing
)
559 preview
.spacing
.cx
= min_spacing
;
561 update_preview_scrollbars(hwndPreview
, &window
);
564 /* Update for zoom ratio changes with same page. */
565 static void update_scaled_preview(HWND hMainWnd
)
567 HWND hwndPreview
= GetDlgItem(hMainWnd
, IDC_PREVIEW
);
568 preview
.window
.right
= 0;
569 InvalidateRect(hwndPreview
, NULL
, TRUE
);
572 LRESULT CALLBACK
preview_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
578 HWND hEditorWnd
= GetDlgItem(GetParent(hWnd
), IDC_EDITOR
);
580 GETTEXTLENGTHEX gt
= {GTL_DEFAULT
, 1200};
581 HDC hdc
= GetDC(hWnd
);
582 HDC hdcTarget
= make_dc();
584 fr
.rc
= preview
.rcPage
= get_print_rect(hdcTarget
);
585 preview
.rcPage
.bottom
+= margins
.bottom
;
586 preview
.rcPage
.right
+= margins
.right
;
587 preview
.rcPage
.top
= preview
.rcPage
.left
= 0;
588 fr
.rcPage
= preview
.rcPage
;
590 preview
.bmSize
.cx
= twips_to_pixels(preview
.rcPage
.right
, GetDeviceCaps(hdc
, LOGPIXELSX
));
591 preview
.bmSize
.cy
= twips_to_pixels(preview
.rcPage
.bottom
, GetDeviceCaps(hdc
, LOGPIXELSY
));
593 fr
.hdc
= CreateCompatibleDC(hdc
);
594 fr
.hdcTarget
= hdcTarget
;
596 fr
.chrg
.cpMax
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
597 preview
.pages
= get_num_pages(hEditorWnd
, fr
);
600 update_preview_sizes(hWnd
, TRUE
);
605 return print_preview(hWnd
);
609 update_preview_sizes(hWnd
, FALSE
);
610 update_scaled_preview(hWnd
);
619 int nBar
= (msg
== WM_VSCROLL
) ? SB_VERT
: SB_HORZ
;
622 GetClientRect(hWnd
, &rc
);
623 si
.cbSize
= sizeof(si
);
625 GetScrollInfo(hWnd
, nBar
, &si
);
627 switch(LOWORD(wParam
))
629 case SB_TOP
: /* == SB_LEFT */
632 case SB_BOTTOM
: /* == SB_RIGHT */
635 case SB_LINEUP
: /* == SB_LINELEFT */
636 si
.nPos
-= si
.nPage
/ 10;
638 case SB_LINEDOWN
: /* == SB_LINERIGHT */
639 si
.nPos
+= si
.nPage
/ 10;
641 case SB_PAGEUP
: /* == SB_PAGELEFT */
644 case SB_PAGEDOWN
: /* SB_PAGERIGHT */
648 si
.nPos
= si
.nTrackPos
;
652 SetScrollInfo(hWnd
, nBar
, &si
, TRUE
);
653 GetScrollInfo(hWnd
, nBar
, &si
);
654 if (si
.nPos
!= origPos
)
656 int amount
= origPos
- si
.nPos
;
657 if (msg
== WM_VSCROLL
)
658 ScrollWindow(hWnd
, 0, amount
, NULL
, NULL
);
660 ScrollWindow(hWnd
, amount
, 0, NULL
, NULL
);
666 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
672 void init_preview(HWND hMainWnd
, LPWSTR wszFileName
)
675 HINSTANCE hInstance
= GetModuleHandleW(0);
679 preview
.wszFileName
= wszFileName
;
680 preview
.zoomratio
= 0;
681 preview
.zoomlevel
= 0;
682 preview_bar_show(hMainWnd
, TRUE
);
684 hwndPreview
= CreateWindowExW(0, wszPreviewWndClass
, NULL
,
685 WS_VISIBLE
| WS_CHILD
| WS_VSCROLL
| WS_HSCROLL
,
686 0, 0, 200, 10, hMainWnd
, (HMENU
)IDC_PREVIEW
, hInstance
, NULL
);
689 void close_preview(HWND hMainWnd
)
691 HWND hwndPreview
= GetDlgItem(hMainWnd
, IDC_PREVIEW
);
692 preview
.window
.right
= 0;
693 preview
.window
.bottom
= 0;
697 preview_bar_show(hMainWnd
, FALSE
);
698 DestroyWindow(hwndPreview
);
701 BOOL
preview_isactive(void)
703 return preview
.page
!= 0;
706 static void add_ruler_units(HDC hdcRuler
, RECT
* drawRect
, BOOL NewMetrics
, LONG EditLeftmost
)
712 static HBITMAP hBitmap
;
713 int i
, x
, y
, RulerTextEnd
;
717 WCHAR FontName
[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
722 DeleteObject(hBitmap
);
725 hdc
= CreateCompatibleDC(0);
727 CmPixels
= twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc
, LOGPIXELSX
));
728 QuarterCmPixels
= (int)((float)CmPixels
/ 4.0);
730 hBitmap
= CreateCompatibleBitmap(hdc
, drawRect
->right
, drawRect
->bottom
);
731 SelectObject(hdc
, hBitmap
);
732 FillRect(hdc
, drawRect
, GetStockObject(WHITE_BRUSH
));
734 hFont
= CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName
);
736 SelectObject(hdc
, hFont
);
737 SetBkMode(hdc
, TRANSPARENT
);
738 SetTextAlign(hdc
, TA_CENTER
);
739 y
= (int)(((float)drawRect
->bottom
- (float)drawRect
->top
) / 2.0) + 1;
740 RulerTextEnd
= drawRect
->right
- EditLeftmost
+ 1;
741 for(i
= 1, x
= EditLeftmost
; x
< (drawRect
->right
- EditLeftmost
+ 1); i
++)
744 WCHAR format
[] = {'%','d',0};
747 x2
+= QuarterCmPixels
;
748 if(x2
> RulerTextEnd
)
751 MoveToEx(hdc
, x2
, y
, NULL
);
752 LineTo(hdc
, x2
, y
+2);
754 x2
+= QuarterCmPixels
;
755 if(x2
> RulerTextEnd
)
758 MoveToEx(hdc
, x2
, y
- 3, NULL
);
759 LineTo(hdc
, x2
, y
+ 3);
761 x2
+= QuarterCmPixels
;
762 if(x2
> RulerTextEnd
)
765 MoveToEx(hdc
, x2
, y
, NULL
);
766 LineTo(hdc
, x2
, y
+2);
772 wsprintfW(str
, format
, i
);
773 TextOutW(hdc
, x
, 5, str
, lstrlenW(str
));
778 BitBlt(hdcRuler
, 0, 0, drawRect
->right
, drawRect
->bottom
, hdc
, 0, 0, SRCAND
);
781 static void paint_ruler(HWND hWnd
, LONG EditLeftmost
, BOOL NewMetrics
)
784 HDC hdc
= BeginPaint(hWnd
, &ps
);
785 HDC hdcPrint
= make_dc();
786 RECT printRect
= get_print_rect(hdcPrint
);
788 HBRUSH hBrush
= CreateSolidBrush(GetSysColor(COLOR_MENU
));
790 GetClientRect(hWnd
, &drawRect
);
791 FillRect(hdc
, &drawRect
, hBrush
);
794 drawRect
.bottom
-= 3;
795 drawRect
.left
= EditLeftmost
;
796 drawRect
.right
= twips_to_pixels(printRect
.right
- margins
.left
, GetDeviceCaps(hdc
, LOGPIXELSX
));
797 FillRect(hdc
, &drawRect
, GetStockObject(WHITE_BRUSH
));
801 DrawEdge(hdc
, &drawRect
, EDGE_SUNKEN
, BF_RECT
);
803 drawRect
.left
= drawRect
.right
- 1;
804 drawRect
.right
= twips_to_pixels(printRect
.right
+ margins
.right
- margins
.left
, GetDeviceCaps(hdc
, LOGPIXELSX
));
805 DrawEdge(hdc
, &drawRect
, EDGE_ETCHED
, BF_RECT
);
809 add_ruler_units(hdc
, &drawRect
, NewMetrics
, EditLeftmost
);
811 SelectObject(hdc
, GetStockObject(BLACK_BRUSH
));
812 DeleteObject(hBrush
);
817 LRESULT CALLBACK
ruler_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
819 static WNDPROC pPrevRulerProc
;
820 static LONG EditLeftmost
;
821 static BOOL NewMetrics
;
828 EditLeftmost
= ((POINTL
*)wParam
)->x
;
829 pPrevRulerProc
= (WNDPROC
)lParam
;
835 paint_ruler(hWnd
, EditLeftmost
, NewMetrics
);
839 return CallWindowProcW(pPrevRulerProc
, hWnd
, msg
, wParam
, lParam
);
845 static void draw_preview_page(HDC hdc
, HDC
* hdcSized
, FORMATRANGE
* lpFr
, float ratio
, int bmNewWidth
, int bmNewHeight
, int bmWidth
, int bmHeight
)
847 HBITMAP hBitmapScaled
= CreateCompatibleBitmap(hdc
, bmNewWidth
, bmNewHeight
);
849 int TopMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.top
, GetDeviceCaps(hdc
, LOGPIXELSX
)) * ratio
);
850 int BottomMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.bottom
, GetDeviceCaps(hdc
, LOGPIXELSX
)) * ratio
);
851 int LeftMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.left
, GetDeviceCaps(hdc
, LOGPIXELSY
)) * ratio
);
852 int RightMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.right
, GetDeviceCaps(hdc
, LOGPIXELSY
)) * ratio
);
856 *hdcSized
= CreateCompatibleDC(hdc
);
857 SelectObject(*hdcSized
, hBitmapScaled
);
859 StretchBlt(*hdcSized
, 0, 0, bmNewWidth
, bmNewHeight
, hdc
, 0, 0, bmWidth
, bmHeight
, SRCCOPY
);
861 /* Draw margin lines */
862 hPen
= CreatePen(PS_DOT
, 1, RGB(0,0,0));
863 SelectObject(*hdcSized
, hPen
);
865 MoveToEx(*hdcSized
, 0, TopMargin
, NULL
);
866 LineTo(*hdcSized
, bmNewWidth
, TopMargin
);
867 MoveToEx(*hdcSized
, 0, BottomMargin
, NULL
);
868 LineTo(*hdcSized
, bmNewWidth
, BottomMargin
);
870 MoveToEx(*hdcSized
, LeftMargin
, 0, NULL
);
871 LineTo(*hdcSized
, LeftMargin
, bmNewHeight
);
872 MoveToEx(*hdcSized
, RightMargin
, 0, NULL
);
873 LineTo(*hdcSized
, RightMargin
, bmNewHeight
);
877 static void draw_preview(HWND hEditorWnd
, FORMATRANGE
* lpFr
, int bmWidth
, int bmHeight
, RECT
* paper
, int page
)
879 HBITMAP hBitmapCapture
= CreateCompatibleBitmap(lpFr
->hdc
, bmWidth
, bmHeight
);
882 char_from_pagenum(hEditorWnd
, lpFr
, page
);
883 SelectObject(lpFr
->hdc
, hBitmapCapture
);
884 FillRect(lpFr
->hdc
, paper
, GetStockObject(WHITE_BRUSH
));
885 bottom
= lpFr
->rc
.bottom
;
886 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)lpFr
);
887 /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in,
888 * but we want to keep the original for drawing margins */
889 lpFr
->rc
.bottom
= bottom
;
890 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
893 static void update_preview_buttons(HWND hMainWnd
)
895 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
896 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_PREVPAGE
), preview
.page
> 1);
897 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_NEXTPAGE
), preview
.hdc2
?
898 (preview
.page
+ 1) < preview
.pages
:
899 preview
.page
< preview
.pages
);
900 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_NUMPAGES
), preview
.pages
> 1 && preview
.zoomlevel
== 0);
901 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_ZOOMIN
), preview
.zoomlevel
< 2);
902 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_ZOOMOUT
), preview
.zoomlevel
> 0);
905 LRESULT
print_preview(HWND hwndPreview
)
909 RECT window
, background
;
911 HWND hMainWnd
= GetParent(hwndPreview
);
914 hdc
= BeginPaint(hwndPreview
, &ps
);
915 GetClientRect(hwndPreview
, &window
);
917 fr
.hdcTarget
= make_dc();
918 fr
.rc
= fr
.rcPage
= preview
.rcPage
;
919 fr
.rc
.left
+= margins
.left
;
920 fr
.rc
.top
+= margins
.top
;
921 fr
.rc
.bottom
-= margins
.bottom
;
922 fr
.rc
.right
-= margins
.right
;
928 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
930 preview
.hdc
= CreateCompatibleDC(hdc
);
934 if(preview
.hdc2
!= (HDC
)-1)
935 DeleteDC(preview
.hdc2
);
936 preview
.hdc2
= CreateCompatibleDC(hdc
);
939 gt
.flags
= GTL_DEFAULT
;
942 fr
.chrg
.cpMax
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
945 paper
.right
= preview
.bmSize
.cx
;
947 paper
.bottom
= preview
.bmSize
.cy
;
949 fr
.hdc
= preview
.hdc
;
950 draw_preview(hEditorWnd
, &fr
, preview
.bmSize
.cx
, preview
.bmSize
.cy
, &paper
, preview
.page
);
954 fr
.hdc
= preview
.hdc2
;
955 draw_preview(hEditorWnd
, &fr
, preview
.bmSize
.cx
, preview
.bmSize
.cy
, &fr
.rcPage
, preview
.page
+ 1);
958 update_preview_buttons(hMainWnd
);
961 FillRect(hdc
, &window
, GetStockObject(GRAY_BRUSH
));
963 scrollpos
.x
= GetScrollPos(hwndPreview
, SB_HORZ
);
964 scrollpos
.y
= GetScrollPos(hwndPreview
, SB_VERT
);
966 background
.left
= preview
.spacing
.cx
- 2 - scrollpos
.x
;
967 background
.right
= background
.left
+ preview
.bmScaledSize
.cx
+ 4;
968 background
.top
= preview
.spacing
.cy
- 2 - scrollpos
.y
;
969 background
.bottom
= background
.top
+ preview
.bmScaledSize
.cy
+ 4;
971 FillRect(hdc
, &background
, GetStockObject(BLACK_BRUSH
));
975 background
.left
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
976 background
.right
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
978 FillRect(hdc
, &background
, GetStockObject(BLACK_BRUSH
));
981 if(window
.right
!= preview
.window
.right
|| window
.bottom
!= preview
.window
.bottom
)
983 draw_preview_page(preview
.hdc
, &preview
.hdcSized
, &fr
, preview
.zoomratio
,
984 preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
985 preview
.bmSize
.cx
, preview
.bmSize
.cy
);
989 draw_preview_page(preview
.hdc2
, &preview
.hdcSized2
, &fr
, preview
.zoomratio
,
990 preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
991 preview
.bmSize
.cx
, preview
.bmSize
.cy
);
995 BitBlt(hdc
, preview
.spacing
.cx
- scrollpos
.x
, preview
.spacing
.cy
- scrollpos
.y
,
996 preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
997 preview
.hdcSized
, 0, 0, SRCCOPY
);
1001 BitBlt(hdc
, preview
.spacing
.cx
* 2 + preview
.bmScaledSize
.cx
- scrollpos
.x
,
1002 preview
.spacing
.cy
- scrollpos
.y
, preview
.bmScaledSize
.cx
,
1003 preview
.bmScaledSize
.cy
, preview
.hdcSized2
, 0, 0, SRCCOPY
);
1006 DeleteDC(fr
.hdcTarget
);
1007 preview
.window
= window
;
1009 EndPaint(hwndPreview
, &ps
);
1014 /* Update for page changes. */
1015 static void update_preview(HWND hMainWnd
)
1017 DeleteDC(preview
.hdc
);
1020 update_scaled_preview(hMainWnd
);
1023 static void toggle_num_pages(HWND hMainWnd
)
1025 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
1026 WCHAR name
[MAX_STRING_LEN
];
1027 HINSTANCE hInst
= GetModuleHandleW(0);
1031 DeleteDC(preview
.hdc2
);
1035 if(preview
.page
== preview
.pages
)
1037 preview
.hdc2
= (HDC
)-1;
1040 LoadStringW(hInst
, preview
.hdc2
? STRING_PREVIEW_ONEPAGE
: STRING_PREVIEW_TWOPAGES
,
1041 name
, MAX_STRING_LEN
);
1043 SetWindowTextW(GetDlgItem(hReBar
, ID_PREVIEW_NUMPAGES
), name
);
1044 update_preview_sizes(GetDlgItem(hMainWnd
, IDC_PREVIEW
), TRUE
);
1045 update_preview(hMainWnd
);
1048 LRESULT
preview_command(HWND hWnd
, WPARAM wParam
)
1050 switch(LOWORD(wParam
))
1053 PostMessageW(hWnd
, WM_CLOSE
, 0, 0);
1056 case ID_PREVIEW_NEXTPAGE
:
1057 case ID_PREVIEW_PREVPAGE
:
1059 if(LOWORD(wParam
) == ID_PREVIEW_NEXTPAGE
)
1064 update_preview(hWnd
);
1068 case ID_PREVIEW_NUMPAGES
:
1069 toggle_num_pages(hWnd
);
1072 case ID_PREVIEW_ZOOMIN
:
1073 if (preview
.zoomlevel
< 2)
1075 preview
.zoomlevel
++;
1076 preview
.zoomratio
= 0;
1079 /* Forced switch to one page when zooming in. */
1080 toggle_num_pages(hWnd
);
1082 HWND hwndPreview
= GetDlgItem(hWnd
, IDC_PREVIEW
);
1083 update_preview_sizes(hwndPreview
, TRUE
);
1084 update_scaled_preview(hWnd
);
1085 update_preview_buttons(hWnd
);
1090 case ID_PREVIEW_ZOOMOUT
:
1091 if (preview
.zoomlevel
> 0)
1093 HWND hwndPreview
= GetDlgItem(hWnd
, IDC_PREVIEW
);
1094 preview
.zoomlevel
--;
1095 preview
.zoomratio
= 0;
1096 update_preview_sizes(hwndPreview
, TRUE
);
1097 update_scaled_preview(hWnd
);
1098 update_preview_buttons(hWnd
);
1103 dialog_print(hWnd
, preview
.wszFileName
);
1104 SendMessageW(hWnd
, WM_CLOSE
, 0, 0);