1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.ComponentModel; 23 using System.Diagnostics; 24 using System.Drawing; 25 using System.Drawing.Drawing2D; 26 using System.Drawing.Imaging; 27 using System.IO; 28 using System.Text; 29 using System.Windows.Forms; 30 31 using KeePass.App; 32 using KeePass.Native; 33 using KeePass.Resources; 34 using KeePass.UI; 35 using KeePass.Util; 36 37 using KeePassLib; 38 using KeePassLib.Utility; 39 40 using NativeLib = KeePassLib.Native.NativeLib; 41 42 namespace KeePass.Forms 43 { 44 public partial class DataViewerForm : Form 45 { 46 private string m_strDataDesc = string.Empty; 47 private byte[] m_pbData = null; 48 49 private bool m_bInitializing = true; 50 51 private uint m_uStartOffset = 0; 52 private BinaryDataClass m_bdc = BinaryDataClass.Unknown; 53 54 private readonly string m_strViewerHex = KPRes.HexViewer; 55 private readonly string m_strViewerText = KPRes.TextViewer; 56 private readonly string m_strViewerImage = KPRes.ImageViewer; 57 private readonly string m_strViewerWeb = KPRes.WebBrowser; 58 59 private readonly string m_strZoomAuto = KPRes.Auto; 60 61 // Link on Windows, hint on Linux (linkifying only works on Windows) 62 private readonly string m_strDataExpand = (NativeLib.IsUnix() ? 63 ("--- " + KPRes.More + " ---") : 64 ("--- " + KPRes.ShowMore + " (" + KPRes.TimeReq + ") ---")); 65 private bool m_bDataExpanded = false; 66 67 private string m_strInitialFormRect = string.Empty; 68 private RichTextBoxContextMenu m_ctxText = new RichTextBoxContextMenu(); 69 70 private Image m_img = null; 71 private Image m_imgResized = null; 72 73 public event EventHandler<DvfContextEventArgs> DvfInit; 74 public event EventHandler<DvfContextEventArgs> DvfUpdating; 75 public event EventHandler<DvfContextEventArgs> DvfRelease; 76 SupportsDataType(BinaryDataClass bdc)77 public static bool SupportsDataType(BinaryDataClass bdc) 78 { 79 return ((bdc == BinaryDataClass.Text) || (bdc == BinaryDataClass.RichText) || 80 (bdc == BinaryDataClass.Image) || (bdc == BinaryDataClass.WebDocument)); 81 } 82 InitEx(string strDataDesc, byte[] pbData)83 public void InitEx(string strDataDesc, byte[] pbData) 84 { 85 if(strDataDesc != null) m_strDataDesc = strDataDesc; 86 87 m_pbData = pbData; 88 } 89 DataViewerForm()90 public DataViewerForm() 91 { 92 InitializeComponent(); 93 94 // GlobalWindowManager.InitializeForm checks docked controls 95 m_rtbText.Dock = DockStyle.Fill; 96 m_pnlImageViewer.Dock = DockStyle.Fill; 97 m_picBox.Dock = DockStyle.Fill; 98 m_webBrowser.Dock = DockStyle.Fill; 99 100 GlobalWindowManager.InitializeForm(this); 101 } 102 OnFormLoad(object sender, EventArgs e)103 private void OnFormLoad(object sender, EventArgs e) 104 { 105 Debug.Assert(m_pbData != null); 106 if(m_pbData == null) throw new InvalidOperationException(); 107 108 m_bInitializing = true; 109 110 GlobalWindowManager.AddWindow(this); 111 112 this.Icon = AppIcons.Default; 113 this.DoubleBuffered = true; 114 115 string strTitle = KPRes.DataViewerKP; 116 if(m_strDataDesc.Length > 0) 117 strTitle = m_strDataDesc + " - " + strTitle; 118 this.Text = strTitle; 119 120 m_strInitialFormRect = UIUtil.SetWindowScreenRectEx(this, 121 Program.Config.UI.DataViewerRect); 122 123 m_tssStatusMain.Text = KPRes.Ready; 124 m_ctxText.Attach(m_rtbText, this); 125 126 m_tslEncoding.Text = KPRes.Encoding + ":"; 127 128 foreach(StrEncodingInfo seiEnum in StrUtil.Encodings) 129 { 130 m_tscEncoding.Items.Add(seiEnum.Name); 131 } 132 133 StrEncodingInfo seiGuess = BinaryDataClassifier.GetStringEncoding( 134 m_pbData, out m_uStartOffset); 135 136 int iSel = 0; 137 if(seiGuess != null) 138 iSel = Math.Max(m_tscEncoding.FindStringExact(seiGuess.Name), 0); 139 m_tscEncoding.SelectedIndex = iSel; 140 141 m_tslZoom.Text = KPRes.Zoom + ":"; 142 143 // Required for mouse wheel handling 144 Debug.Assert(m_tscZoom.DropDownStyle == ComboBoxStyle.DropDownList); 145 146 m_tscZoom.Items.Add(m_strZoomAuto); 147 int[] vZooms = new int[] { 10, 25, 50, 75, 100, 125, 150, 200, 400 }; 148 foreach(int iZoom in vZooms) 149 m_tscZoom.Items.Add(iZoom.ToString() + "%"); 150 m_tscZoom.SelectedIndex = 0; 151 152 m_tsbZoomOut.ToolTipText = KPRes.Zoom + " - (" + UIUtil.GetKeysName( 153 Keys.Control | Keys.Subtract) + ")"; 154 m_tsbZoomIn.ToolTipText = KPRes.Zoom + " + (" + UIUtil.GetKeysName( 155 Keys.Control | Keys.Add) + ")"; 156 157 m_tslViewer.Text = KPRes.ShowIn + ":"; 158 159 m_tscViewers.Items.Add(m_strViewerHex); 160 m_tscViewers.Items.Add(m_strViewerText); 161 m_tscViewers.Items.Add(m_strViewerImage); 162 m_tscViewers.Items.Add(m_strViewerWeb); 163 164 m_bdc = BinaryDataClassifier.Classify(m_strDataDesc, m_pbData); 165 166 if((m_bdc == BinaryDataClass.Text) || (m_bdc == BinaryDataClass.RichText)) 167 m_tscViewers.SelectedIndex = 1; 168 else if(m_bdc == BinaryDataClass.Image) m_tscViewers.SelectedIndex = 2; 169 else if(m_bdc == BinaryDataClass.WebDocument) m_tscViewers.SelectedIndex = 3; 170 else m_tscViewers.SelectedIndex = 0; 171 172 if(this.DvfInit != null) 173 this.DvfInit(this, new DvfContextEventArgs(this, m_pbData, 174 m_strDataDesc, m_tscViewers)); 175 176 m_picBox.MouseWheel += this.OnPicBoxMouseWheel; 177 178 m_bInitializing = false; 179 UpdateDataView(); 180 } 181 OnRichTextBoxLinkClicked(object sender, LinkClickedEventArgs e)182 private void OnRichTextBoxLinkClicked(object sender, LinkClickedEventArgs e) 183 { 184 try 185 { 186 string strLink = e.LinkText; 187 if(string.IsNullOrEmpty(strLink)) { Debug.Assert(false); return; } 188 189 string strViewer = m_tscViewers.Text; 190 bool bTextViewer = ((strViewer == m_strViewerHex) || 191 (strViewer == m_strViewerText)); 192 193 if((strLink == m_strDataExpand) && bTextViewer) 194 { 195 m_bDataExpanded = true; 196 197 UpdateDataView(); 198 199 m_rtbText.Select(m_rtbText.TextLength, 0); 200 m_rtbText.ScrollToCaret(); 201 } 202 else WinUtil.OpenUrl(strLink, null); 203 } 204 catch(Exception) { } // ScrollToCaret might throw (but still works) 205 } 206 BinaryDataToString(bool bReplaceNulls, out bool bDecodedStringValid)207 private string BinaryDataToString(bool bReplaceNulls, out bool bDecodedStringValid) 208 { 209 string strEnc = m_tscEncoding.Text; 210 StrEncodingInfo sei = StrUtil.GetEncoding(strEnc); 211 212 try 213 { 214 string str = (sei.Encoding.GetString(m_pbData, (int)m_uStartOffset, 215 m_pbData.Length - (int)m_uStartOffset) ?? string.Empty); 216 217 bDecodedStringValid = StrUtil.IsValid(str); 218 219 if(bReplaceNulls) str = StrUtil.ReplaceNulls(str); 220 return str; 221 } 222 catch(Exception) { bDecodedStringValid = false; } 223 224 return string.Empty; 225 } 226 SetRtbData(string strData, bool bRtf, bool bFixedFont, bool bLinkify)227 private void SetRtbData(string strData, bool bRtf, bool bFixedFont, 228 bool bLinkify) 229 { 230 if(strData == null) { Debug.Assert(false); strData = string.Empty; } 231 232 m_rtbText.Clear(); // Clear formatting (esp. induced by Unicode) 233 234 if(bFixedFont) FontUtil.AssignDefaultMono(m_rtbText, false); 235 else FontUtil.AssignDefault(m_rtbText); 236 237 if(bRtf) m_rtbText.Rtf = StrUtil.RtfFix(strData); 238 else m_rtbText.Text = strData; 239 240 if(bLinkify) UIUtil.RtfLinkifyUrls(m_rtbText); 241 242 if(!bRtf) 243 { 244 Font f = (bFixedFont ? FontUtil.MonoFont : FontUtil.DefaultFont); 245 if(f != null) 246 { 247 m_rtbText.SelectAll(); 248 m_rtbText.SelectionFont = f; 249 } 250 else { Debug.Assert(false); } 251 } 252 253 m_rtbText.Select(0, 0); 254 } 255 UpdateHexView()256 private void UpdateHexView() 257 { 258 int cbData = (m_bDataExpanded ? m_pbData.Length : 259 Math.Min(m_pbData.Length, 16 * 256)); 260 261 const int cbGrp = 4; 262 const int cbLine = 16; 263 264 int iMaxAddrWidth = Convert.ToString(Math.Max(cbData - 1, 0), 16).Length; 265 266 int cbDataUp = cbData; 267 if((cbDataUp % cbLine) != 0) 268 cbDataUp = cbDataUp + cbLine - (cbDataUp % cbLine); 269 Debug.Assert(((cbDataUp % cbLine) == 0) && (cbDataUp >= cbData)); 270 271 StringBuilder sb = new StringBuilder(); 272 for(int i = 0; i < cbDataUp; ++i) 273 { 274 if((i % cbLine) == 0) 275 { 276 sb.Append(Convert.ToString(i, 16).ToUpper().PadLeft( 277 iMaxAddrWidth, '0')); 278 sb.Append(": "); 279 } 280 281 if(i < cbData) 282 { 283 byte bt = m_pbData[i]; 284 byte btHigh = (byte)(bt >> 4); 285 byte btLow = (byte)(bt & 0x0F); 286 if(btHigh >= 10) sb.Append((char)('A' + btHigh - 10)); 287 else sb.Append((char)('0' + btHigh)); 288 if(btLow >= 10) sb.Append((char)('A' + btLow - 10)); 289 else sb.Append((char)('0' + btLow)); 290 } 291 else sb.Append(" "); 292 293 if(((i + 1) % cbGrp) == 0) 294 sb.Append(' '); 295 296 if(((i + 1) % cbLine) == 0) 297 { 298 sb.Append(' '); 299 int iStart = i - cbLine + 1; 300 int iEndExcl = Math.Min(iStart + cbLine, cbData); 301 for(int j = iStart; j < iEndExcl; ++j) 302 sb.Append(StrUtil.ByteToSafeChar(m_pbData[j])); 303 sb.AppendLine(); 304 } 305 } 306 307 if(cbData < m_pbData.Length) sb.AppendLine(m_strDataExpand); 308 309 SetRtbData(sb.ToString(), false, true, false); 310 311 if(cbData < m_pbData.Length) LinkifyExpandLink(); 312 } 313 UpdateTextView()314 private void UpdateTextView() 315 { 316 bool bValid; 317 string strData = BinaryDataToString(true, out bValid); 318 319 bool bRtf = (m_bdc == BinaryDataClass.RichText); 320 321 const int ccInvMax = 1024; 322 bool bShorten = (!bValid && !bRtf && !m_bDataExpanded && 323 (strData.Length > ccInvMax)); 324 325 if(bShorten) 326 strData = strData.Substring(0, ccInvMax) + MessageService.NewLine + 327 m_strDataExpand + MessageService.NewLine; 328 329 SetRtbData(strData, bRtf, false, true); 330 331 if(bShorten) LinkifyExpandLink(); 332 } 333 LinkifyExpandLink()334 private void LinkifyExpandLink() 335 { 336 int i = m_rtbText.Text.LastIndexOf(m_strDataExpand); 337 if(i < 0) { Debug.Assert(false); return; } 338 339 m_rtbText.Select(i, m_strDataExpand.Length); 340 UIUtil.RtfSetSelectionLink(m_rtbText); 341 m_rtbText.Select(0, 0); 342 } 343 UpdateVisibility(string strViewer, bool bMakeVisible)344 private void UpdateVisibility(string strViewer, bool bMakeVisible) 345 { 346 if(string.IsNullOrEmpty(strViewer)) { Debug.Assert(false); return; } 347 348 if(!bMakeVisible) // Hide all except strViewer 349 { 350 if((strViewer != m_strViewerHex) && (strViewer != m_strViewerText)) 351 m_rtbText.Visible = false; 352 if(strViewer != m_strViewerImage) 353 { 354 m_picBox.Visible = false; 355 m_pnlImageViewer.Visible = false; 356 } 357 if(strViewer != m_strViewerWeb) 358 m_webBrowser.Visible = false; 359 } 360 else // Show strViewer 361 { 362 if((strViewer == m_strViewerHex) || (strViewer == m_strViewerText)) 363 m_rtbText.Visible = true; 364 else if(strViewer == m_strViewerImage) 365 { 366 m_pnlImageViewer.Visible = true; 367 m_picBox.Visible = true; 368 } 369 else if(strViewer == m_strViewerWeb) 370 m_webBrowser.Visible = true; 371 } 372 } 373 UpdateDataView()374 private void UpdateDataView() 375 { 376 if(m_bInitializing) return; 377 378 string strViewer = m_tscViewers.Text; 379 bool bText = ((strViewer == m_strViewerText) || 380 (strViewer == m_strViewerWeb)); 381 bool bImage = (strViewer == m_strViewerImage); 382 383 UpdateVisibility(strViewer, false); 384 m_tssSeparator0.Visible = (bText || bImage); 385 m_tslEncoding.Visible = m_tscEncoding.Visible = bText; 386 m_tslZoom.Visible = m_tscZoom.Visible = m_tsbZoomOut.Visible = 387 m_tsbZoomIn.Visible = bImage; 388 389 try 390 { 391 if(this.DvfUpdating != null) 392 { 393 DvfContextEventArgs args = new DvfContextEventArgs(this, 394 m_pbData, m_strDataDesc, m_tscViewers); 395 this.DvfUpdating(this, args); 396 if(args.Cancel) return; 397 } 398 399 if(strViewer == m_strViewerHex) 400 UpdateHexView(); 401 else if(strViewer == m_strViewerText) 402 UpdateTextView(); 403 else if(strViewer == m_strViewerImage) 404 { 405 if(m_img == null) m_img = GfxUtil.LoadImage(m_pbData); 406 UpdateImageView(); 407 } 408 else if(strViewer == m_strViewerWeb) 409 { 410 string strData = string.Empty; 411 if(m_bdc == BinaryDataClass.WebDocument) 412 { 413 bool bValid; 414 strData = BinaryDataToString(false, out bValid); 415 } 416 UIUtil.SetWebBrowserDocument(m_webBrowser, strData); 417 } 418 } 419 catch(Exception) { Debug.Assert(strViewer == m_strViewerImage); } 420 421 UpdateVisibility(strViewer, true); 422 } 423 OnViewersSelectedIndexChanged(object sender, EventArgs e)424 private void OnViewersSelectedIndexChanged(object sender, EventArgs e) 425 { 426 UpdateDataView(); 427 } 428 OnEncodingSelectedIndexChanged(object sender, EventArgs e)429 private void OnEncodingSelectedIndexChanged(object sender, EventArgs e) 430 { 431 UpdateDataView(); 432 } 433 OnFormSizeChanged(object sender, EventArgs e)434 private void OnFormSizeChanged(object sender, EventArgs e) 435 { 436 UpdateImageView(); 437 } 438 UpdateImageView()439 private void UpdateImageView() 440 { 441 if(m_img == null) return; 442 443 string strZoom = m_tscZoom.Text; 444 if(string.IsNullOrEmpty(strZoom) || (strZoom == m_strZoomAuto)) 445 { 446 m_pnlImageViewer.AutoScroll = false; 447 m_picBox.Dock = DockStyle.Fill; 448 m_picBox.Image = m_img; 449 450 if((m_img.Width > m_picBox.ClientSize.Width) || 451 (m_img.Height > m_picBox.ClientSize.Height)) 452 { 453 m_picBox.SizeMode = PictureBoxSizeMode.Zoom; 454 } 455 else m_picBox.SizeMode = PictureBoxSizeMode.CenterImage; 456 457 return; 458 } 459 460 if(!strZoom.EndsWith("%")) { Debug.Assert(false); return; } 461 462 int iZoom; 463 if(!int.TryParse(strZoom.Substring(0, strZoom.Length - 1), out iZoom)) 464 { 465 Debug.Assert(false); 466 return; 467 } 468 469 int cliW = m_pnlImageViewer.ClientRectangle.Width; 470 int cliH = m_pnlImageViewer.ClientRectangle.Height; 471 472 int dx = (m_img.Width * iZoom) / 100; 473 int dy = (m_img.Height * iZoom) / 100; 474 475 float fScrollX = 0.5f, fScrollY = 0.5f; 476 if(m_pnlImageViewer.AutoScroll) 477 { 478 Point ptOffset = m_pnlImageViewer.AutoScrollPosition; 479 Size sz = m_picBox.ClientSize; 480 481 if(sz.Width > cliW) 482 { 483 fScrollX = Math.Abs((float)ptOffset.X / (float)(sz.Width - cliW)); 484 if(fScrollX < 0.0f) { Debug.Assert(false); fScrollX = 0.0f; } 485 if(fScrollX > 1.0f) { Debug.Assert(false); fScrollX = 1.0f; } 486 } 487 488 if(sz.Height > cliH) 489 { 490 fScrollY = Math.Abs((float)ptOffset.Y / (float)(sz.Height - cliH)); 491 if(fScrollY < 0.0f) { Debug.Assert(false); fScrollY = 0.0f; } 492 if(fScrollY > 1.0f) { Debug.Assert(false); fScrollY = 1.0f; } 493 } 494 } 495 m_pnlImageViewer.AutoScroll = false; 496 497 m_picBox.Dock = DockStyle.None; 498 m_picBox.SizeMode = PictureBoxSizeMode.AutoSize; 499 500 int x = 0, y = 0; 501 if(dx < cliW) x = (cliW - dx) / 2; 502 if(dy < cliH) y = (cliH - dy) / 2; 503 504 m_picBox.Location = new Point(x, y); 505 506 if((dx == m_img.Width) && (dy == m_img.Height)) 507 m_picBox.Image = m_img; 508 else if((m_imgResized != null) && (m_imgResized.Width == dx) && 509 (m_imgResized.Height == dy)) 510 m_picBox.Image = m_imgResized; 511 else 512 { 513 Image imgToDispose = m_imgResized; 514 515 m_imgResized = GfxUtil.ScaleImage(m_img, dx, dy); 516 m_picBox.Image = m_imgResized; 517 518 if(imgToDispose != null) imgToDispose.Dispose(); 519 } 520 521 m_pnlImageViewer.AutoScroll = true; 522 523 int sx = 0, sy = 0; 524 if(dx > cliW) sx = (int)(fScrollX * (float)(dx - cliW)); 525 if(dy > cliH) sy = (int)(fScrollY * (float)(dy - cliH)); 526 try { m_pnlImageViewer.AutoScrollPosition = new Point(sx, sy); } 527 catch(Exception) { Debug.Assert(false); } 528 } 529 OnFormClosing(object sender, FormClosingEventArgs e)530 private void OnFormClosing(object sender, FormClosingEventArgs e) 531 { 532 if(this.DvfRelease != null) 533 { 534 DvfContextEventArgs args = new DvfContextEventArgs(this, 535 m_pbData, m_strDataDesc, m_tscViewers); 536 this.DvfRelease(sender, args); 537 if(args.Cancel) 538 { 539 e.Cancel = true; 540 return; 541 } 542 } 543 544 string strRect = UIUtil.GetWindowScreenRect(this); 545 if(strRect != m_strInitialFormRect) // Don't overwrite "" 546 Program.Config.UI.DataViewerRect = strRect; 547 } 548 OnFormClosed(object sender, FormClosedEventArgs e)549 private void OnFormClosed(object sender, FormClosedEventArgs e) 550 { 551 m_picBox.MouseWheel -= this.OnPicBoxMouseWheel; 552 553 m_picBox.Image = null; 554 if(m_img != null) { m_img.Dispose(); m_img = null; } 555 if(m_imgResized != null) { m_imgResized.Dispose(); m_imgResized = null; } 556 557 m_ctxText.Detach(); 558 GlobalWindowManager.RemoveWindow(this); 559 } 560 ProcessCmdKey(ref Message msg, Keys keyData)561 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 562 { 563 bool bDown; 564 if(!NativeMethods.GetKeyMessageState(ref msg, out bDown)) 565 return base.ProcessCmdKey(ref msg, keyData); 566 567 if(keyData == Keys.Escape) // No modifiers 568 { 569 if(bDown) Close(); 570 return true; 571 } 572 573 Keys kc = (keyData & Keys.KeyCode); 574 bool bCtrl = ((keyData & Keys.Control) != Keys.None); 575 576 if(bCtrl && m_tscZoom.Visible) 577 { 578 if((kc == Keys.Add) || (kc == Keys.Subtract)) 579 { 580 if(bDown) PerformZoom((kc == Keys.Add) ? 1 : -1); 581 return true; 582 } 583 if((kc == Keys.Oemplus) || (kc == Keys.OemMinus)) 584 { 585 if(bDown) PerformZoom((kc == Keys.Oemplus) ? 1 : -1); 586 return true; 587 } 588 } 589 590 return base.ProcessCmdKey(ref msg, keyData); 591 } 592 OnZoomSelectedIndexChanged(object sender, EventArgs e)593 private void OnZoomSelectedIndexChanged(object sender, EventArgs e) 594 { 595 UpdateImageView(); 596 } 597 PerformZoom(int d)598 private void PerformZoom(int d) 599 { 600 if(!m_tscZoom.Visible) { Debug.Assert(false); return; } 601 602 int iCur = m_tscZoom.SelectedIndex, cMax = m_tscZoom.Items.Count; 603 if((iCur < 0) || (iCur >= cMax)) { Debug.Assert(false); return; } 604 605 int iAuto = m_tscZoom.Items.IndexOf(m_strZoomAuto); 606 if((iAuto < 0) || (iAuto >= cMax)) { Debug.Assert(false); return; } 607 608 if(iCur == iAuto) 609 { 610 iCur = GetNearestFixedZoomItemIndex(); 611 if((iCur < 0) || (iCur >= cMax)) { Debug.Assert(false); return; } 612 } 613 614 int iNew = Math.Min(Math.Max(iCur + d, 0), cMax - 1); 615 if((iNew != iCur) && (iNew != iAuto)) m_tscZoom.SelectedIndex = iNew; 616 } 617 OnPicBoxMouseWheel(object sender, MouseEventArgs e)618 private void OnPicBoxMouseWheel(object sender, MouseEventArgs e) 619 { 620 if(e == null) { Debug.Assert(false); return; } 621 if((Control.ModifierKeys & Keys.Control) == Keys.None) return; 622 623 int d = e.Delta / 120; // See Control.MouseWheel event 624 PerformZoom(d); 625 } 626 OnViewerZoomOut(object sender, EventArgs e)627 private void OnViewerZoomOut(object sender, EventArgs e) 628 { 629 PerformZoom(-1); 630 } 631 OnViewerZoomIn(object sender, EventArgs e)632 private void OnViewerZoomIn(object sender, EventArgs e) 633 { 634 PerformZoom(1); 635 } 636 GetNearestFixedZoomItemIndex()637 private int GetNearestFixedZoomItemIndex() 638 { 639 if(m_img == null) { Debug.Assert(false); return -1; } 640 641 int iW = m_img.Width, iH = m_img.Height; 642 if((iW <= 0) || (iH <= 0)) { Debug.Assert(false); return -1; } 643 644 int cW = m_picBox.ClientSize.Width, cH = m_picBox.ClientSize.Height; 645 if((cW <= 0) || (cH <= 0)) { Debug.Assert(false); return -1; } 646 647 int z = 100; 648 if((iW > cW) || (iH > cH)) 649 { 650 int zW = (int)Math.Round(100.0 * (double)cW / (double)iW); 651 int zH = (int)Math.Round(100.0 * (double)cH / (double)iH); 652 z = Math.Min(zW, zH); 653 } 654 655 int dMin = int.MaxValue; 656 int iBest = -1; 657 for(int i = 0; i < m_tscZoom.Items.Count; ++i) 658 { 659 string str = (m_tscZoom.Items[i] as string); 660 if(string.IsNullOrEmpty(str)) { Debug.Assert(false); continue; } 661 662 if(!str.EndsWith("%")) continue; 663 str = str.Substring(0, str.Length - 1); 664 665 int zItem = 0; 666 if(!int.TryParse(str, out zItem)) { Debug.Assert(false); continue; } 667 668 int d = Math.Abs(z - zItem); 669 if(d < dMin) { iBest = i; dMin = d; } 670 } 671 672 return iBest; 673 } 674 } 675 676 public sealed class DvfContextEventArgs : CancellableOperationEventArgs 677 { 678 private DataViewerForm m_form; 679 public DataViewerForm Form { get { return m_form; } } 680 681 private byte[] m_pbData; 682 public byte[] Data { get { return m_pbData; } } 683 684 private string m_strDataDesc; 685 public string DataDescription { get { return m_strDataDesc; } } 686 687 private ToolStripComboBox m_tscViewers; 688 public ToolStripComboBox ViewersComboBox { get { return m_tscViewers; } } 689 DvfContextEventArgs(DataViewerForm form, byte[] pbData, string strDataDesc, ToolStripComboBox cbViewers)690 public DvfContextEventArgs(DataViewerForm form, byte[] pbData, 691 string strDataDesc, ToolStripComboBox cbViewers) 692 { 693 m_form = form; 694 m_pbData = pbData; 695 m_strDataDesc = strDataDesc; 696 m_tscViewers = cbViewers; 697 } 698 } 699 } 700