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 HBRUSH hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU)); 385 386 GetClientRect(hWnd, &drawRect); 387 FillRect(hdc, &drawRect, hBrush); 388 389 InflateRect(&drawRect, 0, -3); 390 drawRect.left = EditLeftmost; 391 drawRect.right = twips_to_pixels(printRect.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX)); 392 FillRect(hdc, &drawRect, GetStockObject(WHITE_BRUSH)); 393 394 drawRect.top--; 395 drawRect.bottom++; 396 DrawEdge(hdc, &drawRect, EDGE_SUNKEN, BF_RECT); 397 398 drawRect.left = drawRect.right - 1; 399 drawRect.right = twips_to_pixels(printRect.right + margins.right - margins.left, GetDeviceCaps(hdc, LOGPIXELSX)); 400 DrawEdge(hdc, &drawRect, EDGE_ETCHED, BF_RECT); 401 402 drawRect.left = 0; 403 drawRect.top = 0; 404 add_ruler_units(hdc, &drawRect, NewMetrics, EditLeftmost); 405 406 SelectObject(hdc, GetStockObject(BLACK_BRUSH)); 407 DeleteObject(hBrush); 408 DeleteDC(hdcPrint); 409 EndPaint(hWnd, &ps); 410 } 411 412 LRESULT CALLBACK ruler_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 413 { 414 static WNDPROC pPrevRulerProc; 415 static LONG EditLeftmost; 416 static BOOL NewMetrics; 417 418 switch(msg) 419 { 420 case WM_USER: 421 if(wParam) 422 { 423 EditLeftmost = ((POINTL*)wParam)->x; 424 pPrevRulerProc = (WNDPROC)lParam; 425 } 426 NewMetrics = TRUE; 427 break; 428 429 case WM_PAINT: 430 paint_ruler(hWnd, EditLeftmost, NewMetrics); 431 break; 432 433 default: 434 return CallWindowProcW(pPrevRulerProc, hWnd, msg, wParam, lParam); 435 } 436 437 return 0; 438 } 439 440 static void print(LPPRINTDLGW pd, LPWSTR wszFileName) 441 { 442 FORMATRANGE fr; 443 DOCINFOW di; 444 HWND hEditorWnd = GetDlgItem(pd->hwndOwner, IDC_EDITOR); 445 int printedPages = 0; 446 447 fr.hdc = pd->hDC; 448 fr.hdcTarget = pd->hDC; 449 450 fr.rc = get_print_rect(fr.hdc); 451 SetRect(&fr.rcPage, 0, 0, fr.rc.right + margins.right, fr.rc.bottom + margins.bottom); 452 453 ZeroMemory(&di, sizeof(di)); 454 di.cbSize = sizeof(di); 455 di.lpszDocName = wszFileName; 456 457 if(pd->Flags & PD_PRINTTOFILE) 458 { 459 di.lpszOutput = dialog_print_to_file(pd->hwndOwner); 460 if(!di.lpszOutput) 461 return; 462 } 463 464 if(pd->Flags & PD_SELECTION) 465 { 466 SendMessageW(hEditorWnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg); 467 } else 468 { 469 GETTEXTLENGTHEX gt; 470 gt.flags = GTL_DEFAULT; 471 gt.codepage = 1200; 472 fr.chrg.cpMin = 0; 473 fr.chrg.cpMax = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0); 474 475 if(pd->Flags & PD_PAGENUMS) 476 char_from_pagenum(hEditorWnd, &fr, pd->nToPage); 477 } 478 479 StartDocW(fr.hdc, &di); 480 do 481 { 482 if(StartPage(fr.hdc) <= 0) 483 break; 484 485 fr.chrg.cpMin = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr); 486 487 if(EndPage(fr.hdc) <= 0) 488 break; 489 490 printedPages++; 491 if((pd->Flags & PD_PAGENUMS) && (printedPages > (pd->nToPage - pd->nFromPage))) 492 break; 493 } 494 while(fr.chrg.cpMin && fr.chrg.cpMin < fr.chrg.cpMax); 495 496 EndDoc(fr.hdc); 497 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0); 498 } 499 500 void dialog_printsetup(HWND hMainWnd) 501 { 502 PAGESETUPDLGW ps; 503 504 ZeroMemory(&ps, sizeof(ps)); 505 ps.lStructSize = sizeof(ps); 506 ps.hwndOwner = hMainWnd; 507 ps.Flags = PSD_INHUNDREDTHSOFMILLIMETERS | PSD_MARGINS; 508 SetRect(&ps.rtMargin, twips_to_centmm(margins.left), twips_to_centmm(margins.top), 509 twips_to_centmm(margins.right), twips_to_centmm(margins.bottom)); 510 ps.hDevMode = devMode; 511 ps.hDevNames = devNames; 512 513 if(PageSetupDlgW(&ps)) 514 { 515 SetRect(&margins, centmm_to_twips(ps.rtMargin.left), centmm_to_twips(ps.rtMargin.top), 516 centmm_to_twips(ps.rtMargin.right), centmm_to_twips(ps.rtMargin.bottom)); 517 devMode = ps.hDevMode; 518 devNames = ps.hDevNames; 519 update_ruler(get_ruler_wnd(hMainWnd)); 520 } 521 } 522 523 void get_default_printer_opts(void) 524 { 525 PRINTDLGW pd; 526 ZeroMemory(&pd, sizeof(pd)); 527 528 ZeroMemory(&pd, sizeof(pd)); 529 pd.lStructSize = sizeof(pd); 530 pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT; 531 pd.hDevMode = devMode; 532 533 PrintDlgW(&pd); 534 535 devMode = pd.hDevMode; 536 devNames = pd.hDevNames; 537 } 538 539 void print_quick(HWND hMainWnd, LPWSTR wszFileName) 540 { 541 PRINTDLGW pd; 542 543 ZeroMemory(&pd, sizeof(pd)); 544 pd.hwndOwner = hMainWnd; 545 pd.hDC = make_dc(); 546 547 print(&pd, wszFileName); 548 DeleteDC(pd.hDC); 549 } 550 551 void dialog_print(HWND hMainWnd, LPWSTR wszFileName) 552 { 553 PRINTDLGW pd; 554 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); 555 int from = 0; 556 int to = 0; 557 558 ZeroMemory(&pd, sizeof(pd)); 559 pd.lStructSize = sizeof(pd); 560 pd.hwndOwner = hMainWnd; 561 pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; 562 pd.nMinPage = 1; 563 pd.nMaxPage = -1; 564 pd.hDevMode = devMode; 565 pd.hDevNames = devNames; 566 567 SendMessageW(hEditorWnd, EM_GETSEL, (WPARAM)&from, (LPARAM)&to); 568 if(from == to) 569 pd.Flags |= PD_NOSELECTION; 570 571 if(PrintDlgW(&pd)) 572 { 573 devMode = pd.hDevMode; 574 devNames = pd.hDevNames; 575 print(&pd, wszFileName); 576 update_ruler(get_ruler_wnd(hMainWnd)); 577 } 578 } 579 580 static void preview_bar_show(HWND hMainWnd, BOOL show) 581 { 582 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); 583 int i; 584 585 if(show) 586 { 587 REBARBANDINFOW rb; 588 HWND hStatic; 589 UINT num_pages_string = preview.pages_shown > 1 ? STRING_PREVIEW_ONEPAGE : 590 STRING_PREVIEW_TWOPAGES; 591 592 AddTextButton(hReBar, STRING_PREVIEW_PRINT, ID_PRINT, BANDID_PREVIEW_BTN1); 593 AddTextButton(hReBar, STRING_PREVIEW_NEXTPAGE, ID_PREVIEW_NEXTPAGE, BANDID_PREVIEW_BTN2); 594 AddTextButton(hReBar, STRING_PREVIEW_PREVPAGE, ID_PREVIEW_PREVPAGE, BANDID_PREVIEW_BTN3); 595 AddTextButton(hReBar, num_pages_string, ID_PREVIEW_NUMPAGES, BANDID_PREVIEW_BTN4); 596 AddTextButton(hReBar, STRING_PREVIEW_ZOOMIN, ID_PREVIEW_ZOOMIN, BANDID_PREVIEW_BTN5); 597 AddTextButton(hReBar, STRING_PREVIEW_ZOOMOUT, ID_PREVIEW_ZOOMOUT, BANDID_PREVIEW_BTN6); 598 AddTextButton(hReBar, STRING_PREVIEW_CLOSE, ID_FILE_EXIT, BANDID_PREVIEW_BTN7); 599 600 hStatic = CreateWindowW(WC_STATICW, NULL, 601 WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, 602 hReBar, NULL, NULL, NULL); 603 604 rb.cbSize = REBARBANDINFOW_V6_SIZE; 605 rb.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_ID; 606 rb.fStyle = RBBS_NOGRIPPER | RBBS_VARIABLEHEIGHT; 607 rb.hwndChild = hStatic; 608 rb.cyChild = rb.cyMinChild = 22; 609 rb.cx = rb.cxMinChild = 90; 610 rb.cxIdeal = 100; 611 rb.wID = BANDID_PREVIEW_BUFFER; 612 613 SendMessageW(hReBar, RB_INSERTBANDW, -1, (LPARAM)&rb); 614 } else 615 { 616 for(i = 0; i <= PREVIEW_BUTTONS; i++) 617 SendMessageW(hReBar, RB_DELETEBAND, SendMessageW(hReBar, RB_IDTOINDEX, BANDID_PREVIEW_BTN1+i, 0), 0); 618 } 619 } 620 621 static const int min_spacing = 10; 622 623 static void update_preview_scrollbars(HWND hwndPreview, RECT *window) 624 { 625 SCROLLINFO sbi; 626 sbi.cbSize = sizeof(sbi); 627 sbi.fMask = SIF_PAGE|SIF_RANGE; 628 sbi.nMin = 0; 629 if (preview.zoomlevel == 0) 630 { 631 /* Hide scrollbars when zoomed out. */ 632 sbi.nMax = 0; 633 sbi.nPage = window->right; 634 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE); 635 sbi.nPage = window->bottom; 636 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE); 637 } else { 638 sbi.nMax = preview.bmScaledSize.cx * preview.pages_shown + 639 min_spacing * (preview.pages_shown + 1); 640 sbi.nPage = window->right; 641 SetScrollInfo(hwndPreview, SB_HORZ, &sbi, TRUE); 642 /* Change in the horizontal scrollbar visibility affects the 643 * client rect, so update the client rect. */ 644 GetClientRect(hwndPreview, window); 645 sbi.nMax = preview.bmScaledSize.cy + min_spacing * 2; 646 sbi.nPage = window->bottom; 647 SetScrollInfo(hwndPreview, SB_VERT, &sbi, TRUE); 648 } 649 } 650 651 static void update_preview_sizes(HWND hwndPreview, BOOL zoomLevelUpdated) 652 { 653 RECT window; 654 655 GetClientRect(hwndPreview, &window); 656 657 /* The zoom ratio isn't updated for partial zoom because of resizing the window. */ 658 if (zoomLevelUpdated || preview.zoomlevel != 1) 659 { 660 float ratio, ratioHeight, ratioWidth; 661 if (preview.zoomlevel == 2) 662 { 663 ratio = 1.0; 664 } else { 665 ratioHeight = (window.bottom - min_spacing * 2) / (float)preview.bmSize.cy; 666 667 ratioWidth = (float)(window.right - 668 min_spacing * (preview.pages_shown + 1)) / 669 (preview.pages_shown * preview.bmSize.cx); 670 671 if(ratioWidth > ratioHeight) 672 ratio = ratioHeight; 673 else 674 ratio = ratioWidth; 675 676 if (preview.zoomlevel == 1) 677 ratio += (1.0 - ratio) / 2; 678 } 679 preview.zoomratio = ratio; 680 } 681 682 preview.bmScaledSize.cx = preview.bmSize.cx * preview.zoomratio; 683 preview.bmScaledSize.cy = preview.bmSize.cy * preview.zoomratio; 684 685 preview.spacing.cy = max(min_spacing, (window.bottom - preview.bmScaledSize.cy) / 2); 686 687 preview.spacing.cx = (window.right - 688 preview.bmScaledSize.cx * preview.pages_shown) / 689 (preview.pages_shown + 1); 690 if (preview.spacing.cx < min_spacing) 691 preview.spacing.cx = min_spacing; 692 693 update_preview_scrollbars(hwndPreview, &window); 694 } 695 696 static void draw_margin_lines(HDC hdc, int x, int y, float ratio) 697 { 698 HPEN hPen, oldPen; 699 SIZE dpi; 700 RECT page_margin = preview.rcPage; 701 702 dpi.cx = GetDeviceCaps(hdc, LOGPIXELSX); 703 dpi.cy = GetDeviceCaps(hdc, LOGPIXELSY); 704 705 SetRect(&page_margin, preview.rcPage.left + margins.left, preview.rcPage.top + margins.top, 706 preview.rcPage.right - margins.right, preview.rcPage.bottom - margins.bottom); 707 708 page_margin.left = (int)((float)twips_to_pixels(page_margin.left, dpi.cx) * ratio); 709 page_margin.top = (int)((float)twips_to_pixels(page_margin.top, dpi.cy) * ratio); 710 page_margin.bottom = (int)((float)twips_to_pixels(page_margin.bottom, dpi.cy) * ratio); 711 page_margin.right = (int)((float)twips_to_pixels(page_margin.right, dpi.cx) * ratio); 712 713 OffsetRect(&page_margin, x, y); 714 715 hPen = CreatePen(PS_DOT, 1, RGB(0,0,0)); 716 oldPen = SelectObject(hdc, hPen); 717 718 MoveToEx(hdc, x, page_margin.top, NULL); 719 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.top); 720 MoveToEx(hdc, x, page_margin.bottom, NULL); 721 LineTo(hdc, x + preview.bmScaledSize.cx, page_margin.bottom); 722 723 MoveToEx(hdc, page_margin.left, y, NULL); 724 LineTo(hdc, page_margin.left, y + preview.bmScaledSize.cy); 725 MoveToEx(hdc, page_margin.right, y, NULL); 726 LineTo(hdc, page_margin.right, y + preview.bmScaledSize.cy); 727 728 SelectObject(hdc, oldPen); 729 DeleteObject(hPen); 730 } 731 732 static BOOL is_last_preview_page(int page) 733 { 734 return preview.pageEnds[page - 1] >= preview.textlength; 735 } 736 737 void init_preview(HWND hMainWnd, LPWSTR wszFileName) 738 { 739 HINSTANCE hInstance = GetModuleHandleW(0); 740 preview.page = 1; 741 preview.hdc = 0; 742 preview.hdc2 = 0; 743 preview.wszFileName = wszFileName; 744 preview.zoomratio = 0; 745 preview.zoomlevel = 0; 746 preview_bar_show(hMainWnd, TRUE); 747 748 CreateWindowExW(0, wszPreviewWndClass, NULL, 749 WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL, 750 0, 0, 200, 10, hMainWnd, (HMENU)IDC_PREVIEW, hInstance, NULL); 751 } 752 753 void close_preview(HWND hMainWnd) 754 { 755 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW); 756 preview.window.right = 0; 757 preview.window.bottom = 0; 758 preview.page = 0; 759 HeapFree(GetProcessHeap(), 0, preview.pageEnds); 760 preview.pageEnds = NULL; 761 preview.pageCapacity = 0; 762 if (preview.zoomlevel > 0) 763 preview.pages_shown = preview.saved_pages_shown; 764 if(preview.hdc) { 765 HBITMAP oldbm = GetCurrentObject(preview.hdc, OBJ_BITMAP); 766 DeleteDC(preview.hdc); 767 DeleteObject(oldbm); 768 preview.hdc = NULL; 769 } 770 if(preview.hdc2) { 771 HBITMAP oldbm = GetCurrentObject(preview.hdc2, OBJ_BITMAP); 772 DeleteDC(preview.hdc2); 773 DeleteObject(oldbm); 774 preview.hdc2 = NULL; 775 } 776 777 preview_bar_show(hMainWnd, FALSE); 778 DestroyWindow(hwndPreview); 779 } 780 781 BOOL preview_isactive(void) 782 { 783 return preview.page != 0; 784 } 785 786 static void draw_preview(HWND hEditorWnd, FORMATRANGE* lpFr, RECT* paper, int page) 787 { 788 int bottom; 789 790 if (!preview.pageEnds) 791 { 792 preview.pageCapacity = 32; 793 preview.pageEnds = HeapAlloc(GetProcessHeap(), 0, 794 sizeof(int) * preview.pageCapacity); 795 if (!preview.pageEnds) return; 796 } else if (page >= preview.pageCapacity) { 797 int *new_buffer; 798 new_buffer = HeapReAlloc(GetProcessHeap(), 0, preview.pageEnds, 799 sizeof(int) * preview.pageCapacity * 2); 800 if (!new_buffer) return; 801 preview.pageCapacity *= 2; 802 preview.pageEnds = new_buffer; 803 } 804 805 FillRect(lpFr->hdc, paper, GetStockObject(WHITE_BRUSH)); 806 if (page > 1 && is_last_preview_page(page - 1)) return; 807 lpFr->chrg.cpMin = page <= 1 ? 0 : preview.pageEnds[page-2]; 808 bottom = lpFr->rc.bottom; 809 preview.pageEnds[page-1] = SendMessageW(hEditorWnd, EM_FORMATRANGE, TRUE, (LPARAM)lpFr); 810 811 /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in, 812 * but we want to keep the original for drawing margins */ 813 lpFr->rc.bottom = bottom; 814 SendMessageW(hEditorWnd, EM_FORMATRANGE, FALSE, 0); 815 } 816 817 static void update_preview_buttons(HWND hMainWnd) 818 { 819 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); 820 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_PREVPAGE), preview.page > 1); 821 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NEXTPAGE), 822 !is_last_preview_page(preview.page) && 823 !is_last_preview_page(preview.page + preview.pages_shown - 1)); 824 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), 825 preview.pages_shown > 1 || 826 (!is_last_preview_page(1) && preview.zoomlevel == 0)); 827 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMIN), preview.zoomlevel < 2); 828 EnableWindow(GetDlgItem(hReBar, ID_PREVIEW_ZOOMOUT), preview.zoomlevel > 0); 829 } 830 831 static LRESULT print_preview(HWND hwndPreview) 832 { 833 HPEN hPen, oldPen; 834 HDC hdc; 835 HRGN back_rgn, excl_rgn; 836 RECT window, background; 837 PAINTSTRUCT ps; 838 int x, y; 839 840 hdc = BeginPaint(hwndPreview, &ps); 841 GetClientRect(hwndPreview, &window); 842 back_rgn = CreateRectRgnIndirect(&window); 843 844 x = preview.spacing.cx - GetScrollPos(hwndPreview, SB_HORZ); 845 y = preview.spacing.cy - GetScrollPos(hwndPreview, SB_VERT); 846 847 /* draw page outlines */ 848 hPen = CreatePen(PS_SOLID|PS_INSIDEFRAME, 2, RGB(0,0,0)); 849 oldPen = SelectObject(hdc, hPen); 850 SetRect(&background, x - 2, y - 2, x + preview.bmScaledSize.cx + 2, 851 y + preview.bmScaledSize.cy + 2); 852 Rectangle(hdc, background.left, background.top, 853 background.right, background.bottom); 854 excl_rgn = CreateRectRgnIndirect(&background); 855 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF); 856 if(preview.pages_shown > 1) 857 { 858 background.left += preview.bmScaledSize.cx + preview.spacing.cx; 859 background.right += preview.bmScaledSize.cx + preview.spacing.cx; 860 Rectangle(hdc, background.left, background.top, 861 background.right, background.bottom); 862 SetRectRgn(excl_rgn, background.left, background.top, 863 background.right, background.bottom); 864 CombineRgn(back_rgn, back_rgn, excl_rgn, RGN_DIFF); 865 } 866 SelectObject(hdc, oldPen); 867 DeleteObject(hPen); 868 FillRgn(hdc, back_rgn, GetStockObject(GRAY_BRUSH)); 869 DeleteObject(excl_rgn); 870 DeleteObject(back_rgn); 871 872 StretchBlt(hdc, x, y, preview.bmScaledSize.cx, preview.bmScaledSize.cy, 873 preview.hdc, 0, 0, preview.bmSize.cx, preview.bmSize.cy, SRCCOPY); 874 875 draw_margin_lines(hdc, x, y, preview.zoomratio); 876 877 if(preview.pages_shown > 1) 878 { 879 if (!is_last_preview_page(preview.page)) { 880 x += preview.spacing.cx + preview.bmScaledSize.cx; 881 StretchBlt(hdc, x, y, 882 preview.bmScaledSize.cx, preview.bmScaledSize.cy, 883 preview.hdc2, 0, 0, 884 preview.bmSize.cx, preview.bmSize.cy, SRCCOPY); 885 886 draw_margin_lines(hdc, x, y, preview.zoomratio); 887 } else { 888 InflateRect(&background, -2, -2); 889 FillRect(hdc, &background, GetStockObject(WHITE_BRUSH)); 890 } 891 } 892 893 preview.window = window; 894 895 EndPaint(hwndPreview, &ps); 896 897 return 0; 898 } 899 900 static void update_preview_statusbar(HWND hMainWnd) 901 { 902 HWND hStatusbar = GetDlgItem(hMainWnd, IDC_STATUSBAR); 903 HINSTANCE hInst = GetModuleHandleW(0); 904 WCHAR *p; 905 WCHAR wstr[MAX_STRING_LEN]; 906 907 p = wstr; 908 if (preview.pages_shown < 2 || is_last_preview_page(preview.page)) 909 { 910 static const WCHAR fmt[] = {' ','%','d','\0'}; 911 p += LoadStringW(hInst, STRING_PREVIEW_PAGE, wstr, MAX_STRING_LEN); 912 wsprintfW(p, fmt, preview.page); 913 } else { 914 static const WCHAR fmt[] = {' ','%','d','-','%','d','\0'}; 915 p += LoadStringW(hInst, STRING_PREVIEW_PAGES, wstr, MAX_STRING_LEN); 916 wsprintfW(p, fmt, preview.page, preview.page + 1); 917 } 918 SetWindowTextW(hStatusbar, wstr); 919 } 920 921 /* Update for page changes. */ 922 static void update_preview(HWND hMainWnd) 923 { 924 RECT paper; 925 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); 926 HWND hwndPreview = GetDlgItem(hMainWnd, IDC_PREVIEW); 927 HBITMAP hBitmapCapture; 928 FORMATRANGE fr; 929 HDC hdc = GetDC(hwndPreview); 930 931 fr.hdcTarget = make_dc(); 932 fr.rc = fr.rcPage = preview.rcPage; 933 fr.rc.left += margins.left; 934 fr.rc.top += margins.top; 935 fr.rc.bottom -= margins.bottom; 936 fr.rc.right -= margins.right; 937 938 fr.chrg.cpMin = 0; 939 fr.chrg.cpMax = preview.textlength; 940 941 SetRect(&paper, 0, 0, preview.bmSize.cx, preview.bmSize.cy); 942 943 if (!preview.hdc) { 944 preview.hdc = CreateCompatibleDC(hdc); 945 hBitmapCapture = CreateCompatibleBitmap(hdc, preview.bmSize.cx, preview.bmSize.cy); 946 SelectObject(preview.hdc, hBitmapCapture); 947 } 948 949 fr.hdc = preview.hdc; 950 draw_preview(hEditorWnd, &fr, &paper, preview.page); 951 952 if(preview.pages_shown > 1) 953 { 954 if (!preview.hdc2) 955 { 956 preview.hdc2 = CreateCompatibleDC(hdc); 957 hBitmapCapture = CreateCompatibleBitmap(hdc, 958 preview.bmSize.cx, 959 preview.bmSize.cy); 960 SelectObject(preview.hdc2, hBitmapCapture); 961 } 962 963 fr.hdc = preview.hdc2; 964 draw_preview(hEditorWnd, &fr, &fr.rcPage, preview.page + 1); 965 } 966 DeleteDC(fr.hdcTarget); 967 ReleaseDC(hwndPreview, hdc); 968 969 InvalidateRect(hwndPreview, NULL, FALSE); 970 update_preview_buttons(hMainWnd); 971 update_preview_statusbar(hMainWnd); 972 } 973 974 static void toggle_num_pages(HWND hMainWnd) 975 { 976 HWND hReBar = GetDlgItem(hMainWnd, IDC_REBAR); 977 WCHAR name[MAX_STRING_LEN]; 978 HINSTANCE hInst = GetModuleHandleW(0); 979 int nPreviewPages; 980 981 preview.pages_shown = preview.pages_shown > 1 ? 1 : 2; 982 983 nPreviewPages = preview.zoomlevel > 0 ? preview.saved_pages_shown : 984 preview.pages_shown; 985 986 LoadStringW(hInst, nPreviewPages > 1 ? STRING_PREVIEW_ONEPAGE : 987 STRING_PREVIEW_TWOPAGES, 988 name, MAX_STRING_LEN); 989 990 SetWindowTextW(GetDlgItem(hReBar, ID_PREVIEW_NUMPAGES), name); 991 update_preview_sizes(GetDlgItem(hMainWnd, IDC_PREVIEW), TRUE); 992 update_preview(hMainWnd); 993 } 994 995 /* Returns the page shown that the point is in (1 or 2) or 0 if the point 996 * isn't inside either page */ 997 static int preview_page_hittest(POINT pt) 998 { 999 RECT rc; 1000 rc.left = preview.spacing.cx; 1001 rc.right = rc.left + preview.bmScaledSize.cx; 1002 rc.top = preview.spacing.cy; 1003 rc.bottom = rc.top + preview.bmScaledSize.cy; 1004 if (PtInRect(&rc, pt)) 1005 return 1; 1006 1007 if (preview.pages_shown <= 1) 1008 return 0; 1009 1010 rc.left += preview.bmScaledSize.cx + preview.spacing.cx; 1011 rc.right += preview.bmScaledSize.cx + preview.spacing.cx; 1012 if (PtInRect(&rc, pt)) 1013 return is_last_preview_page(preview.page) ? 1 : 2; 1014 1015 return 0; 1016 } 1017 1018 LRESULT CALLBACK preview_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1019 { 1020 switch(msg) 1021 { 1022 case WM_CREATE: 1023 { 1024 HWND hMainWnd = GetParent(hWnd); 1025 HWND hEditorWnd = GetDlgItem(hMainWnd, IDC_EDITOR); 1026 FORMATRANGE fr; 1027 GETTEXTLENGTHEX gt = {GTL_DEFAULT, 1200}; 1028 HDC hdc = GetDC(hWnd); 1029 HDC hdcTarget = make_dc(); 1030 1031 fr.rc = preview.rcPage = get_print_rect(hdcTarget); 1032 preview.rcPage.bottom += margins.bottom; 1033 preview.rcPage.right += margins.right; 1034 preview.rcPage.top = preview.rcPage.left = 0; 1035 fr.rcPage = preview.rcPage; 1036 1037 preview.bmSize.cx = twips_to_pixels(preview.rcPage.right, GetDeviceCaps(hdc, LOGPIXELSX)); 1038 preview.bmSize.cy = twips_to_pixels(preview.rcPage.bottom, GetDeviceCaps(hdc, LOGPIXELSY)); 1039 1040 preview.textlength = SendMessageW(hEditorWnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0); 1041 1042 fr.hdc = CreateCompatibleDC(hdc); 1043 fr.hdcTarget = hdcTarget; 1044 fr.chrg.cpMin = 0; 1045 fr.chrg.cpMax = preview.textlength; 1046 DeleteDC(fr.hdc); 1047 DeleteDC(hdcTarget); 1048 ReleaseDC(hWnd, hdc); 1049 1050 update_preview_sizes(hWnd, TRUE); 1051 update_preview(hMainWnd); 1052 break; 1053 } 1054 1055 case WM_PAINT: 1056 return print_preview(hWnd); 1057 1058 case WM_SIZE: 1059 { 1060 update_preview_sizes(hWnd, FALSE); 1061 InvalidateRect(hWnd, NULL, FALSE); 1062 break; 1063 } 1064 1065 case WM_VSCROLL: 1066 case WM_HSCROLL: 1067 { 1068 SCROLLINFO si; 1069 RECT rc; 1070 int nBar = (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ; 1071 int origPos; 1072 1073 GetClientRect(hWnd, &rc); 1074 si.cbSize = sizeof(si); 1075 si.fMask = SIF_ALL; 1076 GetScrollInfo(hWnd, nBar, &si); 1077 origPos = si.nPos; 1078 switch(LOWORD(wParam)) 1079 { 1080 case SB_TOP: /* == SB_LEFT */ 1081 si.nPos = si.nMin; 1082 break; 1083 case SB_BOTTOM: /* == SB_RIGHT */ 1084 si.nPos = si.nMax; 1085 break; 1086 case SB_LINEUP: /* == SB_LINELEFT */ 1087 si.nPos -= si.nPage / 10; 1088 break; 1089 case SB_LINEDOWN: /* == SB_LINERIGHT */ 1090 si.nPos += si.nPage / 10; 1091 break; 1092 case SB_PAGEUP: /* == SB_PAGELEFT */ 1093 si.nPos -= si.nPage; 1094 break; 1095 case SB_PAGEDOWN: /* SB_PAGERIGHT */ 1096 si.nPos += si.nPage; 1097 break; 1098 case SB_THUMBTRACK: 1099 si.nPos = si.nTrackPos; 1100 break; 1101 } 1102 si.fMask = SIF_POS; 1103 SetScrollInfo(hWnd, nBar, &si, TRUE); 1104 GetScrollInfo(hWnd, nBar, &si); 1105 if (si.nPos != origPos) 1106 { 1107 int amount = origPos - si.nPos; 1108 if (msg == WM_VSCROLL) 1109 ScrollWindow(hWnd, 0, amount, NULL, NULL); 1110 else 1111 ScrollWindow(hWnd, amount, 0, NULL, NULL); 1112 } 1113 return 0; 1114 } 1115 1116 case WM_SETCURSOR: 1117 { 1118 POINT pt; 1119 RECT rc; 1120 int bHittest = 0; 1121 DWORD messagePos = GetMessagePos(); 1122 pt.x = (short)LOWORD(messagePos); 1123 pt.y = (short)HIWORD(messagePos); 1124 ScreenToClient(hWnd, &pt); 1125 1126 GetClientRect(hWnd, &rc); 1127 if (PtInRect(&rc, pt)) 1128 { 1129 pt.x += GetScrollPos(hWnd, SB_HORZ); 1130 pt.y += GetScrollPos(hWnd, SB_VERT); 1131 bHittest = preview_page_hittest(pt); 1132 } 1133 1134 if (bHittest) 1135 SetCursor(LoadCursorW(GetModuleHandleW(0), 1136 MAKEINTRESOURCEW(IDC_ZOOM))); 1137 else 1138 SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW)); 1139 1140 return TRUE; 1141 } 1142 1143 case WM_LBUTTONDOWN: 1144 { 1145 int page; 1146 POINT pt; 1147 pt.x = (short)LOWORD(lParam) + GetScrollPos(hWnd, SB_HORZ); 1148 pt.y = (short)HIWORD(lParam) + GetScrollPos(hWnd, SB_VERT); 1149 if ((page = preview_page_hittest(pt)) > 0) 1150 { 1151 HWND hMainWnd = GetParent(hWnd); 1152 1153 /* Convert point from client coordinate to unzoomed page 1154 * coordinate. */ 1155 pt.x -= preview.spacing.cx; 1156 if (page > 1) 1157 pt.x -= preview.bmScaledSize.cx + preview.spacing.cx; 1158 pt.y -= preview.spacing.cy; 1159 pt.x /= preview.zoomratio; 1160 pt.y /= preview.zoomratio; 1161 1162 if (preview.zoomlevel == 0) 1163 preview.saved_pages_shown = preview.pages_shown; 1164 preview.zoomlevel = (preview.zoomlevel + 1) % 3; 1165 preview.zoomratio = 0; 1166 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1) 1167 { 1168 toggle_num_pages(hMainWnd); 1169 } else if (preview.pages_shown > 1) { 1170 if (page >= 2) preview.page++; 1171 toggle_num_pages(hMainWnd); 1172 } else { 1173 update_preview_sizes(hWnd, TRUE); 1174 InvalidateRect(hWnd, NULL, FALSE); 1175 update_preview_buttons(hMainWnd); 1176 } 1177 1178 if (preview.zoomlevel > 0) { 1179 SCROLLINFO si; 1180 /* Convert the coordinate back to client coordinate. */ 1181 pt.x *= preview.zoomratio; 1182 pt.y *= preview.zoomratio; 1183 pt.x += preview.spacing.cx; 1184 pt.y += preview.spacing.cy; 1185 /* Scroll to center view at that point on the page */ 1186 si.cbSize = sizeof(si); 1187 si.fMask = SIF_PAGE; 1188 GetScrollInfo(hWnd, SB_HORZ, &si); 1189 pt.x -= si.nPage / 2; 1190 SetScrollPos(hWnd, SB_HORZ, pt.x, TRUE); 1191 GetScrollInfo(hWnd, SB_VERT, &si); 1192 pt.y -= si.nPage / 2; 1193 SetScrollPos(hWnd, SB_VERT, pt.y, TRUE); 1194 } 1195 } 1196 } 1197 1198 default: 1199 return DefWindowProcW(hWnd, msg, wParam, lParam); 1200 } 1201 1202 return 0; 1203 } 1204 1205 LRESULT preview_command(HWND hWnd, WPARAM wParam) 1206 { 1207 switch(LOWORD(wParam)) 1208 { 1209 case ID_FILE_EXIT: 1210 PostMessageW(hWnd, WM_CLOSE, 0, 0); 1211 break; 1212 1213 case ID_PREVIEW_NEXTPAGE: 1214 case ID_PREVIEW_PREVPAGE: 1215 { 1216 if(LOWORD(wParam) == ID_PREVIEW_NEXTPAGE) 1217 preview.page++; 1218 else 1219 preview.page--; 1220 1221 update_preview(hWnd); 1222 } 1223 break; 1224 1225 case ID_PREVIEW_NUMPAGES: 1226 toggle_num_pages(hWnd); 1227 break; 1228 1229 case ID_PREVIEW_ZOOMIN: 1230 if (preview.zoomlevel < 2) 1231 { 1232 if (preview.zoomlevel == 0) 1233 preview.saved_pages_shown = preview.pages_shown; 1234 preview.zoomlevel++; 1235 preview.zoomratio = 0; 1236 if (preview.pages_shown > 1) 1237 { 1238 /* Forced switch to one page when zooming in. */ 1239 toggle_num_pages(hWnd); 1240 } else { 1241 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW); 1242 update_preview_sizes(hwndPreview, TRUE); 1243 InvalidateRect(hwndPreview, NULL, FALSE); 1244 update_preview_buttons(hWnd); 1245 } 1246 } 1247 break; 1248 1249 case ID_PREVIEW_ZOOMOUT: 1250 if (preview.zoomlevel > 0) 1251 { 1252 HWND hwndPreview = GetDlgItem(hWnd, IDC_PREVIEW); 1253 preview.zoomlevel--; 1254 preview.zoomratio = 0; 1255 if (preview.zoomlevel == 0 && preview.saved_pages_shown > 1) { 1256 toggle_num_pages(hWnd); 1257 } else { 1258 update_preview_sizes(hwndPreview, TRUE); 1259 InvalidateRect(hwndPreview, NULL, FALSE); 1260 update_preview_buttons(hWnd); 1261 } 1262 } 1263 break; 1264 1265 case ID_PRINT: 1266 dialog_print(hWnd, preview.wszFileName); 1267 SendMessageW(hWnd, WM_CLOSE, 0, 0); 1268 break; 1269 } 1270 1271 return 0; 1272 } 1273