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