1 // =================================
   2 // Copyright (c) 2021 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 using System;
   7 using System.Collections;
   8 
   9 namespace System.Windows
  10 {
  11     public class delegate void TreeViewNodeMouseClickEventHandler(TreeViewNodeMouseClickEventArgs& args);
  12     public class delegate void TreeViewNodeEventHandler(TreeViewNodeEventArgs& args);
  13 
  14     public nothrow string DefaultTreeViewNormalNodeFontFamilyName()
  15     {
  16         return "Segoe UI";
  17     }
  18 
  19     public nothrow float DefaultTreeViewNormalNodeFontSize()
  20     {
  21         return 9.0f;
  22     }
  23 
  24     public nothrow FontStyle DefaultTreeViewNormalNodeFontStyle()
  25     {
  26         return FontStyle.regular;
  27     }
  28 
  29     public nothrow string DefaultTreeViewActiveNodeFontFamilyName()
  30     {
  31         return "Segoe UI";
  32     }
  33 
  34     public nothrow float DefaultTreeViewActiveNodeFontSize()
  35     {
  36         return 9.0f;
  37     }
  38 
  39     public nothrow FontStyle DefaultTreeViewActiveNodeFontStyle()
  40     {
  41         return FontStyle.bold;
  42     }
  43 
  44     public nothrow Color DefaultTreeViewBackgroundColor()
  45     {
  46         return Color.White();
  47     }
  48 
  49     public nothrow Color DefaultTreeViewStateIndicatorColor()
  50     {
  51         return Color.Red();
  52     }
  53 
  54     public nothrow Color DefaultTreeViewNodeSelectedColor()
  55     {
  56         return Color(201u222u245u);
  57     }
  58 
  59     public nothrow float DefaultTreeViewStateIndicatorPercentage()
  60     {
  61         return 50.0f;
  62     }
  63 
  64     public nothrow float DefaultTreeViewNodeIndentPercent()
  65     {
  66         return 200.0f;
  67     }
  68 
  69     public nothrow float DefaultTreeViewNodeTextIndentPercent()
  70     {
  71         return 100.0f;
  72     }
  73 
  74     public nothrow Padding DefaultTreeViewNodeImagePadding()
  75     {
  76         return Padding(0000);
  77     }
  78 
  79     public nothrow ControlCreateParams& TreeViewControlCreateParams(ControlCreateParams& controlCreateParams)
  80     {
  81         return controlCreateParams.SetWindowClassName("System.Windows.TreeView").SetWindowClassStyle(DoubleClickWindowClassStyle()).
  82             SetWindowClassBackgroundColor(SystemColor.COLOR_WINDOW).SetBackgroundColor(DefaultTreeViewBackgroundColor());
  83     }
  84 
  85     public class TreeViewCreateParams
  86     {
  87         public nothrow TreeViewCreateParams(ControlCreateParams& controlCreateParams_) : 
  88             controlCreateParams(controlCreateParams_)
  89             normalNodeFontFamilyName(DefaultTreeViewNormalNodeFontFamilyName())
  90             normalNodeFontSize(DefaultTreeViewNormalNodeFontSize())
  91             normalNodeFontStyle(DefaultTreeViewNormalNodeFontStyle())
  92             activeNodeFontFamilyName(DefaultTreeViewActiveNodeFontFamilyName())
  93             activeNodeFontSize(DefaultTreeViewActiveNodeFontSize())
  94             activeNodeFontStyle(DefaultTreeViewActiveNodeFontStyle())
  95             stateIndicatorColor(DefaultTreeViewStateIndicatorColor())
  96             nodeSelectedColor(DefaultTreeViewNodeSelectedColor())
  97             stateIndicatorPercentage(DefaultTreeViewStateIndicatorPercentage())
  98             nodeIndentPercent(DefaultTreeViewNodeIndentPercent())
  99             nodeTextIndentPercent(DefaultTreeViewNodeTextIndentPercent())
 100             nodeImagePadding(DefaultTreeViewNodeImagePadding())
 101         {
 102         }
 103         public nothrow TreeViewCreateParams& Defaults()
 104         {
 105             return *this;
 106         }
 107         public nothrow TreeViewCreateParams& SetNormalNodeFontFamilyName(const string& normalNodeFontFamilyName_)
 108         {
 109             normalNodeFontFamilyName = normalNodeFontFamilyName_;
 110             return *this;
 111         }
 112         public nothrow TreeViewCreateParams& SetNormalNodeFontSize(float normalNodeFontSize_)
 113         {
 114             normalNodeFontSize = normalNodeFontSize_;
 115             return *this;
 116         }
 117         public nothrow TreeViewCreateParams& SetNormalNodeFontStyle(FontStyle normalNodeFontStyle_)
 118         {
 119             normalNodeFontStyle = normalNodeFontStyle_;
 120             return *this;
 121         }
 122         public nothrow TreeViewCreateParams& SetActiveNodeFontFamilyName(const string& activeNodeFontFamilyName_)
 123         {
 124             activeNodeFontFamilyName = activeNodeFontFamilyName_;
 125             return *this;
 126         }
 127         public nothrow TreeViewCreateParams& SetActiveNodeFontSize(float activeNodeFontSize_)
 128         {
 129             activeNodeFontSize = activeNodeFontSize_;
 130             return *this;
 131         }
 132         public nothrow TreeViewCreateParams& SetActiveNodeFontStyle(FontStyle activeNodeFontStyle_)
 133         {
 134             activeNodeFontStyle = activeNodeFontStyle_;
 135             return *this;
 136         }
 137         public nothrow TreeViewCreateParams& SetStateIndicatorColor(const Color& stateIndicatorColor_)
 138         {
 139             stateIndicatorColor = stateIndicatorColor_;
 140             return *this;
 141         }
 142         public nothrow TreeViewCreateParams& SetNodeSelectedColor(const Color& nodeSelectedColor_)
 143         {
 144             nodeSelectedColor = nodeSelectedColor_;
 145             return *this;
 146         }
 147         public nothrow TreeViewCreateParams& SetTextColor(const Color& textColor_)
 148         {
 149             textColor = textColor_;
 150             return *this;
 151         }
 152         public nothrow TreeViewCreateParams& SetStateIndicatorPercentage(float stateIndicatorPercentage_)
 153         {
 154             stateIndicatorPercentage = stateIndicatorPercentage_;
 155             return *this;
 156         }
 157         public nothrow TreeViewCreateParams& SetNodeIndentPercent(float nodeIndentPercent_)
 158         {
 159             nodeIndentPercent = nodeIndentPercent_;
 160             return *this;
 161         }
 162         public nothrow TreeViewCreateParams& SetNodeTextIndentPercent(float nodeTextIndentPercent_)
 163         {
 164             nodeTextIndentPercent = nodeTextIndentPercent_;
 165             return *this;
 166         }
 167         public nothrow TreeViewCreateParams& SetNodeImagePadding(const Padding& nodeImagePadding_)
 168         {
 169             nodeImagePadding = nodeImagePadding_;
 170             return *this;
 171         }
 172         public ControlCreateParams& controlCreateParams;
 173         public string normalNodeFontFamilyName;
 174         public float normalNodeFontSize;
 175         public FontStyle normalNodeFontStyle;
 176         public string activeNodeFontFamilyName;
 177         public float activeNodeFontSize;
 178         public FontStyle activeNodeFontStyle;
 179         public Color stateIndicatorColor;
 180         public Color nodeSelectedColor;
 181         public Color textColor;
 182         public float stateIndicatorPercentage;
 183         public float nodeIndentPercent;
 184         public float nodeTextIndentPercent;
 185         public Padding nodeImagePadding;
 186     }
 187 
 188     public class TreeView : Control
 189     {
 190         private enum Flags : sbyte
 191         {
 192             none = 0changed = 1 << 0treeViewNodeChanged = 1 << 1treeViewNodeStateChanged = 1 << 2toolTipWindowAdded = 1 << 3
 193         }
 194         public TreeView(const Font& normalNodeFont_const Font& activeNodeFont_
 195             const Color& backgroundColorconst Color& stateIndicatorColor_const Color& nodeSelectedColor_const Color& textColor_
 196             const Point& locationconst Size& sizeDock dockAnchors anchors) : 
 197             base("System.Windows.TreeView"DoubleClickWindowClassStyle()DefaultChildWindowStyle()DefaultExtendedWindowStyle()
 198                 backgroundColor"treeView"
 199                 locationsizedockanchors)flags(Flags.none)root()normalNodeFont(normalNodeFont_)activeNodeFont(activeNodeFont_)
 200                 textHeight(0)stateIndicatorPercentage(50.0f)
 201                 stateIndicatorColor(stateIndicatorColor_)nodeSelectedColor(nodeSelectedColor_)nodeSelectedBrush(nodeSelectedColor)
 202                 textColor(textColor_)textBrush(textColor)
 203                 nodeIndentPercent(DefaultTreeViewNodeIndentPercent())
 204                 nodeTextIndentPercent(DefaultTreeViewNodeTextIndentPercent())
 205                 format(StringAlignment.nearStringAlignment.near)bitmapIndex(-1)animationMs(5)selectedNode(null)trackedNode(null)
 206                 toolTipWindow(new ToolTip())
 207         {
 208             SetChanged();
 209             SetMouseHoverMs(DefaultMouseHoverMs());
 210         }
 211         public TreeView(const Point& locationconst Size& sizeDock dockAnchors anchors) : 
 212             this(Font(FontFamily("Segoe UI")9.0f)Font(FontFamily("Segoe UI")9.0fFontStyle.boldUnit.point)
 213             Color.White()Color.Red()Color(201u222u245u)Color.Black()locationsizedockanchors)
 214         {
 215         }
 216         public TreeView(TreeViewCreateParams& createParams) : 
 217             base(createParams.controlCreateParams)
 218             flags(Flags.none)root()
 219             normalNodeFont(
 220                 Font(FontFamily(createParams.normalNodeFontFamilyName)
 221                     createParams.normalNodeFontSize
 222                     createParams.normalNodeFontStyle
 223                     Unit.point))
 224             activeNodeFont(
 225                 Font(FontFamily(createParams.activeNodeFontFamilyName)
 226                     createParams.activeNodeFontSize
 227                     createParams.activeNodeFontStyle
 228                     Unit.point))
 229             textHeight(0)stateIndicatorPercentage(createParams.stateIndicatorPercentage)
 230             stateIndicatorColor(createParams.stateIndicatorColor)
 231             nodeSelectedColor(createParams.nodeSelectedColor)nodeSelectedBrush(nodeSelectedColor)
 232             textColor(createParams.textColor)textBrush(textColor)
 233             nodeIndentPercent(createParams.nodeIndentPercent)
 234             nodeTextIndentPercent(createParams.nodeTextIndentPercent)
 235             nodeImagePadding(createParams.nodeImagePadding)
 236             format(StringAlignment.nearStringAlignment.near)bitmapIndex(-1)animationMs(5)
 237             selectedNode(null)trackedNode(null)toolTipWindow(new ToolTip())
 238         {
 239             SetChanged();
 240             SetMouseHoverMs(DefaultMouseHoverMs());
 241         }
 242         public ~TreeView()
 243         {
 244             if (toolTipWindow != null && ToolTipWindowAdded())
 245             {
 246                 ResetToolTipWindowAdded();
 247                 Window* window = GetWindow();
 248                 if (window != null)
 249                 {
 250                     window->RemoveChild(toolTipWindow);
 251                     toolTipWindow = null;
 252                 }
 253             }
 254         }
 255         public override void PrintWindowTree(int level)
 256         {
 257             LogView* log = Application.GetLogView();
 258             if (log != null)
 259             {
 260                 log->WriteLine(string(' 'level) + "TreeView." + Text() + ".handle=" + ToHexString(cast<ulong>(Handle())) + " " + ParentText() + "[" + Rect(Point()GetSize()).ToString() + "]");
 261             }
 262         }
 263         public void EnsureNodeVisible(TreeViewNode* node)
 264         {
 265             Size size = GetSize();
 266             Point contentLocation = ContentLocation();
 267             Point nodeLocation = node->Location();
 268             if (nodeLocation.y >= contentLocation.y && nodeLocation.y < contentLocation.y + size.h)
 269             {
 270                 return;
 271             }
 272             if (nodeLocation.y > contentLocation.y)
 273             {
 274                 int y = nodeLocation.y - Max(cast<int>(0)cast<int>(size.h - 2 * textHeight));
 275                 Point newOrigin(0y);
 276                 SetContentLocation(newOrigin);
 277                 Invalidate();
 278             }
 279             else
 280             {
 281                 int y = nodeLocation.y;
 282                 Point newOrigin(0y);
 283                 SetContentLocation(newOrigin);
 284                 Invalidate();
 285             }
 286         }
 287         public nothrow bool NodeVisible(TreeViewNode* node) const
 288         {
 289             Size size = GetSize();
 290             Point contentLocation = ContentLocation();
 291             Point nodeLocation = node->Location();
 292             if (nodeLocation.y >= contentLocation.y && nodeLocation.y < contentLocation.y + size.h)
 293             {
 294                 return true;
 295             }
 296             else
 297             {
 298                 return false;
 299             }
 300         }
 301         public List<TreeViewNode*> GetVisibleNodes(int level) const
 302         {
 303             List<TreeViewNode*> visibleNodes;
 304             root->GetVisibleNodes(visibleNodesthislevel);
 305             return visibleNodes;
 306         }
 307         public List<TreeViewNode*> GetVisibleNodes() const
 308         {
 309             return GetVisibleNodes(-1);
 310         }
 311         protected override void OnPaint(PaintEventArgs& args)
 312         {
 313             try
 314             {
 315                 if (Debug.Paint())
 316                 {
 317                     Rect r(Point()GetSize());
 318                     LogView* log = Application.GetLogView();
 319                     if (log != null)
 320                     {
 321                         log->WriteLine("TreeView.OnPaint: " + r.ToString());
 322                     }
 323                 }
 324                 if (!ToolTipWindowAdded())
 325                 {
 326                     SetToolTipWindowAdded();
 327                     Window* window = GetWindow();
 328                     if (window != null)
 329                     {
 330                         window->AddChild(toolTipWindow);
 331                     }
 332                 }
 333                 if (Changed())
 334                 {
 335                     ResetChanged();
 336                     Measure(args.graphics);
 337                     MakeStateIndicatorBitmaps(args.graphics);
 338                     SetTreeViewNodeChanged();
 339                     SetTreeViewNodeStateChanged();
 340                 }
 341                 if (TreeViewNodeChanged())
 342                 {
 343                     ResetTreeViewNodeChanged();
 344                     if (!root.IsNull())
 345                     {
 346                         root->MeasureSize(args.graphicsthis);
 347                     }
 348                 }
 349                 if (TreeViewNodeStateChanged())
 350                 {
 351                     ResetTreeViewNodeStateChanged();
 352                     if (!root.IsNull())
 353                     {
 354                         Rect r(Point()GetSize());
 355                         r.size.w = r.size.w - 1;
 356                         r.size.h = r.size.h - 1;
 357                         int idx = 0;
 358                         Rect rect;
 359                         root->Measure(args.graphicsr.locationthis0idxrect);
 360                         SetContentSize(rect.size);
 361                     }
 362                 }
 363                 args.graphics.Clear(BackgroundColor());
 364                 if (bitmapIndex != -1)
 365                 {
 366                     Point location;
 367                     PointF loc(location.xlocation.y);
 368                     args.graphics.DrawImage(stateIndicatorBitmaps[bitmapIndex]loc);
 369                 }
 370                 else
 371                 {
 372                     if (!root.IsNull())
 373                     {
 374                         root->Draw(args.graphicsthis);
 375                     }
 376                     base->OnPaint(args);
 377                 }
 378             }
 379             catch (const Exception& ex)
 380             {
 381                 MessageBox.Show(ex.Message());
 382             }
 383         }
 384         public inline nothrow TreeViewNode* Root() const
 385         {
 386             return root.Get();
 387         }
 388         public nothrow TreeViewNode* ReleaseRoot()
 389         {
 390             return root.Release();
 391         }
 392         public nothrow void ResetRoot(TreeViewNode* root_)
 393         {
 394             root.Reset(root_);
 395         }
 396         public nothrow void SetRoot(TreeViewNode* root_)
 397         {
 398             if (!root.IsNull())
 399             {
 400                 root->SetTreeView(null);
 401             }
 402             root.Reset(root_);
 403             SetContentLocation(Point(00));
 404             if (!root.IsNull())
 405             {
 406                 root->SetTreeView(this);
 407                 SetTreeViewNodeChanged();
 408                 SetTreeViewNodeStateChanged();
 409                 SetContentChanged();
 410             }
 411             SetChanged();
 412             Invalidate();
 413         }
 414         public inline nothrow const Font& GetNormalNodeFont() const
 415         {
 416             return normalNodeFont;
 417         }
 418         public inline nothrow const Font& GetActiveNodeFont() const
 419         {
 420             return activeNodeFont;
 421         }
 422         public nothrow void SetNormalNodeFont(const Font& normalNodeFont_)
 423         {
 424             normalNodeFont = normalNodeFont_;
 425             SetChanged();
 426         }
 427         public nothrow void SetActiveNodeFont(const Font& activeNodeFont_)
 428         {
 429             activeNodeFont = activeNodeFont_;
 430             SetChanged();
 431         }
 432         public inline nothrow const SolidBrush& TextBrush() const
 433         {
 434             return textBrush;
 435         }
 436         public inline nothrow const SolidBrush& NodeSelectedBrush() const
 437         {
 438             return nodeSelectedBrush;
 439         }
 440         public inline nothrow float TextHeight() const
 441         {
 442             return textHeight;
 443         }
 444         public inline nothrow float StateIndicatorPercentage() const
 445         {
 446             return stateIndicatorPercentage;
 447         }
 448         public inline nothrow void SetStateIndicatorPercentage(float stateIndicatorPercentage_)
 449         {
 450             stateIndicatorPercentage = stateIndicatorPercentage_;
 451             SetChanged();
 452         }
 453         public inline nothrow float StateIndicatorHeight() const
 454         {
 455             return stateIndicatorHeight;
 456         }
 457         public inline nothrow const Color& StateIndicatorColor() const
 458         {
 459             return stateIndicatorColor;
 460         }
 461         public void SetStateIndicatorColor(const Color& stateIndicatorColor_)
 462         {
 463             stateIndicatorColor = stateIndicatorColor_;
 464             SetChanged();
 465         }
 466         public inline nothrow const Color& NodeSelectedColor() const
 467         {
 468             return nodeSelectedColor;
 469         }
 470         public nothrow void SetNodeSelectedColor(const Color& nodeSelectedColor_)
 471         {
 472             if (nodeSelectedColor != nodeSelectedColor_)
 473             {
 474                 nodeSelectedColor = nodeSelectedColor_;
 475                 nodeSelectedBrush = SolidBrush(nodeSelectedColor);
 476             }
 477         }
 478         public inline nothrow const Color& TextColor() const
 479         {
 480             return textColor;
 481         }
 482         public void SetTextColor(const Color& textColor_)
 483         {
 484             if (textColor != textColor_)
 485             {
 486                 textColor = textColor_;
 487                 textBrush = SolidBrush(textColor);
 488                 SetChanged();
 489             }
 490         }
 491         public inline nothrow float NodeIndentPercent() const
 492         {
 493             return nodeIndentPercent;
 494         }
 495         public inline nothrow float NodeTextIndentPercent() const
 496         {
 497             return nodeTextIndentPercent;
 498         }
 499         public inline nothrow int AnimationMs() const
 500         {
 501             return animationMs;
 502         }
 503         public nothrow void SetAnimationMs(int animationMs_)
 504         {
 505             animationMs = animationMs_;
 506         }
 507         public void ShowToolTipWindow(const string& toolTipTextTreeViewNode* node)
 508         {
 509             toolTipWindow->Hide();
 510             Point loc = node->Location();
 511             Size size = node->GetSize();
 512             Point pt(loc.xloc.y + size.h + 4);
 513             if (!node->Children().IsEmpty())
 514             {
 515                 pt.x = pt.x + cast<int>(textHeight + 2.0f);
 516             }
 517             TranslateContentLocation(pt);
 518             pt = ClientToScreen(pt);
 519             toolTipWindow->SetText(toolTipText);
 520             toolTipWindow->MeasureExtent();
 521             Window* window = GetWindow();
 522             if (window != null)
 523             {
 524                 pt = window->ScreenToClient(pt);
 525                 Size sz = toolTipWindow->GetSize();
 526                 Point wloc = window->Location();
 527                 Size wsz = window->GetSize();
 528                 if (pt.y + sz.h > wloc.y + wsz.h)
 529                 {
 530                     pt.y = wloc.y + wsz.h - sz.h;
 531                 }
 532                 if (pt.x + sz.w > wloc.x + wsz.w)
 533                 {
 534                     pt.x = wloc.x + wsz.w - sz.w;
 535                 }
 536                 toolTipWindow->SetLocation(pt);
 537                 toolTipWindow->BringToFront();
 538                 toolTipWindow->Show();
 539                 toolTipWindow->Invalidate();
 540                 toolTipWindow->Update();
 541             }
 542         }
 543         public void HideToolTipWindow()
 544         {
 545             toolTipWindow->Hide();
 546         }
 547         public nothrow Event<TreeViewNodeMouseClickEventHandlerTreeViewNodeMouseClickEventArgs>& NodeClickEvent()
 548         {
 549             return nodeClickEvent;
 550         }
 551         public nothrow Event<TreeViewNodeMouseClickEventHandlerTreeViewNodeMouseClickEventArgs>& NodeDoubleClickEvent()
 552         {
 553             return nodeDoubleClickEvent;
 554         }
 555         public nothrow Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs>& NodeEnterEvent()
 556         {
 557             return nodeEnterEvent;
 558         }
 559         public nothrow Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs>& NodeLeaveEvent()
 560         {
 561             return nodeLeaveEvent;
 562         }
 563         public nothrow Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs>& NodeSelectedEvent()
 564         {
 565             return nodeSelectedEvent;
 566         }
 567         public nothrow Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs>& NodeExpandedEvent()
 568         {
 569             return nodeExpandedEvent;
 570         }
 571         public nothrow Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs>& NodeCollapsedEvent()
 572         {
 573             return nodeCollapsedEvent;
 574         }
 575         public nothrow Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs>& NodeHoveredEvent()
 576         {
 577             return nodeHoveredEvent;
 578         }
 579         protected override void OnMouseDown(MouseEventArgs& args)
 580         {
 581             base->OnMouseDown(args);
 582             if (!root.IsNull())
 583             {
 584                 bool handled = false;
 585                 root->DispatchMouseDown(argshandled);
 586                 if (TreeViewNodeStateChanged())
 587                 {
 588                     DeselectNode();
 589                     Invalidate();
 590                 }
 591             }
 592         }
 593         protected override void OnMouseUp(MouseEventArgs& args)
 594         {
 595             base->OnMouseUp(args);
 596             if (!root.IsNull())
 597             {
 598                 bool handled = false;
 599                 root->DispatchMouseUp(argshandled);
 600             }
 601         }
 602         protected override void OnMouseDoubleClick(MouseEventArgs& args)
 603         {
 604             base->OnMouseDoubleClick(args);
 605             if (!root.IsNull())
 606             {
 607                 bool handled = false;
 608                 root->DispatchMouseDoubleClick(argshandled);
 609                 if (TreeViewNodeStateChanged())
 610                 {
 611                     DeselectNode();
 612                     Invalidate();
 613                 }
 614             }
 615         }
 616         protected override void OnMouseEnter()
 617         {
 618             base->OnMouseEnter();
 619             trackedNode = null;
 620         }
 621         protected override void OnMouseMove(MouseEventArgs& args)
 622         {
 623             base->OnMouseMove(args);
 624             if (!root.IsNull())
 625             {
 626                 bool handled = false;
 627                 root->DispatchMouseMove(argshandled);
 628                 if (!handled)
 629                 {
 630                     if (trackedNode != null)
 631                     {
 632                         if (trackedNode->MouseEntered())
 633                         {
 634                             trackedNode->ResetMouseEntered();
 635                             trackedNode->MouseLeaveInternal();
 636                         }
 637                         trackedNode = null;
 638                     }
 639                 }
 640             }
 641         }
 642         protected override void OnMouseLeave()
 643         {
 644             base->OnMouseLeave();
 645             if (trackedNode != null)
 646             {
 647                 if (trackedNode->MouseEntered())
 648                 {
 649                     trackedNode->ResetMouseEntered();
 650                     trackedNode->MouseLeaveInternal();
 651                 }
 652                 trackedNode = null;
 653             }
 654         }
 655         protected override void OnMouseHover(MouseEventArgs& args)
 656         {
 657             base->OnMouseHover(args);
 658             if (!root.IsNull())
 659             {
 660                 bool handled = false;
 661                 root->DispatchMouseHover(argshandled);
 662             }
 663         }
 664         internal inline nothrow bool Changed() const
 665         {
 666             return (flags & Flags.changed) != Flags.none;
 667         }
 668         public inline nothrow void SetChanged()
 669         {
 670             flags = cast<Flags>(flags | Flags.changed);
 671         }
 672         private inline nothrow void ResetChanged()
 673         {
 674             flags = cast<Flags>(flags & ~Flags.changed);
 675         }
 676         internal inline nothrow bool TreeViewNodeChanged() const
 677         {
 678             return (flags & Flags.treeViewNodeChanged) != Flags.none;
 679         }
 680         internal inline nothrow void SetTreeViewNodeChanged()
 681         {
 682             flags = cast<Flags>(flags | Flags.treeViewNodeChanged);
 683         }
 684         private inline nothrow void ResetTreeViewNodeChanged()
 685         {
 686             flags = cast<Flags>(flags & ~Flags.treeViewNodeChanged);
 687         }
 688         internal inline nothrow bool TreeViewNodeStateChanged() const
 689         {
 690             return (flags & Flags.treeViewNodeStateChanged) != Flags.none;
 691         }
 692         private inline nothrow void ResetTreeViewNodeStateChanged()
 693         {
 694             flags = cast<Flags>(flags & ~Flags.treeViewNodeStateChanged);
 695         }
 696         internal inline nothrow void SetTreeViewNodeStateChanged()
 697         {
 698             flags = cast<Flags>(flags | Flags.treeViewNodeStateChanged);
 699         }
 700         private inline nothrow bool ToolTipWindowAdded() const
 701         {
 702             return (flags & Flags.toolTipWindowAdded) != Flags.none;
 703         }
 704         private inline nothrow void SetToolTipWindowAdded()
 705         {
 706             flags = cast<Flags>(flags | Flags.toolTipWindowAdded);
 707         }
 708         private inline nothrow void ResetToolTipWindowAdded()
 709         {
 710             flags = cast<Flags>(flags & ~Flags.toolTipWindowAdded);
 711         }
 712         private void Measure(Graphics& graphics)
 713         {
 714             string s = "RootNode";
 715             RectF normalTextRect = graphics.MeasureStringChecked(snormalNodeFontPointF(00)format);
 716             textHeight = normalTextRect.size.h;
 717             RectF activeTextRect = graphics.MeasureStringChecked(sactiveNodeFontPointF(00)format);
 718             textHeight = Max(textHeightactiveTextRect.size.h);
 719             stateIndicatorHeight = stateIndicatorPercentage * textHeight / 100.0f;
 720             SetScrollUnits(cast<int>(textHeight + 0.5)cast<int>(textHeight + 0.5));
 721         }
 722         private void MakeStateIndicatorBitmaps(Graphics& graphics)
 723         {
 724             SolidBrush stateIndicatorBrush(stateIndicatorColor);
 725             stateIndicatorBitmaps.Clear();
 726             PointF center(textHeight / 2textHeight / 2);
 727             float w = cast<float>((Sqrt(3.0) / 2) * stateIndicatorHeight);
 728             PointF pt1(center.x - w / 2center.y - stateIndicatorHeight / 2);
 729             PointF pt2(center.x - w / 2center.y + stateIndicatorHeight / 2);
 730             PointF pt3(center.x + w / 2center.y);
 731             for (int i = 9; i >= 0; --i;)
 732             {
 733                 float angle = i * 10.0f;
 734                 List<PointF> triangle;
 735                 triangle.Add(pt1);
 736                 triangle.Add(pt2);
 737                 triangle.Add(pt3);
 738                 Bitmap bm(cast<int>(textHeight)cast<int>(textHeight)graphics);
 739                 Graphics bmGraphics = Graphics.FromImage(bm);
 740                 bmGraphics.Clear(BackgroundColor());
 741                 if (i > 0)
 742                 {
 743                     Matrix id;
 744                     Matrix rm = RotateAt(idanglecenter);
 745                     rm.TransformPointsChecked(triangle);
 746                 }
 747                 List<Point> indicatorTriangle;
 748                 for (const PointF& pt : triangle)
 749                 {
 750                     indicatorTriangle.Add(Point(cast<int>(pt.x)cast<int>(pt.y)));
 751                 }
 752                 bmGraphics.SetSmoothingModeChecked(SmoothingMode.highQuality);
 753                 bmGraphics.FillPolygonChecked(stateIndicatorBrush3indicatorTriangle.Begin().Ptr());
 754                 stateIndicatorBitmaps.Add(Rvalue(bm));
 755             }
 756         }
 757         internal void DoAnimation(TreeViewNode.State targetStateconst Rect& stateRect)
 758         {
 759             if (targetState == TreeViewNode.State.expanded)
 760             {
 761                 for (long i = stateIndicatorBitmaps.Count() - 1; i >= 0; --i;)
 762                 {
 763                     UpdateGuard guard(thisi);
 764                     Invalidate(stateRect.ToWinRect());
 765                     Update();
 766                     Sleep(Duration.FromMilliseconds(animationMs));
 767                 }
 768             }
 769             else if (targetState == TreeViewNode.State.collapsed)
 770             {
 771                 for (long i = 0; i < stateIndicatorBitmaps.Count(); ++i;)
 772                 {
 773                     UpdateGuard guard(thisi);
 774                     Invalidate(stateRect.ToWinRect());
 775                     Update();
 776                     Sleep(Duration.FromMilliseconds(animationMs));
 777                 }
 778             }
 779         }
 780         private class UpdateGuard
 781         {
 782             public nothrow UpdateGuard(TreeView* view_long bitmapIndex) : view(view_)
 783             {
 784                 view->SetBitmapIndex(bitmapIndex);
 785             }
 786             public ~UpdateGuard()
 787             {
 788                 view->ResetBitmapIndex();
 789             }
 790             private TreeView* view;
 791         }
 792         private nothrow void SetBitmapIndex(long bitmapIndex_)
 793         {
 794             bitmapIndex = bitmapIndex_;
 795         }
 796         private nothrow void ResetBitmapIndex()
 797         {
 798             bitmapIndex = -1;
 799         }
 800         public const Bitmap& NodeExpandedBitmap() const
 801         {
 802             if (stateIndicatorBitmaps.IsEmpty())
 803             {
 804                 throw Exception("no state indicator bitmaps");
 805             }
 806             return stateIndicatorBitmaps.Front();
 807         }
 808         public const Bitmap& NodeCollapsedBitmap() const
 809         {
 810             if (stateIndicatorBitmaps.IsEmpty())
 811             {
 812                 throw Exception("no state indicator bitmaps");
 813             }
 814             return stateIndicatorBitmaps.Back();
 815         }
 816         public inline nothrow const StringFormat& Format() const
 817         {
 818             return format;
 819         }
 820         internal nothrow void SetSelectedNode(TreeViewNode* node)
 821         {
 822             if (selectedNode != node)
 823             {
 824                 if (selectedNode != null)
 825                 {
 826                     selectedNode->ResetSelected();
 827                 }
 828                 selectedNode = node;
 829                 SetTreeViewNodeStateChanged();
 830             }
 831         }
 832         public nothrow TreeViewNode* SelectedNode() const
 833         {
 834             return selectedNode;
 835         }
 836         public void DeselectNode()
 837         {
 838             if (selectedNode != null)
 839             {
 840                 TreeViewNode* selectedNodeParent = selectedNode->Parent();
 841                 while (selectedNodeParent != null)
 842                 {
 843                     if (selectedNodeParent->GetState() == TreeViewNode.State.collapsed)
 844                     {
 845                         SetSelectedNode(null);
 846                         break;
 847                     }
 848                     selectedNodeParent = selectedNodeParent->Parent();
 849                 }
 850             }
 851         }
 852         internal inline nothrow TreeViewNode* TrackedNode() const
 853         {
 854             return trackedNode;
 855         }
 856         internal nothrow void SetTrackedNode(TreeViewNode* trackedNode_)
 857         {
 858             trackedNode = trackedNode_;
 859         }
 860         public inline nothrow const Padding& NodeImagePadding() const
 861         {
 862             return nodeImagePadding;
 863         }
 864         protected virtual void OnNodeClick(TreeViewNodeMouseClickEventArgs& args)
 865         {
 866             nodeClickEvent.Fire(args);
 867         }
 868         internal void NodeClick(const Point& locationMouseButtons buttonsTreeViewNode* node)
 869         {
 870             TreeViewNodeMouseClickEventArgs args(locationbuttons1node);
 871             OnNodeClick(args);
 872         }
 873         protected virtual void OnNodeDoubleClick(TreeViewNodeMouseClickEventArgs& args)
 874         {
 875             nodeDoubleClickEvent.Fire(args);
 876         }
 877         internal void NodeDoubleClick(const Point& locationMouseButtons buttonsTreeViewNode* node)
 878         {
 879             TreeViewNodeMouseClickEventArgs args(locationbuttons2node);
 880             OnNodeDoubleClick(args);
 881         }
 882         protected virtual void OnNodeEnter(TreeViewNodeEventArgs& args)
 883         {
 884             nodeEnterEvent.Fire(args);
 885         }
 886         internal void NodeEnter(TreeViewNode* node)
 887         {
 888             TreeViewNodeEventArgs args(node);
 889             OnNodeEnter(args);
 890         }
 891         protected virtual void OnNodeLeave(TreeViewNodeEventArgs& args)
 892         {
 893             nodeLeaveEvent.Fire(args);
 894         }
 895         internal void NodeLeave(TreeViewNode* node)
 896         {
 897             TreeViewNodeEventArgs args(node);
 898             OnNodeLeave(args);
 899         }
 900         protected virtual void OnNodeSelected(TreeViewNodeEventArgs& args)
 901         {
 902             nodeSelectedEvent.Fire(args);
 903         }
 904         internal void NodeSelected(TreeViewNode* node)
 905         {
 906             TreeViewNodeEventArgs args(node);
 907             OnNodeSelected(args);
 908         }
 909         protected virtual void OnNodeExpanded(TreeViewNodeEventArgs& args)
 910         {
 911             nodeExpandedEvent.Fire(args);
 912         }
 913         internal void NodeExpanded(TreeViewNode* node)
 914         {
 915             TreeViewNodeEventArgs args(node);
 916             OnNodeExpanded(args);
 917         }
 918         protected virtual void OnNodeCollapsed(TreeViewNodeEventArgs& args)
 919         {
 920             nodeCollapsedEvent.Fire(args);
 921         }
 922         protected virtual void OnNodeHovered(TreeViewNodeEventArgs& args)
 923         {
 924             nodeHoveredEvent.Fire(args);
 925         }
 926         internal void NodeCollapsed(TreeViewNode* node)
 927         {
 928             TreeViewNodeEventArgs args(node);
 929             OnNodeCollapsed(args);
 930         }
 931         internal void NodeHovered(TreeViewNode* node)
 932         {
 933             TreeViewNodeEventArgs args(node);
 934             OnNodeHovered(args);
 935         }
 936         public inline nothrow ImageList* GetImageList() const
 937         {
 938             return imageList;
 939         }
 940         public nothrow void SetImageList(ImageList* imageList_)
 941         {
 942             imageList = imageList_;
 943         }
 944         private Flags flags;
 945         private UniquePtr<TreeViewNode> root;
 946         private Font normalNodeFont;
 947         private Font activeNodeFont;
 948         private float textHeight;
 949         private float stateIndicatorPercentage;
 950         private float stateIndicatorHeight;
 951         private Color stateIndicatorColor;
 952         private Color nodeSelectedColor;
 953         private Color textColor;
 954         private float nodeIndentPercent;
 955         private float nodeTextIndentPercent;
 956         private Padding nodeImagePadding;
 957         private SolidBrush nodeSelectedBrush;
 958         private SolidBrush textBrush;
 959         private List<Bitmap> stateIndicatorBitmaps;
 960         private StringFormat format;
 961         private long bitmapIndex;
 962         private int animationMs;
 963         private TreeViewNode* selectedNode;
 964         private TreeViewNode* trackedNode;
 965         private ToolTip* toolTipWindow;
 966         private ImageList* imageList;
 967         private Event<TreeViewNodeMouseClickEventHandlerTreeViewNodeMouseClickEventArgs> nodeClickEvent;
 968         private Event<TreeViewNodeMouseClickEventHandlerTreeViewNodeMouseClickEventArgs> nodeDoubleClickEvent;
 969         private Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs> nodeEnterEvent;
 970         private Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs> nodeLeaveEvent;
 971         private Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs> nodeSelectedEvent;
 972         private Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs> nodeExpandedEvent;
 973         private Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs> nodeCollapsedEvent;
 974         private Event<TreeViewNodeEventHandlerTreeViewNodeEventArgs> nodeHoveredEvent;
 975     }
 976 
 977     public class TreeViewNode : Component
 978     {
 979         public enum State : sbyte
 980         {
 981             collapsed = 0expanded = 1
 982         }
 983         private enum Flags : sbyte
 984         {
 985             none = 0mouseEntered = 1 << 0selected = 1 << 1active = 1 << 2
 986         }
 987         public explicit nothrow TreeViewNode(const string& text_) : 
 988             treeView(null)text(text_)children(this)state(State.collapsed)flags(Flags.none)index(-1)imageIndex(-1)expandedImageIndex(-1)
 989         {
 990         }
 991         public nothrow void SetTreeView(TreeView* treeView_)
 992         {
 993             treeView = treeView_;
 994         }
 995         public nothrow TreeViewNode* Parent() const
 996         {
 997             Container* container = GetContainer();
 998             if (container != null)
 999             {
1000                 Component* parent = container->Parent();
1001                 if (parent != null)
1002                 {
1003                     if (parent is TreeViewNode*)
1004                     {
1005                         return cast<TreeViewNode*>(parent);
1006                     }
1007                 }
1008             }
1009             return null;
1010         }
1011         public nothrow TreeView* GetTreeView() const
1012         {
1013             if (treeView != null)
1014             {
1015                 return treeView;
1016             }
1017             TreeViewNode* parent = Parent();
1018             if (parent != null)
1019             {
1020                 return parent->GetTreeView();
1021             }
1022             return null;
1023         }
1024         public void AddChild(TreeViewNode* child)
1025         {
1026             children.AddChild(child);
1027             TreeView* view = GetTreeView();
1028             if (view != null)
1029             {
1030                 view->SetTreeViewNodeChanged();
1031             }
1032         }
1033         public UniquePtr<TreeViewNode> RemoveChild(TreeViewNode* child)
1034         {
1035             UniquePtr<Component> removed = children.RemoveChild(child);
1036             TreeView* view = GetTreeView();
1037             if (view != null)
1038             {
1039                 view->SetTreeViewNodeChanged();
1040             }
1041             return UniquePtr<TreeViewNode>(cast<TreeViewNode*>(removed.Release()));
1042         }
1043         public void RemoveChildren()
1044         {
1045             Component* component = children.FirstChild();
1046             while (component != null)
1047             {
1048                 Component* next = component->NextSibling();
1049                 UniquePtr<Component> removed = children.RemoveChild(component);
1050                 component = next;
1051             }
1052         }
1053         public nothrow int Level() const
1054         {
1055             TreeViewNode* parent = Parent();
1056             if (parent != null)
1057             {
1058                 return parent->Level() + 1;
1059             }
1060             return 0;
1061         }
1062         public nothrow const Point& Location() const
1063         {
1064             return location;
1065         }
1066         public nothrow const Size& GetSize() const
1067         {
1068             return size;
1069         }
1070         public nothrow void MeasureSize(Graphics& graphicsTreeView* treeView)
1071         {
1072             RectF textRect = graphics.MeasureStringChecked(texttreeView->GetNormalNodeFont()PointF(00)treeView->Format());
1073             SizeF imageSize(00);
1074             if (imageIndex != -1)
1075             {
1076                 Padding padding = treeView->NodeImagePadding();
1077                 ImageList* imageList = treeView->GetImageList();
1078                 if (imageList != null)
1079                 {
1080                     Bitmap* bitmap = imageList->GetImage(imageIndex);
1081                     imageSize.w = bitmap->GetWidth() + padding.Horizontal();
1082                     imageSize.h = bitmap->GetHeight() + padding.Vertical();
1083                 }
1084             }
1085             size = Size(cast<int>(treeView->TextHeight() + textRect.size.w + imageSize.w)cast<int>(Max(textRect.size.himageSize.h)));
1086             Component* child = children.FirstChild();
1087             while (child != null)
1088             {
1089                 if (child is TreeViewNode*)
1090                 {
1091                     TreeViewNode* childNode = cast<TreeViewNode*>(child);
1092                     childNode->MeasureSize(graphicstreeView);
1093                 }
1094                 child = child->NextSibling();
1095             }
1096         }
1097         internal nothrow void Measure(Graphics& graphicsconst Point& locTreeView* treeViewint levelint& idxRect& parentRect)
1098         {
1099             //location = Point(cast<int>(loc.x + level * 2 * treeView->TextHeight()), cast<int>(loc.y + idx * treeView->TextHeight()));
1100             float imageHeight = 0;
1101             if (imageIndex != -1)
1102             {
1103                 Padding padding = treeView->NodeImagePadding();
1104                 ImageList* imageList = treeView->GetImageList();
1105                 if (imageList != null)
1106                 {
1107                     Bitmap* image = imageList->GetImage(imageIndex);
1108                     imageHeight = image->GetHeight() + padding.Vertical();
1109                 }
1110             }
1111             location = Point(cast<int>(loc.x + level * treeView->NodeIndentPercent() * treeView->TextHeight() / 100.0f)
1112                 cast<int>(loc.y + idx * Max(treeView->TextHeight()imageHeight)));
1113             Rect rect(locationsize);
1114             childRect = rect;
1115             parentRect = Rect.Union(parentRectchildRect);
1116             if (state == State.expanded)
1117             {
1118                 Component* child = children.FirstChild();
1119                 while (child != null)
1120                 {
1121                     if (child is TreeViewNode*)
1122                     {
1123                         TreeViewNode* childNode = cast<TreeViewNode*>(child);
1124                         ++idx;
1125                         childNode->Measure(graphicsloctreeViewlevel + 1idxchildRect);
1126                         parentRect = Rect.Union(parentRectchildRect);
1127                     }
1128                     child = child->NextSibling();
1129                 }
1130             }
1131         }
1132         internal void DispatchMouseDown(MouseEventArgs& argsbool& handled)
1133         {
1134             Rect r(locationsize);
1135             if (r.Contains(args.location))
1136             {
1137                 OnMouseDown(args);
1138                 handled = true;
1139             }
1140             else
1141             {
1142                 if (childRect.Contains(args.location))
1143                 {
1144                     Component* child = children.FirstChild();
1145                     while (child != null)
1146                     {
1147                         if (child is TreeViewNode*)
1148                         {
1149                             TreeViewNode* childNode = cast<TreeViewNode*>(child);
1150                             childNode->DispatchMouseDown(argshandled);
1151                             if (handled)
1152                             {
1153                                 return;
1154                             }
1155                         }
1156                         child = child->NextSibling();
1157                     }
1158                 }
1159             }
1160         }
1161         internal void DispatchMouseUp(MouseEventArgs& argsbool& handled)
1162         {
1163             Rect r(locationsize);
1164             if (r.Contains(args.location))
1165             {
1166                 OnMouseUp(args);
1167                 handled = true;
1168             }
1169             else
1170             {
1171                 if (childRect.Contains(args.location))
1172                 {
1173                     Component* child = children.FirstChild();
1174                     while (child != null)
1175                     {
1176                         if (child is TreeViewNode*)
1177                         {
1178                             TreeViewNode* childNode = cast<TreeViewNode*>(child);
1179                             childNode->DispatchMouseUp(argshandled);
1180                             if (handled)
1181                             {
1182                                 return;
1183                             }
1184                         }
1185                         child = child->NextSibling();
1186                     }
1187                 }
1188             }
1189         }
1190         internal void DispatchMouseDoubleClick(MouseEventArgs& argsbool& handled)
1191         {
1192             Rect r(locationsize);
1193             if (r.Contains(args.location))
1194             {
1195                 OnMouseDoubleClick(args);
1196                 handled = true;
1197             }
1198             else
1199             {
1200                 if (childRect.Contains(args.location))
1201                 {
1202                     Component* child = children.FirstChild();
1203                     while (child != null)
1204                     {
1205                         if (child is TreeViewNode*)
1206                         {
1207                             TreeViewNode* childNode = cast<TreeViewNode*>(child);
1208                             childNode->DispatchMouseDoubleClick(argshandled);
1209                             if (handled)
1210                             {
1211                                 return;
1212                             }
1213                         }
1214                         child = child->NextSibling();
1215                     }
1216                 }
1217             }
1218         }
1219         internal void DispatchMouseMove(MouseEventArgs& argsbool& handled)
1220         {
1221             Rect r(locationsize);
1222             if (r.Contains(args.location))
1223             {
1224                 handled = true;
1225                 TreeView* view = GetTreeView();
1226                 if (view != null)
1227                 {
1228                     TreeViewNode* prevNode = view->TrackedNode();
1229                     if (prevNode != null && prevNode != this)
1230                     {
1231                         if (prevNode->MouseEntered())
1232                         {
1233                             prevNode->ResetMouseEntered();
1234                             prevNode->OnMouseLeave();
1235                         }
1236                     }
1237                     view->SetTrackedNode(this);
1238                     if (!MouseEntered())
1239                     {
1240                         SetMouseEntered();
1241                         OnMouseEnter();
1242                     }
1243                 }
1244             }
1245             else
1246             {
1247                 if (childRect.Contains(args.location))
1248                 {
1249                     Component* child = children.FirstChild();
1250                     while (child != null)
1251                     {
1252                         if (child is TreeViewNode*)
1253                         {
1254                             TreeViewNode* childNode = cast<TreeViewNode*>(child);
1255                             childNode->DispatchMouseMove(argshandled);
1256                             if (handled)
1257                             {
1258                                 return;
1259                             }
1260                         }
1261                         child = child->NextSibling();
1262                     }
1263                 }
1264             }
1265         }
1266         internal void MouseLeaveInternal()
1267         {
1268             OnMouseLeave();
1269         }
1270         internal void DispatchMouseHover(MouseEventArgs& argsbool& handled)
1271         {
1272             Rect r(locationsize);
1273             if (r.Contains(args.location))
1274             {
1275                 handled = true;
1276                 OnMouseHover();
1277             }
1278             else
1279             {
1280                 if (childRect.Contains(args.location))
1281                 {
1282                     Component* child = children.FirstChild();
1283                     while (child != null)
1284                     {
1285                         if (child is TreeViewNode*)
1286                         {
1287                             TreeViewNode* childNode = cast<TreeViewNode*>(child);
1288                             childNode->DispatchMouseHover(argshandled);
1289                             if (handled)
1290                             {
1291                                 return;
1292                             }
1293                         }
1294                         child = child->NextSibling();
1295                     }
1296                 }
1297             }
1298         }
1299         private void OnMouseDown(MouseEventArgs& args)
1300         {
1301             if (args.buttons == MouseButtons.lbutton)
1302             {
1303                 TreeView* view = GetTreeView();
1304                 if (view != null)
1305                 {
1306                     if (children.IsEmpty())
1307                     {
1308                         Select();
1309                     }
1310                     else
1311                     {
1312                         int stateSquareSideLength = cast<int>(view->TextHeight());
1313                         Rect stateRect(locationSize(stateSquareSideLengthstateSquareSideLength));
1314                         if (stateRect.Contains(args.location))
1315                         {
1316                             Toggle();
1317                         }
1318                         else
1319                         {
1320                             Select();
1321                         }
1322                     }
1323                 }
1324             }
1325             else if (args.buttons == MouseButtons.rbutton)
1326             {
1327                 Select();
1328             }
1329         }
1330         private void OnMouseUp(MouseEventArgs& args)
1331         {
1332             if (args.buttons == MouseButtons.lbutton)
1333             {
1334                 if (Selected())
1335                 {
1336                     TreeView* view = GetTreeView();
1337                     if (view != null)
1338                     {
1339                         view->NodeClick(args.locationargs.buttonsthis);
1340                     }
1341                 }
1342             }
1343             else if (args.buttons == MouseButtons.rbutton)
1344             {
1345                 if (Selected())
1346                 {
1347                     TreeView* view = GetTreeView();
1348                     if (view != null)
1349                     {
1350                         view->NodeClick(args.locationargs.buttonsthis);
1351                     }
1352                 }
1353             }
1354         }
1355         private void OnMouseDoubleClick(MouseEventArgs& args)
1356         {
1357             TreeView* view = GetTreeView();
1358             if (view != null)
1359             {
1360                 view->NodeDoubleClick(args.locationargs.buttonsthis);
1361             }
1362         }
1363         private void OnMouseEnter()
1364         {
1365             TreeView* view = GetTreeView();
1366             if (view != null)
1367             {
1368                 view->NodeEnter(this);
1369             }
1370         }
1371         private void OnMouseLeave()
1372         {
1373             TreeView* view = GetTreeView();
1374             if (view != null)
1375             {
1376                 view->NodeLeave(this);
1377             }
1378         }
1379         private void OnMouseHover()
1380         {
1381             TreeView* view = GetTreeView();
1382             if (view != null)
1383             {
1384                 view->NodeHovered(this);
1385             }
1386         }
1387         public void Toggle()
1388         {
1389             switch (state)
1390             {
1391                 case State.expanded: Collapse(); break;
1392                 case State.collapsed: Expand(); break;
1393             }
1394         }
1395         public void Select()
1396         {
1397             if (!Selected())
1398             {
1399                 SetSelected();
1400                 TreeView* view = GetTreeView();
1401                 if (view != null)
1402                 {
1403                     view->SetSelectedNode(this);
1404                     view->NodeSelected(this);
1405                 }
1406             }
1407         }
1408         public void Deselect()
1409         {
1410             if (Selected())
1411             {
1412                 ResetSelected();
1413                 TreeView* view = GetTreeView();
1414                 if (view != null)
1415                 {
1416                     view->SetSelectedNode(null);
1417                 }
1418             }
1419         }
1420         public void Expand()
1421         {
1422             if (children.IsEmpty()) return;
1423             DoAnimation();
1424             Expand(false);
1425             TreeView* view = GetTreeView();
1426             if (view != null)
1427             {
1428                 view->NodeExpanded(this);
1429             }
1430         }
1431         public void ExpandAll()
1432         {
1433             if (children.IsEmpty()) return;
1434             DoAnimation();
1435             Expand(true);
1436             TreeView* view = GetTreeView();
1437             if (view != null)
1438             {
1439                 view->NodeExpanded(this);
1440             }
1441         }
1442         public void Expand(bool all)
1443         {
1444             if (children.IsEmpty()) return;
1445             SetState(State.expanded);
1446             if (all)
1447             {
1448                 Component* child = children.FirstChild();
1449                 while (child != null)
1450                 {
1451                     if (child is TreeViewNode*)
1452                     {
1453                         TreeViewNode* childNode = cast<TreeViewNode*>(child);
1454                         childNode->Expand(all);
1455                     }
1456                     child = child->NextSibling();
1457                 }
1458             }
1459         }
1460         public void Collapse()
1461         {
1462             if (children.IsEmpty()) return;
1463             DoAnimation();
1464             Collapse(false);
1465             TreeView* view = GetTreeView();
1466             if (view != null)
1467             {
1468                 view->NodeCollapsed(this);
1469             }
1470         }
1471         public void CollapseAll()
1472         {
1473             if (children.IsEmpty()) return;
1474             DoAnimation();
1475             Collapse(true);
1476             TreeView* view = GetTreeView();
1477             if (view != null)
1478             {
1479                 view->NodeCollapsed(this);
1480             }
1481         }
1482         public void Collapse(bool all)
1483         {
1484             if (children.IsEmpty()) return;
1485             SetState(State.collapsed);
1486             if (all)
1487             {
1488                 Component* child = children.FirstChild();
1489                 while (child != null)
1490                 {
1491                     if (child is TreeViewNode*)
1492                     {
1493                         TreeViewNode* childNode = cast<TreeViewNode*>(child);
1494                         childNode->Collapse(all);
1495                     }
1496                     child = child->NextSibling();
1497                 }
1498             }
1499         }
1500         private void DoAnimation()
1501         {
1502             TreeView* view = GetTreeView();
1503             if (view != null)
1504             {
1505                 int stateSquareSideLength = cast<int>(view->TextHeight());
1506                 Rect stateRect(locationSize(stateSquareSideLengthstateSquareSideLength));
1507                 view->DoAnimation(cast<State>(1 - state)stateRect);
1508             }
1509         }
1510         public inline nothrow const string& Text() const
1511         {
1512             return text;
1513         }
1514         public nothrow void SetText(const string& text_)
1515         {
1516             text = text_;
1517             TreeView* view = GetTreeView();
1518             if (view != null)
1519             {
1520                 view->SetTreeViewNodeChanged();
1521             }
1522         }
1523         public inline nothrow Container& Children() const
1524         {
1525             return children;
1526         }
1527         public inline nothrow State GetState() const
1528         {
1529             return state;
1530         }
1531         public nothrow void SetState(State state_)
1532         {
1533             if (state != state_)
1534             {
1535                 state = state_;
1536                 TreeView* view = GetTreeView();
1537                 if (view != null)
1538                 {
1539                     view->SetTreeViewNodeStateChanged();
1540                     if (state == State.collapsed)
1541                     {
1542                         view->SetContentLocation(Point(00));
1543                     }
1544                 }
1545             }
1546         }
1547         public inline nothrow void* Data() const
1548         {
1549             return data;
1550         }
1551         public inline nothrow void SetData(void* data_)
1552         {
1553             data = data_;
1554         }
1555         public void EnsureVisible()
1556         {
1557             TreeView* treeView = GetTreeView();
1558             if (treeView != null)
1559             {
1560                 treeView->EnsureNodeVisible(this);
1561             }
1562         }
1563         public void GetVisibleNodes(List<TreeViewNode*>& visibleNodesTreeView* treeViewint selectLevel)
1564         {
1565             if (selectLevel == -1 || Level() == selectLevel)
1566             {
1567                 if (treeView->NodeVisible(this))
1568                 {
1569                     visibleNodes.Add(this);
1570                 }
1571             }
1572             if (state == State.expanded)
1573             {
1574                 Component* child = children.FirstChild();
1575                 while (child != null)
1576                 {
1577                     if (child is TreeViewNode*)
1578                     {
1579                         TreeViewNode* childNode = cast<TreeViewNode*>(child);
1580                         childNode->GetVisibleNodes(visibleNodestreeViewselectLevel);
1581                     }
1582                     child = child->NextSibling();
1583                 }
1584             }
1585         }
1586         public void Draw(Graphics& graphicsTreeView* treeView)
1587         {
1588             bool isVisible = treeView->NodeVisible(this);
1589             Point loc = location;
1590             if (!children.IsEmpty())
1591             {
1592                 if (isVisible)
1593                 {
1594                     switch (state)
1595                     {
1596                         case State.expanded:
1597                         {
1598                             graphics.DrawImageChecked(treeView->NodeExpandedBitmap()PointF(loc.xloc.y));
1599                             break;
1600                         }
1601                         case State.collapsed:
1602                         {
1603                             graphics.DrawImageChecked(treeView->NodeCollapsedBitmap()PointF(loc.xloc.y));
1604                             break;
1605                         }
1606                     }
1607                 }
1608                 loc.x = cast<int>(loc.x + treeView->NodeTextIndentPercent() * treeView->TextHeight() / 100.0f);
1609             }
1610             if (isVisible)
1611             {
1612                 if (imageIndex != -1)
1613                 {
1614                     DrawImage(treeViewgraphicsloc);
1615                 }
1616             }
1617             if (isVisible)
1618             {
1619                 if (Selected())
1620                 {
1621                     Rect rect(locsize);
1622                     graphics.FillRectangleChecked(treeView->NodeSelectedBrush()rect);
1623                 }
1624                 if (Active())
1625                 {
1626                     graphics.DrawStringChecked(texttreeView->GetActiveNodeFont()PointF(loc.xloc.y)treeView->TextBrush());
1627                 }
1628                 else
1629                 {
1630                     graphics.DrawStringChecked(texttreeView->GetNormalNodeFont()PointF(loc.xloc.y)treeView->TextBrush());
1631                 }
1632             }
1633             if (state == State.expanded)
1634             {
1635                 Component* child = children.FirstChild();
1636                 while (child != null)
1637                 {
1638                     if (child is TreeViewNode*)
1639                     {
1640                         TreeViewNode* childNode = cast<TreeViewNode*>(child);
1641                         childNode->Draw(graphicstreeView);
1642                     }
1643                     child = child->NextSibling();
1644                 }
1645             }
1646         }
1647         internal inline nothrow bool MouseEntered() const
1648         {
1649             return (flags & Flags.mouseEntered) != Flags.none;
1650         }
1651         internal inline nothrow void SetMouseEntered()
1652         {
1653             flags = cast<Flags>(flags | Flags.mouseEntered);
1654         }
1655         internal inline nothrow void ResetMouseEntered()
1656         {
1657             flags = cast<Flags>(flags & ~Flags.mouseEntered);
1658         }
1659         public inline nothrow bool Selected() const
1660         {
1661             return (flags & Flags.selected) != Flags.none;
1662         }
1663         private inline nothrow void SetSelected()
1664         {
1665             flags = cast<Flags>(flags | Flags.selected);
1666         }
1667         internal inline nothrow void ResetSelected()
1668         {
1669             flags = cast<Flags>(flags & ~Flags.selected);
1670         }
1671         public inline nothrow bool Active() const
1672         {
1673             return (flags & Flags.active) != Flags.none;
1674         }
1675         public nothrow void SetActive(bool active)
1676         {
1677             if (Active() != active)
1678             {
1679                 if (active)
1680                 {
1681                     flags = cast<Flags>(flags | Flags.active);
1682                 }
1683                 else
1684                 {
1685                     flags = cast<Flags>(flags & ~Flags.active);
1686                 }
1687                 TreeView* view = GetTreeView();
1688                 if (view != null)
1689                 {
1690                     view->SetTreeViewNodeStateChanged();
1691                 }
1692             }
1693         }
1694         public inline nothrow int Index() const
1695         {
1696             return index;
1697         }
1698         public nothrow void SetIndex(int index_)
1699         {
1700             index = index_;
1701         }
1702         public inline nothrow int ImageIndex() const
1703         {
1704             return imageIndex;
1705         }
1706         public nothrow void SetImageIndex(int imageIndex_)
1707         {
1708             if (imageIndex != imageIndex_)
1709             {
1710                 imageIndex = imageIndex_;
1711                 TreeView* view = GetTreeView();
1712                 if (view != null)
1713                 {
1714                     view->SetTreeViewNodeStateChanged();
1715                     view->SetChanged();
1716                     view->Invalidate();
1717                 }
1718             }
1719         }
1720         public nothrow void SetExpandedImageIndex(int expandedImageIndex_)
1721         {
1722             if (expandedImageIndex != expandedImageIndex_)
1723             {
1724                 expandedImageIndex = expandedImageIndex_;
1725                 TreeView* view = GetTreeView();
1726                 if (view != null)
1727                 {
1728                     view->SetTreeViewNodeStateChanged();
1729                     view->SetChanged();
1730                     view->Invalidate();
1731                 }
1732             }
1733         }
1734         public nothrow void DrawImage(TreeView* viewGraphics& graphicsPoint& loc)
1735         {
1736             ImageList* imageList = view->GetImageList();
1737             if (imageList != null)
1738             {
1739                 int imgIndex = imageIndex;
1740                 if (state == State.expanded)
1741                 {
1742                     if (expandedImageIndex != -1)
1743                     {
1744                         imgIndex = expandedImageIndex;
1745                     }
1746                 }
1747                 Bitmap* image = imageList->GetImage(imgIndex);
1748                 if (image != null)
1749                 {
1750                     int imageWidth = cast<int>(image->GetWidth());
1751                     int imageHeight = cast<int>(image->GetHeight());
1752                     Padding padding = view->NodeImagePadding();
1753                     Rect r(locSize(imageWidth + padding.Horizontal()imageHeight + padding.Vertical()));
1754                     ImageAttributes attributes;
1755                     Color transparentColor = System.Windows.Color.DefaultBitmapTransparent();
1756                     attributes.SetColorKeyChecked(transparentColortransparentColorColorAdjustType.default_);
1757                     graphics.DrawImageChecked(*imager00imageWidth + padding.Horizontal()imageHeight + padding.Vertical()Unit.pixelattributes);
1758                     loc.x = loc.x + imageWidth + padding.Horizontal();
1759                 }
1760             }
1761         }
1762         private TreeView* treeView;
1763         private string text;
1764         private Container children;
1765         private State state;
1766         private Flags flags;
1767         private void* data;
1768         private Point location;
1769         private Size size;
1770         private Rect childRect;
1771         private int index;
1772         private int imageIndex;
1773         private int expandedImageIndex;
1774     }
1775 }