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