/* * Wordpad implementation - Printing and print preview functions * * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <windows.h> #include <richedit.h> #include <commctrl.h> #include "wordpad.h" typedef struct _previewinfo { int page; int pages; HDC hdc; HDC hdc2; HDC hdcSized; HDC hdcSized2; RECT window; LPWSTR wszFileName; } previewinfo, *ppreviewinfo; static HGLOBAL devMode; static HGLOBAL devNames; static RECT margins; static previewinfo preview; static const WCHAR var_pagemargin[] = {'P','a','g','e','M','a','r','g','i','n',0}; static LPWSTR get_print_file_filter(HWND hMainWnd) { static WCHAR wszPrintFilter[MAX_STRING_LEN*2+6+4+1]; const WCHAR files_prn[] = {'*','.','P','R','N',0}; const WCHAR files_all[] = {'*','.','*','\0'}; LPWSTR p; HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hMainWnd, GWLP_HINSTANCE); p = wszPrintFilter; LoadStringW(hInstance, STRING_PRINTER_FILES_PRN, p, MAX_STRING_LEN); p += lstrlenW(p) + 1; lstrcpyW(p, files_prn); p += lstrlenW(p) + 1; LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN); p += lstrlenW(p) + 1; lstrcpyW(p, files_all); p += lstrlenW(p) + 1; *p = 0; return wszPrintFilter; } void registry_set_pagemargins(HKEY hKey) { RegSetValueExW(hKey, var_pagemargin, 0, REG_BINARY, (LPBYTE)&margins, sizeof(RECT)); } void registry_read_pagemargins(HKEY hKey) { DWORD size = sizeof(RECT); if(!hKey || RegQueryValueExW(hKey, var_pagemargin, 0, NULL, (LPBYTE)&margins, &size) != ERROR_SUCCESS || size != sizeof(RECT)) { margins.top = 1417; margins.bottom = 1417; margins.left = 1757; margins.right = 1757; } } static void AddTextButton(HWND hRebarWnd, UINT string, UINT command, UINT id) { REBARBANDINFOW rb; HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hRebarWnd, GWLP_HINSTANCE); WCHAR text[MAX_STRING_LEN]; HWND hButton; LoadStringW(hInstance, string, text, MAX_STRING_LEN); hButton = CreateWindowW(WC_BUTTONW, text, WS_VISIBLE | WS_CHILD, 5, 5, 100, 15, hRebarWnd, ULongToHandle(command), hInstance, NULL); rb.cbSize = sizeof(rb); rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID; rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT; rb.hwndChild = hButton; rb.cyChild = rb.cyMinChild = 22; rb.cx = rb.cxMinChild = 90; rb.cxIdeal = 100; rb.wID = id; SendMessageW(hRebarWnd, RB_INSERTBAND, -1, (LPARAM)&rb); } static HDC make_dc(void) { if(devNames && devMode) { LPDEVNAMES dn = GlobalLock(devNames); LPDEVMODEW dm = GlobalLock(devMode); HDC ret; ret = CreateDCW((LPWSTR)dn + dn->wDriverOffset, (LPWSTR)dn + dn->wDeviceOffset, 0, dm); GlobalUnlock(dn); GlobalUnlock(dm); return ret; } else { return 0; } } static LONG twips_to_centmm(int twips) { return MulDiv(twips, CENTMM_PER_INCH, TWIPS_PER_INCH); } static LONG centmm_to_twips(int mm) { return MulDiv(mm, TWIPS_PER_INCH, CENTMM_PER_INCH); } static LONG twips_to_pixels(int twips, int dpi) { return MulDiv(twips, dpi, TWIPS_PER_INCH); } static LONG devunits_to_twips(int units, int dpi) { return MulDiv(units, TWIPS_PER_INCH, dpi); } static RECT get_print_rect(HDC hdc) { RECT rc; int width, height; if(hdc) { int dpiY = GetDeviceCaps(hdc, LOGPIXELSY); int dpiX = GetDeviceCaps(hdc, LOGPIXELSX); width = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALWIDTH), dpiX); height = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALHEIGHT), dpiY); } else { width = centmm_to_twips(18500); height = centmm_to_twips(27000); } rc.left = margins.left; rc.right = width - margins.right; rc.top = margins.top; rc.bottom = height - margins.bottom; return rc; } void target_device(HWND hMainWnd, DWORD wordWrap) { HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); if(wordWrap == ID_WORDWRAP_MARGIN) { int width = 0; LRESULT result; HDC hdc = make_dc(); RECT rc = get_print_rect(hdc); width = rc.right - rc.left; if(!hdc) { HDC hMaindc = GetDC(hMainWnd); hdc = CreateCompatibleDC(hMaindc); ReleaseDC(hMainWnd, hMaindc); } result = SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, (WPARAM)hdc, width); DeleteDC(hdc); if (result) return; /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping * to window using the NULL DC. */ } if (wordWrap != ID_WORDWRAP_NONE) { SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 0); } else { SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 1); } } static LPWSTR dialog_print_to_file(HWND hMainWnd) { OPENFILENAMEW ofn; static WCHAR file[MAX_PATH] = {'O','U','T','P','U','T','.','P','R','N',0}; static const WCHAR defExt[] = {'P','R','N',0}; static LPWSTR file_filter; if(!file_filter) file_filter = get_print_file_filter(hMainWnd); ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; ofn.hwndOwner = hMainWnd; ofn.lpstrFilter = file_filter; ofn.lpstrFile = file; ofn.nMaxFile = MAX_PATH; ofn.lpstrDefExt = defExt; if(GetSaveFileNameW(&ofn)) return file; else return FALSE; } static int get_num_pages(HWND hEditorWnd, FORMATRANGE fr) { int page = 0; fr.chrg.cpMin = 0; do { page++; fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr); } while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax); return page; } static void char_from_pagenum(HWND hEditorWnd, FORMATRANGE *fr, int page) { int i; fr->chrg.cpMin = 0; for(i = 1; i < page; i++) { fr->chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)fr); } } static HWND get_ruler_wnd(HWND hMainWnd) { return GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER); } void redraw_ruler(HWND hRulerWnd) { RECT rc; GetClientRect(hRulerWnd, &rc); InvalidateRect(hRulerWnd, &rc, TRUE); } static void update_ruler(HWND hRulerWnd) { SendMessageW(hRulerWnd, WM_USER, 0, 0); redraw_ruler(hRulerWnd); } static void print(LPPRINTDLGW pd, LPWSTR wszFileName) { FORMATRANGE fr; DOCINFOW di; HWND hEditorWnd = GetDlgItem(pd->hwndOwner, IDC_EDITOR); int printedPages = 0; fr.hdc = pd->hDC; fr.hdcTarget = pd->hDC; fr.rc = get_print_rect(fr.hdc); fr.rcPage.left = 0; fr.rcPage.right = fr.rc.right + margins.right; fr.rcPage.top = 0; fr.rcPage.bottom = fr.rc.bottom + margins.bottom; ZeroMemory(&di, sizeof(di)); di.cbSize = sizeof(di); di.lpszDocName = wszFileName; if(pd->Flags & PD_PRINTTOFILE) { di.lpszOutput = dialog_print_to_file(pd->hwndOwner); if(!di.lpszOutput) return; } if(pd->Flags & PD_SELECTION) { SendMessageW(hEditorWnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg); } else { GETTEXTLENGTHEX gt; gt.flags = GTL_DEFAULT; gt.codepage = 1200; fr.chrg.cpMin = 0; fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0); if(pd->Flags & PD_PAGENUMS) char_from_pagenum(hEditorWnd, &fr, pd->nToPage); } StartDocW(fr.hdc, &di); do { if(StartPage(fr.hdc) <= 0) break; fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr); if(EndPage(fr.hdc) <= 0) break; printedPages++; if((pd->Flags & PD_PAGENUMS) && (printedPages > (pd->nToPage - pd->nFromPage))) break; } while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax); EndDoc(fr.hdc); SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0); } void dialog_printsetup(HWND hMainWnd) { PAGESETUPDLGW ps; ZeroMemory(&ps, sizeof(ps)); ps.lStructSize = sizeof(ps); ps.hwndOwner = hMainWnd; ps.Flags = PSD_INHUNDREDTHSOFMILLIMETERS | PSD_MARGINS; ps.rtMargin.left = twips_to_centmm(margins.left); ps.rtMargin.right = twips_to_centmm(margins.right); ps.rtMargin.top = twips_to_centmm(margins.top); ps.rtMargin.bottom = twips_to_centmm(margins.bottom); ps.hDevMode = devMode; ps.hDevNames = devNames; if(PageSetupDlgW(&ps)) { margins.left = centmm_to_twips(ps.rtMargin.left); margins.right = centmm_to_twips(ps.rtMargin.right); margins.top = centmm_to_twips(ps.rtMargin.top); margins.bottom = centmm_to_twips(ps.rtMargin.bottom); devMode = ps.hDevMode; devNames = ps.hDevNames; update_ruler(get_ruler_wnd(hMainWnd)); } } void get_default_printer_opts(void) { PRINTDLGW pd; ZeroMemory(&pd, sizeof(pd)); ZeroMemory(&pd, sizeof(pd)); pd.lStructSize = sizeof(pd); pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT; pd.hDevMode = devMode; PrintDlgW(&pd); devMode = pd.hDevMode; devNames = pd.hDevNames; } void print_quick(LPWSTR wszFileName) { PRINTDLGW pd; ZeroMemory(&pd, sizeof(pd)); pd.hDC = make_dc(); print(&pd, wszFileName); } void dialog_print(HWND hMainWnd, LPWSTR wszFileName) { PRINTDLGW pd; HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); int from = 0; int to = 0; ZeroMemory(&pd, sizeof(pd)); pd.lStructSize = sizeof(pd); pd.hwndOwner = hMainWnd; pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; pd.nMinPage = 1; pd.nMaxPage = -1; pd.hDevMode = devMode; pd.hDevNames = devNames; SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to); if(from == to) pd.Flags |= PD_NOSELECTION; if(PrintDlgW(&pd)) { devMode = pd.hDevMode; devNames = pd.hDevNames; print(&pd, wszFileName); update_ruler(get_ruler_wnd(hMainWnd)); } } static void preview_bar_show(HWND hMainWnd, BOOL show) { HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); int i; if(show) { REBARBANDINFOW rb; HWND hStatic; AddTextButton(hReBar, STRING_PREVIEW_PRINT, ID_PRINT, BANDID_PREVIEW_BTN1); AddTextButton(hReBar, STRING_PREVIEW_NEXTPAGE, ID_PREVIEW_NEXTPAGE, BANDID_PREVIEW_BTN2); AddTextButton(hReBar, STRING_PREVIEW_PREVPAGE, ID_PREVIEW_PREVPAGE, BANDID_PREVIEW_BTN3); AddTextButton(hReBar, STRING_PREVIEW_TWOPAGES, ID_PREVIEW_NUMPAGES, BANDID_PREVIEW_BTN4); AddTextButton(hReBar, STRING_PREVIEW_CLOSE, ID_FILE_EXIT, BANDID_PREVIEW_BTN5); hStatic = CreateWindowW(WC_STATICW, NULL, WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, hReBar, NULL, NULL, NULL); rb.cbSize = sizeof(rb); rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID; rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT; rb.hwndChild = hStatic; rb.cyChild = rb.cyMinChild = 22; rb.cx = rb.cxMinChild = 90; rb.cxIdeal = 100; rb.wID = BANDID_PREVIEW_BUFFER; SendMessageW(hReBar, RB_INSERTBAND, -1, (LPARAM)&rb); } else { for(i = 0; i <= PREVIEW_BUTTONS; i++) SendMessageW(hReBar, RB_DELETEBAND, SendMessageW(hReBar, RB_IDTOINDEX, BANDID_PREVIEW_BTN1+i, 0), 0); } } void init_preview(HWND hMainWnd, LPWSTR wszFileName) { preview.page = 1; preview.hdc = 0; preview.hdc2 = 0; preview.wszFileName = wszFileName; preview_bar_show(hMainWnd, TRUE); } void close_preview(HWND hMainWnd) { preview.window.right = 0; preview.window.bottom = 0; preview.page = 0; preview.pages = 0; preview_bar_show(hMainWnd, FALSE); } BOOL preview_isactive(void) { return preview.page != 0; } static void add_ruler_units(HDC hdcRuler, RECT* drawRect, BOOL NewMetrics, LONG EditLeftmost) { static HDC hdc; if(NewMetrics) { static HBITMAP hBitmap; int i, x, y, RulerTextEnd; int CmPixels; int QuarterCmPixels; HFONT hFont; WCHAR FontName[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0}; if(hdc) { DeleteDC(hdc); DeleteObject(hBitmap); } hdc = CreateCompatibleDC(0); CmPixels = twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc, LOGPIXELSX)); QuarterCmPixels = (int)((float)CmPixels / 4.0); hBitmap = CreateCompatibleBitmap(hdc, drawRect->right, drawRect->bottom); SelectObject(hdc, hBitmap); FillRect(hdc, drawRect, GetStockObject(WHITE_BRUSH)); hFont = CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName); SelectObject(hdc, hFont); SetBkMode(hdc, TRANSPARENT); SetTextAlign(hdc, TA_CENTER); y = (int)(((float)drawRect->bottom - (float)drawRect->top) / 2.0) + 1; RulerTextEnd = drawRect->right - EditLeftmost + 1; for(i = 1, x = EditLeftmost; x < (drawRect->right - EditLeftmost + 1); i ++) { WCHAR str[3]; WCHAR format[] = {'%','d',0}; int x2 = x; x2 += QuarterCmPixels; if(x2 > RulerTextEnd) break; MoveToEx(hdc, x2, y, NULL); LineTo(hdc, x2, y+2); x2 += QuarterCmPixels; if(x2 > RulerTextEnd) break; MoveToEx(hdc, x2, y - 3, NULL); LineTo(hdc, x2, y + 3); x2 += QuarterCmPixels; if(x2 > RulerTextEnd) break; MoveToEx(hdc, x2, y, NULL); LineTo(hdc, x2, y+2); x += CmPixels; if(x > RulerTextEnd) break; wsprintfW(str, format, i); TextOutW(hdc, x, 5, str, lstrlenW(str)); } DeleteObject(hFont); } BitBlt(hdcRuler, 0, 0, drawRect->right, drawRect->bottom, hdc, 0, 0, SRCAND); } static void paint_ruler(HWND hWnd, LONG EditLeftmost, BOOL NewMetrics) { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); HDC hdcPrint = make_dc(); RECT printRect = get_print_rect(hdcPrint); RECT drawRect; HBRUSH hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU)); GetClientRect(hWnd, &drawRect); FillRect(hdc, &drawRect, hBrush); drawRect.top += 3; drawRect.bottom -= 3; drawRect.left = EditLeftmost; drawRect.right = twips_to_pixels(printRect.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX)); FillRect(hdc, &drawRect, GetStockObject(WHITE_BRUSH)); drawRect.top--; drawRect.bottom++; DrawEdge(hdc, &drawRect, EDGE_SUNKEN, BF_RECT); drawRect.left = drawRect.right - 1; drawRect.right = twips_to_pixels(printRect.right + margins.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX)); DrawEdge(hdc, &drawRect, EDGE_ETCHED, BF_RECT); drawRect.left = 0; drawRect.top = 0; add_ruler_units(hdc, &drawRect, NewMetrics, EditLeftmost); SelectObject(hdc, GetStockObject(BLACK_BRUSH)); DeleteObject(hBrush); DeleteDC(hdcPrint); EndPaint(hWnd, &ps); } LRESULT CALLBACK ruler_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { static WNDPROC pPrevRulerProc; static LONG EditLeftmost; static BOOL NewMetrics; switch(msg) { case WM_USER: if(wParam) { EditLeftmost = ((POINTL*)wParam)->x; pPrevRulerProc = (WNDPROC)lParam; } NewMetrics = TRUE; break; case WM_PAINT: paint_ruler(hWnd, EditLeftmost, NewMetrics); break; default: return CallWindowProcW(pPrevRulerProc, hWnd, msg, wParam, lParam); } return 0; } static void draw_preview_page(HDC hdc, HDC* hdcSized, FORMATRANGE* lpFr, float ratio, int bmNewWidth, int bmNewHeight, int bmWidth, int bmHeight) { HBITMAP hBitmapScaled = CreateCompatibleBitmap(hdc, bmNewWidth, bmNewHeight); HPEN hPen; int TopMargin = (int)((float)twips_to_pixels(lpFr->rc.top, GetDeviceCaps(hdc, LOGPIXELSX)) * ratio); int BottomMargin = (int)((float)twips_to_pixels(lpFr->rc.bottom, GetDeviceCaps(hdc, LOGPIXELSX)) * ratio); int LeftMargin = (int)((float)twips_to_pixels(lpFr->rc.left, GetDeviceCaps(hdc, LOGPIXELSY)) * ratio); int RightMargin = (int)((float)twips_to_pixels(lpFr->rc.right, GetDeviceCaps(hdc, LOGPIXELSY)) * ratio); if(*hdcSized) DeleteDC(*hdcSized); *hdcSized = CreateCompatibleDC(hdc); SelectObject(*hdcSized, hBitmapScaled); StretchBlt(*hdcSized, 0, 0, bmNewWidth, bmNewHeight, hdc, 0, 0, bmWidth, bmHeight, SRCCOPY); /* Draw margin lines */ hPen = CreatePen(PS_DOT, 1, RGB(0,0,0)); SelectObject(*hdcSized, hPen); MoveToEx(*hdcSized, 0, TopMargin, NULL); LineTo(*hdcSized, bmNewWidth, TopMargin); MoveToEx(*hdcSized, 0, BottomMargin, NULL); LineTo(*hdcSized, bmNewWidth, BottomMargin); MoveToEx(*hdcSized, LeftMargin, 0, NULL); LineTo(*hdcSized, LeftMargin, bmNewHeight); MoveToEx(*hdcSized, RightMargin, 0, NULL); LineTo(*hdcSized, RightMargin, bmNewHeight); } static void draw_preview(HWND hEditorWnd, FORMATRANGE* lpFr, int bmWidth, int bmHeight, RECT* paper, int page) { HBITMAP hBitmapCapture = CreateCompatibleBitmap(lpFr->hdc, bmWidth, bmHeight); char_from_pagenum(hEditorWnd, lpFr, page); SelectObject(lpFr->hdc, hBitmapCapture); FillRect(lpFr->hdc, paper, GetStockObject(WHITE_BRUSH)); SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)lpFr); /* EM_FORMATRANGE sets fr.rc to indicate the area printed in, but we want to keep the original for drawing margins */ lpFr->rc = get_print_rect(lpFr->hdcTarget); SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0); } LRESULT print_preview(HWND hMainWnd) { FORMATRANGE fr; GETTEXTLENGTHEX gt; HDC hdc; RECT window, background; int bmWidth, bmHeight, bmNewWidth, bmNewHeight; float ratioWidth, ratioHeight, ratio; int xOffset, yOffset; int barheight; float spacing = 20.0; HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); PAINTSTRUCT ps; hdc = BeginPaint(hMainWnd, &ps); GetClientRect(hMainWnd, &window); fr.hdcTarget = make_dc(); fr.rc = get_print_rect(fr.hdcTarget); fr.rcPage.left = 0; fr.rcPage.top = 0; fr.rcPage.bottom = fr.rc.bottom + margins.bottom; fr.rcPage.right = fr.rc.right + margins.right; bmWidth = twips_to_pixels(fr.rcPage.right, GetDeviceCaps(hdc, LOGPIXELSX)); bmHeight = twips_to_pixels(fr.rcPage.bottom, GetDeviceCaps(hdc, LOGPIXELSY)); if(!preview.hdc) { RECT paper; HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); preview.hdc = CreateCompatibleDC(hdc); if(preview.hdc2) { if(preview.hdc2 != (HDC)-1) DeleteDC(preview.hdc2); preview.hdc2 = CreateCompatibleDC(hdc); } fr.hdc = preview.hdc; gt.flags = GTL_DEFAULT; gt.codepage = 1200; fr.chrg.cpMin = 0; fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0); paper.left = 0; paper.right = bmWidth; paper.top = 0; paper.bottom = bmHeight; if(!preview.pages) preview.pages = get_num_pages(hEditorWnd, fr); fr.hdc = preview.hdc; draw_preview(hEditorWnd, &fr, bmWidth, bmHeight, &paper, preview.page); if(preview.hdc2) { fr.hdc = preview.hdc2; draw_preview(hEditorWnd, &fr, bmWidth, bmHeight, &paper, preview.page + 1); } EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_PREVPAGE), preview.page > 1); EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NEXTPAGE), preview.hdc2 ? (preview.page + 1) < preview.pages : preview.page < preview.pages); EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), preview.pages > 1); } barheight = SendMessageW(hReBar, RB_GETBARHEIGHT, 0, 0); ratioHeight = ((float)window.bottom - spacing - (float)barheight) / (float)bmHeight; if(preview.hdc2) ratioWidth = ((float)window.right / 2.0 - spacing * 2.0) / (float)bmWidth; else ratioWidth = ((float)window.right - spacing * 3.0) / (float)bmWidth; if(ratioWidth > ratioHeight) ratio = ratioHeight; else ratio = ratioWidth; bmNewWidth = (int)((float)bmWidth * ratio); bmNewHeight = (int)((float)bmHeight * ratio); yOffset = ((window.bottom - bmNewHeight + barheight) / 2); if(!preview.hdc2) xOffset = (window.right - bmNewWidth) / 2; else xOffset = (window.right - bmNewWidth * 2) / 2; window.top = barheight; FillRect(hdc, &window, GetStockObject(GRAY_BRUSH)); background.left = xOffset - 2; background.right = xOffset + bmNewWidth + 2; background.top = yOffset - 2; background.bottom = yOffset + bmNewHeight + 2; FillRect(hdc, &background, GetStockObject(BLACK_BRUSH)); if(window.right != preview.window.right || window.bottom != preview.window.bottom) { draw_preview_page(preview.hdc, &preview.hdcSized, &fr, ratio, bmNewWidth, bmNewHeight, bmWidth, bmHeight); if(preview.hdc2) { background.left += bmNewWidth + spacing; background.right += bmNewWidth + spacing; FillRect(hdc, &background, GetStockObject(BLACK_BRUSH)); draw_preview_page(preview.hdc2, &preview.hdcSized2, &fr, ratio, bmNewWidth, bmNewHeight, bmWidth, bmHeight); } } BitBlt(hdc, xOffset, yOffset, bmNewWidth, bmNewHeight, preview.hdcSized, 0, 0, SRCCOPY); if(preview.hdc2) { BitBlt(hdc, xOffset + bmNewWidth + spacing, yOffset, bmNewWidth, bmNewHeight, preview.hdcSized2, 0, 0, SRCCOPY); } DeleteDC(fr.hdcTarget); preview.window = window; EndPaint(hMainWnd, &ps); return 0; } static void update_preview(HWND hWnd) { RECT rc; DeleteDC(preview.hdc); preview.hdc = 0; preview.window.right = 0; GetClientRect(hWnd, &rc); rc.top += SendMessageW(GetDlgItem(hWnd, IDC_REBAR), RB_GETBARHEIGHT, 0, 0); InvalidateRect(hWnd, &rc, TRUE); } LRESULT preview_command(HWND hWnd, WPARAM wParam) { switch(LOWORD(wParam)) { case ID_FILE_EXIT: PostMessageW(hWnd, WM_CLOSE, 0, 0); break; case ID_PREVIEW_NEXTPAGE: case ID_PREVIEW_PREVPAGE: { if(LOWORD(wParam) == ID_PREVIEW_NEXTPAGE) preview.page++; else preview.page--; update_preview(hWnd); } break; case ID_PREVIEW_NUMPAGES: { HWND hReBar = GetDlgItem(hWnd, IDC_REBAR); WCHAR name[MAX_STRING_LEN]; HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE); if(preview.hdc2) { DeleteDC(preview.hdc2); preview.hdc2 = 0; } else { if(preview.page == preview.pages) preview.page--; preview.hdc2 = (HDC)-1; } LoadStringW(hInst, preview.hdc2 ? STRING_PREVIEW_ONEPAGE : STRING_PREVIEW_TWOPAGES, name, MAX_STRING_LEN); SetWindowTextW(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), name); update_preview(hWnd); } break; case ID_PRINT: dialog_print(hWnd, preview.wszFileName); SendMessageW(hWnd, WM_CLOSE, 0, 0); break; } return 0; }