1 /* 2 * "GEDKeeper", the personal genealogical database editor. 3 * Copyright (C) 2009-2021 by Sergey V. Zhdanovskih. 4 * 5 * This file is part of "GEDKeeper". 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 //define DEBUG_IMAGE 22 23 using System; 24 using BSLib; 25 using BSLib.Design; 26 using BSLib.Design.Graphics; 27 using Eto.Drawing; 28 using Eto.Forms; 29 using GDModel; 30 using GKCore; 31 using GKCore.Charts; 32 using GKCore.Interfaces; 33 using GKCore.Options; 34 using GKUI.Platform; 35 using BSDColors = BSLib.Design.BSDConsts.Colors; 36 37 namespace GKUI.Components 38 { 39 /// <summary> 40 /// 41 /// </summary> 42 public class TreeChartBox : CustomChart, ITreeChart 43 { 44 #region Private fields 45 46 private readonly TreeChartModel fModel; 47 private readonly TreeControlsList<ITreeControl> fTreeControls; 48 private readonly TweenLibrary fTween; 49 50 private ITreeControl fActiveControl; 51 private long fHighlightedStart; 52 private ChartControlMode fMode = ChartControlMode.Default; 53 private int fMouseX; 54 private int fMouseY; 55 private TreeChartOptions fOptions; 56 private TreeChartPerson fSelected; 57 private GDMIndividualRecord fSaveSelection; 58 private ITimer fTimer; 59 private bool fTraceKinships; 60 private bool fTraceSelected; 61 62 #endregion 63 64 #region Public properties 65 66 public event PersonModifyEventHandler PersonModify; 67 68 public event RootChangedEventHandler RootChanged; 69 70 public event EventHandler PersonProperties; 71 72 public event EventHandler ZoomChanged; 73 74 public event InfoRequestEventHandler InfoRequest; 75 76 77 public IBaseWindow Base 78 { 79 get { return fModel.Base; } 80 set { fModel.Base = value; } 81 } 82 83 public bool CertaintyIndex 84 { 85 get { 86 return fModel.CertaintyIndex; 87 } 88 set { 89 fModel.CertaintyIndex = value; 90 Invalidate(); 91 } 92 } 93 94 public int DepthLimitAncestors 95 { 96 get { return fModel.DepthLimitAncestors; } 97 set { fModel.DepthLimitAncestors = value; } 98 } 99 100 public int DepthLimitDescendants 101 { 102 get { return fModel.DepthLimitDescendants; } 103 set { fModel.DepthLimitDescendants = value; } 104 } 105 106 public int IndividualsCount 107 { 108 get { return fModel.PreparedIndividuals.Count; } 109 } 110 111 public TreeChartKind Kind 112 { 113 get { return fModel.Kind; } 114 set { fModel.Kind = value; } 115 } 116 117 public ITreeLayout Layout 118 { 119 get { return fModel.Layout; } 120 set { fModel.Layout = value; } 121 } 122 123 public TreeChartModel Model 124 { 125 get { return fModel; } 126 } 127 128 public TreeChartOptions Options 129 { 130 get { 131 return fOptions; 132 } 133 set { 134 fOptions = value; 135 fModel.Options = value; 136 } 137 } 138 139 public float Scale 140 { 141 get { return fModel.Scale; } 142 } 143 144 public TreeChartPerson Selected 145 { 146 get { return fSelected; } 147 set { SetSelected(value); } 148 } 149 150 public bool TraceSelected 151 { 152 get { return fTraceSelected; } 153 set { fTraceSelected = value; } 154 } 155 156 public bool TraceKinships 157 { 158 get { return fTraceKinships; } 159 set { fTraceKinships = value; } 160 } 161 162 #endregion 163 164 #region Instance control 165 TreeChartBox()166 public TreeChartBox() 167 { 168 BackgroundColor = Colors.White; 169 170 fModel = new TreeChartModel(); 171 fRenderer = null; 172 fSelected = null; 173 fTraceSelected = true; 174 175 fTreeControls = new TreeControlsList<ITreeControl>(); 176 fTreeControls.Add(new TCScaleControl(this)); 177 fTreeControls.Add(new TCGenerationsControl(this, TreeChartKind.ckDescendants)); 178 //fPersonControl = new PersonControl(this); 179 180 InitTimer(); 181 fTween = new TweenLibrary(); 182 183 SetLayout(new NativeTreeLayout()); 184 } 185 TreeChartBox(ChartRenderer renderer)186 public TreeChartBox(ChartRenderer renderer) : this() 187 { 188 SetRenderer(renderer); 189 } 190 Dispose(bool disposing)191 protected override void Dispose(bool disposing) 192 { 193 if (disposing) { 194 fTween.Dispose(); 195 fModel.Dispose(); 196 197 if (fTimer != null) fTimer.Dispose(); 198 if (fTreeControls != null) fTreeControls.Dispose(); 199 } 200 base.Dispose(disposing); 201 } 202 SetLayout(ITreeLayout layout)203 public void SetLayout(ITreeLayout layout) 204 { 205 fModel.Layout = layout; 206 } 207 SetRenderer(ChartRenderer renderer)208 public override void SetRenderer(ChartRenderer renderer) 209 { 210 base.SetRenderer(renderer); 211 fModel.SetRenderer(renderer); 212 } 213 InitTimer()214 private void InitTimer() 215 { 216 fTimer = AppHost.Instance.CreateTimer(10, TickTimer); 217 fTimer.Start(); 218 } 219 TickTimer(object sender, EventArgs e)220 private void TickTimer(object sender, EventArgs e) 221 { 222 if (fModel.HighlightedPerson == null) return; 223 224 DateTime st = DateTime.FromBinary(fHighlightedStart); 225 DateTime cur = DateTime.Now; 226 TimeSpan d = cur - st; 227 228 if (d.TotalSeconds >= 1/* && !fPersonControl.Visible*/) { 229 fModel.HighlightedPerson = null; 230 //fPersonControl.Visible = true; 231 Invalidate(); 232 } 233 } 234 SetScale(float value)235 public void SetScale(float value) 236 { 237 fModel.Scale = value; 238 239 RecalcChart(); 240 241 if (fTraceSelected && fSelected != null) { 242 CenterPerson(fSelected, false); 243 } 244 245 fTreeControls.UpdateState(); 246 247 DoZoomChanged(); 248 } 249 GenChart(bool rootCenter)250 public void GenChart(bool rootCenter) 251 { 252 GenChart(fModel.Root.Rec, fModel.Kind, rootCenter); 253 } 254 GenChart(GDMIndividualRecord iRec, TreeChartKind kind, bool rootCenter)255 public void GenChart(GDMIndividualRecord iRec, TreeChartKind kind, bool rootCenter) 256 { 257 if (iRec == null) return; 258 259 try { 260 fSelected = null; 261 262 fModel.GenChart(iRec, kind, rootCenter); 263 264 RecalcChart(); 265 266 if (rootCenter) CenterPerson(fModel.Root, false); 267 268 NavAdd(iRec); 269 DoRootChanged(fModel.Root); 270 } catch (Exception ex) { 271 Logger.WriteError("TreeChartBox.GenChart()", ex); 272 } 273 } 274 RefreshTree()275 public void RefreshTree() 276 { 277 try { 278 if (fModel.Root == null) return; 279 280 GDMIndividualRecord rootRec = fModel.Root.Rec; 281 282 SaveSelection(); 283 GenChart(rootRec, fModel.Kind, false); 284 RestoreSelection(); 285 } catch (Exception ex) { 286 Logger.WriteError("TreeChartBox.RefreshTree()", ex); 287 } 288 } 289 SaveSelection()290 public void SaveSelection() 291 { 292 fSaveSelection = (fSelected == null) ? null : fSelected.Rec; 293 } 294 RestoreSelection()295 public void RestoreSelection() 296 { 297 SelectByRec(fSaveSelection); 298 } 299 RebuildKinships(bool noRedraw = false)300 public void RebuildKinships(bool noRedraw = false) 301 { 302 if (!fOptions.Kinship || fSelected == null) return; 303 304 try { 305 fModel.KinRoot = fSelected; 306 RecalcChart(noRedraw); 307 } catch (Exception ex) { 308 Logger.WriteError("TreeChartBox.RebuildKinships()", ex); 309 } 310 } 311 312 #endregion 313 314 #region Drawing routines 315 GetOffsets()316 public ExtPoint GetOffsets() 317 { 318 return fModel.GetOffsets(); 319 } 320 DrawBackground(BackgroundMode background)321 private void DrawBackground(BackgroundMode background) 322 { 323 if (background == BackgroundMode.bmNone) return; 324 325 bool bgImage = false; /*((BackgroundImage != null) && 326 (background == BackgroundMode.bmAny || 327 background == BackgroundMode.bmImage));*/ 328 329 if (bgImage) { 330 /*var imgRect = new Rectangle(0, 0, fImageWidth, fImageHeight); 331 332 using (Brush textureBrush = new TextureBrush(BackgroundImage, WrapMode.Tile)) { 333 gfx.FillRectangle(textureBrush, imgRect); 334 }*/ 335 } else { 336 bool bgFill = (background == BackgroundMode.bmAny || 337 background == BackgroundMode.bmImage); 338 339 if (bgFill) { 340 fRenderer.DrawRectangle(null, UIHelper.ConvertColor(BackgroundColor), 0, 0, fModel.ImageWidth, fModel.ImageHeight); 341 } 342 } 343 } 344 InternalDraw(ChartDrawMode drawMode, BackgroundMode background)345 private void InternalDraw(ChartDrawMode drawMode, BackgroundMode background) 346 { 347 // drawing relative offset of tree on graphics 348 int spx = 0; 349 int spy = 0; 350 351 if (drawMode == ChartDrawMode.dmInteractive) { 352 var imageViewport = base.ImageViewport; 353 spx = imageViewport.Left; 354 spy = imageViewport.Top; 355 fModel.VisibleArea = UIHelper.Rt2Rt(base.Viewport); 356 } else { 357 if (drawMode == ChartDrawMode.dmStaticCentered) { 358 Size clientSize = CanvasRectangle.Size; 359 360 if (fModel.ImageWidth < clientSize.Width) { 361 spx += (clientSize.Width - fModel.ImageWidth) / 2; 362 } 363 364 if (fModel.ImageHeight < clientSize.Height) { 365 spy += (clientSize.Height - fModel.ImageHeight) / 2; 366 } 367 } 368 369 fModel.VisibleArea = ExtRect.CreateBounds(0, 0, fModel.ImageWidth, fModel.ImageHeight); 370 } 371 372 fModel.SetOffsets(spx, spy); 373 374 fRenderer.SetSmoothing(true); 375 376 DrawBackground(background); 377 378 #if DEBUG_IMAGE 379 using (Pen pen = new Pen(Color.Red)) { 380 fRenderer.DrawRectangle(pen, Color.Transparent, fSPX, fSPY, fImageWidth, fImageHeight); 381 } 382 #endif 383 384 bool hasDeep = (fSelected != null && fSelected != fModel.Root && fSelected.Rec != null); 385 386 if (hasDeep && fOptions.DeepMode == DeepMode.Background) { 387 DrawDeep(fOptions.DeepMode, spx, spy); 388 } 389 390 fRenderer.SetTranslucent(0.0f); 391 fModel.Draw(drawMode); 392 393 if (hasDeep && fOptions.DeepMode == DeepMode.Foreground) { 394 DrawDeep(fOptions.DeepMode, spx, spy); 395 } 396 397 if (fOptions.BorderStyle != GfxBorderStyle.None) { 398 //fRenderer.SetSmoothing(false); 399 var rt = ExtRect.CreateBounds(spx, spy, fModel.ImageWidth, fModel.ImageHeight); 400 BorderPainter.DrawBorder(fRenderer, rt, fOptions.BorderStyle); 401 //fRenderer.SetSmoothing(true); 402 } 403 } 404 DrawDeep(DeepMode mode, int spx, int spy)405 private void DrawDeep(DeepMode mode, int spx, int spy) 406 { 407 try { 408 using (var deepModel = new TreeChartModel()) { 409 deepModel.Assign(fModel); 410 deepModel.SetRenderer(fRenderer); 411 deepModel.DepthLimitAncestors = 2; 412 deepModel.DepthLimitDescendants = 2; 413 deepModel.GenChart(fSelected.Rec, TreeChartKind.ckBoth, true); 414 deepModel.RecalcChart(true); 415 416 var pers = deepModel.FindPersonByRec(fSelected.Rec); 417 if (pers == null) { 418 Logger.WriteError("TreeChartBox.DrawDeep(): unexpected failure"); 419 return; 420 } 421 422 int dmX = (spx + (fSelected.PtX - pers.PtX)); 423 int dmY = (spy + (fSelected.PtY - pers.PtY)); 424 deepModel.SetOffsets(dmX, dmY); 425 deepModel.VisibleArea = ExtRect.CreateBounds(0, 0, deepModel.ImageWidth, deepModel.ImageHeight); 426 427 switch (mode) { 428 case DeepMode.Background: 429 fRenderer.SetTranslucent(0.75f); 430 break; 431 432 case DeepMode.Foreground: 433 fRenderer.SetTranslucent(0.25f); 434 IPen xpen = fRenderer.CreatePen(ChartRenderer.GetColor(BSDColors.Black), 2.0f); 435 IColor bColor = ChartRenderer.GetColor(BSDColors.White); 436 fRenderer.DrawRoundedRectangle(xpen, bColor, dmX, dmY, deepModel.ImageWidth, deepModel.ImageHeight, 6); 437 fRenderer.SetTranslucent(0.00f); 438 break; 439 } 440 441 deepModel.Draw(ChartDrawMode.dmStatic); 442 } 443 } catch (Exception ex) { 444 Logger.WriteError("TreeChartBox.DrawDeep()", ex); 445 } 446 } 447 448 #endregion 449 450 #region Sizes and adjustment routines 451 452 /*private ExtRect GetImageViewport() 453 { 454 ExtRect viewport; 455 456 var imageSize = GetImageSize(); 457 if (!imageSize.IsEmpty) { 458 Rectangle scrollableViewport = this.Viewport; 459 viewport = ExtRect.CreateBounds( 460 scrollableViewport.Left, scrollableViewport.Top, 461 scrollableViewport.Width, scrollableViewport.Height); 462 } else { 463 viewport = ExtRect.Empty; 464 } 465 466 return viewport; 467 }*/ 468 GetClientRect()469 public ExtRect GetClientRect() 470 { 471 return UIHelper.Rt2Rt(base.Viewport); 472 } 473 RecalcChart(bool noRedraw = false)474 public void RecalcChart(bool noRedraw = false) 475 { 476 Graphics gfx = null; 477 if (fRenderer is EtoGfxRenderer) { 478 //gfx = CreateGraphics(); 479 //fRenderer.SetTarget(gfx, false); 480 } 481 482 try { 483 fModel.RecalcChart(noRedraw); 484 } finally { 485 if (fRenderer is EtoGfxRenderer && gfx != null) { 486 gfx.Dispose(); 487 } 488 } 489 490 var imageSize = GetImageSize(); 491 SetImageSize(imageSize, noRedraw); 492 } 493 ToggleCollapse(TreeChartPerson person)494 public void ToggleCollapse(TreeChartPerson person) 495 { 496 try { 497 if (person != null) { 498 fModel.ToggleCollapse(person); 499 500 SaveSelection(); 501 RecalcChart(false); 502 RestoreSelection(); 503 } 504 } catch (Exception ex) { 505 Logger.WriteError("TreeChartBox.ToggleCollapse()", ex); 506 } 507 } 508 ToggleCollapse()509 public void ToggleCollapse() 510 { 511 ToggleCollapse(fSelected); 512 } 513 514 #endregion 515 516 #region Event processing 517 DoPersonModify(PersonModifyEventArgs eArgs)518 private void DoPersonModify(PersonModifyEventArgs eArgs) 519 { 520 var eventHandler = (PersonModifyEventHandler)PersonModify; 521 if (eventHandler != null) 522 eventHandler(this, eArgs); 523 } 524 DoRootChanged(TreeChartPerson person)525 private void DoRootChanged(TreeChartPerson person) 526 { 527 var eventHandler = (RootChangedEventHandler)RootChanged; 528 if (eventHandler != null) 529 eventHandler(this, person); 530 } 531 DoInfoRequest(TreeChartPerson person)532 private void DoInfoRequest(TreeChartPerson person) 533 { 534 var eventHandler = (InfoRequestEventHandler)InfoRequest; 535 if (eventHandler != null) 536 eventHandler(this, person); 537 } 538 DoPersonProperties(MouseEventArgs eArgs)539 private void DoPersonProperties(MouseEventArgs eArgs) 540 { 541 var eventHandler = (/*Mouse*/ EventHandler)PersonProperties; 542 if (eventHandler != null) 543 eventHandler(this, eArgs); 544 } 545 DoZoomChanged()546 private void DoZoomChanged() 547 { 548 var eventHandler = (EventHandler)ZoomChanged; 549 if (eventHandler != null) 550 eventHandler(this, new EventArgs()); 551 } 552 OnKeyDown(KeyEventArgs e)553 protected override void OnKeyDown(KeyEventArgs e) 554 { 555 switch (e.Key) { 556 case Keys.F4: 557 ToggleCollapse(); 558 break; 559 560 case Keys.Plus: 561 SetScale(fModel.Scale + 0.05f); 562 e.Handled = true; 563 break; 564 565 case Keys.Minus: 566 SetScale(fModel.Scale - 0.05f); 567 e.Handled = true; 568 break; 569 } 570 571 base.OnKeyDown(e); 572 } 573 OnSizeChanged(EventArgs e)574 protected override void OnSizeChanged(EventArgs e) 575 { 576 base.OnSizeChanged(e); 577 578 SaveSelection(); 579 580 var imageSize = GetImageSize(); 581 SetImageSize(imageSize); 582 fTreeControls.UpdateView(); 583 584 RestoreSelection(); 585 } 586 OnScroll(ScrollEventArgs e)587 protected override void OnScroll(ScrollEventArgs e) 588 { 589 base.OnScroll(e); 590 591 //SaveSelection(); 592 //var imageSize = GetImageSize(); 593 //SetImageSize(imageSize); 594 fTreeControls.UpdateView(); 595 //RestoreSelection(); 596 } 597 OnPaint(PaintEventArgs e)598 protected override void OnPaint(PaintEventArgs e) 599 { 600 fRenderer.SetTarget(e.Graphics); 601 602 InternalDraw(ChartDrawMode.dmInteractive, BackgroundMode.bmAny); 603 604 // interactive controls 605 fTreeControls.Draw(fRenderer); 606 607 base.OnPaint(e); 608 } 609 OnMouseDoubleClick(MouseEventArgs e)610 protected override void OnMouseDoubleClick(MouseEventArgs e) 611 { 612 TreeChartPerson p = fSelected; 613 DoPersonModify(new PersonModifyEventArgs(p)); 614 615 e.Handled = true; 616 base.OnMouseDoubleClick(e); 617 } 618 OnMouseWheel(MouseEventArgs e)619 protected override void OnMouseWheel(MouseEventArgs e) 620 { 621 if (e.Modifiers == Keys.Control) { 622 float newScale = (e.Delta.Height > 0) ? fModel.Scale + 0.05f : fModel.Scale - 0.05f; 623 SetScale(newScale); 624 } 625 626 e.Handled = true; 627 base.OnMouseWheel(e); 628 } 629 GetMouseAction(MouseEventArgs e, MouseEvent mouseEvent, out TreeChartPerson person)630 private MouseAction GetMouseAction(MouseEventArgs e, MouseEvent mouseEvent, out TreeChartPerson person) 631 { 632 var result = MouseAction.None; 633 person = null; 634 635 Point mpt = GetImageRelativeLocation(e.Location); 636 int aX = mpt.X; 637 int aY = mpt.Y; 638 639 int num = fModel.Persons.Count; 640 for (int i = 0; i < num; i++) { 641 TreeChartPerson p = fModel.Persons[i]; 642 ExtRect persRt = p.Rect; 643 644 if (persRt.Contains(aX, aY)) { 645 person = p; 646 647 if (e.Buttons == MouseButtons.Primary && mouseEvent == MouseEvent.meDown) { 648 result = MouseAction.Select; 649 break; 650 } else if (e.Buttons == MouseButtons.Alternate && mouseEvent == MouseEvent.meUp) { 651 result = MouseAction.Properties; 652 break; 653 } else if (mouseEvent == MouseEvent.meMove) { 654 result = MouseAction.Highlight; 655 break; 656 } 657 } 658 659 ExtRect expRt = TreeChartModel.GetExpanderRect(persRt); 660 if ((e.Buttons == MouseButtons.Primary && mouseEvent == MouseEvent.meUp) && expRt.Contains(aX, aY)) { 661 person = p; 662 result = MouseAction.Expand; 663 break; 664 } 665 666 expRt = TreeChartModel.GetPersonExpandRect(persRt); 667 if ((e.Buttons == MouseButtons.Primary && mouseEvent == MouseEvent.meUp) && expRt.Contains(aX, aY)) { 668 person = p; 669 result = MouseAction.PersonExpand; 670 break; 671 } 672 673 ExtRect infoRt = TreeChartModel.GetInfoRect(persRt); 674 if ((e.Buttons == MouseButtons.Primary && mouseEvent == MouseEvent.meUp) && infoRt.Contains(aX, aY)) { 675 person = p; 676 result = MouseAction.Info; 677 break; 678 } 679 } 680 681 if (result == MouseAction.None && person == null) { 682 if (e.Buttons == MouseButtons.Alternate && mouseEvent == MouseEvent.meDown) { 683 result = MouseAction.Drag; 684 } 685 } 686 687 return result; 688 } 689 OnMouseDown(MouseEventArgs e)690 protected override void OnMouseDown(MouseEventArgs e) 691 { 692 Point pt = new Point(e.Location); 693 fMouseX = pt.X; 694 fMouseY = pt.Y; 695 696 Point scrPt = GetScrollRelativeLocation(e.Location); 697 698 switch (fMode) { 699 case ChartControlMode.Default: 700 TreeChartPerson mPers; 701 MouseAction mAct = GetMouseAction(e, MouseEvent.meDown, out mPers); 702 703 switch (mAct) { 704 case MouseAction.Select: 705 SelectBy(mPers, true); 706 break; 707 708 case MouseAction.Drag: 709 Cursor = Cursors.Move; 710 fMode = ChartControlMode.DragImage; 711 break; 712 } 713 break; 714 715 case ChartControlMode.DragImage: 716 break; 717 718 case ChartControlMode.ControlsVisible: 719 fTreeControls.MouseDown(scrPt.X, scrPt.Y); 720 break; 721 } 722 723 e.Handled = true; 724 base.OnMouseDown(e); 725 } 726 OnMouseMove(MouseEventArgs e)727 protected override void OnMouseMove(MouseEventArgs e) 728 { 729 //Point ctPt = new Point((int)e.Location.X, (int)e.Location.Y); 730 Point scrPt = GetScrollRelativeLocation(e.Location); 731 732 switch (fMode) { 733 case ChartControlMode.Default: 734 TreeChartPerson mPers; 735 MouseAction mAct = GetMouseAction(e, MouseEvent.meMove, out mPers); 736 737 if (mAct == MouseAction.Highlight) { 738 SetHighlight(mPers); 739 } else { 740 SetHighlight(null); 741 742 ITreeControl ctl = fTreeControls.Contains(scrPt.X, scrPt.Y); 743 744 if (ctl != null) { 745 fMode = ChartControlMode.ControlsVisible; 746 ctl.UpdateState(); 747 ctl.Visible = true; 748 ctl.MouseMove(scrPt.X, scrPt.Y); 749 fActiveControl = ctl; 750 751 //pt = new Point(pt.X + Left, pt.Y + Top); 752 //fToolTip.Show(ctl.Tip, this, pt, 1500); 753 ToolTip = ctl.Tip; 754 } 755 } 756 break; 757 758 case ChartControlMode.DragImage: 759 Point pt = new Point(e.Location); 760 AdjustScroll(-(pt.X - fMouseX), -(pt.Y - fMouseY)); 761 fMouseX = pt.X; 762 fMouseY = pt.Y; 763 break; 764 765 case ChartControlMode.ControlsVisible: 766 if (fActiveControl != null) { 767 if (!(fActiveControl.Contains(scrPt.X, scrPt.Y) || fActiveControl.MouseCaptured)) { 768 fMode = ChartControlMode.Default; 769 fActiveControl.Visible = false; 770 //fToolTip.Hide(this); 771 ToolTip = ""; 772 fActiveControl = null; 773 } else { 774 fActiveControl.MouseMove(scrPt.X, scrPt.Y); 775 } 776 } 777 break; 778 } 779 780 e.Handled = true; 781 base.OnMouseMove(e); 782 } 783 OnMouseUp(MouseEventArgs e)784 protected override void OnMouseUp(MouseEventArgs e) 785 { 786 Point scrPt = GetScrollRelativeLocation(e.Location); 787 788 switch (fMode) { 789 case ChartControlMode.Default: 790 TreeChartPerson mPers; 791 MouseAction mAct = GetMouseAction(e, MouseEvent.meUp, out mPers); 792 793 switch (mAct) { 794 case MouseAction.None: 795 break; 796 797 case MouseAction.Properties: 798 SelectBy(mPers, false); 799 if (fSelected == mPers && fSelected.Rec != null) { 800 DoPersonProperties(new MouseEventArgs(e.Buttons, Keys.None, e.Location)); 801 } 802 break; 803 804 case MouseAction.Expand: 805 DoRootChanged(mPers); 806 GenChart(mPers.Rec, TreeChartKind.ckBoth, true); 807 break; 808 809 case MouseAction.PersonExpand: 810 ToggleCollapse(mPers); 811 break; 812 813 case MouseAction.Info: 814 DoInfoRequest(mPers); 815 break; 816 } 817 break; 818 819 case ChartControlMode.DragImage: 820 Cursor = Cursors.Default; 821 fMode = ChartControlMode.Default; 822 break; 823 824 case ChartControlMode.ControlsVisible: 825 fTreeControls.MouseUp(scrPt.X, scrPt.Y); 826 break; 827 } 828 829 e.Handled = true; 830 base.OnMouseUp(e); 831 } 832 833 #endregion 834 835 #region Navigation 836 SetNavObject(object obj)837 protected override void SetNavObject(object obj) 838 { 839 var iRec = obj as GDMIndividualRecord; 840 GenChart(iRec, TreeChartKind.ckBoth, true); 841 } 842 SetSelected(TreeChartPerson value)843 private void SetSelected(TreeChartPerson value) 844 { 845 if (fSelected != null) fSelected.Selected = false; 846 fSelected = value; 847 if (fSelected != null) fSelected.Selected = true; 848 849 Invalidate(); 850 } 851 SetHighlight(TreeChartPerson person)852 private void SetHighlight(TreeChartPerson person) 853 { 854 if (fModel.HighlightedPerson == person) return; 855 856 fModel.HighlightedPerson = person; 857 fHighlightedStart = DateTime.Now.ToBinary(); 858 859 /*if (person == null) { 860 //fPersonControl.Visible = false; 861 } else { 862 //fPersonControl.SetPerson(person); 863 }*/ 864 865 Invalidate(); 866 } 867 SelectBy(TreeChartPerson person, bool needCenter)868 private void SelectBy(TreeChartPerson person, bool needCenter) 869 { 870 if (person == null) return; 871 872 SetSelected(person); 873 874 //if (fTraceKinships && fOptions.Kinship) RebuildKinships(true); 875 876 if (needCenter && fTraceSelected) CenterPerson(person); 877 } 878 SelectByRec(GDMIndividualRecord iRec)879 public void SelectByRec(GDMIndividualRecord iRec) 880 { 881 if (iRec == null) return; 882 883 int num = fModel.Persons.Count; 884 for (int i = 0; i < num; i++) { 885 TreeChartPerson p = fModel.Persons[i]; 886 if (p.Rec == iRec) { 887 SetSelected(p); 888 889 if (fTraceSelected) CenterPerson(p); 890 891 return; 892 } 893 } 894 895 SetSelected(null); 896 } 897 CenterPerson(TreeChartPerson person, bool animation = true)898 public void CenterPerson(TreeChartPerson person, bool animation = true) 899 { 900 if (person == null) return; 901 902 Rectangle viewport = this.Viewport; 903 int widthMax = fModel.ImageWidth - viewport.Width; 904 int heightMax = fModel.ImageHeight - viewport.Height; 905 906 int srcX = viewport.Left; 907 int srcY = viewport.Top; 908 int dstX = Math.Min(Math.Max(0, ((person.PtX) - (viewport.Width / 2))), widthMax); 909 int dstY = Math.Min(Math.Max(0, ((person.PtY + (person.Height / 2)) - (viewport.Height / 2))), heightMax); 910 911 if ((srcX != dstX) || (srcY != dstY)) { 912 int timeInterval = animation ? 20 : 1; 913 fTween.StartTween(UpdateScrollPosition, srcX, srcY, dstX, dstY, TweenAnimation.EaseInOutQuad, timeInterval); 914 } 915 } 916 917 /*private void SetScroll(int x, int y) 918 { 919 UpdateScrollPosition(x, y); 920 }*/ 921 922 #endregion 923 924 #region Print support 925 GetImageSize()926 public override ExtSize GetImageSize() 927 { 928 return fModel.ImageSize; 929 } 930 RenderImage(RenderTarget target, bool forciblyCentered = false)931 public override void RenderImage(RenderTarget target, bool forciblyCentered = false) 932 { 933 BackgroundMode bgMode = (target == RenderTarget.Printer) ? BackgroundMode.bmImage : BackgroundMode.bmAny; 934 ChartDrawMode drawMode = (!forciblyCentered) ? ChartDrawMode.dmStatic : ChartDrawMode.dmStaticCentered; 935 InternalDraw(drawMode, bgMode); 936 } 937 938 #endregion 939 } 940 } 941