2 * Wordpad implementation - Printing and print preview functions
4 * Copyright 2007 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
35 } previewinfo
, *ppreviewinfo
;
37 static HGLOBAL devMode
;
38 static HGLOBAL devNames
;
41 static previewinfo preview
;
43 static const WCHAR var_pagemargin
[] = {'P','a','g','e','M','a','r','g','i','n',0};
45 static LPWSTR
get_print_file_filter(HWND hMainWnd
)
47 static WCHAR wszPrintFilter
[MAX_STRING_LEN
*2+6+4+1];
48 const WCHAR files_prn
[] = {'*','.','P','R','N',0};
49 const WCHAR files_all
[] = {'*','.','*','\0'};
51 HINSTANCE hInstance
= (HINSTANCE
)GetWindowLongPtr(hMainWnd
, GWLP_HINSTANCE
);
54 LoadStringW(hInstance
, STRING_PRINTER_FILES_PRN
, p
, MAX_STRING_LEN
);
56 lstrcpyW(p
, files_prn
);
58 LoadStringW(hInstance
, STRING_ALL_FILES
, p
, MAX_STRING_LEN
);
60 lstrcpyW(p
, files_all
);
64 return wszPrintFilter
;
67 void registry_set_pagemargins(HKEY hKey
)
69 RegSetValueExW(hKey
, var_pagemargin
, 0, REG_BINARY
, (LPBYTE
)&margins
, sizeof(RECT
));
72 void registry_read_pagemargins(HKEY hKey
)
74 DWORD size
= sizeof(RECT
);
76 if(!hKey
|| RegQueryValueExW(hKey
, var_pagemargin
, 0, NULL
, (LPBYTE
)&margins
,
77 &size
) != ERROR_SUCCESS
|| size
!= sizeof(RECT
))
80 margins
.bottom
= 1417;
86 static void AddTextButton(HWND hRebarWnd
, int string
, int command
, int id
)
89 HINSTANCE hInstance
= (HINSTANCE
)GetWindowLongPtr(hRebarWnd
, GWLP_HINSTANCE
);
90 WCHAR text
[MAX_STRING_LEN
];
93 LoadStringW(hInstance
, string
, text
, MAX_STRING_LEN
);
94 hButton
= CreateWindowW(WC_BUTTONW
, text
,
95 WS_VISIBLE
| WS_CHILD
, 5, 5, 100, 15,
96 hRebarWnd
, (HMENU
)command
, hInstance
, NULL
);
98 rb
.cbSize
= sizeof(rb
);
99 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
100 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
101 rb
.hwndChild
= hButton
;
102 rb
.cyChild
= rb
.cyMinChild
= 22;
103 rb
.cx
= rb
.cxMinChild
= 90;
107 SendMessageW(hRebarWnd
, RB_INSERTBAND
, -1, (LPARAM
)&rb
);
110 static HDC
make_dc(void)
112 if(devNames
&& devMode
)
114 LPDEVNAMES dn
= GlobalLock(devNames
);
115 LPDEVMODEW dm
= GlobalLock(devMode
);
118 ret
= CreateDCW((LPWSTR
)dn
+ dn
->wDriverOffset
,
119 (LPWSTR
)dn
+ dn
->wDeviceOffset
, 0, dm
);
131 static LONG
twips_to_centmm(int twips
)
133 return MulDiv(twips
, 1000, 567);
136 LONG
centmm_to_twips(int mm
)
138 return MulDiv(mm
, 567, 1000);
141 static LONG
twips_to_pixels(int twips
, int dpi
)
143 float ret
= ((float)twips
/ ((float)567 * 2.54)) * (float)dpi
;
147 static LONG
devunits_to_twips(int units
, int dpi
)
149 float ret
= ((float)units
/ (float)dpi
) * (float)567 * 2.54;
154 static RECT
get_print_rect(HDC hdc
)
161 int dpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
162 int dpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
163 width
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALWIDTH
), dpiX
);
164 height
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALHEIGHT
), dpiY
);
167 width
= centmm_to_twips(18500);
168 height
= centmm_to_twips(27000);
171 rc
.left
= margins
.left
;
172 rc
.right
= width
- margins
.right
;
173 rc
.top
= margins
.top
;
174 rc
.bottom
= height
- margins
.bottom
;
179 void target_device(HWND hMainWnd
, DWORD wordWrap
)
181 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
185 if(wordWrap
== ID_WORDWRAP_MARGIN
)
187 RECT rc
= get_print_rect(hdc
);
193 HDC hMaindc
= GetDC(hMainWnd
);
194 hdc
= CreateCompatibleDC(hMaindc
);
195 ReleaseDC(hMainWnd
, hMaindc
);
198 SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, (WPARAM
)hdc
, width
);
203 static LPWSTR
dialog_print_to_file(HWND hMainWnd
)
206 static WCHAR file
[MAX_PATH
] = {'O','U','T','P','U','T','.','P','R','N',0};
207 static const WCHAR defExt
[] = {'P','R','N',0};
208 static LPWSTR file_filter
;
211 file_filter
= get_print_file_filter(hMainWnd
);
213 ZeroMemory(&ofn
, sizeof(ofn
));
215 ofn
.lStructSize
= sizeof(ofn
);
216 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
| OFN_OVERWRITEPROMPT
;
217 ofn
.hwndOwner
= hMainWnd
;
218 ofn
.lpstrFilter
= file_filter
;
219 ofn
.lpstrFile
= (LPWSTR
)file
;
220 ofn
.nMaxFile
= MAX_PATH
;
221 ofn
.lpstrDefExt
= (LPWSTR
)defExt
;
223 if(GetSaveFileNameW(&ofn
))
229 static int get_num_pages(HWND hEditorWnd
, FORMATRANGE fr
)
236 fr
.chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
,
239 while(fr
.chrg
.cpMin
&& fr
.chrg
.cpMin
< fr
.chrg
.cpMax
);
244 static void char_from_pagenum(HWND hEditorWnd
, FORMATRANGE
*fr
, int page
)
248 for(i
= 1; i
<= page
; i
++)
253 fr
->chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)fr
);
257 static void print(LPPRINTDLGW pd
, LPWSTR wszFileName
)
261 HWND hEditorWnd
= GetDlgItem(pd
->hwndOwner
, IDC_EDITOR
);
262 int printedPages
= 0;
265 fr
.hdcTarget
= pd
->hDC
;
267 fr
.rc
= get_print_rect(fr
.hdc
);
269 fr
.rcPage
.right
= fr
.rc
.right
+ margins
.right
;
271 fr
.rcPage
.bottom
= fr
.rc
.bottom
+ margins
.bottom
;
273 ZeroMemory(&di
, sizeof(di
));
274 di
.cbSize
= sizeof(di
);
275 di
.lpszDocName
= wszFileName
;
277 if(pd
->Flags
& PD_PRINTTOFILE
)
279 di
.lpszOutput
= dialog_print_to_file(pd
->hwndOwner
);
284 if(pd
->Flags
& PD_SELECTION
)
286 SendMessageW(hEditorWnd
, EM_EXGETSEL
, 0, (LPARAM
)&fr
.chrg
);
290 gt
.flags
= GTL_DEFAULT
;
293 fr
.chrg
.cpMax
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
295 if(pd
->Flags
& PD_PAGENUMS
)
296 char_from_pagenum(hEditorWnd
, &fr
, pd
->nToPage
);
299 StartDocW(fr
.hdc
, &di
);
302 if(StartPage(fr
.hdc
) <= 0)
305 fr
.chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
307 if(EndPage(fr
.hdc
) <= 0)
311 if((pd
->Flags
& PD_PAGENUMS
) && (printedPages
> (pd
->nToPage
- pd
->nFromPage
)))
314 while(fr
.chrg
.cpMin
&& fr
.chrg
.cpMin
< fr
.chrg
.cpMax
);
317 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
320 void dialog_printsetup(HWND hMainWnd
)
324 ZeroMemory(&ps
, sizeof(ps
));
325 ps
.lStructSize
= sizeof(ps
);
326 ps
.hwndOwner
= hMainWnd
;
327 ps
.Flags
= PSD_INHUNDREDTHSOFMILLIMETERS
| PSD_MARGINS
;
328 ps
.rtMargin
.left
= twips_to_centmm(margins
.left
);
329 ps
.rtMargin
.right
= twips_to_centmm(margins
.right
);
330 ps
.rtMargin
.top
= twips_to_centmm(margins
.top
);
331 ps
.rtMargin
.bottom
= twips_to_centmm(margins
.bottom
);
332 ps
.hDevMode
= devMode
;
333 ps
.hDevNames
= devNames
;
335 if(PageSetupDlgW(&ps
))
337 margins
.left
= centmm_to_twips(ps
.rtMargin
.left
);
338 margins
.right
= centmm_to_twips(ps
.rtMargin
.right
);
339 margins
.top
= centmm_to_twips(ps
.rtMargin
.top
);
340 margins
.bottom
= centmm_to_twips(ps
.rtMargin
.bottom
);
341 devMode
= ps
.hDevMode
;
342 devNames
= ps
.hDevNames
;
346 void get_default_printer_opts(void)
349 ZeroMemory(&pd
, sizeof(pd
));
351 ZeroMemory(&pd
, sizeof(pd
));
352 pd
.lStructSize
= sizeof(pd
);
353 pd
.Flags
= PD_RETURNDC
| PD_RETURNDEFAULT
;
354 pd
.hDevMode
= devMode
;
358 devMode
= pd
.hDevMode
;
359 devNames
= pd
.hDevNames
;
362 void print_quick(LPWSTR wszFileName
)
366 ZeroMemory(&pd
, sizeof(pd
));
369 print(&pd
, wszFileName
);
372 void dialog_print(HWND hMainWnd
, LPWSTR wszFileName
)
375 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
379 ZeroMemory(&pd
, sizeof(pd
));
380 pd
.lStructSize
= sizeof(pd
);
381 pd
.hwndOwner
= hMainWnd
;
382 pd
.Flags
= PD_RETURNDC
| PD_USEDEVMODECOPIESANDCOLLATE
;
385 pd
.hDevMode
= devMode
;
386 pd
.hDevNames
= devNames
;
388 SendMessageW(hEditorWnd
, EM_GETSEL
, (WPARAM
)&from
, (LPARAM
)&to
);
390 pd
.Flags
|= PD_NOSELECTION
;
394 devMode
= pd
.hDevMode
;
395 devNames
= pd
.hDevNames
;
396 print(&pd
, wszFileName
);
400 static void preview_bar_show(HWND hMainWnd
, BOOL show
)
402 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
410 AddTextButton(hReBar
, STRING_PREVIEW_PRINT
, ID_PRINT
, BANDID_PREVIEW_BTN1
);
411 AddTextButton(hReBar
, STRING_PREVIEW_NEXTPAGE
, ID_PREVIEW_NEXTPAGE
, BANDID_PREVIEW_BTN2
);
412 AddTextButton(hReBar
, STRING_PREVIEW_PREVPAGE
, ID_PREVIEW_PREVPAGE
, BANDID_PREVIEW_BTN3
);
413 AddTextButton(hReBar
, STRING_PREVIEW_CLOSE
, ID_FILE_EXIT
, BANDID_PREVIEW_BTN4
);
415 hStatic
= CreateWindowW(WC_STATICW
, NULL
,
416 WS_VISIBLE
| WS_CHILD
, 0, 0, 0, 0,
417 hReBar
, NULL
, NULL
, NULL
);
419 rb
.cbSize
= sizeof(rb
);
420 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
421 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
422 rb
.hwndChild
= hStatic
;
423 rb
.cyChild
= rb
.cyMinChild
= 22;
424 rb
.cx
= rb
.cxMinChild
= 90;
426 rb
.wID
= BANDID_PREVIEW_BUFFER
;
428 SendMessageW(hReBar
, RB_INSERTBAND
, -1, (LPARAM
)&rb
);
431 for(i
= 0; i
<= PREVIEW_BUTTONS
; i
++)
432 SendMessageW(hReBar
, RB_DELETEBAND
, SendMessageW(hReBar
, RB_IDTOINDEX
, BANDID_PREVIEW_BTN1
+i
, 0), 0);
436 void init_preview(HWND hMainWnd
, LPWSTR wszFileName
)
440 preview
.wszFileName
= wszFileName
;
441 preview_bar_show(hMainWnd
, TRUE
);
444 void close_preview(HWND hMainWnd
)
446 preview
.window
.right
= 0;
447 preview
.window
.bottom
= 0;
451 preview_bar_show(hMainWnd
, FALSE
);
454 BOOL
preview_isactive(void)
456 return preview
.page
!= 0;
459 LRESULT
print_preview(HWND hMainWnd
)
464 RECT window
, background
;
465 HBITMAP hBitmapCapture
, hBitmapScaled
;
466 int bmWidth
, bmHeight
, bmNewWidth
, bmNewHeight
;
467 float ratioWidth
, ratioHeight
, ratio
;
468 int xOffset
, yOffset
;
470 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
473 hdc
= BeginPaint(hMainWnd
, &ps
);
474 GetClientRect(hMainWnd
, &window
);
476 fr
.hdcTarget
= make_dc();
477 fr
.rc
= get_print_rect(fr
.hdcTarget
);
480 fr
.rcPage
.bottom
= fr
.rc
.bottom
+ margins
.bottom
;
481 fr
.rcPage
.right
= fr
.rc
.right
+ margins
.right
;
483 bmWidth
= twips_to_pixels(fr
.rcPage
.right
, GetDeviceCaps(hdc
, LOGPIXELSX
));
484 bmHeight
= twips_to_pixels(fr
.rcPage
.bottom
, GetDeviceCaps(hdc
, LOGPIXELSY
));
486 hBitmapCapture
= CreateCompatibleBitmap(hdc
, bmWidth
, bmHeight
);
491 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
493 preview
.hdc
= CreateCompatibleDC(hdc
);
494 fr
.hdc
= preview
.hdc
;
495 gt
.flags
= GTL_DEFAULT
;
498 fr
.chrg
.cpMax
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
501 paper
.right
= bmWidth
;
503 paper
.bottom
= bmHeight
;
506 preview
.pages
= get_num_pages(hEditorWnd
, fr
);
508 SelectObject(preview
.hdc
, hBitmapCapture
);
510 char_from_pagenum(hEditorWnd
, &fr
, preview
.page
);
512 FillRect(preview
.hdc
, &paper
, GetStockObject(WHITE_BRUSH
));
513 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
514 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
516 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_PREVPAGE
), preview
.page
> 1);
517 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_NEXTPAGE
), preview
.page
< preview
.pages
);
520 barheight
= SendMessageW(hReBar
, RB_GETBARHEIGHT
, 0, 0);
521 ratioWidth
= ((float)window
.right
- 20.0) / (float)bmHeight
;
522 ratioHeight
= ((float)window
.bottom
- 20.0 - (float)barheight
) / (float)bmHeight
;
524 if(ratioWidth
> ratioHeight
)
529 bmNewWidth
= (int)((float)bmWidth
* ratio
);
530 bmNewHeight
= (int)((float)bmHeight
* ratio
);
531 hBitmapScaled
= CreateCompatibleBitmap(hdc
, bmNewWidth
, bmNewHeight
);
533 xOffset
= ((window
.right
- bmNewWidth
) / 2);
534 yOffset
= ((window
.bottom
- bmNewHeight
+ barheight
) / 2);
536 if(window
.right
!= preview
.window
.right
|| window
.bottom
!= preview
.window
.bottom
)
538 DeleteDC(preview
.hdcSized
),
539 preview
.hdcSized
= CreateCompatibleDC(hdc
);
540 SelectObject(preview
.hdcSized
, hBitmapScaled
);
542 StretchBlt(preview
.hdcSized
, 0, 0, bmNewWidth
, bmNewHeight
, preview
.hdc
, 0, 0, bmWidth
, bmHeight
, SRCCOPY
);
545 window
.top
= barheight
;
546 FillRect(hdc
, &window
, GetStockObject(GRAY_BRUSH
));
548 SelectObject(hdc
, hBitmapScaled
);
550 background
.left
= xOffset
- 2;
551 background
.right
= xOffset
+ bmNewWidth
+ 2;
552 background
.top
= yOffset
- 2;
553 background
.bottom
= yOffset
+ bmNewHeight
+ 2;
555 FillRect(hdc
, &background
, GetStockObject(BLACK_BRUSH
));
557 BitBlt(hdc
, xOffset
, yOffset
, bmNewWidth
, bmNewHeight
, preview
.hdcSized
, 0, 0, SRCCOPY
);
559 DeleteDC(fr
.hdcTarget
);
560 preview
.window
= window
;
562 EndPaint(hMainWnd
, &ps
);
567 LRESULT
preview_command(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
569 switch(LOWORD(wParam
))
572 PostMessageW(hWnd
, WM_CLOSE
, 0, 0);
575 case ID_PREVIEW_NEXTPAGE
:
576 case ID_PREVIEW_PREVPAGE
:
578 HWND hReBar
= GetDlgItem(hWnd
, IDC_REBAR
);
581 if(LOWORD(wParam
) == ID_PREVIEW_NEXTPAGE
)
587 preview
.window
.right
= 0;
589 GetClientRect(hWnd
, &rc
);
590 rc
.top
+= SendMessageW(hReBar
, RB_GETBARHEIGHT
, 0, 0);
591 InvalidateRect(hWnd
, &rc
, TRUE
);
596 dialog_print(hWnd
, preview
.wszFileName
);
597 SendMessageW(hWnd
, WM_CLOSE
, 0, 0);