1 /* 2 * Wordpad implementation - Printing and print preview functions 3 * 4 * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com> 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 #include <stdarg.h> 22 #include <windef.h> 23 #include <winbase.h> 24 #include <winreg.h> 25 #include <wingdi.h> 26 #include <winuser.h> 27 #include <richedit.h> 28 #include <commctrl.h> 29 #include <commdlg.h> 30 31 #include "wordpad.h" 32 33 typedef struct _previewinfo 34 { 35 int page; 36 int pages_shown; 37 int saved_pages_shown; 38 int *pageEnds, pageCapacity; 39 int textlength; 40 HDC hdc; 41 HDC hdc2; 42 RECT window; 43 RECT rcPage; 44 SIZE bmSize; 45 SIZE bmScaledSize; 46 SIZE spacing; 47 float zoomratio; 48 int zoomlevel; 49 LPWSTR wszFileName; 50 } previewinfo, *ppreviewinfo; 51 52 static HGLOBAL devMode; 53 static HGLOBAL devNames; 54 55 static RECT margins; 56 static previewinfo preview; 57 58 extern const WCHAR wszPreviewWndClass[]; 59 60 static const WCHAR var_pagemargin[] = {'P','a','g','e','M','a','r','g','i','n',0}; 61 static const WCHAR var_previewpages[] = {'P','r','e','v','i','e','w','P','a','g','e','s',0}; 62 63 static LPWSTR get_print_file_filter(HWND hMainWnd) 64 { 65 static WCHAR wszPrintFilter[MAX_STRING_LEN*2+6+4+1]; 66 const WCHAR files_prn[] = {'*','.','P','R','N',0}; 67 const WCHAR files_all[] = {'*','.','*','\0'}; 68 LPWSTR p; 69 HINSTANCE hInstance = GetModuleHandleW(0); 70 71 p = wszPrintFilter; 72 LoadStringW(hInstance, STRING_PRINTER_FILES_PRN, p, MAX_STRING_LEN); 73 p += lstrlenW(p) + 1; 74 lstrcpyW(p, files_prn); 75 p += lstrlenW(p) + 1; 76 LoadStringW(hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN); 77 p += lstrlenW(p) + 1; 78 lstrcpyW(p, files_all); 79 p += lstrlenW(p) + 1; 80 *p = 0; 81 82 return wszPrintFilter; 83 } 84 85 void registry_set_pagemargins(HKEY hKey) 86 { 87 RegSetValueExW(hKey, var_pagemargin, 0, REG_BINARY, (LPBYTE)&margins, sizeof(RECT)); 88 } 89 90 void registry_read_pagemargins(HKEY hKey) 91 { 92 DWORD size = sizeof(RECT); 93 94 if(!hKey || RegQueryValueExW(hKey, var_pagemargin, 0, NULL, (LPBYTE)&margins, 95 &size) != ERROR_SUCCESS || size != sizeof(RECT)) 96 SetRect(&margins, 1757, 1417, 1757, 1417); 97 } 98 99 void registry_set_previewpages(HKEY hKey) 100 { 101 RegSetValueExW(hKey, var_previewpages, 0, REG_DWORD, 102 (LPBYTE)&preview.pages_shown, sizeof(DWORD)); 103 } 104 105 void registry_read_previewpages(HKEY hKey) 106 { 107 DWORD size = sizeof(DWORD); 108 if(!hKey || 109 RegQueryValueExW(hKey, var_previewpages, 0, NULL, 110 (LPBYTE)&preview.pages_shown, &size) != ERROR_SUCCESS || 111 size != sizeof(DWORD)) 112 { 113 preview.pages_shown = 1; 114 } else { 115 if (preview.pages_shown < 1) preview.pages_shown = 1; 116 else if (preview.pages_shown > 2) preview.pages_shown = 2; 117 } 118 } 119 120 121 static void AddTextButton(HWND hRebarWnd, UINT string, UINT command, UINT id) 122 { 123 REBARBANDINFOW rb; 124 HINSTANCE hInstance = GetModuleHandleW(0); 125 WCHAR text[MAX_STRING_LEN]; 126 HWND hButton; 127 128 LoadStringW(hInstance, string, text, MAX_STRING_LEN); 129 hButton = CreateWindowW(WC_BUTTONW, text, 130 WS_VISIBLE | WS_CHILD, 5, 5, 100, 15, 131 hRebarWnd, ULongToHandle(command), hInstance, NULL); 132 133 rb.cbSize = REBARBANDINFOW_V6_SIZE; 134 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID; 135 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT; 136 rb.hwndChild = hButton; 137 rb.cyChild = rb.cyMinChild = 22; 138 rb.cx = rb.cxMinChild = 90; 139 rb.cxIdeal = 100; 140 rb.wID = id; 141 142 SendMessageW(hRebarWnd, RB_INSERTBANDW, -1, (LPARAM)&rb); 143 } 144 145 static HDC make_dc(void) 146 { 147 if(devNames && devMode) 148 { 149 LPDEVNAMES dn = GlobalLock(devNames); 150 LPDEVMODEW dm = GlobalLock(devMode); 151 HDC ret; 152 153 ret = CreateDCW((LPWSTR)dn + dn->wDriverOffset, 154 (LPWSTR)dn + dn->wDeviceOffset, 0, dm); 155 156 GlobalUnlock(dn); 157 GlobalUnlock(dm); 158 159 return ret; 160 } else 161 { 162 return 0; 163 } 164 } 165 166 static LONG twips_to_centmm(int twips) 167 { 168 return MulDiv(twips, CENTMM_PER_INCH, TWIPS_PER_INCH); 169 } 170 171 static LONG centmm_to_twips(int mm) 172 { 173 return MulDiv(mm, TWIPS_PER_INCH, CENTMM_PER_INCH); 174 } 175 176 static LONG twips_to_pixels(int twips, int dpi) 177 { 178 return MulDiv(twips, dpi, TWIPS_PER_INCH); 179 } 180 181 static LONG devunits_to_twips(int units, int dpi) 182 { 183 return MulDiv(units, TWIPS_PER_INCH, dpi); 184 } 185 186 187 static RECT get_print_rect(HDC hdc) 188 { 189 RECT rc; 190 int width, height; 191 192 if(hdc) 193 { 194 int dpiY = GetDeviceCaps(hdc, LOGPIXELSY); 195 int dpiX = GetDeviceCaps(hdc, LOGPIXELSX); 196 width = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALWIDTH), dpiX); 197 height = devunits_to_twips(GetDeviceCaps(hdc, PHYSICALHEIGHT), dpiY); 198 } else 199 { 200 width = centmm_to_twips(18500); 201 height = centmm_to_twips(27000); 202 } 203 204 SetRect(&rc, margins.left, margins.top, width - margins.right, height - margins.bottom); 205 206 return rc; 207 } 208 209 void target_device(HWND hMainWnd, DWORD wordWrap) 210 { 211 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); 212 213 if(wordWrap == ID_WORDWRAP_MARGIN) 214 { 215 int width = 0; 216 LRESULT result; 217 HDC hdc = make_dc(); 218 RECT rc = get_print_rect(hdc); 219 220 width = rc.right - rc.left; 221 if(!hdc) 222 { 223 HDC hMaindc = GetDC(hMainWnd); 224 hdc = CreateCompatibleDC(hMaindc); 225 ReleaseDC(hMainWnd, hMaindc); 226 } 227 result = SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, (WPARAM)hdc, width); 228 DeleteDC(hdc); 229 if (result) 230 return; 231 /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping 232 * to window using the NULL DC. */ 233 } 234 235 if (wordWrap != ID_WORDWRAP_NONE) { 236 SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 0); 237 } else { 238 SendMessageW(hEditorWnd, EM_SETTARGETDEVICE, 0, 1); 239 } 240 241 } 242 243 static LPWSTR dialog_print_to_file(HWND hMainWnd) 244 { 245 OPENFILENAMEW ofn; 246 static WCHAR file[MAX_PATH] = {'O','U','T','P','U','T','.','P','R','N',0}; 247 static const WCHAR defExt[] = {'P','R','N',0}; 248 static LPWSTR file_filter; 249 250 if(!file_filter) 251 file_filter = get_print_file_filter(hMainWnd); 252 253 ZeroMemory(&ofn, sizeof(ofn)); 254 255 ofn.lStructSize = sizeof(ofn); 256 ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; 257 ofn.hwndOwner = hMainWnd; 258 ofn.lpstrFilter = file_filter; 259 ofn.lpstrFile = file; 260 ofn.nMaxFile = MAX_PATH; 261 ofn.lpstrDefExt = defExt; 262 263 if(GetSaveFileNameW(&ofn)) 264 return file; 265 else 266 return FALSE; 267 } 268 269 static void char_from_pagenum(HWND hEditorWnd, FORMATRANGE *fr, int page) 270 { 271 int i; 272 273 fr->chrg.cpMin = 0; 274 275 for(i = 1; i < page; i++) 276 { 277 int bottom = fr->rc.bottom; 278 fr->chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, (LPARAM)fr); 279 fr->rc.bottom = bottom; 280 } 281 } 282 283 static HWND get_ruler_wnd(HWND hMainWnd) 284 { 285 return GetDlgItem(GetDlgItem(hMainWnd, IDC_REBAR), IDC_RULER); 286 } 287 288 void redraw_ruler(HWND hRulerWnd) 289 { 290 RECT rc; 291 292 GetClientRect(hRulerWnd, &rc); 293 InvalidateRect(hRulerWnd, &rc, TRUE); 294 } 295 296 static void update_ruler(HWND hRulerWnd) 297 { 298 SendMessageW(hRulerWnd, WM_USER, 0, 0); 299 redraw_ruler(hRulerWnd); 300 } 301 302 static void add_ruler_units(HDC hdcRuler, RECT* drawRect, BOOL NewMetrics, LONG EditLeftmost) 303 { 304 static HDC hdc; 305 306 if(NewMetrics) 307 { 308 static HBITMAP hBitmap; 309 int i, x, y, RulerTextEnd; 310 int CmPixels; 311 int QuarterCmPixels; 312 HFONT hFont; 313 WCHAR FontName[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0}; 314 315 if(hdc) 316 { 317 DeleteDC(hdc); 318 DeleteObject(hBitmap); 319 } 320 321 hdc = CreateCompatibleDC(0); 322 323 CmPixels = twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc, LOGPIXELSX)); 324 QuarterCmPixels = (int)((float)CmPixels / 4.0); 325 326 hBitmap = CreateCompatibleBitmap(hdc, drawRect->right, drawRect->bottom); 327 SelectObject(hdc, hBitmap); 328 FillRect(hdc, drawRect, GetStockObject(WHITE_BRUSH)); 329 330 hFont = CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName); 331 332 SelectObject(hdc, hFont); 333 SetBkMode(hdc, TRANSPARENT); 334 SetTextAlign(hdc, TA_CENTER); 335 y = (int)(((float)drawRect->bottom - (float)drawRect->top) / 2.0) + 1; 336 RulerTextEnd = drawRect->right - EditLeftmost + 1; 337 for(i = 1, x = EditLeftmost; x < (drawRect->right - EditLeftmost + 1); i ++) 338 { 339 WCHAR str[3]; 340 WCHAR format[] = {'%','d',0}; 341 int x2 = x; 342 343 x2 += QuarterCmPixels; 344 if(x2 > RulerTextEnd) 345 break; 346 347 MoveToEx(hdc, x2, y, NULL); 348 LineTo(hdc, x2, y+2); 349 350 x2 += QuarterCmPixels; 351 if(x2 > RulerTextEnd) 352 break; 353 354 MoveToEx(hdc, x2, y - 3, NULL); 355 LineTo(hdc, x2, y + 3); 356 357 x2 += QuarterCmPixels; 358 if(x2 > RulerTextEnd) 359 break; 360 361 MoveToEx(hdc, x2, y, NULL); 362 LineTo(hdc, x2, y+2); 363 364 x += CmPixels; 365 if(x > RulerTextEnd) 366 break; 367 368 wsprintfW(str, format, i); 369 TextOutW(hdc, x, 5, str, lstrlenW(str)); 370 } 371 DeleteObject(hFont); 372 } 373 374 BitBlt(hdcRuler, 0, 0, drawRect->right, drawRect->bottom, hdc, 0, 0, SRCAND); 375 } 376 377 static void paint_ruler(HWND hWnd, LONG EditLeftmost, BOOL NewMetrics) 378 { 379 PAINTSTRUCT ps; 380 HDC hdc = BeginPaint(hWnd, &ps); 381 HDC hdcPrint = make_dc(); 382 RECT printRect = get_print_rect(hdcPrint); 383 RECT drawRect; 384 385 GetClientRect(hWnd, &drawRect); 386 FillRect(hdc, &drawRect, GetSysColorBrush(COLOR_MENU)); 387 388 InflateRect(&drawRect, 0, -3); 389 drawRect.left = EditLeftmost; 390 drawRect.right = twips_to_pixels(printRect.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX)); 391 FillRect(hdc, &drawRect, GetStockObject(WHITE_BRUSH)); 392 393 drawRect.top--; 394 drawRect.bottom++; 395 DrawEdge(hdc, &drawRect, EDGE_SUNKEN, BF_RECT); 396 397 drawRect.left = drawRect.right - 1; 398 drawRect.right = twips_to_pixels(printRect.right + margins.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX)); 399 DrawEdge(hdc, &drawRect, EDGE_ETCHED, BF_RECT); 400 401 drawRect.left = 0; 402 drawRect.top = 0; 403 add_ruler_units(hdc, &drawRect, NewMetrics, EditLeftmost); 404 405 SelectObject(hdc, GetStockObject(BLACK_BRUSH)); 406 DeleteDC(hdcPrint); 407 EndPaint(hWnd, &ps); 408 } 409 410 LRESULT CALLBACK ruler_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 411 { 412 static WNDPROC pPrevRulerProc; 413 static LONG EditLeftmost; 414 static BOOL NewMetrics; 415 416 switch(msg) 417 { 418 case WM_USER: 419 if(wParam) 420 { 421 EditLeftmost = ((POINTL*)wParam)->x; 422 pPrevRulerProc = (WNDPROC)lParam; 423 } 424 NewMetrics = TRUE; 425 break; 426 427 case WM_PAINT: 428 paint_ruler(hWnd, EditLeftmost, NewMetrics); 429 break; 430 431 default: 432 return CallWindowProcW(pPrevRulerProc, hWnd, msg, wParam, lParam); 433 } 434 435 return 0; 436 } 437 438 static void print(LPPRINTDLGW pd, LPWSTR wszFileName) 439 { 440 FORMATRANGE fr; 441 DOCINFOW di; 442 HWND hEditorWnd = GetDlgItem(pd->hwndOwner, IDC_EDITOR); 443 int printedPages = 0; 444 445 fr.hdc = pd->hDC; 446 fr.hdcTarget = pd->hDC; 447 448 fr.rc = get_print_rect(fr.hdc); 449 SetRect(&fr.rcPage, 0, 0, fr.rc.right + margins.right, fr.rc.bottom + margins.bottom); 450 451 ZeroMemory(&di, sizeof(di)); 452 di.cbSize = sizeof(di); 453 di.lpszDocName = wszFileName; 454 455 if(pd->Flags & PD_PRINTTOFILE) 456 { 457 di.lpszOutput = dialog_print_to_file(pd->hwndOwner); 458 if(!di.lpszOutput) 459 return; 460 } 461 462 if(pd->Flags & PD_SELECTION) 463 { 464 SendMessageW(hEditorWnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg); 465 } else 466 { 467 GETTEXTLENGTHEX gt; 468 gt.flags = GTL_DEFAULT; 469 gt.codepage = 1200; 470 fr.chrg.cpMin = 0; 471 fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0); 472 473 if(pd->Flags & PD_PAGENUMS) 474 char_from_pagenum(hEditorWnd, &fr, pd->nToPage); 475 } 476 477 StartDocW(fr.hdc, &di); 478 do 479 { 480 if(StartPage(fr.hdc) <= 0) 481 break; 482 483 fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr); 484 485 if(EndPage(fr.hdc) <= 0) 486 break; 487 488 printedPages++; 489 if((pd->Flags & PD_PAGENUMS) && (printedPages > (pd->nToPage - pd->nFromPage))) 490 break; 491 } 492 while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax); 493 494 EndDoc(fr.hdc); 495 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0); 496 } 497 498 void dialog_printsetup(HWND hMainWnd) 499 { 500 PAGESETUPDLGW ps; 501 502 ZeroMemory(&ps, sizeof(ps)); 503 ps.lStructSize = sizeof(ps); 504 ps.hwndOwner = hMainWnd; 505 ps.Flags = PSD_INHUNDREDTHSOFMILLIMETERS | PSD_MARGINS; 506 SetRect(&ps.rtMargin, twips_to_centmm(margins.left), twips_to_centmm(margins.top), 507 twips_to_centmm(margins.right), twips_to_centmm(margins.bottom)); 508 ps.hDevMode = devMode; 509 ps.hDevNames = devNames; 510 511 if(PageSetupDlgW(&ps)) 512 { 513 SetRect(&margins, centmm_to_twips(ps.rtMargin.left), centmm_to_twips(ps.rtMargin.top), 514 centmm_to_twips(ps.rtMargin.right), centmm_to_twips(ps.rtMargin.bottom)); 515 devMode = ps.hDevMode; 516 devNames = ps.hDevNames; 517 update_ruler(get_ruler_wnd(hMainWnd)); 518 } 519 } 520 521 void get_default_printer_opts(void) 522 { 523 PRINTDLGW pd; 524 ZeroMemory(&pd, sizeof(pd)); 525 526 ZeroMemory(&pd, sizeof(pd)); 527 pd.lStructSize = sizeof(pd); 528 pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT; 529 pd.hDevMode = devMode; 530 531 PrintDlgW(&pd); 532 533 devMode = pd.hDevMode; 534 devNames = pd.hDevNames; 535 } 536 537 void print_quick(HWND hMainWnd, LPWSTR wszFileName) 538 { 539 PRINTDLGW pd; 540 541 ZeroMemory(&pd, sizeof(pd)); 542 pd.hwndOwner = hMainWnd; 543 pd.hDC = make_dc(); 544 545 print(&pd, wszFileName); 546 DeleteDC(pd.hDC); 547 } 548 549 void dialog_print(HWND hMainWnd, LPWSTR wszFileName) 550 { 551 PRINTDLGW pd; 552 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); 553 int from = 0; 554 int to = 0; 555 556 ZeroMemory(&pd, sizeof(pd)); 557 pd.lStructSize = sizeof(pd); 558 pd.hwndOwner = hMainWnd; 559 pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; 560 pd.nMinPage = 1; 561 pd.nMaxPage = -1; 562 pd.hDevMode = devMode; 563 pd.hDevNames = devNames; 564 565 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to); 566 if(from == to) 567 pd.Flags |= PD_NOSELECTION; 568 569 if(PrintDlgW(&pd)) 570 { 571 devMode = pd.hDevMode; 572 devNames = pd.hDevNames; 573 print(&pd, wszFileName); 574 update_ruler(get_ruler_wnd(hMainWnd)); 575 } 576 } 577 578 static void preview_bar_show(HWND hMainWnd, BOOL show) 579 { 580 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); 581 int i; 582 583 if(show) 584 { 585 REBARBANDINFOW rb; 586 HWND hStatic; 587 UINT num_pages_string = preview.pages_shown > 1 ? STRING_PREVIEW_ONEPAGE : 588 STRING_PREVIEW_TWOPAGES; 589 590 AddTextButton(hReBar, STRING_PREVIEW_PRINT, ID_PRINT, BANDID_PREVIEW_BTN1); 591 AddTextButton(hReBar, STRING_PREVIEW_NEXTPAGE, ID_PREVIEW_NEXTPAGE, BANDID_PREVIEW_BTN2); 592 AddTextButton(hReBar, STRING_PREVIEW_PREVPAGE, ID_PREVIEW_PREVPAGE, BANDID_PREVIEW_BTN3); 593 AddTextButton(hReBar, num_pages_string, ID_PREVIEW_NUMPAGES, BANDID_PREVIEW_BTN4); 594 AddTextButton(hReBar, STRING_PREVIEW_ZOOMIN, ID_PREVIEW_ZOOMIN, BANDID_PREVIEW_BTN5); 595 AddTextButton(hReBar, STRING_PREVIEW_ZOOMOUT, ID_PREVIEW_ZOOMOUT, BANDID_PREVIEW_BTN6); 596 AddTextButton(hReBar, STRING_PREVIEW_CLOSE, ID_FILE_EXIT, BANDID_PREVIEW_BTN7); 597 598 hStatic = CreateWindowW(WC_STATICW, NULL, 599 WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, 600 hReBar, NULL, NULL, NULL); 601 602 rb.cbSize = REBARBANDINFOW_V6_SIZE; 603 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID; 604 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT; 605 rb.hwndChild = hStatic; 606 rb.cyChild = rb.cyMinChild = 22; 607 rb.cx = rb.cxMinChild = 90; 608 rb.cxIdeal = 100; 609 rb.wID = BANDID_PREVIEW_BUFFER; 610 611 SendMessageW(hReBar, RB_INSERTBANDW, -1, (LPARAM)&rb); 612 } else 613 { 614 for(i = 0; i <= PREVIEW_BUTTONS; i++) 615 SendMessageW(hReBar, RB_DELETEBAND, SendMessageW(hReBar, RB_IDTOINDEX, BANDID_PREVIEW_BTN1+i, 0), 0); 616 } 617 } 618 619 static const int min_spacing = 10; 620 621 static void update_preview_scrollbars(HWND hwndPreview, RECT *window) 622 { 623 SCROLLINFO sbi; 624 sbi.cbSize = sizeof(sbi); 625 sbi.fMask = SIF_PAGE|SIF_RANGE; 626 sbi.nMin = 0; 627 if (preview.zoomlevel == 0) 628 { 629 /* Hide scrollbars when zoomed out. */ 630 sbi.nMax = 0; 631 sbi.nPage = window->right; 632 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE); 633 sbi.nPage = window->bottom; 634 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE); 635 } else { 636 sbi.nMax = preview.bmScaledSize.cx * preview.pages_shown + 637 min_spacing * (preview.pages_shown + 1); 638 sbi.nPage = window->right; 639 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE); 640 /* Change in the horizontal scrollbar visibility affects the 641 * client rect, so update the client rect. */ 642 GetClientRect(hwndPreview, window); 643 sbi.nMax = preview.bmScaledSize.cy + min_spacing * 2; 644 sbi.nPage = window->bottom; 645 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE); 646 } 647 } 648 649 static void update_preview_sizes(HWND hwndPreview, BOOL zoomLevelUpdated) 650 { 651 RECT window; 652 653 GetClientRect(hwndPreview, &window); 654 655 /* The zoom ratio isn't updated for partial zoom because of resizing the window. */ 656 if (zoomLevelUpdated || preview.zoomlevel != 1) 657 { 658 float ratio, ratioHeight, ratioWidth; 659 if (preview.zoomlevel == 2) 660 { 661 ratio = 1.0; 662 } else { 663 ratioHeight = (window.bottom - min_spacing * 2) / (float)preview.bmSize.cy; 664 665 ratioWidth = (float)(window.right - 666 min_spacing * (preview.pages_shown + 1)) / 667 (preview.pages_shown * preview.bmSize.cx); 668 669 if(ratioWidth > ratioHeight) 670 ratio = ratioHeight; 671 else 672 ratio = ratioWidth; 673 674 if (preview.zoomlevel == 1) 675 ratio += (1.0 - ratio) / 2; 676 } 677 preview.zoomratio = ratio; 678 } 679 680 preview.bmScaledSize.cx = preview.bmSize.cx * preview.zoomratio; 681 preview.bmScaledSize.cy = preview.bmSize.cy * preview.zoomratio; 682 683 preview.spacing.cy = max(min_spacing, (window.bottom - preview.bmScaledSize.cy) / 2); 684 685 preview.spacing.cx = (window.right - 686 preview.bmScaledSize.cx * preview.pages_shown) / 687 (preview.pages_shown + 1); 688 if (preview.spacing.cx < min_spacing) 689 preview.spacing.cx = min_spacing; 690 691 update_preview_scrollbars(hwndPreview, &window); 692 } 693 694 static void draw_margin_lines(HDC hdc, int x, int y, float ratio) 695 { 696 HPEN hPen, oldPen; 697 SIZE dpi; 698 RECT page_margin = preview.rcPage; 699 700 dpi.cx = GetDeviceCaps(hdc, LOGPIXELSX); 701 dpi.cy = GetDeviceCaps(hdc, LOGPIXELSY); 702 703 SetRect(&page_margin, preview.rcPage.left + margins.left, preview.rcPage.top + margins.top, 704 preview.rcPage.right - margins.right, preview.rcPage.bottom - margins.bottom); 705 706 page_margin.left = (int)((float)twips_to_pixels(page_margin.left, dpi.cx) * ratio); 707 page_margin.top = (int)((float)twips_to_pixels(page_margin.top, dpi.cy) * ratio); 708 page_margin.bottom = (int)((float)twips_to_pixels(page_margin.bottom, dpi.cy) * ratio); 709 page_margin.right = (int)((float)twips_to_pixels(page_margin.right, dpi.cx) * ratio); 710 711 OffsetRect(&page_margin, x, y); 712 713 hPen = CreatePen(PS_DOT, 1, RGB(0,0,0)); 714 oldPen = SelectObject(hdc, hPen); 715 716 MoveToEx(hdc, x, page_margin.top, NULL); 717 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.top); 718 MoveToEx(hdc, x, page_margin.bottom, NULL); 719 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.bottom); 720 721 MoveToEx(hdc, page_margin.left, y, NULL); 722 LineTo(hdc, page_margin.left, y + preview.bmScaledSize.cy); 723 MoveToEx(hdc, page_margin.right, y, NULL); 724 LineTo(hdc, page_margin.right, y + preview.bmScaledSize.cy); 725 726 SelectObject(hdc, oldPen); 727 DeleteObject(hPen); 728 } 729 730 static BOOL is_last_preview_page(int page) 731 { 732 return preview.pageEnds[page - 1] >= preview.textlength; 733 } 734 735 void init_preview(HWND hMainWnd, LPWSTR wszFileName) 736 { 737 HINSTANCE hInstance = GetModuleHandleW(0); 738 preview.page = 1; 739 preview.hdc = 0; 740 preview.hdc2 = 0; 741 preview.wszFileName = wszFileName; 742 preview.zoomratio = 0; 743 preview.zoomlevel = 0; 744 preview_bar_show(hMainWnd, TRUE); 745 746 CreateWindowExW(0, wszPreviewWndClass, NULL, 747 WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL, 748 0, 0, 200, 10, hMainWnd, (HMENU)IDC_PREVIEW, hInstance, NULL); 749 } 750 751 void close_preview(HWND hMainWnd) 752 { 753 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW); 754 preview.window.right = 0; 755 preview.window.bottom = 0; 756 preview.page = 0; 757 HeapFree(GetProcessHeap(), 0, preview.pageEnds); 758 preview.pageEnds = NULL; 759 preview.pageCapacity = 0; 760 if (preview.zoomlevel > 0) 761 preview.pages_shown = preview.saved_pages_shown; 762 if(preview.hdc) { 763 HBITMAP oldbm = GetCurrentObject(preview.hdc, OBJ_BITMAP); 764 DeleteDC(preview.hdc); 765 DeleteObject(oldbm); 766 preview.hdc = NULL; 767 } 768 if(preview.hdc2) { 769 HBITMAP oldbm = GetCurrentObject(preview.hdc2, OBJ_BITMAP); 770 DeleteDC(preview.hdc2); 771 DeleteObject(oldbm); 772 preview.hdc2 = NULL; 773 } 774 775 preview_bar_show(hMainWnd, FALSE); 776 DestroyWindow(hwndPreview); 777 } 778 779 BOOL preview_isactive(void) 780 { 781 return preview.page != 0; 782 } 783 784 static void draw_preview(HWND hEditorWnd, FORMATRANGE* lpFr, RECT* paper, int page) 785 { 786 int bottom; 787 788 if (!preview.pageEnds) 789 { 790 preview.pageCapacity = 32; 791 preview.pageEnds = HeapAlloc(GetProcessHeap(), 0, 792 sizeof(int) * preview.pageCapacity); 793 if (!preview.pageEnds) return; 794 } else if (page >= preview.pageCapacity) { 795 int *new_buffer; 796 new_buffer = HeapReAlloc(GetProcessHeap(), 0, preview.pageEnds, 797 sizeof(int) * preview.pageCapacity * 2); 798 if (!new_buffer) return; 799 preview.pageCapacity *= 2; 800 preview.pageEnds = new_buffer; 801 } 802 803 FillRect(lpFr->hdc, paper, GetStockObject(WHITE_BRUSH)); 804 if (page > 1 && is_last_preview_page(page - 1)) return; 805 lpFr->chrg.cpMin = page <= 1 ? 0 : preview.pageEnds[page-2]; 806 bottom = lpFr->rc.bottom; 807 preview.pageEnds[page-1] = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)lpFr); 808 809 /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in, 810 * but we want to keep the original for drawing margins */ 811 lpFr->rc.bottom = bottom; 812 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0); 813 } 814 815 static void update_preview_buttons(HWND hMainWnd) 816 { 817 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); 818 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_PREVPAGE), preview.page > 1); 819 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NEXTPAGE), 820 !is_last_preview_page(preview.page) && 821 !is_last_preview_page(preview.page + preview.pages_shown - 1)); 822 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), 823 preview.pages_shown > 1 || 824 (!is_last_preview_page(1) && preview.zoomlevel == 0)); 825 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMIN), preview.zoomlevel < 2); 826 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMOUT), preview.zoomlevel > 0); 827 } 828 829 static LRESULT print_preview(HWND hwndPreview) 830 { 831 HPEN hPen, oldPen; 832 HDC hdc; 833 HRGN back_rgn, excl_rgn; 834 RECT window, background; 835 PAINTSTRUCT ps; 836 int x, y; 837 838 hdc = BeginPaint(hwndPreview, &ps); 839 GetClientRect(hwndPreview, &window); 840 back_rgn = CreateRectRgnIndirect(&window); 841 842 x = preview.spacing.cx - GetScrollPos(hwndPreview, SB_HORZ); 843 y = preview.spacing.cy - GetScrollPos(hwndPreview, SB_VERT); 844 845 /* draw page outlines */ 846 hPen = CreatePen(PS_SOLID|PS_INSIDEFRAME, 2, RGB(0,0,0)); 847 oldPen = SelectObject(hdc, hPen); 848 SetRect(&background, x - 2, y - 2, x + preview.bmScaledSize.cx + 2, 849 y + preview.bmScaledSize.cy + 2); 850 Rectangle(hdc, background.left, background.top, 851 background.right, background.bottom); 852 excl_rgn = CreateRectRgnIndirect(&background); 853 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF); 854 if(preview.pages_shown > 1) 855 { 856 background.left += preview.bmScaledSize.cx + preview.spacing.cx; 857 background.right += preview.bmScaledSize.cx + preview.spacing.cx; 858 Rectangle(hdc, background.left, background.top, 859 background.right, background.bottom); 860 SetRectRgn(excl_rgn, background.left, background.top, 861 background.right, background.bottom); 862 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF); 863 } 864 SelectObject(hdc, oldPen); 865 DeleteObject(hPen); 866 FillRgn(hdc, back_rgn, GetStockObject(GRAY_BRUSH)); 867 DeleteObject(excl_rgn); 868 DeleteObject(back_rgn); 869 870 StretchBlt(hdc, x, y, preview.bmScaledSize.cx, preview.bmScaledSize.cy, 871 preview.hdc, 0, 0, preview.bmSize.cx, preview.bmSize.cy, SRCCOPY); 872 873 draw_margin_lines(hdc, x, y, preview.zoomratio); 874 875 if(preview.pages_shown > 1) 876 { 877 if (!is_last_preview_page(preview.page)) { 878 x += preview.spacing.cx + preview.bmScaledSize.cx; 879 StretchBlt(hdc, x, y, 880 preview.bmScaledSize.cx, preview.bmScaledSize.cy, 881 preview.hdc2, 0, 0, 882 preview.bmSize.cx, preview.bmSize.cy, SRCCOPY); 883 884 draw_margin_lines(hdc, x, y, preview.zoomratio); 885 } else { 886 InflateRect(&background, -2, -2); 887 FillRect(hdc, &background, GetStockObject(WHITE_BRUSH)); 888 } 889 } 890 891 preview.window = window; 892 893 EndPaint(hwndPreview, &ps); 894 895 return 0; 896 } 897 898 static void update_preview_statusbar(HWND hMainWnd) 899 { 900 HWND hStatusbar = GetDlgItem(hMainWnd, IDC_STATUSBAR); 901 HINSTANCE hInst = GetModuleHandleW(0); 902 WCHAR *p; 903 WCHAR wstr[MAX_STRING_LEN]; 904 905 p = wstr; 906 if (preview.pages_shown < 2 || is_last_preview_page(preview.page)) 907 { 908 static const WCHAR fmt[] = {' ','%','d','\0'}; 909 p += LoadStringW(hInst, STRING_PREVIEW_PAGE, wstr, MAX_STRING_LEN); 910 wsprintfW(p, fmt, preview.page); 911 } else { 912 static const WCHAR fmt[] = {' ','%','d','-','%','d','\0'}; 913 p += LoadStringW(hInst, STRING_PREVIEW_PAGES, wstr, MAX_STRING_LEN); 914 wsprintfW(p, fmt, preview.page, preview.page + 1); 915 } 916 SetWindowTextW(hStatusbar, wstr); 917 } 918 919 /* Update for page changes. */ 920 static void update_preview(HWND hMainWnd) 921 { 922 RECT paper; 923 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); 924 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW); 925 HBITMAP hBitmapCapture; 926 FORMATRANGE fr; 927 HDC hdc = GetDC(hwndPreview); 928 929 fr.hdcTarget = make_dc(); 930 fr.rc = fr.rcPage = preview.rcPage; 931 fr.rc.left += margins.left; 932 fr.rc.top += margins.top; 933 fr.rc.bottom -= margins.bottom; 934 fr.rc.right -= margins.right; 935 936 fr.chrg.cpMin = 0; 937 fr.chrg.cpMax = preview.textlength; 938 939 SetRect(&paper, 0, 0, preview.bmSize.cx, preview.bmSize.cy); 940 941 if (!preview.hdc) { 942 preview.hdc = CreateCompatibleDC(hdc); 943 hBitmapCapture = CreateCompatibleBitmap(hdc, preview.bmSize.cx, preview.bmSize.cy); 944 SelectObject(preview.hdc, hBitmapCapture); 945 } 946 947 fr.hdc = preview.hdc; 948 draw_preview(hEditorWnd, &fr, &paper, preview.page); 949 950 if(preview.pages_shown > 1) 951 { 952 if (!preview.hdc2) 953 { 954 preview.hdc2 = CreateCompatibleDC(hdc); 955 hBitmapCapture = CreateCompatibleBitmap(hdc, 956 preview.bmSize.cx, 957 preview.bmSize.cy); 958 SelectObject(preview.hdc2, hBitmapCapture); 959 } 960 961 fr.hdc = preview.hdc2; 962 draw_preview(hEditorWnd, &fr, &fr.rcPage, preview.page + 1); 963 } 964 DeleteDC(fr.hdcTarget); 965 ReleaseDC(hwndPreview, hdc); 966 967 InvalidateRect(hwndPreview, NULL, FALSE); 968 update_preview_buttons(hMainWnd); 969 update_preview_statusbar(hMainWnd); 970 } 971 972 static void toggle_num_pages(HWND hMainWnd) 973 { 974 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); 975 WCHAR name[MAX_STRING_LEN]; 976 HINSTANCE hInst = GetModuleHandleW(0); 977 int nPreviewPages; 978 979 preview.pages_shown = preview.pages_shown > 1 ? 1 : 2; 980 981 nPreviewPages = preview.zoomlevel > 0 ? preview.saved_pages_shown : 982 preview.pages_shown; 983 984 LoadStringW(hInst, nPreviewPages > 1 ? STRING_PREVIEW_ONEPAGE : 985 STRING_PREVIEW_TWOPAGES, 986 name, MAX_STRING_LEN); 987 988 SetWindowTextW(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), name); 989 update_preview_sizes(GetDlgItem(hMainWnd, IDC_PREVIEW), TRUE); 990 update_preview(hMainWnd); 991 } 992 993 /* Returns the page shown that the point is in (1 or 2) or 0 if the point 994 * isn't inside either page */ 995 static int preview_page_hittest(POINT pt) 996 { 997 RECT rc; 998 rc.left = preview.spacing.cx; 999 rc.right = rc.left + preview.bmScaledSize.cx; 1000 rc.top = preview.spacing.cy; 1001 rc.bottom = rc.top + preview.bmScaledSize.cy; 1002 if (PtInRect(&rc, pt)) 1003 return 1; 1004 1005 if (preview.pages_shown <= 1) 1006 return 0; 1007 1008 rc.left += preview.bmScaledSize.cx + preview.spacing.cx; 1009 rc.right += preview.bmScaledSize.cx + preview.spacing.cx; 1010 if (PtInRect(&rc, pt)) 1011 return is_last_preview_page(preview.page) ? 1 : 2; 1012 1013 return 0; 1014 } 1015 1016 LRESULT CALLBACK preview_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1017 { 1018 switch(msg) 1019 { 1020 case WM_CREATE: 1021 { 1022 HWND hMainWnd = GetParent(hWnd); 1023 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); 1024 FORMATRANGE fr; 1025 GETTEXTLENGTHEX gt = {GTL_DEFAULT, 1200}; 1026 HDC hdc = GetDC(hWnd); 1027 HDC hdcTarget = make_dc(); 1028 1029 fr.rc = preview.rcPage = get_print_rect(hdcTarget); 1030 preview.rcPage.bottom += margins.bottom; 1031 preview.rcPage.right += margins.right; 1032 preview.rcPage.top = preview.rcPage.left = 0; 1033 fr.rcPage = preview.rcPage; 1034 1035 preview.bmSize.cx = twips_to_pixels(preview.rcPage.right, GetDeviceCaps(hdc, LOGPIXELSX)); 1036 preview.bmSize.cy = twips_to_pixels(preview.rcPage.bottom, GetDeviceCaps(hdc, LOGPIXELSY)); 1037 1038 preview.textlength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0); 1039 1040 fr.hdc = CreateCompatibleDC(hdc); 1041 fr.hdcTarget = hdcTarget; 1042 fr.chrg.cpMin = 0; 1043 fr.chrg.cpMax = preview.textlength; 1044 DeleteDC(fr.hdc); 1045 DeleteDC(hdcTarget); 1046 ReleaseDC(hWnd, hdc); 1047 1048 update_preview_sizes(hWnd, TRUE); 1049 update_preview(hMainWnd); 1050 break; 1051 } 1052 1053 case WM_PAINT: 1054 return print_preview(hWnd); 1055 1056 case WM_SIZE: 1057 { 1058 update_preview_sizes(hWnd, FALSE); 1059 InvalidateRect(hWnd, NULL, FALSE); 1060 break; 1061 } 1062 1063 case WM_VSCROLL: 1064 case WM_HSCROLL: 1065 { 1066 SCROLLINFO si; 1067 RECT rc; 1068 int nBar = (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ; 1069 int origPos; 1070 1071 GetClientRect(hWnd, &rc); 1072 si.cbSize = sizeof(si); 1073 si.fMask = SIF_ALL; 1074 GetScrollInfo(hWnd, nBar, &si); 1075 origPos = si.nPos; 1076 switch(LOWORD(wParam)) 1077 { 1078 case SB_TOP: /* == SB_LEFT */ 1079 si.nPos = si.nMin; 1080 break; 1081 case SB_BOTTOM: /* == SB_RIGHT */ 1082 si.nPos = si.nMax; 1083 break; 1084 case SB_LINEUP: /* == SB_LINELEFT */ 1085 si.nPos -= si.nPage / 10; 1086 break; 1087 case SB_LINEDOWN: /* == SB_LINERIGHT */ 1088 si.nPos += si.nPage / 10; 1089 break; 1090 case SB_PAGEUP: /* == SB_PAGELEFT */ 1091 si.nPos -= si.nPage; 1092 break; 1093 case SB_PAGEDOWN: /* SB_PAGERIGHT */ 1094 si.nPos += si.nPage; 1095 break; 1096 case SB_THUMBTRACK: 1097 si.nPos = si.nTrackPos; 1098 break; 1099 } 1100 si.fMask = SIF_POS; 1101 SetScrollInfo(hWnd, nBar, &si, TRUE); 1102 GetScrollInfo(hWnd, nBar, &si); 1103 if (si.nPos != origPos) 1104 { 1105 int amount = origPos - si.nPos; 1106 if (msg == WM_VSCROLL) 1107 ScrollWindow(hWnd, 0, amount, NULL, NULL); 1108 else 1109 ScrollWindow(hWnd, amount, 0, NULL, NULL); 1110 } 1111 return 0; 1112 } 1113 1114 case WM_SETCURSOR: 1115 { 1116 POINT pt; 1117 RECT rc; 1118 int bHittest = 0; 1119 DWORD messagePos = GetMessagePos(); 1120 pt.x = (short)LOWORD(messagePos); 1121 pt.y = (short)HIWORD(messagePos); 1122 ScreenToClient(hWnd, &pt); 1123 1124 GetClientRect(hWnd, &rc); 1125 if (PtInRect(&rc, pt)) 1126 { 1127 pt.x += GetScrollPos(hWnd, SB_HORZ); 1128 pt.y += GetScrollPos(hWnd, SB_VERT); 1129 bHittest = preview_page_hittest(pt); 1130 } 1131 1132 if (bHittest) 1133 SetCursor(LoadCursorW(GetModuleHandleW(0), 1134 MAKEINTRESOURCEW(IDC_ZOOM))); 1135 else 1136 SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW)); 1137 1138 return TRUE; 1139 } 1140 1141 case WM_LBUTTONDOWN: 1142 { 1143 int page; 1144 POINT pt; 1145 pt.x = (short)LOWORD(lParam) + GetScrollPos(hWnd, SB_HORZ); 1146 pt.y = (short)HIWORD(lParam) + GetScrollPos(hWnd, SB_VERT); 1147 if ((page = preview_page_hittest(pt)) > 0) 1148 { 1149 HWND hMainWnd = GetParent(hWnd); 1150 1151 /* Convert point from client coordinate to unzoomed page 1152 * coordinate. */ 1153 pt.x -= preview.spacing.cx; 1154 if (page > 1) 1155 pt.x -= preview.bmScaledSize.cx + preview.spacing.cx; 1156 pt.y -= preview.spacing.cy; 1157 pt.x /= preview.zoomratio; 1158 pt.y /= preview.zoomratio; 1159 1160 if (preview.zoomlevel == 0) 1161 preview.saved_pages_shown = preview.pages_shown; 1162 preview.zoomlevel = (preview.zoomlevel + 1) % 3; 1163 preview.zoomratio = 0; 1164 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1) 1165 { 1166 toggle_num_pages(hMainWnd); 1167 } else if (preview.pages_shown > 1) { 1168 if (page >= 2) preview.page++; 1169 toggle_num_pages(hMainWnd); 1170 } else { 1171 update_preview_sizes(hWnd, TRUE); 1172 InvalidateRect(hWnd, NULL, FALSE); 1173 update_preview_buttons(hMainWnd); 1174 } 1175 1176 if (preview.zoomlevel > 0) { 1177 SCROLLINFO si; 1178 /* Convert the coordinate back to client coordinate. */ 1179 pt.x *= preview.zoomratio; 1180 pt.y *= preview.zoomratio; 1181 pt.x += preview.spacing.cx; 1182 pt.y += preview.spacing.cy; 1183 /* Scroll to center view at that point on the page */ 1184 si.cbSize = sizeof(si); 1185 si.fMask = SIF_PAGE; 1186 GetScrollInfo(hWnd, SB_HORZ, &si); 1187 pt.x -= si.nPage / 2; 1188 SetScrollPos(hWnd, SB_HORZ, pt.x, TRUE); 1189 GetScrollInfo(hWnd, SB_VERT, &si); 1190 pt.y -= si.nPage / 2; 1191 SetScrollPos(hWnd, SB_VERT, pt.y, TRUE); 1192 } 1193 } 1194 } 1195 1196 default: 1197 return DefWindowProcW(hWnd, msg, wParam, lParam); 1198 } 1199 1200 return 0; 1201 } 1202 1203 LRESULT preview_command(HWND hWnd, WPARAM wParam) 1204 { 1205 switch(LOWORD(wParam)) 1206 { 1207 case ID_FILE_EXIT: 1208 PostMessageW(hWnd, WM_CLOSE, 0, 0); 1209 break; 1210 1211 case ID_PREVIEW_NEXTPAGE: 1212 case ID_PREVIEW_PREVPAGE: 1213 { 1214 if(LOWORD(wParam) == ID_PREVIEW_NEXTPAGE) 1215 preview.page++; 1216 else 1217 preview.page--; 1218 1219 update_preview(hWnd); 1220 } 1221 break; 1222 1223 case ID_PREVIEW_NUMPAGES: 1224 toggle_num_pages(hWnd); 1225 break; 1226 1227 case ID_PREVIEW_ZOOMIN: 1228 if (preview.zoomlevel < 2) 1229 { 1230 if (preview.zoomlevel == 0) 1231 preview.saved_pages_shown = preview.pages_shown; 1232 preview.zoomlevel++; 1233 preview.zoomratio = 0; 1234 if (preview.pages_shown > 1) 1235 { 1236 /* Forced switch to one page when zooming in. */ 1237 toggle_num_pages(hWnd); 1238 } else { 1239 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW); 1240 update_preview_sizes(hwndPreview, TRUE); 1241 InvalidateRect(hwndPreview, NULL, FALSE); 1242 update_preview_buttons(hWnd); 1243 } 1244 } 1245 break; 1246 1247 case ID_PREVIEW_ZOOMOUT: 1248 if (preview.zoomlevel > 0) 1249 { 1250 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW); 1251 preview.zoomlevel--; 1252 preview.zoomratio = 0; 1253 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1) { 1254 toggle_num_pages(hWnd); 1255 } else { 1256 update_preview_sizes(hwndPreview, TRUE); 1257 InvalidateRect(hwndPreview, NULL, FALSE); 1258 update_preview_buttons(hWnd); 1259 } 1260 } 1261 break; 1262 1263 case ID_PRINT: 1264 dialog_print(hWnd, preview.wszFileName); 1265 SendMessageW(hWnd, WM_CLOSE, 0, 0); 1266 break; 1267 } 1268 1269 return 0; 1270 } 1271