1 // =================================
   2 // Copyright (c) 2024 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 using System;
   7 using System.Collections;
   8 using System.Windows.API;
   9 
  10 namespace System.Windows
  11 {
  12     public Color DefaultMenuBackgroundColor()
  13     {
  14         return GetSystemColor(SystemColor.COLOR_MENU);
  15     }
  16 
  17     public Color DefaultMenuTextColor()
  18     {
  19         return GetSystemColor(SystemColor.COLOR_MENUTEXT);
  20     }
  21 
  22     public Color DefaultDisabledMenuTextColor()
  23     {
  24         Color color = GetSystemColor(SystemColor.COLOR_GRAYTEXT);
  25         if (color == Color.Black())
  26         {
  27             return Color(195u195u198u);
  28         }
  29         return color;
  30     }
  31 
  32     public Color DefaultMenuMouseOverColor()
  33     {
  34         return Color(201u222u245u);
  35     }
  36 
  37     public Color DefaultMenuOpenColor()
  38     {
  39         return Color.White();
  40     }
  41 
  42     public ControlCreateParams& MenuControlControlCreateParams(ControlCreateParams& controlCreateParams)
  43     {
  44         return controlCreateParams.SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor());
  45     }
  46 
  47     public class MenuControlCreateParams
  48     {
  49         public MenuControlCreateParams(ControlCreateParams& controlCreateParams_) : 
  50             controlCreateParams(controlCreateParams_)
  51             fontFamilyName("Segoe UI")
  52             fontSize(9.000000f)
  53             textColor(DefaultMenuTextColor())
  54             disabledTextColor(DefaultDisabledMenuTextColor())
  55             mouseOverColor(DefaultMenuMouseOverColor())
  56             menuOpenColor(DefaultMenuOpenColor())
  57         {
  58         }
  59         public MenuControlCreateParams& Defaults()
  60         {
  61             return *this;
  62         }
  63         public ControlCreateParams& controlCreateParams;
  64         public string fontFamilyName;
  65         public float fontSize;
  66         public Color textColor;
  67         public Color disabledTextColor;
  68         public Color mouseOverColor;
  69         public Color menuOpenColor;
  70     }
  71 
  72     public abstract class MenuControl : Control
  73     {
  74         public MenuControl(const Font& font_const string& windowClassNameWindowClassStyle windowClassStyleWindowStyle style
  75             ExtendedWindowStyle exStyle
  76             const Color& backgroundColorconst string& textconst Point& locationconst Size& sizeDock dockAnchors anchors) : 
  77             base(windowClassNamewindowClassStylestyleexStylebackgroundColortextlocationsizedockanchors)
  78             font(font_)textColor(DefaultMenuTextColor())disabledTextColor(DefaultDisabledMenuTextColor())mouseOverColor(201u222u245u)
  79             menuOpenColor(Color.White())shadowColor(ShadowColor())textBrush(textColor)disabledTextBrush(disabledTextColor)
  80             backgroundBrush(BackgroundColor())mouseOverBrush(mouseOverColor)menuOpenBrush(menuOpenColor)
  81             shadowBrush(shadowColor)blackBrush(Color.Black())blackPen(Color.Black())darkPen(Color.DarkGray())
  82             format(StringAlignment.nearStringAlignment.nearHotKeyPrefix.show)
  83         {
  84         }
  85         public MenuControl(MenuControlCreateParams& createParams) : 
  86             base(createParams.controlCreateParams)
  87             font(FontFamily(createParams.fontFamilyName)createParams.fontSize)
  88             textColor(createParams.textColor)
  89             disabledTextColor(createParams.disabledTextColor)
  90             mouseOverColor(createParams.mouseOverColor)
  91             menuOpenColor(createParams.menuOpenColor)
  92             shadowColor(ShadowColor())
  93             textBrush(textColor)disabledTextBrush(disabledTextColor)
  94             backgroundBrush(BackgroundColor())mouseOverBrush(mouseOverColor)menuOpenBrush(menuOpenColor)
  95             shadowBrush(shadowColor)blackBrush(Color.Black())blackPen(Color.Black())darkPen(Color.DarkGray())
  96             format(StringAlignment.nearStringAlignment.nearHotKeyPrefix.show)
  97         {
  98         }
  99         public override Padding DefaultPadding() const
 100         {
 101             return Padding(6262);
 102         }
 103         public inline const Font& GetFont() const
 104         {
 105             return font;
 106         }
 107         public inline const Color& TextColor() const
 108         {
 109             return textColor;
 110         }
 111         public inline const Color& DisabledTextColor() const
 112         {
 113             return disabledTextColor;
 114         }
 115         public inline const Color& MouseOverColor() const
 116         {
 117             return mouseOverColor;
 118         }
 119         public inline const Color& MenuOpenColor() const
 120         {
 121             return menuOpenColor;
 122         }
 123         public inline const Color& ShadowColor() const
 124         {
 125             return shadowColor;
 126         }
 127         public inline const Brush& TextBrush() const
 128         {
 129             return textBrush;
 130         }
 131         public inline const Brush& DisabledTextBrush() const
 132         {
 133             return disabledTextBrush;
 134         }
 135         public inline const Brush& BackgroundBrush() const
 136         {
 137             return backgroundBrush;
 138         }
 139         public inline const Brush& MouseOverBrush() const
 140         {
 141             return mouseOverBrush;
 142         }
 143         public inline const Brush& MenuOpenBrush() const
 144         {
 145             return menuOpenBrush;
 146         }
 147         public inline const Brush& ShadowBrush() const
 148         {
 149             return shadowBrush;
 150         }
 151         public inline const Brush& BlackBrush() const
 152         {
 153             return blackBrush;
 154         }
 155         public inline const Pen& BlackPen() const
 156         {
 157             return blackPen;
 158         }
 159         public inline const Pen& DarkPen() const
 160         {
 161             return darkPen;
 162         }
 163         public inline const StringFormat& Format() const
 164         {
 165             return format;
 166         }
 167         internal virtual MenuItem* GetMenuItemByAccessKey(wchar accessKey)
 168         {
 169             return null;
 170         }
 171         internal virtual MenuItem* GetOpenedMenuItem() const
 172         {
 173             return null;
 174         }
 175         internal virtual MenuItem* GetSelectedMenuItem() const
 176         {
 177             return null;
 178         }
 179         internal virtual void SetSelectedMenuItem(MenuItem* selectedMenuItem_)
 180         {
 181         }
 182         internal virtual bool IsOpen() const
 183         {
 184             return false;
 185         }
 186         public virtual void SetOpen()
 187         {
 188         }
 189         [nodiscard]
 190         internal virtual Result<bool> SetClosed()
 191         {
 192             return Result<bool>(true);
 193         }
 194         [nodiscard]
 195         internal virtual Result<bool> SetMenuInvalidated()
 196         {
 197             return Result<bool>(true);
 198         }
 199         internal virtual MenuItem* GetFirstMenuItem() const
 200         {
 201             return null;
 202         }
 203         internal virtual MenuItem* GetLastMenuItem() const
 204         {
 205             return null;
 206         }
 207         internal virtual MenuItem* LatestOpenedMenuItem() const
 208         {
 209             return null;
 210         }
 211         internal virtual void SetLatestOpenedMenuItem(MenuItem* menuItem)
 212         {
 213         }
 214         internal virtual MenuItem* GetLatestMouseDownMenuItem() const
 215         {
 216             return null;
 217         }
 218         internal virtual void SetLatestMouseDownMenuItem(MenuItem* menuItem)
 219         {
 220         }
 221         [nodiscard]
 222         internal virtual Result<bool> InvalidateMenu()
 223         {
 224             return Result<bool>(true);
 225         }
 226         internal virtual void SetMenuChanged()
 227         {
 228         }
 229         private Font font;
 230         private Color textColor;
 231         private Color disabledTextColor;
 232         private Color mouseOverColor;
 233         private Color menuOpenColor;
 234         private Color shadowColor;
 235         private SolidBrush textBrush;
 236         private SolidBrush disabledTextBrush;
 237         private SolidBrush backgroundBrush;
 238         private SolidBrush mouseOverBrush;
 239         private SolidBrush menuOpenBrush;
 240         private SolidBrush shadowBrush;
 241         private SolidBrush blackBrush;
 242         private Pen blackPen;
 243         private Pen darkPen;
 244         private StringFormat format;
 245     }
 246 
 247     public const int initialMenuBarHeight = 20;
 248 
 249     public ControlCreateParams& MenuBarControlCreateParams(ControlCreateParams& controlCreateParams)
 250     {
 251         return controlCreateParams.SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor()).
 252             SetWindowClassName("System.Windows.MenuBar").SetDock(Dock.top).SetSize(Size(0initialMenuBarHeight));
 253     }
 254 
 255     public class MenuBarCreateParams
 256     {
 257         public MenuBarCreateParams(MenuControlCreateParams& menuControlCreateParams_) : menuControlCreateParams(menuControlCreateParams_)
 258         {
 259         }
 260         public MenuBarCreateParams& Defaults()
 261         {
 262             return *this;
 263         }
 264         public MenuControlCreateParams& menuControlCreateParams;
 265     }
 266 
 267     public class MenuBar : MenuControl
 268     {
 269         private enum Flags : sbyte
 270         {
 271             noneopen = 1 << 0menuChanged = 1 << 1menuBoxAdded = 1 << 2menuInvalidated = 1 << 3menuKeyDisabled = 1 << 4
 272         }
 273 
 274         internal Color ShadowColor()
 275         {
 276             Color shadowColor = GetSystemColor(SystemColor.COLOR_BTNSHADOW);
 277             shadowColor.alpha = 196u;
 278             return shadowColor;
 279         }
 280 
 281         public MenuBar(const Font& font_) : base(font_"System.Windows.MenuBar"DefaultWindowClassStyle()DefaultChildWindowStyle()
 282             DefaultExtendedWindowStyle()DefaultMenuBackgroundColor()"menuBar"Point()Size(0initialMenuBarHeight)Dock.topAnchors.none)
 283             flags(Flags.none)children(this)latestOpenedMenuItem(null)selectedMenuItem(null)latestMouseDownMenuItem(null)
 284         {
 285             SetMenuChanged();
 286         }
 287         public MenuBar() : this(Font(FontFamily("Segoe UI")9.000000f))
 288         {
 289         }
 290         public MenuBar(MenuBarCreateParams& createParams) : 
 291             base(createParams.menuControlCreateParams)
 292             flags(Flags.none)children(this)latestOpenedMenuItem(null)selectedMenuItem(null)latestMouseDownMenuItem(null)
 293         {
 294             SetMenuChanged();
 295         }
 296         [nodiscard]
 297         public Result<bool> CloseMenu()
 298         {
 299             if (!IsOpen()) return Result<bool>(false);
 300             auto result = SetClosed();
 301             if (result.Error()) return result;
 302             SetLatestOpenedMenuItem(null);
 303             Component* child = children.FirstChild();
 304             while (child != null)
 305             {
 306                 if (child is MenuItem*)
 307                 {
 308                     MenuItem* menuItem = cast<MenuItem*>(child);
 309                     result = menuItem->SetState(MenuItem.State.closedthis);
 310                     if (result.Error()) return result;
 311                 }
 312                 child = child->NextSibling();
 313             }
 314             return InvalidateMenu();
 315         }
 316         [nodiscard]
 317         public Result<bool> AddMenuItem(MenuItem* menuItem)
 318         {
 319             auto result = children.AddChild(menuItem);
 320             if (result.Error())
 321             {
 322                 return Result<bool>(ErrorId(result.GetErrorId()));
 323             }
 324             SetMenuChanged();
 325             return Result<bool>(true);
 326         }
 327         [nodiscard]
 328         public override Result<bool> PrintWindowTree(int level)
 329         {
 330             LogView* log = Application.GetLogView();
 331             if (log != null)
 332             {
 333                 auto handleResult = ToHexString(cast<ulong>(Handle()));
 334                 if (handleResult.Error())
 335                 {
 336                     return Result<bool>(ErrorId(handleResult.GetErrorId()));
 337                 }
 338                 const string& handleStr = handleResult.Value();
 339                 auto parentTextResult = ParentText();
 340                 if (parentTextResult.Error())
 341                 {
 342                     return Result<bool>(ErrorId(parentTextResult.GetErrorId()));
 343                 }
 344                 const string& parentText = parentTextResult.Value();
 345                 auto result = log->WriteLine(string(' 'level) + "MenuBar." + Text() + ".handle=" + handleStr + " " + parentText + "[" + 
 346                     Rect(Point()GetSize()).ToString() + "]");
 347                 if (result.Error()) return result;
 348             }
 349             return Result<bool>(true);
 350         }
 351         [nodiscard]
 352         protected override Result<bool> OnPaint(PaintEventArgs& args)
 353         {
 354             if (Debug.Paint())
 355             {
 356                 auto locResult = Location();
 357                 if (locResult.Error())
 358                 {
 359                     return Result<bool>(ErrorId(locResult.GetErrorId()));
 360                 }
 361                 else
 362                 {
 363                     Point loc = locResult.Value();
 364                     Rect r(locGetSize());
 365                     LogView* log = Application.GetLogView();
 366                     if (log != null)
 367                     {
 368                         auto result = log->WriteLine("MenuBar.OnPaint: " + r.ToString());
 369                         if (result.Error()) return result;
 370                     }
 371                 }
 372             }
 373             if (!MenuBoxAdded())
 374             {
 375                 SetMenuBoxAdded();
 376                 auto result = AddMenuBox();
 377                 if (result.Error())
 378                 {
 379                     return Result<bool>(ErrorId(result.GetErrorId()));
 380                 }
 381             }
 382             auto clearResult = args.graphics.Clear(BackgroundColor());
 383             if (clearResult.Error())
 384             {
 385                 return Result<bool>(ErrorId(clearResult.GetErrorId()));
 386             }
 387             if (MenuChanged())
 388             {
 389                 ResetMenuChanged();
 390                 CollectShortcuts();
 391                 Size size = GetSize();
 392                 size.h = cast<int>(GetFont().GetHeight(args.graphics));
 393                 size.h = size.h + DefaultPadding().Vertical();
 394                 auto result = SetSize(size);
 395                 if (result.Error()) return result;
 396                 auto locateResult = LocateMenuItems(args.graphicssize);
 397                 if (locateResult.Error())
 398                 {
 399                     return Result<bool>(ErrorId(locateResult.GetErrorId()));
 400                 }
 401             }
 402             auto locResult = Location();
 403             if (locResult.Error())
 404             {
 405                 return Result<bool>(ErrorId(locResult.GetErrorId()));
 406             }
 407             Point loc = locResult.Value();
 408             auto drawResult = DrawMenuItems(argsfalseloc);
 409             if (drawResult.Error())
 410             {
 411                 return Result<bool>(ErrorId(drawResult.GetErrorId()));
 412             }
 413             auto paintResult = base->OnPaint(args);
 414             if (paintResult.Error())
 415             {
 416                 return Result<bool>(ErrorId(paintResult.GetErrorId()));
 417             }
 418             return Result<bool>(true);
 419         }
 420         private Result<bool> LocateMenuItems(Graphics& graphicsconst Size& size)
 421         {
 422             auto locResult = Location();
 423             if (locResult.Error())
 424             {
 425                 return Result<bool>(ErrorId(locResult.GetErrorId()));
 426             }
 427             Point loc = locResult.Value();
 428             Rect itemRect(locSize(0size.h));
 429             Padding padding = DefaultPadding();
 430             PointF origin(00);
 431             Component* child = children.FirstChild();
 432             while (child != null)
 433             {
 434                 if (child is MenuItem*)
 435                 {
 436                     MenuItem* menuItem = cast<MenuItem*>(child);
 437                     Padding menuItemPadding = menuItem->DefaultPadding();
 438                     auto measureResult = graphics.MeasureStringRectF(menuItem->Text()GetFont()originFormat());
 439                     if (measureResult.Error())
 440                     {
 441                         return Result<bool>(ErrorId(measureResult.GetErrorId()));
 442                     }
 443                     RectF r = Rvalue(measureResult.Value());
 444                     int w = cast<int>(r.size.w) + padding.Horizontal() + menuItemPadding.Horizontal();
 445                     itemRect.size.w = w;
 446                     menuItem->SetLocation(itemRect.location);
 447                     menuItem->SetSize(itemRect.size);
 448                     menuItem->CalculateChildRect(graphicsGetFont()Format()Point(itemRect.location.xitemRect.location.y + itemRect.size.h));
 449                     itemRect.location.x = itemRect.location.x + w;
 450                 }
 451                 child = child->NextSibling();
 452             }
 453             return Result<bool>(true);
 454         }
 455         private Control* ParentControl() const
 456         {
 457             ComponentContainer* container = GetContainer();
 458             if (container != null)
 459             {
 460                 Component* parent = container->Parent();
 461                 if (parent != null && (parent is Control*))
 462                 {
 463                     return cast<Control*>(parent);
 464                 }
 465             }
 466             return null;
 467         }
 468         [nodiscard]
 469         private Result<bool> InvalidateParentRect(const Rect& parentRect)
 470         {
 471             Control* parentControl = ParentControl();
 472             if (parentControl != null)
 473             {
 474                 auto result = parentControl->Invalidate(parentRect.ToWinRect());
 475                 if (result.Error()) return result;
 476             }
 477             return Result<bool>(true);
 478         }
 479         internal Result<bool> DrawMenuItems(PaintEventArgs& argsbool drawSubItemsconst Point& origin)
 480         {
 481             Padding padding = DefaultPadding();
 482             Size size = GetSize();
 483             Component* child = children.FirstChild();
 484             while (child != null)
 485             {
 486                 if (child is MenuItem*)
 487                 {
 488                     MenuItem* menuItem = cast<MenuItem*>(child);
 489                     auto drawResult = menuItem->Draw(
 490                         args.graphicspaddingTextBrush()DisabledTextBrush()BackgroundBrush()MouseOverBrush()MenuOpenBrush()ShadowBrush()
 491                         BlackBrush()BlackPen()DarkPen()GetFont()Format()MenuOpenColor()thisdrawSubItemsorigin);
 492                     if (drawResult.Error())
 493                     {
 494                         return Result<bool>(ErrorId(drawResult.GetErrorId()));
 495                     }
 496                 }
 497                 child = child->NextSibling();
 498             }
 499             return Result<bool>(true);
 500         }
 501         [nodiscard]
 502         internal Result<bool> DoKeyDown(KeyEventArgs& args)
 503         {
 504             return OnKeyDown(args);
 505         }
 506         [nodiscard]
 507         protected override Result<bool> OnKeyDown(KeyEventArgs& args)
 508         {
 509             auto result = base->OnKeyDown(args);
 510             if (result.Error()) return result;
 511             if (!args.handled)
 512             {
 513                 auto it = shortcuts.Find(args.key);
 514                 if (it != shortcuts.End())
 515                 {
 516                     MenuItem* menuItem = it->second;
 517                     if (menuItem->IsEnabled())
 518                     {
 519                         result = menuItem->DoClick();
 520                         if (result.Error()) return result;
 521                         args.handled = true;
 522                     }
 523                 }
 524             }
 525             return Result<bool>(true);
 526         }
 527         [nodiscard]
 528         internal Result<bool> MouseEnterInternal()
 529         {
 530             EnterLeaveEventArgs args;
 531             auto result = OnMouseEnter(args);
 532             if (result.Error()) return result;
 533             if (args.errorId != 0)
 534             {
 535                 return Result<bool>(ErrorId(args.errorId));
 536             }
 537             return Result<bool>(true);
 538         }
 539         [nodiscard]
 540         protected override Result<bool> OnMouseEnter(EnterLeaveEventArgs& args)
 541         {
 542             return base->OnMouseEnter(args);
 543         }
 544         [nodiscard]
 545         internal Result<bool> MouseMoveInternal(MouseEventArgs& args)
 546         {
 547             return OnMouseMove(args);
 548         }
 549         [nodiscard]
 550         protected override Result<bool> OnMouseMove(MouseEventArgs& args)
 551         {
 552             ResetMenuInvalidated();
 553             auto result = base->OnMouseMove(args);
 554             if (result.Error()) return result;
 555             bool handled = false;
 556             Component* child = children.FirstChild();
 557             while (child != null)
 558             {
 559                 if (child is MenuItem*)
 560                 {
 561                     MenuItem* menuItem = cast<MenuItem*>(child);
 562                     if (!menuItem->Contains(args.location))
 563                     {
 564                         result = menuItem->ResetSelected(this);
 565                         if (result.Error()) return result;
 566                         if (menuItem->MouseInClient())
 567                         {
 568                             menuItem->ResetMouseInClient();
 569                             result = menuItem->DoMouseLeave(this);
 570                             if (result.Error()) return result;
 571                         }
 572                     }
 573                 }
 574                 child = child->NextSibling();
 575             }
 576             child = children.FirstChild();
 577             while (child != null)
 578             {
 579                 if (child is MenuItem*)
 580                 {
 581                     MenuItem* menuItem = cast<MenuItem*>(child);
 582                     if (menuItem->Contains(args.location))
 583                     {
 584                         auto result = menuItem->SetSelected(this);
 585                         if (result.Error()) return result;
 586                         if (!menuItem->MouseInClient())
 587                         {
 588                             menuItem->SetMouseInClient();
 589                             result = menuItem->DoMouseEnter(IsOpen()this);
 590                             if (result.Error()) return result;
 591                         }
 592                         else
 593                         {
 594                             result = menuItem->DoMouseMove(args);
 595                             if (result.Error()) return result;
 596                         }
 597                         handled = true;
 598                     }
 599                 }
 600                 child = child->NextSibling();
 601             }
 602             if (!handled)
 603             {
 604                 if (IsOpen())
 605                 {
 606                     if (latestOpenedMenuItem != null)
 607                     {
 608                         Component* child = children.FirstChild();
 609                         while (child != null && !handled)
 610                         {
 611                             if (child is MenuItem*)
 612                             {
 613                                 MenuItem* menuItem = cast<MenuItem*>(child);
 614                                 if (menuItem->IsSameOrParentOf(latestOpenedMenuItem))
 615                                 {
 616                                     auto result = menuItem->DispatchMouseMove(argshandledthis);
 617                                     if (result.Error()) return result;
 618                                 }
 619                             }
 620                             child = child->NextSibling();
 621                         }
 622                     }
 623                 }
 624             }
 625             if (MenuInvalidated())
 626             {
 627                 auto result = InvalidateMenu();
 628                 if (result.Error()) return result;
 629             }
 630             return Result<bool>(true);
 631         }
 632         [nodiscard]
 633         internal Result<bool> MouseLeaveInternal()
 634         {
 635             EnterLeaveEventArgs args;
 636             auto result = OnMouseLeave(args);
 637             if (result.Error()) return result;
 638             if (args.errorId != 0)
 639             {
 640                 return Result<bool>(ErrorId(args.errorId));
 641             }
 642             return Result<bool>(true);
 643         }
 644         [nodiscard]
 645         protected override Result<bool> OnMouseLeave(EnterLeaveEventArgs& args)
 646         {
 647             ResetMenuInvalidated();
 648             auto result = base->OnMouseLeave(args);
 649             if (result.Error()) return result;
 650             Component* child = children.FirstChild();
 651             while (child != null)
 652             {
 653                 if (child is MenuItem*)
 654                 {
 655                     MenuItem* menuItem = cast<MenuItem*>(child);
 656                     if (menuItem->MouseInClient() || menuItem->Children().IsEmpty())
 657                     {
 658                         result = menuItem->ResetSelected(this);
 659                         if (result.Error()) return result;
 660                         menuItem->ResetMouseInClient();
 661                         Point mousePos;
 662                         WinGetMessagePos(mousePos.xmousePos.y);
 663                         auto clientMousePosResult = ScreenToClient(mousePos);
 664                         if (clientMousePosResult.Error())
 665                         {
 666                             return Result<bool>(ErrorId(clientMousePosResult.GetErrorId()));
 667                         }
 668                         else
 669                         {
 670                             mousePos = clientMousePosResult.Value();
 671                             if (menuItem != latestOpenedMenuItem || !menuItem->UnionRectContains(mousePos))
 672                             {
 673                                 auto result = menuItem->DoMouseLeave(this);
 674                                 if (result.Error()) return result;
 675                             }
 676                         }
 677                     }
 678                     else
 679                     {
 680                         result = menuItem->ResetSelected(this);
 681                         if (result.Error()) return result;
 682                         menuItem->ResetMouseInClient();
 683                     }
 684                 }
 685                 child = child->NextSibling();
 686             }
 687             if (MenuInvalidated())
 688             {
 689                 auto result = InvalidateMenu();
 690                 if (result.Error()) return result;
 691             }
 692             return Result<bool>(true);
 693         }
 694         [nodiscard]
 695         internal override Result<bool> InvalidateMenu()
 696         {
 697             auto result = Invalidate();
 698             if (result.Error()) return result;
 699             Rect menuRect;
 700             Component* child = children.FirstChild();
 701             while (child != null)
 702             {
 703                 if (child is MenuItem*)
 704                 {
 705                     MenuItem* menuItem = cast<MenuItem*>(child);
 706                     if (menuItem->GetState() == MenuItem.State.open)
 707                     {
 708                         menuItem->GetOpenRect(menuRect);
 709                     }
 710                 }
 711                 child = child->NextSibling();
 712             }
 713             if (IsOpen())
 714             {
 715                 if (menuBox != null)
 716                 {
 717                     menuBox->SetPaintThisMenuBox(true);
 718                     auto locResult = Location();
 719                     if (locResult.Error())
 720                     {
 721                         return Result<bool>(ErrorId(locResult.GetErrorId()));
 722                     }
 723                     Point loc = locResult.Value();
 724                     auto result = menuBox->SetLocation(Point(loc.x + menuRect.location.xloc.y + menuRect.location.y));
 725                     if (result.Error()) return result;
 726                     result = menuBox->SetSize(menuRect.size);
 727                     if (result.Error()) return result;
 728                     Control* parentControl = ParentControl();
 729                     Control* topControl = null;
 730                     if (parentControl != null)
 731                     {
 732                         topControl = parentControl->TopControl();
 733                     }
 734                     result = menuBox->BringToFront();
 735                     if (result.Error()) return result;
 736                     result = menuBox->Show();
 737                     if (result.Error()) return result;
 738                     result = menuBox->Invalidate();
 739                     if (result.Error()) return result;
 740                     menuBox->Update();
 741                     if (topControl != null)
 742                     {
 743                         result = topControl->BringToFront();
 744                         if (result.Error()) return result;
 745                     }
 746                 }
 747             }
 748             else
 749             {
 750                 if (menuBox != null)
 751                 {
 752                     menuBox->SetPaintThisMenuBox(false);
 753                     auto result = menuBox->Hide();
 754                     if (result.Error()) return result;
 755                 }
 756                 auto result = InvalidateParentRect(menuRect);
 757                 if (result.Error()) return result;
 758                 Control* parentControl = ParentControl();
 759                 if (parentControl != null)
 760                 {
 761                     parentControl->Update();
 762                 }
 763             }
 764             return Result<bool>(true);
 765         }
 766         private void CollectShortcuts()
 767         {
 768             shortcuts.Clear();
 769             Component* child = children.FirstChild();
 770             while (child != null)
 771             {
 772                 if (child is MenuItem*)
 773                 {
 774                     MenuItem* menuItem = cast<MenuItem*>(child);
 775                     menuItem->CollectShortcuts(shortcuts);
 776                 }
 777                 child = child->NextSibling();
 778             }
 779         }
 780         internal Result<bool> HandleAccessKey(wchar accessKeyKeys keyCodebool& wantsKeys)
 781         {
 782             ResetMenuInvalidated();
 783             LogView* logView = Application.GetLogView();
 784             if (logView != null)
 785             {
 786                 auto accessKeyHexResult = ToHexString(cast<ushort>(accessKey));
 787                 if (accessKeyHexResult.Error())
 788                 {
 789                     return Result<bool>(ErrorId(accessKeyHexResult.GetErrorId()));
 790                 }
 791                 auto accessKeyStrResult = ToString(accessKey);
 792                 if (accessKeyStrResult.Error())
 793                 {
 794                     return Result<bool>(ErrorId(accessKeyStrResult.GetErrorId()));
 795                 }
 796                 string s = "MENUBAR: access key = \'" + accessKeyStrResult.Value() + "\' " + accessKeyHexResult.Value() + ", key code = " + 
 797                     KeyCodeStrings.Instance().GetKeyCodeString(keyCode);
 798                 auto result = logView->WriteLine(s);
 799                 if (result.Error()) return result;
 800             }
 801             if (accessKey == '\0' && keyCode == Keys.none)
 802             {
 803                 if (!MenuKeyDisabled())
 804                 {
 805                     if (selectedMenuItem == null)
 806                     {
 807                         MenuItem* firstMenuItem = GetFirstMenuItem();
 808                         if (firstMenuItem != null)
 809                         {
 810                             SetOpen();
 811                             SetSelectedMenuItem(firstMenuItem);
 812                             wantsKeys = true;
 813                             auto result = InvalidateMenu();
 814                             if (result.Error()) return result;
 815                             return Result<bool>(true);
 816                         }
 817                     }
 818                     else
 819                     {
 820                         auto result = SetClosed();
 821                         if (result.Error()) return result;
 822                         MenuItem* openedMenuItem = GetOpenedMenuItem();
 823                         if (openedMenuItem != null)
 824                         {
 825                             result = openedMenuItem->SetState(MenuItem.State.closedthis);
 826                             if (result.Error()) return result;
 827                         }
 828                         result = selectedMenuItem->ResetSelected(this);
 829                         if (result.Error()) return result;
 830                         SetSelectedMenuItem(null);
 831                         wantsKeys = false;
 832                         result = InvalidateMenu();
 833                         if (result.Error()) return result;
 834                         return Result<bool>(true);
 835                     }
 836                 }
 837             }
 838             else if (accessKey != '\0' && keyCode == Keys.none)
 839             {
 840                 MenuItem* menuItem = GetMenuItemByAccessKey(accessKey);
 841                 if (menuItem != null)
 842                 {
 843                     MenuItem* firstMenuItem = menuItem->GetFirstMenuItem();
 844                     if (firstMenuItem != null)
 845                     {
 846                         if (selectedMenuItem != null)
 847                         {
 848                             MenuItem* openedMenuItem = GetOpenedMenuItem();
 849                             if (openedMenuItem != null)
 850                             {
 851                                 auto result = openedMenuItem->SetState(MenuItem.State.closedthis);
 852                                 if (result.Error()) return result;
 853                             }
 854                         }
 855                         SetOpen();
 856                         auto result = menuItem->SetState(MenuItem.State.openthis);
 857                         if (result.Error()) return result;
 858                         SetSelectedMenuItem(firstMenuItem);
 859                         wantsKeys = true;
 860                         result = InvalidateMenu();
 861                         if (result.Error()) return result;
 862                         return Result<bool>(true);
 863                     }
 864                 }
 865             }
 866             else if (accessKey == '\0' && keyCode != Keys.none)
 867             {
 868                 if (keyCode == Keys.menu)
 869                 {
 870                     wantsKeys = true;
 871                     return Result<bool>(true);
 872                 }
 873                 else
 874                 {
 875                     if (selectedMenuItem != null)
 876                     {
 877                         MenuItem* parentItem = selectedMenuItem->GetParentMenuItem();
 878                         Result<bool> handled = selectedMenuItem->HandleKey(keyCodewantsKeysparentItemthis);
 879                         if (MenuInvalidated())
 880                         {
 881                             auto result = InvalidateMenu();
 882                             if (result.Error()) return result;
 883                         }
 884                         return Result<bool>(handled.Value());
 885                     }
 886                 }
 887             }
 888             if (MenuInvalidated())
 889             {
 890                 auto result = InvalidateMenu();
 891                 if (result.Error()) return result;
 892             }
 893             wantsKeys = false;
 894             return Result<bool>(false);
 895         }
 896         [nodiscard]
 897         internal Result<bool> MouseDownInternal(MouseEventArgs& args)
 898         {
 899             return OnMouseDown(args);
 900         }
 901         [nodiscard]
 902         protected override Result<bool> OnMouseDown(MouseEventArgs& args)
 903         {
 904             auto result = base->OnMouseDown(args);
 905             if (result.Error()) return result;
 906             SetLatestMouseDownMenuItem(null);
 907             bool handled = false;
 908             Component* child = children.FirstChild();
 909             while (child != null)
 910             {
 911                 if (child is MenuItem*)
 912                 {
 913                     MenuItem* menuItem = cast<MenuItem*>(child);
 914                     result = menuItem->DoMouseDown(argshandledthis);
 915                     if (result.Error()) return result;
 916                     if (handled)
 917                     {
 918                         auto result = InvalidateMenu();
 919                         if (result.Error()) return result;
 920                         return Result<bool>(true);
 921                     }
 922                 }
 923                 child = child->NextSibling();
 924             }
 925             if (IsOpen())
 926             {
 927                 auto result = SetClosed();
 928                 if (result.Error()) return result;
 929                 SetLatestOpenedMenuItem(null);
 930                 Component* child = children.FirstChild();
 931                 while (child != null)
 932                 {
 933                     if (child is MenuItem*)
 934                     {
 935                         MenuItem* menuItem = cast<MenuItem*>(child);
 936                         result = menuItem->SetState(MenuItem.State.closedthis);
 937                         if (result.Error()) return result;
 938                     }
 939                     child = child->NextSibling();
 940                 }
 941                 result = InvalidateMenu();
 942                 if (result.Error()) return result;
 943             }
 944             return Result<bool>(true);
 945         }
 946         [nodiscard]
 947         internal Result<bool> MouseUpInternal(MouseEventArgs& args)
 948         {
 949             return OnMouseUp(args);
 950         }
 951         [nodiscard]
 952         protected override Result<bool> OnMouseUp(MouseEventArgs& args)
 953         {
 954             auto result = base->OnMouseUp(args);
 955             if (result.Error()) return result;
 956             bool handled = false;
 957             Component* child = children.FirstChild();
 958             while (child != null)
 959             {
 960                 if (child is MenuItem*)
 961                 {
 962                     MenuItem* menuItem = cast<MenuItem*>(child);
 963                     if (menuItem->IsEnabled())
 964                     {
 965                         auto result = menuItem->DoMouseUp(argshandledthis);
 966                         if (result.Error()) return result;
 967                         if (handled)
 968                         {
 969                             result = InvalidateMenu();
 970                             if (result.Error()) return result;
 971                             return Result<bool>(true);
 972                         }
 973                     }
 974                 }
 975                 child = child->NextSibling();
 976             }
 977             return Result<bool>(true);
 978         }
 979         internal override void SetLatestOpenedMenuItem(MenuItem* menuItem)
 980         {
 981             latestOpenedMenuItem = menuItem;
 982         }
 983         internal override MenuItem* LatestOpenedMenuItem() const
 984         {
 985             return latestOpenedMenuItem;
 986         }
 987         internal override MenuItem* GetOpenedMenuItem() const
 988         {
 989             Component* child = children.FirstChild();
 990             while (child != null)
 991             {
 992                 if (child is MenuItem*)
 993                 {
 994                     MenuItem* childItem = cast<MenuItem*>(child);
 995                     if (childItem->GetState() == MenuItem.State.open)
 996                     {
 997                         return childItem;
 998                     }
 999                 }
1000                 child = child->NextSibling();
1001             }
1002             return null;
1003         }
1004         internal override MenuItem* GetFirstMenuItem() const
1005         {
1006             Component* child = children.FirstChild();
1007             while (child != null)
1008             {
1009                 if (child is MenuItem*)
1010                 {
1011                     MenuItem* menuItem = cast<MenuItem*>(child);
1012                     return menuItem;
1013                 }
1014                 child = child->NextSibling();
1015             }
1016             return null;
1017         }
1018         internal override MenuItem* GetLastMenuItem() const
1019         {
1020             Component* child = children.LastChild();
1021             while (child != null)
1022             {
1023                 if (child is MenuItem*)
1024                 {
1025                     MenuItem* menuItem = cast<MenuItem*>(child);
1026                     return menuItem;
1027                 }
1028                 child = child->PrevSibling();
1029             }
1030             return null;
1031         }
1032         internal override MenuItem* GetMenuItemByAccessKey(wchar accessKey)
1033         {
1034             Component* child = children.FirstChild();
1035             while (child != null)
1036             {
1037                 if (child is MenuItem*)
1038                 {
1039                     MenuItem* menuItem = cast<MenuItem*>(child);
1040                     if (menuItem->AccessKey() == accessKey)
1041                     {
1042                         return menuItem;
1043                     }
1044                 }
1045                 child = child->NextSibling();
1046             }
1047             return null;
1048         }
1049         internal override MenuItem* GetSelectedMenuItem() const
1050         {
1051             return selectedMenuItem;
1052         }
1053         internal override void SetSelectedMenuItem(MenuItem* selectedMenuItem_)
1054         {
1055             selectedMenuItem = selectedMenuItem_;
1056         }
1057         internal override MenuItem* GetLatestMouseDownMenuItem() const
1058         {
1059             return latestMouseDownMenuItem;
1060         }
1061         internal override void SetLatestMouseDownMenuItem(MenuItem* menuItem)
1062         {
1063             latestMouseDownMenuItem = menuItem;
1064         }
1065         public void DisableMenuKey()
1066         {
1067             flags = cast<Flags>(flags | Flags.menuKeyDisabled);
1068         }
1069         public inline bool MenuKeyDisabled() const
1070         {
1071             return (flags & Flags.menuKeyDisabled) != Flags.none;
1072         }
1073         private inline bool MenuChanged()
1074         {
1075             return (flags & Flags.menuChanged) != Flags.none;
1076         }
1077         internal override void SetMenuChanged()
1078         {
1079             flags = cast<Flags>(flags | Flags.menuChanged);
1080         }
1081         private inline void ResetMenuChanged()
1082         {
1083             flags = cast<Flags>(flags & ~Flags.menuChanged);
1084         }
1085         private inline bool MenuInvalidated() const
1086         {
1087             return (flags & Flags.menuInvalidated) != Flags.none;
1088         }
1089         internal override Result<bool> SetMenuInvalidated()
1090         {
1091             flags = cast<Flags>(flags | Flags.menuInvalidated);
1092             return Result<bool>(true);
1093         }
1094         private inline void ResetMenuInvalidated()
1095         {
1096             flags = cast<Flags>(flags & ~Flags.menuInvalidated);
1097         }
1098         internal override bool IsOpen() const
1099         {
1100             return (flags & Flags.open) != Flags.none;
1101         }
1102         public override void SetOpen()
1103         {
1104             flags = cast<Flags>(flags | Flags.open);
1105         }
1106         [nodiscard]
1107         public override Result<bool> SetClosed()
1108         {
1109             if (IsOpen())
1110             {
1111                 flags = cast<Flags>(flags & ~Flags.open);
1112                 auto result = InvalidateMenu();
1113                 if (result.Error()) return result;
1114             }
1115             return Result<bool>(true);
1116         }
1117         private bool MenuBoxAdded() const
1118         {
1119             return (flags & Flags.menuBoxAdded) != Flags.none;
1120         }
1121         private void SetMenuBoxAdded()
1122         {
1123             flags = cast<Flags>(flags | Flags.menuBoxAdded);
1124         }
1125         private Result<bool> AddMenuBox()
1126         {
1127             Control* parentControl = ParentControl();
1128             if (parentControl != null && parentControl is ContainerControl*)
1129             {
1130                 menuBox = new MenuBox(GetFont()thisnull);
1131                 if (menuBox->Error())
1132                 {
1133                     return Result<bool>(ErrorId(menuBox->GetErrorId()));
1134                 }
1135                 ContainerControl* containerControl = cast<ContainerControl*>(parentControl);
1136                 auto result = containerControl->InsertChildAfter(menuBoxthis);
1137                 if (result.Error())
1138                 {
1139                     return Result<bool>(ErrorId(result.GetErrorId()));
1140                 }
1141             }
1142             return Result<bool>(true);
1143         }
1144         private Flags flags;
1145         private ComponentContainer children;
1146         private MenuItem* latestOpenedMenuItem;
1147         private MenuItem* selectedMenuItem;
1148         private MenuItem* latestMouseDownMenuItem;
1149         private HashMap<KeysMenuItem*> shortcuts;
1150         private MenuBox* menuBox;
1151     }
1152 
1153     public ControlCreateParams& MenuBoxControlCreateParams(ControlCreateParams& controlCreateParams)
1154     {
1155         return controlCreateParams.SetWindowStyle(HiddenChildWindowStyle()).
1156             SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor()).
1157             SetWindowClassName("System.Windows.MenuBox");
1158     }
1159 
1160     public class MenuBoxCreateParams
1161     {
1162         public MenuBoxCreateParams(MenuControlCreateParams& menuControlCreateParams_) : menuControlCreateParams(menuControlCreateParams_)
1163         {
1164         }
1165         public MenuBoxCreateParams& Defaults()
1166         {
1167             return *this;
1168         }
1169         public MenuControlCreateParams& menuControlCreateParams;
1170     }
1171 
1172     public class MenuBox : MenuControl
1173     {
1174         public MenuBox(const Font& fontMenuBar* menuBar_MenuItem* rootItem_) : 
1175             base(font"System.Windows.MenuBox"DefaultWindowClassStyle()HiddenChildWindowStyle()DefaultExtendedWindowStyle()
1176             Color.White()"menuBox"Point()Size()Dock.noneAnchors.none)menuBar(menuBar_)rootItem(rootItem_)paintThisMenuBox(false)
1177         {
1178             if (rootItem != null && rootItem->Error())
1179             {
1180                 SetErrorId(rootItem->GetErrorId());
1181                 return;
1182             }
1183         }
1184         public MenuBox(MenuBoxCreateParams& createParamsMenuBar* menuBar_MenuItem* rootItem_) : 
1185             base(createParams.menuControlCreateParams)menuBar(menuBar_)rootItem(rootItem_)paintThisMenuBox(false)
1186         {
1187             if (rootItem != null && rootItem->Error())
1188             {
1189                 SetErrorId(rootItem->GetErrorId());
1190                 return;
1191             }
1192         }
1193         public void SetPaintThisMenuBox(bool paintThisMenuBox_)
1194         {
1195             paintThisMenuBox = paintThisMenuBox_;
1196         }
1197         public inline bool PaintThisMenuBox() const
1198         {
1199             return paintThisMenuBox;
1200         }
1201         [nodiscard]
1202         public override Result<bool> PrintWindowTree(int level)
1203         {
1204             LogView* log = Application.GetLogView();
1205             if (log != null)
1206             {
1207                 auto handleResult = ToHexString(cast<ulong>(Handle()));
1208                 if (handleResult.Error())
1209                 {
1210                     return Result<bool>(ErrorId(handleResult.GetErrorId()));
1211                 }
1212                 const string& handleStr = handleResult.Value();
1213                 auto parentTextResult = ParentText();
1214                 if (parentTextResult.Error())
1215                 {
1216                     return Result<bool>(ErrorId(parentTextResult.GetErrorId()));
1217                 }
1218                 const string& parentText = parentTextResult.Value();
1219                 auto result = log->WriteLine(string(' 'level) + "MenuBox." + Text() + ".handle=" + handleStr + " " + parentText + 
1220                     "[" + Rect(Point()GetSize()).ToString() + "]");
1221                 if (result.Error()) return result;
1222             }
1223             return Result<bool>(true);
1224         }
1225         protected virtual Result<Point> GetBoxLocation() const
1226         {
1227             return Location();
1228         }
1229         [nodiscard]
1230         protected override Result<bool> OnPaint(PaintEventArgs& args)
1231         {
1232             if (Debug.Paint())
1233             {
1234                 Rect r(Point()GetSize());
1235                 LogView* log = Application.GetLogView();
1236                 if (log != null)
1237                 {
1238                     auto result = log->WriteLine("MenuBox.OnPaint: " + r.ToString());
1239                     if (result.Error()) return result;
1240                 }
1241             }
1242             auto locResult = Location();
1243             if (locResult.Error())
1244             {
1245                 return Result<bool>(ErrorId(locResult.GetErrorId()));
1246             }
1247             Point loc = locResult.Value();
1248             if (!paintMenu)
1249             {
1250                 if (paintThisMenuBox)
1251                 {
1252                     Control* parentControl = ParentControl();
1253                     if (parentControl != null)
1254                     {
1255                         Bitmap menuBoxBitmap(args.clipRect.size.wargs.clipRect.size.hargs.graphics);
1256                         auto menuBoxBitmapResult = Graphics.FromImage(menuBoxBitmap);
1257                         if (menuBoxBitmapResult.Error())
1258                         {
1259                             return Result<bool>(ErrorId(menuBoxBitmapResult.GetErrorId()));
1260                         }
1261                         Graphics& menuBoxGraphics = menuBoxBitmapResult.Value();
1262                         Rect menuBoxClipRect(Point(00)Size(args.clipRect.size.wargs.clipRect.size.h));
1263                         auto setClipResult = menuBoxGraphics.SetClip(menuBoxClipRect);
1264                         if (setClipResult.Error())
1265                         {
1266                             return Result<bool>(ErrorId(setClipResult.GetErrorId()));
1267                         }
1268                         auto translateResult = menuBoxGraphics.TranslateTransform(-loc.x-loc.y);
1269                         if (translateResult.Error())
1270                         {
1271                             return Result<bool>(ErrorId(translateResult.GetErrorId()));
1272                         }
1273                         PaintEventArgs paintMenuBoxArgs(menuBoxGraphicsmenuBoxClipRect);
1274                         bool prevPaintMenu = paintMenu;
1275                         paintMenu = true;
1276                         bool skipMenuBar = this is ContextMenu*;
1277                         auto paintResult = parentControl->PaintAll(paintMenuBoxArgsskipMenuBar);
1278                         if (paintResult.Error())
1279                         {
1280                             return Result<bool>(ErrorId(paintResult.GetErrorId()));
1281                         }
1282                         paintMenu = prevPaintMenu;
1283                         auto drawImageResult = args.graphics.DrawImage(menuBoxBitmapPointF(00));
1284                         if (drawImageResult.Error())
1285                         {
1286                             return Result<bool>(ErrorId(drawImageResult.GetErrorId()));
1287                         }
1288                     }
1289                 }
1290             }
1291             else
1292             {
1293                 if (menuBar != null)
1294                 {
1295                     auto drawResult = menuBar->DrawMenuItems(argstrueloc);
1296                     if (drawResult.Error())
1297                     {
1298                         return Result<bool>(ErrorId(drawResult.GetErrorId()));
1299                     }
1300                 }
1301                 else if (rootItem != null)
1302                 {
1303                     auto drawResult = rootItem->Draw(args.graphicsDefaultPadding()TextBrush()DisabledTextBrush()BackgroundBrush()MouseOverBrush()
1304                         MenuOpenBrush()ShadowBrush()BlackBrush()BlackPen()
1305                         DarkPen()GetFont()Format()MenuOpenColor()thistruePoint());
1306                     if (drawResult.Error())
1307                     {
1308                         return Result<bool>(ErrorId(drawResult.GetErrorId()));
1309                     }
1310                 }
1311             }
1312             return Result<bool>(true);
1313         }
1314         private Control* ParentControl() const
1315         {
1316             ComponentContainer* container = GetContainer();
1317             if (container != null)
1318             {
1319                 Component* parent = container->Parent();
1320                 if (parent != null && (parent is Control*))
1321                 {
1322                     return cast<Control*>(parent);
1323                 }
1324             }
1325             return null;
1326         }
1327         [nodiscard]
1328         protected override Result<bool> OnMouseEnter(EnterLeaveEventArgs& args)
1329         {
1330             auto result = base->OnMouseEnter(args);
1331             if (result.Error()) return result;
1332             if (menuBar != null)
1333             {
1334                 result = menuBar->MouseEnterInternal();
1335                 if (result.Error()) return result;
1336             }
1337             return Result<bool>(true);
1338         }
1339         [nodiscard]
1340         protected override Result<bool> OnMouseMove(MouseEventArgs& args)
1341         {
1342             auto result = base->OnMouseMove(args);
1343             if (result.Error()) return result;
1344             if (menuBar != null)
1345             {
1346                 auto locResult = Location();
1347                 if (locResult.Error())
1348                 {
1349                     return Result<bool>(ErrorId(locResult.GetErrorId()));
1350                 }
1351                 Point loc = locResult.Value();
1352                 args.location.x = args.location.x + loc.x;
1353                 args.location.y = args.location.y + loc.y;
1354                 auto result = menuBar->MouseMoveInternal(args);
1355                 if (result.Error()) return result;
1356             }
1357             else if (rootItem != null)
1358             {
1359                 bool handled = false;
1360                 auto result = rootItem->DispatchMouseMove(argshandledthis);
1361                 if (result.Error()) return result;
1362             }
1363             return Result<bool>(true);
1364         }
1365         [nodiscard]
1366         protected override Result<bool> OnMouseLeave(EnterLeaveEventArgs& args)
1367         {
1368             auto result = base->OnMouseLeave(args);
1369             if (result.Error()) return result;
1370             if (menuBar != null)
1371             {
1372                 result = menuBar->MouseLeaveInternal();
1373                 if (result.Error()) return result;
1374             }
1375             else if (rootItem != null)
1376             {
1377                 result = rootItem->LeaveChildren(this);
1378                 if (result.Error()) return result;
1379             }
1380             return Result<bool>(true);
1381         }
1382         [nodiscard]
1383         protected override Result<bool> OnMouseDown(MouseEventArgs& args)
1384         {
1385             auto result = base->OnMouseDown(args);
1386             if (result.Error()) return result;
1387             if (menuBar != null)
1388             {
1389                 auto locResult = Location();
1390                 if (locResult.Error())
1391                 {
1392                     return Result<bool>(ErrorId(locResult.GetErrorId()));
1393                 }
1394                 Point loc = locResult.Value();
1395                 args.location.x = args.location.x + loc.x;
1396                 args.location.y = args.location.y + loc.y;
1397                 result = menuBar->MouseDownInternal(args);
1398                 if (result.Error()) return result;
1399             }
1400             else if (rootItem != null)
1401             {
1402                 SetLatestMouseDownMenuItem(null);
1403                 bool handled = false;
1404                 auto result = rootItem->DoMouseDown(argshandledthis);
1405                 if (result.Error()) return result;
1406                 if (handled)
1407                 {
1408                     result = Invalidate();
1409                     if (result.Error()) return result;
1410                 }
1411             }
1412             return Result<bool>(true);
1413         }
1414         [nodiscard]
1415         protected override Result<bool> OnMouseUp(MouseEventArgs& args)
1416         {
1417             auto result = base->OnMouseUp(args);
1418             if (result.Error()) return result;
1419             if (menuBar != null)
1420             {
1421                 auto locResult = Location();
1422                 if (locResult.Error())
1423                 {
1424                     return Result<bool>(ErrorId(locResult.GetErrorId()));
1425                 }
1426                 Point loc = locResult.Value();
1427                 args.location.x = args.location.x + loc.x;
1428                 args.location.y = args.location.y + loc.y;
1429                 result = menuBar->MouseUpInternal(args);
1430                 if (result.Error()) return result;
1431             }
1432             else if (rootItem != null)
1433             {
1434                 bool handled = false;
1435                 auto result = rootItem->DoMouseUp(argshandledthis);
1436                 if (result.Error()) return result;
1437                 if (handled)
1438                 {
1439                     result = Invalidate();
1440                     if (result.Error()) return result;
1441                 }
1442             }
1443             return Result<bool>(true);
1444         }
1445         protected inline MenuItem* GetRootItem() const
1446         {
1447             return rootItem;
1448         }
1449         private MenuBar* menuBar;
1450         private MenuItem* rootItem;
1451         private bool paintThisMenuBox;
1452         private bool paintMenu;
1453     }
1454 
1455     public abstract class ClickAction
1456     {
1457         public ClickAction()
1458         {
1459             clickEventHandler = Click;
1460         }
1461         public virtual default ~ClickAction();
1462         public void AddHandlerTo(MenuItem& menuItem)
1463         {
1464             menuItem.ClickEvent().AddHandler(clickEventHandler);
1465         }
1466         private void Click(ClickEventArgs& args)
1467         {
1468             auto result = Execute();
1469             if (result.Error())
1470             {
1471                 args.errorId = result.GetErrorId();
1472             }
1473         }
1474         [nodiscard]
1475         protected abstract Result<bool> Execute();
1476         private ClickEventHandler clickEventHandler;
1477     }
1478 
1479     public class ClickActions
1480     {
1481         public void Add(ClickAction* action)
1482         {
1483             clickActions.Add(UniquePtr<ClickAction>(action));
1484         }
1485         private List<UniquePtr<ClickAction>> clickActions;
1486     }
1487 
1488     public ControlCreateParams& ContextMenuControlCreateParams(ControlCreateParams& controlCreateParams)
1489     {
1490         return controlCreateParams.SetWindowStyle(HiddenChildWindowStyle()).
1491             SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor()).
1492             SetWindowClassName("System.Windows.ContextMenu");
1493     }
1494 
1495     public MenuBoxCreateParams& ContextMenuMenuBoxCreateParams(MenuBoxCreateParams& menuBoxCreateParams)
1496     {
1497         return menuBoxCreateParams;
1498     }
1499 
1500     public class ContextMenuCreateParams
1501     {
1502         public ContextMenuCreateParams(MenuBoxCreateParams& menuBoxCreateParams_) : menuBoxCreateParams(menuBoxCreateParams_)
1503         {
1504         }
1505         public ContextMenuCreateParams& Defaults()
1506         {
1507             return *this;
1508         }
1509         public MenuBoxCreateParams& menuBoxCreateParams;
1510     }
1511 
1512     public class ContextMenu : MenuBox
1513     {
1514         public ContextMenu(const Font& font) : 
1515             base(fontnullnew MenuItem("root"))
1516             rootItemPtr(GetRootItem())latestOpenedMenuItem(null)selectedMenuItem(null)latestMouseDownMenuItem(null)
1517         {
1518         }
1519         public ContextMenu() : this(Font(FontFamily("Segoe UI")9.000000f))
1520         {
1521         }
1522         public ContextMenu(ContextMenuCreateParams& createParams) : 
1523             base(createParams.menuBoxCreateParamsnullnew MenuItem("root"))
1524             rootItemPtr(GetRootItem())latestOpenedMenuItem(null)selectedMenuItem(null)latestMouseDownMenuItem(null)
1525         {
1526         }
1527         [nodiscard]
1528         public Result<bool> AddMenuItem(MenuItemBase* menuItem)
1529         {
1530             return rootItemPtr->AddMenuItem(menuItem);
1531         }
1532         [nodiscard]
1533         public Result<bool> AddMenuItemAction(MenuItem* menuItemClickAction* action)
1534         {
1535             auto result = rootItemPtr->AddMenuItem(menuItem);
1536             if (result.Error()) return result;
1537             action->AddHandlerTo(*menuItem);
1538             clickActions.Add(action);
1539             return Result<bool>(true);
1540         }
1541         [nodiscard]
1542         public Result<bool> CalculateSize()
1543         {
1544             auto result = rootItemPtr->SetState(MenuItem.State.openthis);
1545             if (result.Error()) return result;
1546             auto windowHandleGraphicsResult = Graphics.FromWindowHandle(Handle());
1547             if (windowHandleGraphicsResult.Error())
1548             {
1549                 return Result<bool>(ErrorId(windowHandleGraphicsResult.GetErrorId()));
1550             }
1551             Graphics& graphics = windowHandleGraphicsResult.Value();
1552             rootItemPtr->CalculateChildRect(graphicsGetFont()Format()Point(00));
1553             Rect menuRect;
1554             rootItemPtr->GetOpenRect(menuRect);
1555             result = SetSize(menuRect.size);
1556             if (result.Error()) return result;
1557             return Result<bool>(true);
1558         }
1559         public bool HasMenuItems()
1560         {
1561             return !rootItemPtr->Children().IsEmpty();
1562         }
1563         protected override Result<Point> GetBoxLocation() const
1564         {
1565             return Result<Point>(Point(00));
1566         }
1567         [nodiscard]
1568         protected override Result<bool> OnPaint(PaintEventArgs& args)
1569         {
1570             SetPaintThisMenuBox(true);
1571             return base->OnPaint(args);
1572         }
1573         [nodiscard]
1574         protected override Result<bool> OnVisibleChanged()
1575         {
1576             auto result = base->OnVisibleChanged();
1577             if (result.Error()) return result;
1578             if (!IsVisible())
1579             {
1580                 result = rootItemPtr->SetState(MenuItem.State.closedthis);
1581                 if (result.Error()) return result;
1582                 SetPaintThisMenuBox(false);
1583             }
1584             return Result<bool>(true);
1585         }
1586         [nodiscard]
1587         internal override Result<bool> SetMenuInvalidated()
1588         {
1589             return Invalidate();
1590         }
1591         internal override bool IsOpen() const
1592         {
1593             return rootItemPtr->GetState() == MenuItem.State.open;
1594         }
1595         internal override MenuItem* GetSelectedMenuItem() const
1596         {
1597             return selectedMenuItem;
1598         }
1599         internal override void SetSelectedMenuItem(MenuItem* selectedMenuItem_)
1600         {
1601             selectedMenuItem = selectedMenuItem_;
1602         }
1603         internal override MenuItem* LatestOpenedMenuItem() const
1604         {
1605             return latestOpenedMenuItem;
1606         }
1607         internal override void SetLatestOpenedMenuItem(MenuItem* menuItem)
1608         {
1609             latestOpenedMenuItem = menuItem;
1610         }
1611         internal override MenuItem* GetLatestMouseDownMenuItem() const
1612         {
1613             return latestMouseDownMenuItem;
1614         }
1615         internal override void SetLatestMouseDownMenuItem(MenuItem* menuItem)
1616         {
1617             latestMouseDownMenuItem = menuItem;
1618         }
1619         internal override MenuItem* GetOpenedMenuItem() const
1620         {
1621             return rootItemPtr.Get();
1622         }
1623         private UniquePtr<MenuItem> rootItemPtr;
1624         private MenuItem* latestOpenedMenuItem;
1625         private MenuItem* selectedMenuItem;
1626         private MenuItem* latestMouseDownMenuItem;
1627         private ClickActions clickActions;
1628     }
1629 
1630     public abstract class MenuItemBase : Component
1631     {
1632         public MenuItemBase() : location()size()
1633         {
1634         }
1635         public abstract Result<bool> Draw(Graphics& graphicsconst Padding& parentPaddingconst Brush& textBrushconst Brush& disabledTextBrush
1636             const Brush& backgroundBrushconst Brush& mouseOverBrushconst Brush& menuOpenBrushconst Brush& shadowBrushconst Brush& blackBrush
1637             const Pen& blackPenconst Pen& darkPenconst Font& fontconst StringFormat& formatconst Color& menuOpenColor
1638             MenuControl* menuControlbool drawSubItemsconst Point& origin);
1639         internal MenuItem* GetParentMenuItem() const
1640         {
1641             ComponentContainer* container = GetContainer();
1642             if (container != null)
1643             {
1644                 Component* parent = container->Parent();
1645                 if (parent != null)
1646                 {
1647                     if (parent is MenuItem*)
1648                     {
1649                         MenuItem* parentMenuItem = cast<MenuItem*>(parent);
1650                         return parentMenuItem;
1651                     }
1652                 }
1653             }
1654             return null;
1655         }
1656         public virtual Padding DefaultPadding() const
1657         {
1658             return Padding(0000);
1659         }
1660         public int Level() const
1661         {
1662             MenuItem* parent = GetParentMenuItem();
1663             if (parent == null)
1664             {
1665                 return 0;
1666             }
1667             else
1668             {
1669                 return parent->Level() + 1;
1670             }
1671         }
1672         public const Point& Location() const
1673         {
1674             return location;
1675         }
1676         public void SetLocation(const Point& location_)
1677         {
1678             location = location_;
1679         }
1680         public const Size& GetSize() const
1681         {
1682             return size;
1683         }
1684         public void SetSize(const Size& size_)
1685         {
1686             size = size_;
1687         }
1688         public abstract Size MeasureItem(Graphics& graphicsconst Font& fontconst StringFormat& formatint& maxShortcutWidthint& childIndicatorWidth);
1689         private Point location;
1690         private Size size;
1691     }
1692 
1693     public class MenuItem : MenuItemBase
1694     {
1695         public enum State : sbyte
1696         {
1697             closed = 0open = 1
1698         }
1699         private enum Flags : sbyte
1700         {
1701             none = 0disabled = 1 << 0selected = 1 << 1mouseInClient = 1 << 2lbuttonPressed = 1 << 3
1702         }
1703         public explicit MenuItem(const string& text_) : 
1704             base()text(text_)children(this)state(State.closed)childRect()unionRect()flags(Flags.none)accessKey('\0')shortcut(Keys.none)shortcutFieldWidth(0)
1705         {
1706             SetAccessKey();
1707         }
1708         [nodiscard]
1709         public Result<bool> AddMenuItem(MenuItemBase* menuItem)
1710         {
1711             return children.AddChild(menuItem);
1712         }
1713         public MenuItem* GetFirstMenuItem() const
1714         {
1715             Component* child = children.FirstChild();
1716             while (child != null)
1717             {
1718                 if (child is MenuItem*)
1719                 {
1720                     MenuItem* childMenuItem = cast<MenuItem*>(child);
1721                     return childMenuItem;
1722                 }
1723                 child = child->NextSibling();
1724             }
1725             return null;
1726         }
1727         public MenuItem* GetLastMenuItem() const
1728         {
1729             Component* child = children.LastChild();
1730             while (child != null)
1731             {
1732                 if (child is MenuItem*)
1733                 {
1734                     MenuItem* childMenuItem = cast<MenuItem*>(child);
1735                     return childMenuItem;
1736                 }
1737                 child = child->PrevSibling();
1738             }
1739             return null;
1740         }
1741         public MenuItem* GetNextMenuItem() const
1742         {
1743             Component* next = NextSibling();
1744             while (next != null)
1745             {
1746                 if (next is MenuItem*)
1747                 {
1748                     MenuItem* nextMenuItem = cast<MenuItem*>(next);
1749                     return nextMenuItem;
1750                 }
1751                 next = next->NextSibling();
1752             }
1753             return null;
1754         }
1755         public MenuItem* GetPrevMenuItem() const
1756         {
1757             Component* prev = PrevSibling();
1758             while (prev != null)
1759             {
1760                 if (prev is MenuItem*)
1761                 {
1762                     MenuItem* prevMenuItem = cast<MenuItem*>(prev);
1763                     return prevMenuItem;
1764                 }
1765                 prev = prev->PrevSibling();
1766             }
1767             return null;
1768         }
1769         public MenuItem* GetParentMenuItem() const
1770         {
1771             ComponentContainer* container = GetContainer();
1772             if (container != null)
1773             {
1774                 Component* parent = container->Parent();
1775                 if (parent != null)
1776                 {
1777                     if (parent is MenuItem*)
1778                     {
1779                         MenuItem* parentItem = cast<MenuItem*>(parent);
1780                         return parentItem;
1781                     }
1782                 }
1783             }
1784             return null;
1785         }
1786         private MenuControl* GetMenuControl() const
1787         {
1788             ComponentContainer* container = GetContainer();
1789             if (container != null)
1790             {
1791                 Component* parent = container->Parent();
1792                 if (parent != null)
1793                 {
1794                     if (parent is MenuItem*)
1795                     {
1796                         MenuItem* parentItem = cast<MenuItem*>(parent);
1797                         return parentItem->GetMenuControl();
1798                     }
1799                     else if (parent is MenuControl*)
1800                     {
1801                         MenuControl* menuControl = cast<MenuControl*>(parent);
1802                         return menuControl;
1803                     }
1804                 }
1805             }
1806             return null;
1807         }
1808         [nodiscard]
1809         internal Result<bool> HandleKey(Keys keybool& wantsKeysMenuItem* parentMenuItemMenuControl* menuControl)
1810         {
1811             if (key >= Keys.a && key <= Keys.z || key >= Keys.d0 && key <= Keys.d9)
1812             {
1813                 wchar accessKey = cast<wchar>(cast<int>(key));
1814                 MenuItem* childItem = null;
1815                 if (parentMenuItem != null)
1816                 {
1817                     childItem = parentMenuItem->GetChildItemByAccessKey(accessKey);
1818                 }
1819                 else
1820                 {
1821                     childItem = menuControl->GetMenuItemByAccessKey(accessKey);
1822                 }
1823                 if (childItem != null && childItem->IsEnabled())
1824                 {
1825                     auto result = childItem->Execute(parentMenuItemwantsKeysmenuControl);
1826                     if (result.Error()) return result;
1827                     return Result<bool>(true);
1828                 }
1829                 else
1830                 {
1831                     wantsKeys = true;
1832                     return Result<bool>(false);
1833                 }
1834             }
1835             else
1836             {
1837                 switch (key)
1838                 {
1839                     case Keys.enter:
1840                     {
1841                         if (IsEnabled())
1842                         {
1843                             auto result = Execute(parentMenuItemwantsKeysmenuControl);
1844                             if (result.Error()) return result;
1845                             return Result<bool>(true);
1846                         }
1847                         else
1848                         {
1849                             wantsKeys = true;
1850                             return Result<bool>(false);
1851                         }
1852                     }
1853                     case Keys.escape:
1854                     {
1855                         MenuItem* openedMenuItem = menuControl->GetOpenedMenuItem();
1856                         if (openedMenuItem != null)
1857                         {
1858                             auto result = openedMenuItem->SetState(State.closedmenuControl);
1859                             if (result.Error()) return result;
1860                         }
1861                         wantsKeys = false;
1862                         menuControl->SetSelectedMenuItem(null);
1863                         auto result = menuControl->SetClosed();
1864                         if (result.Error()) return result;
1865                         result = menuControl->SetMenuInvalidated();
1866                         if (result.Error()) return result;
1867                         return Result<bool>(true);
1868                     }
1869                     case Keys.home:
1870                     {
1871                         if (Level() == 0)
1872                         {
1873                             MenuItem* firstMenuItem = menuControl->GetFirstMenuItem();
1874                             if (firstMenuItem != null)
1875                             {
1876                                 menuControl->SetSelectedMenuItem(firstMenuItem);
1877                                 wantsKeys = true;
1878                                 auto result = menuControl->SetMenuInvalidated();
1879                                 if (result.Error()) return result;
1880                                 return Result<bool>(true);
1881                             }
1882                         }
1883                         else
1884                         {
1885                             MenuItem* parentMenuItem = GetParentMenuItem();
1886                             if (parentMenuItem != null)
1887                             {
1888                                 MenuItem* firstMenuItem = parentMenuItem->GetFirstMenuItem();
1889                                 if (firstMenuItem != null)
1890                                 {
1891                                     menuControl->SetSelectedMenuItem(firstMenuItem);
1892                                     wantsKeys = true;
1893                                     auto result = menuControl->SetMenuInvalidated();
1894                                     if (result.Error()) return result;
1895                                     return Result<bool>(true);
1896                                 }
1897                             }
1898                         }
1899                         break;
1900                     }
1901                     case Keys.end:
1902                     {
1903                         if (Level() == 0)
1904                         {
1905                             MenuItem* lastMenuItem = menuControl->GetLastMenuItem();
1906                             if (lastMenuItem != null)
1907                             {
1908                                 menuControl->SetSelectedMenuItem(lastMenuItem);
1909                                 wantsKeys = true;
1910                                 auto result = menuControl->SetMenuInvalidated();
1911                                 if (result.Error()) return result;
1912                                 return Result<bool>(true);
1913                             }
1914                         }
1915                         else
1916                         {
1917                             MenuItem* parentMenuItem = GetParentMenuItem();
1918                             if (parentMenuItem != null)
1919                             {
1920                                 MenuItem* lastMenuItem = parentMenuItem->GetLastMenuItem();
1921                                 if (lastMenuItem != null)
1922                                 {
1923                                     menuControl->SetSelectedMenuItem(lastMenuItem);
1924                                     wantsKeys = true;
1925                                     auto result = menuControl->SetMenuInvalidated();
1926                                     if (result.Error()) return result;
1927                                     return Result<bool>(true);
1928                                 }
1929                             }
1930                         }
1931                         break;
1932                     }
1933                     case Keys.down:
1934                     {
1935                         if (Level() == 0)
1936                         {
1937                             auto result = SetState(state.openmenuControl);
1938                             if (result.Error()) return result;
1939                             MenuItem* firstChild = GetFirstMenuItem();
1940                             if (firstChild != null)
1941                             {
1942                                 menuControl->SetSelectedMenuItem(firstChild);
1943                                 wantsKeys = true;
1944                                 result = menuControl->SetMenuInvalidated();
1945                                 if (result.Error()) return result;
1946                                 return Result<bool>(true);
1947                             }
1948                         }
1949                         else
1950                         {
1951                             MenuItem* nextMenuItem = GetNextMenuItem();
1952                             if (nextMenuItem != null)
1953                             {
1954                                 menuControl->SetSelectedMenuItem(nextMenuItem);
1955                                 wantsKeys = true;
1956                                 auto result = menuControl->SetMenuInvalidated();
1957                                 if (result.Error()) return result;
1958                                 return Result<bool>(true);
1959                             }
1960                             else
1961                             {
1962                                 if (parentMenuItem != null)
1963                                 {
1964                                     MenuItem* firstMenuItem = parentMenuItem->GetFirstMenuItem();
1965                                     if (firstMenuItem != null)
1966                                     {
1967                                         menuControl->SetSelectedMenuItem(firstMenuItem);
1968                                         wantsKeys = true;
1969                                         auto result = menuControl->SetMenuInvalidated();
1970                                         if (result.Error()) return result;
1971                                         return Result<bool>(true);
1972                                     }
1973                                 }
1974                             }
1975                         }
1976                         break;
1977                     }
1978                     case Keys.up:
1979                     {
1980                         if (Level() == 0)
1981                         {
1982                             auto result = SetState(state.openmenuControl);
1983                             if (result.Error()) return result;
1984                             MenuItem* lastChild = GetLastMenuItem();
1985                             if (lastChild != null)
1986                             {
1987                                 menuControl->SetSelectedMenuItem(lastChild);
1988                                 wantsKeys = true;
1989                                 result = menuControl->SetMenuInvalidated();
1990                                 if (result.Error()) return result;
1991                                 return Result<bool>(true);
1992                             }
1993                         }
1994                         else
1995                         {
1996                             MenuItem* prevMenuItem = GetPrevMenuItem();
1997                             if (prevMenuItem != null)
1998                             {
1999                                 menuControl->SetSelectedMenuItem(prevMenuItem);
2000                                 wantsKeys = true;
2001                                 auto result = menuControl->SetMenuInvalidated();
2002                                 if (result.Error()) return result;
2003                                 return Result<bool>(true);
2004                             }
2005                             else
2006                             {
2007                                 if (parentMenuItem != null)
2008                                 {
2009                                     MenuItem* lastMenuItem = parentMenuItem->GetLastMenuItem();
2010                                     if (lastMenuItem != null)
2011                                     {
2012                                         menuControl->SetSelectedMenuItem(lastMenuItem);
2013                                         wantsKeys = true;
2014                                         auto result = menuControl->SetMenuInvalidated();
2015                                         if (result.Error()) return result;
2016                                         return Result<bool>(true);
2017                                     }
2018                                 }
2019                             }
2020                         }
2021                         break;
2022                     }
2023                     case Keys.right:
2024                     {
2025                         if (Level() == 0)
2026                         {
2027                             MenuItem* nextMenuItem = GetNextMenuItem();
2028                             if (nextMenuItem != null)
2029                             {
2030                                 menuControl->SetSelectedMenuItem(nextMenuItem);
2031                                 wantsKeys = true;
2032                                 auto result = menuControl->SetMenuInvalidated();
2033                                 if (result.Error()) return result;
2034                                 return Result<bool>(true);
2035                             }
2036                             else
2037                             {
2038                                 MenuItem* firstMenuItem = menuControl->GetFirstMenuItem();
2039                                 if (firstMenuItem != null)
2040                                 {
2041                                     menuControl->SetSelectedMenuItem(firstMenuItem);
2042                                     wantsKeys = true;
2043                                     auto result = menuControl->SetMenuInvalidated();
2044                                     if (result.Error()) return result;
2045                                     return Result<bool>(true);
2046                                 }
2047                             }
2048                         }
2049                         else
2050                         {
2051                             MenuItem* firstChild = GetFirstMenuItem();
2052                             if (firstChild != null)
2053                             {
2054                                 auto result = SetState(State.openmenuControl);
2055                                 if (result.Error()) return result;
2056                                 menuControl->SetSelectedMenuItem(firstChild);
2057                                 wantsKeys = true;
2058                                 result = menuControl->SetMenuInvalidated();
2059                                 if (result.Error()) return result;
2060                                 return Result<bool>(true);
2061                             }
2062                             else
2063                             {
2064                                 while (parentMenuItem != null)
2065                                 {
2066                                     if (parentMenuItem->Level() == 0)
2067                                     {
2068                                         MenuItem* nextMenuItem = parentMenuItem->GetNextMenuItem();
2069                                         if (nextMenuItem != null)
2070                                         {
2071                                             auto result = parentMenuItem->SetState(State.closedmenuControl);
2072                                             if (result.Error()) return result;
2073                                             result = nextMenuItem->SetState(State.openmenuControl);
2074                                             if (result.Error()) return result;
2075                                             MenuItem* firstChild = nextMenuItem->GetFirstMenuItem();
2076                                             if (firstChild != null)
2077                                             {
2078                                                 menuControl->SetSelectedMenuItem(firstChild);
2079                                                 wantsKeys = true;
2080                                                 result = menuControl->SetMenuInvalidated();
2081                                                 if (result.Error()) return result;
2082                                                 return Result<bool>(true);
2083                                             }
2084                                         }
2085                                         else
2086                                         {
2087                                             MenuItem* firstMenuItem = menuControl->GetFirstMenuItem();
2088                                             if (firstMenuItem != null)
2089                                             {
2090                                                 auto result = parentMenuItem->SetState(State.closedmenuControl);
2091                                                 if (result.Error()) return result;
2092                                                 result = firstMenuItem->SetState(State.openmenuControl);
2093                                                 if (result.Error()) return result;
2094                                                 MenuItem* firstChild = firstMenuItem->GetFirstMenuItem();
2095                                                 if (firstChild != null)
2096                                                 {
2097                                                     menuControl->SetSelectedMenuItem(firstChild);
2098                                                     wantsKeys = true;
2099                                                     result = menuControl->SetMenuInvalidated();
2100                                                     if (result.Error()) return result;
2101                                                     return Result<bool>(true);
2102                                                 }
2103                                             }
2104                                         }
2105                                     }
2106                                     else
2107                                     {
2108                                         MenuItem* grandParentMenuItem = parentMenuItem->GetParentMenuItem();
2109                                         MenuItem* nextMenuItem = grandParentMenuItem->GetNextMenuItem();
2110                                         if (nextMenuItem != null)
2111                                         {
2112                                             auto result = parentMenuItem->SetState(State.closedmenuControl);
2113                                             if (result.Error()) return result;
2114                                             result = grandParentMenuItem->SetState(State.closedmenuControl);
2115                                             if (result.Error()) return result;
2116                                             result = nextMenuItem->SetState(State.openmenuControl);
2117                                             if (result.Error()) return result;
2118                                             MenuItem* firstChild = nextMenuItem->GetFirstMenuItem();
2119                                             if (firstChild != null)
2120                                             {
2121                                                 menuControl->SetSelectedMenuItem(firstChild);
2122                                                 wantsKeys = true;
2123                                                 result = menuControl->SetMenuInvalidated();
2124                                                 if (result.Error()) return result;
2125                                                 return Result<bool>(true);
2126                                             }
2127                                         }
2128                                         else
2129                                         {
2130                                             parentMenuItem = grandParentMenuItem;
2131                                         }
2132                                     }
2133                                 }
2134                             }
2135                         }
2136                         break;
2137                     }
2138                     case Keys.left:
2139                     {
2140                         if (Level() == 0)
2141                         {
2142                             MenuItem* prevMenuItem = GetPrevMenuItem();
2143                             if (prevMenuItem != null)
2144                             {
2145                                 menuControl->SetSelectedMenuItem(prevMenuItem);
2146                                 wantsKeys = true;
2147                                 auto result = menuControl->SetMenuInvalidated();
2148                                 if (result.Error()) return result;
2149                                 return Result<bool>(true);
2150                             }
2151                             else
2152                             {
2153                                 MenuItem* lastMenuItem = menuControl->GetLastMenuItem();
2154                                 if (lastMenuItem != null)
2155                                 {
2156                                     menuControl->SetSelectedMenuItem(lastMenuItem);
2157                                     wantsKeys = true;
2158                                     auto result = menuControl->SetMenuInvalidated();
2159                                     if (result.Error()) return result;
2160                                     return Result<bool>(true);
2161                                 }
2162                             }
2163                         }
2164                         else
2165                         {
2166                             if (parentMenuItem != null)
2167                             {
2168                                 MenuItem* prevMenuItem = parentMenuItem->GetPrevMenuItem();
2169                                 if (prevMenuItem != null)
2170                                 {
2171                                     auto result = parentMenuItem->SetState(State.closedmenuControl);
2172                                     if (result.Error()) return result;
2173                                     result = prevMenuItem->SetState(State.openmenuControl);
2174                                     if (result.Error()) return result;
2175                                     MenuItem* firstChild = prevMenuItem->GetFirstMenuItem();
2176                                     if (firstChild != null)
2177                                     {
2178                                         menuControl->SetSelectedMenuItem(firstChild);
2179                                         wantsKeys = true;
2180                                         result = menuControl->SetMenuInvalidated();
2181                                         if (result.Error()) return result;
2182                                         return Result<bool>(true);
2183                                     }
2184                                 }
2185                                 else
2186                                 {
2187                                     MenuItem* grandParentMenuItem = parentMenuItem->GetParentMenuItem();
2188                                     if (grandParentMenuItem != null)
2189                                     {
2190                                         auto result = grandParentMenuItem->SetState(State.openmenuControl);
2191                                         if (result.Error()) return result;
2192                                         MenuItem* firstMenuItem = grandParentMenuItem->GetFirstMenuItem();
2193                                         if (firstMenuItem != null)
2194                                         {
2195                                             result = firstMenuItem->SetState(State.closedmenuControl);
2196                                             if (result.Error()) return result;
2197                                             menuControl->SetSelectedMenuItem(firstMenuItem);
2198                                         }
2199                                     }
2200                                     else
2201                                     {
2202                                         MenuItem* lastMenuItem = menuControl->GetLastMenuItem();
2203                                         if (lastMenuItem != null)
2204                                         {
2205                                             auto result = parentMenuItem->SetState(State.closedmenuControl);
2206                                             if (result.Error()) return result;
2207                                             result = lastMenuItem->SetState(State.openmenuControl);
2208                                             if (result.Error()) return result;
2209                                             MenuItem* firstChild = lastMenuItem->GetFirstMenuItem();
2210                                             if (firstChild != null)
2211                                             {
2212                                                 menuControl->SetSelectedMenuItem(firstChild);
2213                                                 wantsKeys = true;
2214                                                 result = menuControl->SetMenuInvalidated();
2215                                                 if (result.Error()) return result;
2216                                                 return Result<bool>(true);
2217                                             }
2218                                         }
2219                                     }
2220                                 }
2221                             }
2222                         }
2223                         break;
2224                     }
2225                 }
2226             }
2227             wantsKeys = true;
2228             return Result<bool>(false);
2229         }
2230         [nodiscard]
2231         private Result<bool> Close(MenuControl* menuControl)
2232         {
2233             auto result = SetState(State.closedmenuControl);
2234             if (result.Error()) return result;
2235             MenuItem* parentItem = GetParentMenuItem();
2236             while (parentItem != null)
2237             {
2238                 result = parentItem->SetState(State.closedmenuControl);
2239                 if (result.Error()) return result;
2240                 parentItem = parentItem->GetParentMenuItem();
2241             }
2242             menuControl->SetSelectedMenuItem(null);
2243             result = menuControl->SetClosed();
2244             if (result.Error()) return result;
2245             result = menuControl->SetMenuInvalidated();
2246             if (result.Error()) return result;
2247             return Result<bool>(true);
2248         }
2249         [nodiscard]
2250         private Result<bool> Execute(MenuItem* parentMenuItembool& wantsKeysMenuControl* menuControl)
2251         {
2252             if (children.IsEmpty())
2253             {
2254                 if (IsEnabled())
2255                 {
2256                     auto result = Close(menuControl);
2257                     if (result.Error()) return result;
2258                     wantsKeys = false;
2259                     result = DoClick();
2260                     if (result.Error()) return result;
2261                 }
2262             }
2263             else
2264             {
2265                 if (IsEnabled())
2266                 {
2267                     auto result = SetState(State.openmenuControl);
2268                     if (result.Error()) return result;
2269                     MenuItem* firstMenuItem = GetFirstMenuItem();
2270                     if (firstMenuItem != null)
2271                     {
2272                         menuControl->SetSelectedMenuItem(firstMenuItem);
2273                         wantsKeys = true;
2274                         result = menuControl->SetMenuInvalidated();
2275                         if (result.Error()) return result;
2276                     }
2277                 }
2278             }
2279             return Result<bool>(true);
2280         }
2281         [nodiscard]
2282         internal Result<bool> DoMouseDown(MouseEventArgs& argsbool& handledMenuControl* menuControl)
2283         {
2284             if (Level() == 0)
2285             {
2286                 if (Contains(args.location))
2287                 {
2288                     SetMouseInClient();
2289                     if (menuControl->IsOpen())
2290                     {
2291                         auto result = menuControl->SetClosed();
2292                         if (result.Error()) return result;
2293                         menuControl->SetLatestOpenedMenuItem(null);
2294                         result = SetState(State.closedmenuControl);
2295                         if (result.Error()) return result;
2296                         result = DoMouseDown(argsmenuControl);
2297                         if (result.Error()) return result;
2298                         handled = true;
2299                     }
2300                     else
2301                     {
2302                         menuControl->SetOpen();
2303                         auto result = SetState(State.openmenuControl);
2304                         if (result.Error()) return result;
2305                         menuControl->SetLatestOpenedMenuItem(this);
2306                         result = DoMouseDown(argsmenuControl);
2307                         if (result.Error()) return result;
2308                         handled = true;
2309                     }
2310                 }
2311                 else
2312                 {
2313                     Component* child = children.FirstChild();
2314                     while (child != null)
2315                     {
2316                         if (child is MenuItem*)
2317                         {
2318                             MenuItem* childItem = cast<MenuItem*>(child);
2319                             auto result = childItem->DoMouseDown(argshandledmenuControl);
2320                             if (result.Error()) return result;
2321                             if (handled) return Result<bool>(true);
2322                         }
2323                         child = child->NextSibling();
2324                     }
2325                 }
2326             }
2327             else
2328             {
2329                 if (menuControl->IsOpen())
2330                 {
2331                     MenuItem* parentMenuItem = GetParentMenuItem();
2332                     if (parentMenuItem != null)
2333                     {
2334                         if (parentMenuItem->state == State.open)
2335                         {
2336                             if (Contains(args.location))
2337                             {
2338                                 if (!children.IsEmpty())
2339                                 {
2340                                     if (state == State.closed)
2341                                     {
2342                                         auto result = SetState(State.openmenuControl);
2343                                         if (result.Error()) return result;
2344                                         menuControl->SetLatestOpenedMenuItem(this);
2345                                         result = DoMouseDown(argsmenuControl);
2346                                         if (result.Error()) return result;
2347                                         handled = true;
2348                                     }
2349                                     else if (state == State.open)
2350                                     {
2351                                         auto result = SetState(State.closedmenuControl);
2352                                         if (result.Error()) return result;
2353                                         menuControl->SetLatestOpenedMenuItem(null);
2354                                         result = DoMouseDown(argsmenuControl);
2355                                         if (result.Error()) return result;
2356                                         handled = true;
2357                                     }
2358                                 }
2359                                 else
2360                                 {
2361                                     auto result = DoMouseDown(argsmenuControl);
2362                                     if (result.Error()) return result;
2363                                     if ((args.buttons & MouseButtons.lbutton) != 0)
2364                                     {
2365                                         SetLButtonPressed();
2366                                     }
2367                                     handled = true;
2368                                 }
2369                             }
2370                         }
2371                     }
2372                     Component* child = children.FirstChild();
2373                     while (child != null)
2374                     {
2375                         if (child is MenuItem*)
2376                         {
2377                             MenuItem* childItem = cast<MenuItem*>(child);
2378                             auto result = childItem->DoMouseDown(argshandledmenuControl);
2379                             if (result.Error()) return result;
2380                             if (handled) return Result<bool>(true);
2381                         }
2382                         child = child->NextSibling();
2383                     }
2384                 }
2385             }
2386             return Result<bool>(true);
2387         }
2388         [nodiscard]
2389         internal Result<bool> DoMouseUp(MouseEventArgs& argsbool& handledMenuControl* menuControl)
2390         {
2391             if (Level() == 0)
2392             {
2393                 if (Contains(args.location))
2394                 {
2395                     auto result = DoMouseUp(argsmenuControl);
2396                     if (result.Error()) return result;
2397                     handled = true;
2398                 }
2399                 else
2400                 {
2401                     Component* child = children.FirstChild();
2402                     while (child != null)
2403                     {
2404                         if (child is MenuItem*)
2405                         {
2406                             MenuItem* childItem = cast<MenuItem*>(child);
2407                             if (childItem->IsEnabled())
2408                             {
2409                                 auto result = childItem->DoMouseUp(argshandledmenuControl);
2410                                 if (result.Error()) return result;
2411                                 if (handled) return Result<bool>(true);
2412                             }
2413                         }
2414                         child = child->NextSibling();
2415                     }
2416                 }
2417             }
2418             else
2419             {
2420                 if (menuControl->IsOpen())
2421                 {
2422                     MenuItem* parentMenuItem = GetParentMenuItem();
2423                     if (parentMenuItem != null)
2424                     {
2425                         if (parentMenuItem->state == State.open)
2426                         {
2427                             if (Contains(args.location))
2428                             {
2429                                 auto result = DoMouseUp(argsmenuControl);
2430                                 if (result.Error()) return result;
2431                                 handled = true;
2432                                 if (handled) return Result<bool>(true);
2433                             }
2434                         }
2435                     }
2436                     Component* child = children.FirstChild();
2437                     while (child != null)
2438                     {
2439                         if (child is MenuItem*)
2440                         {
2441                             MenuItem* childItem = cast<MenuItem*>(child);
2442                             if (childItem->IsEnabled())
2443                             {
2444                                 auto result = childItem->DoMouseUp(argshandledmenuControl);
2445                                 if (result.Error()) return result;
2446                                 if (handled) return Result<bool>(true);
2447                             }
2448                         }
2449                         child = child->NextSibling();
2450                     }
2451                 }
2452             }
2453             return Result<bool>(true);
2454         }
2455         [nodiscard]
2456         private Result<bool> DoMouseDown(MouseEventArgs& argsMenuControl* menuControl)
2457         {
2458             menuControl->SetLatestMouseDownMenuItem(this);
2459             ResetLButtonPressed();
2460             return OnMouseDown(args);
2461         }
2462         [nodiscard]
2463         protected virtual Result<bool> OnMouseDown(MouseEventArgs& args)
2464         {
2465             mouseDownEvent.Fire(args);
2466             return Result<bool>(true);
2467         }
2468         [nodiscard]
2469         private Result<bool> DoMouseUp(MouseEventArgs& argsMenuControl* menuControl)
2470         {
2471             if (!IsEnabled()) return Result<bool>(false);
2472             OnMouseUp(args);
2473             bool isMenuBar = menuControl is MenuBar*;
2474             MenuItem* latestMouseDownMenuItem = menuControl->GetLatestMouseDownMenuItem();
2475             if ((args.buttons & MouseButtons.lbutton) != 0)
2476             {
2477                 if (LButtonPressed())
2478                 {
2479                     ResetLButtonPressed();
2480                     if (latestMouseDownMenuItem == this && children.IsEmpty())
2481                     {
2482                         auto result = ResetSelected(menuControl);
2483                         if (result.Error()) return result;
2484                         ResetMouseInClient();
2485                         result = this->DoMouseLeave(menuControl);
2486                         if (result.Error()) return result;
2487                         result = LeaveChildren(menuControl);
2488                         if (result.Error()) return result;
2489                         result = Close(menuControl);
2490                         if (result.Error()) return result;
2491                         result = DoClick();
2492                         if (result.Error()) return result;
2493                     }
2494                     if (isMenuBar)
2495                     {
2496                         MenuItem* openedMenuItem = menuControl->GetOpenedMenuItem();
2497                         if (openedMenuItem != null)
2498                         {
2499                             auto result = openedMenuItem->SetState(State.closedmenuControl);
2500                             if (result.Error()) return result;
2501                         }
2502                         auto result = menuControl->SetClosed();
2503                         if (result.Error()) return result;
2504                         result = menuControl->SetMenuInvalidated();
2505                         if (result.Error()) return result;
2506                     }
2507                 }
2508             }
2509             return Result<bool>(true);
2510         }
2511         protected virtual void OnMouseUp(MouseEventArgs& args)
2512         {
2513             mouseUpEvent.Fire(args);
2514         }
2515         [nodiscard]
2516         internal Result<bool> DoMouseEnter(bool parentIsOpenMenuControl* menuControl)
2517         {
2518             if (parentIsOpen)
2519             {
2520                 Component* prev = PrevSibling();
2521                 while (prev != null)
2522                 {
2523                     if (prev is MenuItem*)
2524                     {
2525                         MenuItem* prevItem = cast<MenuItem*>(prev);
2526                         auto result = prevItem->DoMouseLeave(menuControl);
2527                         if (result.Error()) return result;
2528                     }
2529                     prev = prev->PrevSibling();
2530                 }
2531                 Component* next = NextSibling();
2532                 while (next != null)
2533                 {
2534                     if (next is MenuItem*)
2535                     {
2536                         MenuItem* nextItem = cast<MenuItem*>(next);
2537                         auto result = nextItem->DoMouseLeave(menuControl);
2538                         if (result.Error()) return result;
2539                     }
2540                     next = next->NextSibling();
2541                 }
2542                 Component* child = children.FirstChild();
2543                 while (child != null)
2544                 {
2545                     if (child is MenuItem*)
2546                     {
2547                         MenuItem* childMenuItem = cast<MenuItem*>(child);
2548                         auto result = childMenuItem->ResetSelected(menuControl);
2549                         if (result.Error()) return result;
2550                         if (childMenuItem->MouseInClient())
2551                         {
2552                             childMenuItem->ResetMouseInClient();
2553                             result = childMenuItem->DoMouseLeave(menuControl);
2554                             if (result.Error()) return result;
2555                         }
2556                     }
2557                     child = child->NextSibling();
2558                 }
2559             }
2560             if (parentIsOpen)
2561             {
2562                 auto result = SetState(State.openmenuControl);
2563                 if (result.Error()) return result;
2564                 menuControl->SetLatestOpenedMenuItem(this);
2565             }
2566             EnterLeaveEventArgs args;
2567             auto result = OnMouseEnter(args);
2568             if (result.Error()) return result;
2569             result = menuControl->SetMenuInvalidated();
2570             if (result.Error()) return result;
2571             return Result<bool>(true);
2572         }
2573         [nodiscard]
2574         internal Result<bool> DoMouseMove(MouseEventArgs& args)
2575         {
2576             auto result = OnMouseMove(args);
2577             if (result.Error()) return result;
2578             return Result<bool>(true);
2579         }
2580         [nodiscard]
2581         protected virtual Result<bool> OnMouseEnter(EnterLeaveEventArgs& args)
2582         {
2583             mouseEnterEvent.Fire(args);
2584             if (args.errorId != 0)
2585             {
2586                 return Result<bool>(ErrorId(args.errorId));
2587             }
2588             return Result<bool>(true);
2589         }
2590         [nodiscard]
2591         internal Result<bool> LeaveChildren(MenuControl* menuControl)
2592         {
2593             Component* child = children.FirstChild();
2594             while (child != null)
2595             {
2596                 if (child is MenuItem*)
2597                 {
2598                     MenuItem* childMenuItem = cast<MenuItem*>(child);
2599                     auto result = childMenuItem->ResetSelected(menuControl);
2600                     if (result.Error()) return result;
2601                     childMenuItem->ResetMouseInClient();
2602                     result = childMenuItem->DoMouseLeave(menuControl);
2603                     if (result.Error()) return result;
2604                     result = childMenuItem->LeaveChildren(menuControl);
2605                     if (result.Error()) return result;
2606                 }
2607                 child = child->NextSibling();
2608             }
2609             return Result<bool>(true);
2610         }
2611         [nodiscard]
2612         internal Result<bool> DoMouseLeave(MenuControl* menuControl)
2613         {
2614             ResetLButtonPressed();
2615             if (state == State.open)
2616             {
2617                 auto result = SetState(State.closedmenuControl);
2618                 if (result.Error()) return result;
2619                 result = LeaveChildren(menuControl);
2620                 if (result.Error()) return result;
2621                 EnterLeaveEventArgs args;
2622                 result = OnMouseLeave(args);
2623                 if (result.Error()) return result;
2624                 if (args.errorId != 0)
2625                 {
2626                     return Result<bool>(ErrorId(args.errorId));
2627                 }
2628             }
2629             else if (Level() == 0)
2630             {
2631                 EnterLeaveEventArgs args;
2632                 auto result = OnMouseLeave(args);
2633                 if (result.Error()) return result;
2634                 if (args.errorId != 0)
2635                 {
2636                     return Result<bool>(ErrorId(args.errorId));
2637                 }
2638             }
2639             return Result<bool>(true);
2640         }
2641         [nodiscard]
2642         protected virtual Result<bool> OnMouseLeave(EnterLeaveEventArgs& args)
2643         {
2644             mouseLeaveEvent.Fire(args);
2645             if (args.errorId != 0)
2646             {
2647                 return Result<bool>(ErrorId(args.errorId));
2648             }
2649             return Result<bool>(true);
2650         }
2651         [nodiscard]
2652         internal Result<bool> DispatchMouseMove(MouseEventArgs& argsbool& handledMenuControl* menuControl)
2653         {
2654             if (unionRect.Contains(args.location))
2655             {
2656                 if (Contains(args.location))
2657                 {
2658                     auto result = SetSelected(menuControl);
2659                     if (result.Error()) return result;
2660                 }
2661                 else
2662                 {
2663                     auto result = ResetSelected(menuControl);
2664                     if (result.Error()) return result;
2665                     ResetMouseInClient();
2666                 }
2667                 Component* child = children.FirstChild();
2668                 while (child != null)
2669                 {
2670                     if (child is MenuItem*)
2671                     {
2672                         MenuItem* childMenuItem = cast<MenuItem*>(child);
2673                         if (childMenuItem->Contains(args.location))
2674                         {
2675                             auto result = childMenuItem->SetSelected(menuControl);
2676                             if (result.Error()) return result;
2677                             if (!childMenuItem->MouseInClient())
2678                             {
2679                                 childMenuItem->SetMouseInClient();
2680                                 result = childMenuItem->DoMouseEnter(truemenuControl);
2681                                 if (result.Error()) return result;
2682                                 handled = true;
2683                             }
2684                             else
2685                             {
2686                                 result = childMenuItem->DoMouseMove(args);
2687                                 if (result.Error()) return result;
2688                             }
2689                         }
2690                         else
2691                         {
2692                             auto result = childMenuItem->ResetSelected(menuControl);
2693                             if (result.Error()) return result;
2694                             if (childMenuItem->MouseInClient())
2695                             {
2696                                 childMenuItem->ResetMouseInClient();
2697                                 if (!childMenuItem->IsSameOrParentOf(menuControl->LatestOpenedMenuItem()))
2698                                 {
2699                                     result = childMenuItem->DoMouseLeave(menuControl);
2700                                     if (result.Error()) return result;
2701                                 }
2702                             }
2703                         }
2704                     }
2705                     child = child->NextSibling();
2706                 }
2707             }
2708             else
2709             {
2710                 Component* child = children.FirstChild();
2711                 while (child != null)
2712                 {
2713                     if (child is MenuItem*)
2714                     {
2715                         MenuItem* childMenuItem = cast<MenuItem*>(child);
2716                         if (childMenuItem->IsSameOrParentOf(menuControl->LatestOpenedMenuItem()))
2717                         {
2718                             auto result = childMenuItem->DispatchMouseMove(argshandledmenuControl);
2719                             if (result.Error()) return result;
2720                             if (handled) return Result<bool>(true);
2721                         }
2722                     }
2723                     child = child->NextSibling();
2724                 }
2725             }
2726             return Result<bool>(true);
2727         }
2728         [nodiscard]
2729         protected virtual Result<bool> OnMouseMove(MouseEventArgs& args)
2730         {
2731             mouseMoveEvent.Fire(args);
2732             return Result<bool>(true);
2733         }
2734         [nodiscard]
2735         internal Result<bool> DoClick()
2736         {
2737             LogView* logView = Application.GetLogView();
2738             if (logView != null)
2739             {
2740                 auto result = logView->WriteLine("MENUITEM: " + text + " CLICK!");
2741                 if (result.Error()) return result;
2742             }
2743             ClickEventArgs args;
2744             auto result = OnClick(args);
2745             if (result.Error()) return result;
2746             if (args.errorId != 0)
2747             {
2748                 return Result<bool>(ErrorId(args.errorId));
2749             }
2750             return Result<bool>(true);
2751         }
2752         [nodiscard]
2753         protected virtual Result<bool> OnClick(ClickEventArgs& args)
2754         {
2755             clickEvent.Fire(args);
2756             return Result<bool>(true);
2757         }
2758         public void CalculateChildRect(Graphics& graphicsconst Font& fontconst StringFormat& formatconst Point& location)
2759         {
2760             childRect = Rect();
2761             childRect.location = location;
2762             Component* child = children.FirstChild();
2763             shortcutFieldWidth = 0;
2764             childIndicatorFieldWidth = 0;
2765             while (child != null)
2766             {
2767                 if (child is MenuItemBase*)
2768                 {
2769                     MenuItemBase* item = cast<MenuItemBase*>(child);
2770                     Size size = item->MeasureItem(graphicsfontformatshortcutFieldWidthchildIndicatorFieldWidth);
2771                     childRect.size.w = Max(childRect.size.wsize.w);
2772                     childRect.size.h = childRect.size.h + size.h;
2773                 }
2774                 child = child->NextSibling();
2775             }
2776             childRect.size.w = childRect.size.w + shortcutFieldWidth + childIndicatorFieldWidth;
2777             Rect itemRect(childRect.locationSize(childRect.size.w0));
2778             child = children.FirstChild();
2779             while (child != null)
2780             {
2781                 if (child is MenuItemBase*)
2782                 {
2783                     MenuItemBase* item = cast<MenuItemBase*>(child);
2784                     item->SetLocation(itemRect.location);
2785                     itemRect.size.h = item->GetSize().h;
2786                     item->SetSize(itemRect.size);
2787                     itemRect.location.y = itemRect.location.y + itemRect.size.h;
2788                 }
2789                 child = child->NextSibling();
2790             }
2791             int shadowWidth = ShadowWidth();
2792             childRect.size.h = childRect.size.h + shadowWidth;
2793             childRect.size.w = childRect.size.w + shadowWidth;
2794             child = children.FirstChild();
2795             while (child != null)
2796             {
2797                 if (child is MenuItem*)
2798                 {
2799                     MenuItem* item = cast<MenuItem*>(child);
2800                     if (!item->Children().IsEmpty())
2801                     {
2802                         Point itemLocation = item->Location();
2803                         Size itemSize = item->GetSize();
2804                         item->CalculateChildRect(graphicsfontformatPoint(itemLocation.x + itemSize.w - shadowWidthitemLocation.y));
2805                     }
2806                 }
2807                 child = child->NextSibling();
2808             }
2809             Rect r(Location()GetSize());
2810             unionRect = Rect.Union(rchildRect);
2811         }
2812         [nodiscard]
2813         public override Result<bool> Draw(Graphics& graphicsconst Padding& parentPaddingconst Brush& textBrushconst Brush& disabledTextBrush
2814             const Brush& backgroundBrushconst Brush& mouseOverBrushconst Brush& menuOpenBrushconst Brush& shadowBrushconst Brush& blackBrush
2815             const Pen& blackPenconst Pen& darkPenconst Font& fontconst StringFormat& format
2816             const Color& menuOpenColorMenuControl* menuControlbool drawSubItemsconst Point& origin)
2817         {
2818             switch (state)
2819             {
2820                 case State.closed:
2821                 {
2822                     auto drawResult = DrawClosed(graphicsparentPaddingtextBrushdisabledTextBrushmouseOverBrushbackgroundBrushmenuOpenBrush
2823                         blackBrushblackPenfontformatmenuOpenColormenuControldrawSubItemsorigin);
2824                     if (drawResult.Error())
2825                     {
2826                         return Result<bool>(ErrorId(drawResult.GetErrorId()));
2827                     }
2828                     break;
2829                 }
2830                 case State.open:
2831                 {
2832                     auto drawResult = DrawOpen(graphicsparentPaddingtextBrushdisabledTextBrushbackgroundBrushmouseOverBrushmenuOpenBrush
2833                         shadowBrushblackBrushblackPendarkPenfontformatmenuOpenColormenuControldrawSubItemsorigin);
2834                     if (drawResult.Error())
2835                     {
2836                         return Result<bool>(ErrorId(drawResult.GetErrorId()));
2837                     }
2838                     break;
2839                 }
2840             }
2841             return Result<bool>(true);
2842         }
2843         public const string& Text() const
2844         {
2845             return text;
2846         }
2847         [nodiscard]
2848         public Result<bool> SetText(const string& text_MenuControl* menuControl)
2849         {
2850             text = text_;
2851             SetAccessKey();
2852             auto result = menuControl->InvalidateMenu();
2853             if (result.Error()) return result;
2854             return Result<bool>(true);
2855         }
2856         public inline wchar AccessKey() const
2857         {
2858             return accessKey;
2859         }
2860         private Result<bool> SetAccessKey()
2861         {
2862             auto utf16Result = ToUtf16(text);
2863             if (utf16Result.Error())
2864             {
2865                 return Result<bool>(ErrorId(utf16Result.GetErrorId()));
2866             }
2867             wstring s = Rvalue(utf16Result.Value());
2868             long ampPos = s.Find('&');
2869             if (ampPos != -1 && ampPos < s.Length() - 1)
2870             {
2871                 auto upperResult = ToUpper(cast<uchar>(s[ampPos + 1]));
2872                 if (upperResult.Error())
2873                 {
2874                     return Result<bool>(ErrorId(upperResult.GetErrorId()));
2875                 }
2876                 accessKey = cast<wchar>(upperResult.Value());
2877             }
2878             else
2879             {
2880                 accessKey = '\0';
2881             }
2882             return Result<bool>(true);
2883         }
2884         public void SetShortcut(Keys shortcut_)
2885         {
2886             shortcut = shortcut_;
2887             MenuControl* menuControl = GetMenuControl();
2888             if (menuControl != null)
2889             {
2890                 menuControl->SetMenuChanged();
2891             }
2892         }
2893         private MenuItem* GetChildItemByAccessKey(wchar accessKey)
2894         {
2895             Component* child = children.FirstChild();
2896             while (child != null)
2897             {
2898                 if (child is MenuItem*)
2899                 {
2900                     MenuItem* menuItem = cast<MenuItem*>(child);
2901                     if (menuItem->AccessKey() == accessKey)
2902                     {
2903                         return menuItem;
2904                     }
2905                 }
2906                 child = child->NextSibling();
2907             }
2908             return null;
2909         }
2910         internal void CollectShortcuts(HashMap<KeysMenuItem*>& shortcuts)
2911         {
2912             if (shortcut != Keys.none)
2913             {
2914                 shortcuts[shortcut] = this;
2915             }
2916             Component* child = children.FirstChild();
2917             while (child != null)
2918             {
2919                 if (child is MenuItem*)
2920                 {
2921                     MenuItem* menuItem = cast<MenuItem*>(child);
2922                     menuItem->CollectShortcuts(shortcuts);
2923                 }
2924                 child = child->NextSibling();
2925             }
2926         }
2927         public const ComponentContainer& Children() const
2928         {
2929             return children;
2930         }
2931         public override Padding DefaultPadding() const
2932         {
2933             if (Level() == 0)
2934             {
2935                 return Padding(4040);
2936             }
2937             else
2938             {
2939                 return Padding(324324);
2940             }
2941         }
2942         public Padding ShortcutPadding() const
2943         {
2944             if (Level() == 0)
2945             {
2946                 return Padding(0000);
2947             }
2948             else
2949             {
2950                 return Padding(4040);
2951             }
2952         }
2953         public virtual int ShadowWidth() const
2954         {
2955             return 3;
2956         }
2957         public virtual int ChildIndicatorIndent() const
2958         {
2959             return 9;
2960         }
2961         public virtual int ChildIndicatorWidth() const
2962         {
2963             return 6;
2964         }
2965         public bool Contains(const Point& p)
2966         {
2967             Rect r(Location()GetSize());
2968             if (r.Contains(p))
2969             {
2970                 return true;
2971             }
2972             return false;
2973         }
2974         public bool UnionRectContains(const Point& p)
2975         {
2976             return unionRect.Contains(p);
2977         }
2978         public inline const Rect& UnionRect() const
2979         {
2980             return unionRect;
2981         }
2982         public void GetOpenRect(Rect& parentRect)
2983         {
2984             if (!childRect.IsEmpty())
2985             {
2986                 if (parentRect.IsEmpty())
2987                 {
2988                     parentRect = childRect;
2989                 }
2990                 else
2991                 {
2992                     parentRect = Rect.Union(parentRectchildRect);
2993                 }
2994             }
2995             Component* child = children.FirstChild();
2996             while (child != null)
2997             {
2998                 if (child is MenuItem*)
2999                 {
3000                     MenuItem* menuItem = cast<MenuItem*>(child);
3001                     if (menuItem->GetState() == MenuItem.State.open)
3002                     {
3003                         menuItem->GetOpenRect(parentRect);
3004                     }
3005                 }
3006                 child = child->NextSibling();
3007             }
3008         }
3009         public inline State GetState() const
3010         {
3011             return state;
3012         }
3013         [nodiscard]
3014         internal Result<bool> SetState(State state_MenuControl* menuControl)
3015         {
3016             if (state != state_)
3017             {
3018                 state = state_;
3019                 auto result = menuControl->SetMenuInvalidated();
3020                 if (result.Error()) return result;
3021             }
3022             return Result<bool>(true);
3023         }
3024         public override Size MeasureItem(Graphics& graphicsconst Font& fontconst StringFormat& formatint& shortcutFieldWidthint& childIndicatorFieldWidth)
3025         {
3026             Padding padding = DefaultPadding();
3027             auto measureStringResult = graphics.MeasureStringRectF(textfontPointF(00)format);
3028             if (measureStringResult.Error())
3029             {
3030                 SetErrorId(measureStringResult.GetErrorId());
3031                 return Size();
3032             }
3033             RectF rect = Rvalue(measureStringResult.Value());
3034             int w = cast<int>(rect.size.w);
3035             w = w + padding.Horizontal();
3036             if (shortcut != Keys.none)
3037             {
3038                 string shortcutText = ToString(shortcut);
3039                 auto shortcutTextResult = graphics.MeasureStringRectF(shortcutTextfontPointF(00)format);
3040                 if (shortcutTextResult.Error())
3041                 {
3042                     SetErrorId(measureStringResult.GetErrorId());
3043                     return Size();
3044                 }
3045                 RectF shortcutRect = Rvalue(shortcutTextResult.Value());
3046                 Padding shortcutPadding = ShortcutPadding();
3047                 int shortcutWidth = cast<int>(shortcutRect.size.w + shortcutPadding.Horizontal());
3048                 shortcutFieldWidth = Max(shortcutFieldWidthshortcutWidth);
3049             }
3050             if (Level() > 0 && !children.IsEmpty())
3051             {
3052                 childIndicatorFieldWidth = Max(childIndicatorFieldWidthChildIndicatorIndent());
3053             }
3054             int h = cast<int>(rect.size.h);
3055             h = h + padding.Vertical();
3056             Size size(wh);
3057             SetSize(size);
3058             return size;
3059         }
3060         private Result<bool> DrawClosed(Graphics& graphicsconst Padding& parentPaddingconst Brush& textBrushconst Brush& disabledTextBrush
3061             const Brush& mouseOverBrushconst Brush& backgroundBrush
3062             const Brush& menuOpenBrushconst Brush& blackBrushconst Pen& blackPenconst Font& fontconst StringFormat& formatconst Color& menuOpenColor
3063             MenuControl* menuControlbool drawSubItemsconst Point& origin)
3064         {
3065             Point loc = Location();
3066             loc.x = loc.x - origin.x;
3067             loc.y = loc.y - origin.y;
3068             Size size = GetSize();
3069             Rect r(locsize);
3070             r.size.w = r.size.w - 1;
3071             r.size.h = r.size.h - 1;
3072             MenuItem* selectedMenuItem = menuControl->GetSelectedMenuItem();
3073             if (Selected() || this == selectedMenuItem)
3074             {
3075                 auto fillRectangleResult = graphics.FillRectangle(mouseOverBrushr);
3076                 if (fillRectangleResult.Error())
3077                 {
3078                     return Result<bool>(ErrorId(fillRectangleResult.GetErrorId()));
3079                 }
3080                 auto drawRectangleResult = graphics.DrawRectangle(blackPenr);
3081                 if (drawRectangleResult.Error())
3082                 {
3083                     return Result<bool>(ErrorId(drawRectangleResult.GetErrorId()));
3084                 }
3085             }
3086             if (Level() == 0)
3087             {
3088                 if (!drawSubItems)
3089                 {
3090                     if (!Selected() && this != selectedMenuItem)
3091                     {
3092                         auto fillRectangleResult = graphics.FillRectangle(backgroundBrushr);
3093                         if (fillRectangleResult.Error())
3094                         {
3095                             return Result<bool>(ErrorId(fillRectangleResult.GetErrorId()));
3096                         }
3097                     }
3098                     StringFormat textFormat(format);
3099                     auto setAlignmentResult = textFormat.SetAlignment(StringAlignment.center);
3100                     if (setAlignmentResult.Error())
3101                     {
3102                         return Result<bool>(ErrorId(setAlignmentResult.GetErrorId()));
3103                     }
3104                     RectF rect(PointF(loc.xloc.y)SizeF(size.wsize.h));
3105                     if (IsEnabled())
3106                     {
3107                         auto drawStringResult = graphics.DrawString(textfontrecttextFormattextBrush);
3108                         if (drawStringResult.Error())
3109                         {
3110                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3111                         }
3112                     }
3113                     else
3114                     {
3115                         auto drawStringResult = graphics.DrawString(textfontrecttextFormatdisabledTextBrush);
3116                         if (drawStringResult.Error())
3117                         {
3118                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3119                         }
3120                     }
3121                 }
3122             }
3123             else
3124             {
3125                 if (drawSubItems)
3126                 {
3127                     Padding padding = DefaultPadding();
3128                     if (IsEnabled())
3129                     {
3130                         auto drawStringResult = graphics.DrawString(textfontPointF(loc.x + padding.leftloc.y + padding.top)formattextBrush);
3131                         if (drawStringResult.Error())
3132                         {
3133                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3134                         }
3135                         DrawShortcut(graphicstextBrushfontformatorigin);
3136                     }
3137                     else
3138                     {
3139                         auto drawStringResult = graphics.DrawString(textfontPointF(loc.x + padding.leftloc.y + padding.top)formatdisabledTextBrush);
3140                         if (drawStringResult.Error())
3141                         {
3142                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3143                         }
3144                         DrawShortcut(graphicsdisabledTextBrushfontformatorigin);
3145                     }
3146                     DrawChildIndicator(graphicsblackBrushorigin);
3147                 }
3148             }
3149             return Result<bool>(true);
3150         }
3151         private Result<bool> DrawOpen(Graphics& graphicsconst Padding& parentPaddingconst Brush& textBrush
3152             const Brush& disabledTextBrushconst Brush& backgroundBrushconst Brush& mouseOverBrush
3153             const Brush& menuOpenBrushconst Brush& shadowBrushconst Brush& blackBrushconst Pen& blackPenconst Pen& darkPenconst Font& font
3154             const StringFormat& formatconst Color& menuOpenColorMenuControl* menuControlbool drawSubItemsconst Point& origin)
3155         {
3156             Point loc = Location();
3157             loc.x = loc.x - origin.x;
3158             loc.y = loc.y - origin.y;
3159             Size size = GetSize();
3160             Rect r(locsize);
3161             r.size.w = r.size.w - 1;
3162             r.size.h = r.size.h - 1;
3163             int shadowWidth = ShadowWidth();
3164             if (Level() == 0)
3165             {
3166                 if (!drawSubItems)
3167                 {
3168                     auto fillRectangleResult = graphics.FillRectangle(menuOpenBrushr);
3169                     if (fillRectangleResult.Error())
3170                     {
3171                         return Result<bool>(ErrorId(fillRectangleResult.GetErrorId()));
3172                     }
3173                     auto drawLineResult = graphics.DrawLine(blackPenr.locationPoint(r.location.x + r.size.wr.location.y));
3174                     if (drawLineResult.Error())
3175                     {
3176                         return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3177                     }
3178                     drawLineResult = graphics.DrawLine(blackPenr.locationPoint(r.location.xr.location.y + r.size.h));
3179                     if (drawLineResult.Error())
3180                     {
3181                         return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3182                     }
3183                     drawLineResult = graphics.DrawLine(blackPenPoint(r.location.x + r.size.wr.location.y)Point(r.location.x + r.size.wr.location.y + r.size.h));
3184                     if (drawLineResult.Error())
3185                     {
3186                         return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3187                     }
3188                     if (children.IsEmpty())
3189                     {
3190                         drawLineResult = graphics.DrawLine(blackPenPoint(r.location.xr.location.y + r.size.h)Point(r.location.x + r.size.wr.location.y + r.size.h));
3191                         if (drawLineResult.Error())
3192                         {
3193                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3194                         }
3195                     }
3196                     StringFormat textFormat(format);
3197                     if (textFormat.Error()) return Result<bool>(ErrorId(textFormat.GetErrorId()));
3198                     auto result = textFormat.SetAlignment(StringAlignment.center);
3199                     if (result.Error()) return result;
3200                     RectF rect(PointF(loc.xloc.y)SizeF(size.wsize.h));
3201                     if (IsEnabled())
3202                     {
3203                         auto drawStringResult = graphics.DrawString(textfontrecttextFormattextBrush);
3204                         if (drawStringResult.Error())
3205                         {
3206                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3207                         }
3208                     }
3209                     else
3210                     {
3211                         auto drawStringResult = graphics.DrawString(textfontrecttextFormatdisabledTextBrush);
3212                         if (drawStringResult.Error())
3213                         {
3214                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3215                         }
3216                     }
3217                 }
3218             }
3219             else
3220             {
3221                 if (drawSubItems)
3222                 {
3223                     MenuItem* selectedMenuItem = menuControl->GetSelectedMenuItem();
3224                     if (Selected() || this == selectedMenuItem)
3225                     {
3226                         auto fillRectangleResult = graphics.FillRectangle(mouseOverBrushr);
3227                         if (fillRectangleResult.Error())
3228                         {
3229                             return Result<bool>(ErrorId(fillRectangleResult.GetErrorId()));
3230                         }
3231                         auto drawRectangleResult = graphics.DrawRectangle(blackPenr);
3232                         if (drawRectangleResult.Error())
3233                         {
3234                             return Result<bool>(ErrorId(drawRectangleResult.GetErrorId()));
3235                         }
3236                     }
3237                     else
3238                     {
3239                         Rect inside = r;
3240                         inside.Inflate(-1-1);
3241                         auto fillRectangleResult = graphics.FillRectangle(menuOpenBrushinside);
3242                         if (fillRectangleResult.Error())
3243                         {
3244                             return Result<bool>(ErrorId(fillRectangleResult.GetErrorId()));
3245                         }
3246                     }
3247                     Padding padding = DefaultPadding();
3248                     if (IsEnabled())
3249                     {
3250                         auto drawStringResult = graphics.DrawString(textfontPointF(loc.x + padding.leftloc.y + padding.top)formattextBrush);
3251                         if (drawStringResult.Error())
3252                         {
3253                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3254                         }
3255                         auto drawShortcutResult = DrawShortcut(graphicstextBrushfontformatorigin);
3256                         if (drawShortcutResult.Error())
3257                         {
3258                             return Result<bool>(ErrorId(drawShortcutResult.GetErrorId()));
3259                         }
3260                     }
3261                     else
3262                     {
3263                         auto drawStringResult = graphics.DrawString(textfontPointF(loc.x + padding.leftloc.y + padding.top)formatdisabledTextBrush);
3264                         if (drawStringResult.Error())
3265                         {
3266                             return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3267                         }
3268                         auto drawShortcutResult = DrawShortcut(graphicsdisabledTextBrushfontformatorigin);
3269                         if (drawShortcutResult.Error())
3270                         {
3271                             return Result<bool>(ErrorId(drawShortcutResult.GetErrorId()));
3272                         }
3273                     }
3274                     auto drawIndicatorResult = DrawChildIndicator(graphicsblackBrushorigin);
3275                     if (drawIndicatorResult.Error())
3276                     {
3277                         return Result<bool>(ErrorId(drawIndicatorResult.GetErrorId()));
3278                     }
3279                 }
3280             }
3281             if (!childRect.IsEmpty())
3282             {
3283                 if (drawSubItems)
3284                 {
3285                     auto getClipResult = graphics.GetClip();
3286                     if (getClipResult.Error())
3287                     {
3288                         return Result<bool>(ErrorId(getClipResult.GetErrorId()));
3289                     }
3290                     Region prevClipRegion = getClipResult.Value();
3291                     Rect menuBox = childRect;
3292                     menuBox.location.x = menuBox.location.x - origin.x;
3293                     menuBox.location.y = menuBox.location.y - origin.y;
3294                     menuBox.size.h = menuBox.size.h - shadowWidth;
3295                     menuBox.size.w = menuBox.size.w - shadowWidth;
3296                     auto setClipResult = graphics.SetClip(menuBox);
3297                     if (setClipResult.Error())
3298                     {
3299                         return Result<bool>(ErrorId(setClipResult.GetErrorId()));
3300                     }
3301                     auto clearResult = graphics.Clear(menuOpenColor);
3302                     if (clearResult.Error())
3303                     {
3304                         return Result<bool>(ErrorId(clearResult.GetErrorId()));
3305                     }
3306                     Rect cr(childRect);
3307                     cr.location.x = cr.location.x - origin.x;
3308                     cr.location.y = cr.location.y - origin.y;
3309                     setClipResult = graphics.SetClip(cr);
3310                     if (setClipResult.Error())
3311                     {
3312                         return Result<bool>(ErrorId(setClipResult.GetErrorId()));
3313                     }
3314                     Rect bottomShadowRect(
3315                         Point(cr.location.x + shadowWidthcr.location.y + cr.size.h - shadowWidth)
3316                         Size(cr.size.w - shadowWidthshadowWidth));
3317                     auto fillRectangleResult = graphics.FillRectangle(shadowBrushbottomShadowRect);
3318                     if (fillRectangleResult.Error())
3319                     {
3320                         return Result<bool>(ErrorId(fillRectangleResult.GetErrorId()));
3321                     }
3322                     Rect rightShadowRect(
3323                         Point(cr.location.x + cr.size.w - shadowWidthcr.location.y + shadowWidth)
3324                         Size(shadowWidthcr.size.h - shadowWidth));
3325                     fillRectangleResult = graphics.FillRectangle(shadowBrushrightShadowRect);
3326                     if (fillRectangleResult.Error())
3327                     {
3328                         return Result<bool>(ErrorId(fillRectangleResult.GetErrorId()));
3329                     }
3330                     Rect rect = childRect;
3331                     rect.location.x = rect.location.x - origin.x;
3332                     rect.location.y = rect.location.y - origin.y;
3333                     rect.size.w = rect.size.w - 1;
3334                     rect.size.h = rect.size.h - 1;
3335                     if (Level() == 0)
3336                     {
3337                         auto drawLineResult = graphics.DrawLine(blackPenrect.locationPoint(rect.location.xrect.location.y + rect.size.h - shadowWidth));
3338                         if (drawLineResult.Error())
3339                         {
3340                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3341                         }
3342                         drawLineResult = graphics.DrawLine(blackPenPoint(rect.location.xrect.location.y + rect.size.h - shadowWidth)
3343                             Point(rect.location.x + rect.size.w - shadowWidthrect.location.y + rect.size.h - shadowWidth));
3344                         if (drawLineResult.Error())
3345                         {
3346                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3347                         }
3348                         drawLineResult = graphics.DrawLine(blackPenPoint(rect.location.x + rect.size.w - shadowWidthrect.location.y + rect.size.h - shadowWidth)
3349                             Point(rect.location.x + rect.size.w - shadowWidthrect.location.y));
3350                         if (drawLineResult.Error())
3351                         {
3352                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3353                         }
3354                         drawLineResult = graphics.DrawLine(blackPen
3355                             Point(rect.location.x + rect.size.w - shadowWidthrect.location.y)Point(r.location.x + r.size.wrect.location.y));
3356                         if (drawLineResult.Error())
3357                         {
3358                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3359                         }
3360                     }
3361                     else
3362                     {
3363                         auto drawLineResult = graphics.DrawLine(blackPenrect.locationPoint(rect.location.xrect.location.y + rect.size.h - shadowWidth));
3364                         if (drawLineResult.Error())
3365                         {
3366                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3367                         }
3368                         drawLineResult = graphics.DrawLine(blackPenPoint(rect.location.xr.location.y + rect.size.h - shadowWidth)
3369                             Point(rect.location.x + rect.size.w - shadowWidthrect.location.y + rect.size.h - shadowWidth));
3370                         if (drawLineResult.Error())
3371                         {
3372                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3373                         }
3374                         drawLineResult = graphics.DrawLine(blackPenPoint(rect.location.x + rect.size.w - shadowWidthrect.location.y + rect.size.h - shadowWidth)
3375                             Point(rect.location.x + rect.size.w - shadowWidthrect.location.y));
3376                         if (drawLineResult.Error())
3377                         {
3378                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3379                         }
3380                         drawLineResult = graphics.DrawLine(blackPenPoint(rect.location.x + rect.size.w - shadowWidthrect.location.y)
3381                             Point(rect.location.xrect.location.y));
3382                         if (drawLineResult.Error())
3383                         {
3384                             return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3385                         }
3386                     }
3387                     Component* child = children.FirstChild();
3388                     while (child != null)
3389                     {
3390                         if (child is MenuItemBase*)
3391                         {
3392                             MenuItemBase* menuItem = cast<MenuItem*>(child);
3393                             auto drawResult = menuItem->Draw(graphicsparentPaddingtextBrushdisabledTextBrushbackgroundBrushmouseOverBrush
3394                                 menuOpenBrushshadowBrushblackBrushblackPendarkPenfontformatmenuOpenColormenuControldrawSubItemsorigin);
3395                             if (drawResult.Error())
3396                             {
3397                                 return Result<bool>(ErrorId(drawResult.GetErrorId()));
3398                             }
3399                         }
3400                         child = child->NextSibling();
3401                     }
3402                     setClipResult = graphics.SetClip(prevClipRegion);
3403                     if (setClipResult.Error())
3404                     {
3405                         return Result<bool>(ErrorId(setClipResult.GetErrorId()));
3406                     }
3407                 }
3408             }
3409             return Result<bool>(true);
3410         }
3411         private Result<bool> DrawShortcut(Graphics& graphicsconst Brush& textBrushconst Font& fontconst StringFormat& formatconst Point& origin)
3412         {
3413             if (shortcut != Keys.none)
3414             {
3415                 string shortcutText = ToString(shortcut);
3416                 Padding shortcutPadding = ShortcutPadding();
3417                 int shortcutFieldWidth = 0;
3418                 int childIndicatorFieldWidth = 0;
3419                 MenuItem* parent = GetParentMenuItem();
3420                 if (parent != null)
3421                 {
3422                     shortcutFieldWidth = parent->shortcutFieldWidth;
3423                     childIndicatorFieldWidth = parent->childIndicatorFieldWidth;
3424                 }
3425                 Padding padding = DefaultPadding();
3426                 int shadowWidth = ShadowWidth();
3427                 Point loc = Location();
3428                 loc.x = loc.x - origin.x;
3429                 loc.y = loc.y - origin.y;
3430                 Size size = GetSize();
3431                 auto drawStringResult = graphics.DrawString(shortcutTextfont
3432                     PointF(loc.x + size.w - shadowWidth - shortcutFieldWidth - childIndicatorFieldWidth + shortcutPadding.leftloc.y + padding.top)formattextBrush);
3433                 if (drawStringResult.Error())
3434                 {
3435                     return Result<bool>(ErrorId(drawStringResult.GetErrorId()));
3436                 }
3437             }
3438             return Result<bool>(true);
3439         }
3440         private Result<bool> DrawChildIndicator(Graphics& graphicsconst Brush& blackBrushconst Point& origin)
3441         {
3442             if (children.IsEmpty()) return Result<bool>(true);
3443             Point loc = Location();
3444             loc.x = loc.x - origin.x;
3445             loc.y = loc.y - origin.y;
3446             Size size = GetSize();
3447             int childIndicatorIndent = ChildIndicatorIndent();
3448             int childIndicatorWidth = ChildIndicatorWidth();
3449             int shadowWidth = ShadowWidth();
3450             Point up(loc.x + size.w - childIndicatorIndent - shadowWidthloc.y + size.h / 2 - childIndicatorWidth / 2);
3451             Point down(loc.x + size.w - childIndicatorIndent - shadowWidthloc.y + size.h / 2 + childIndicatorWidth / 2);
3452             Point right(loc.x + size.w - childIndicatorIndent + cast<int>((Sqrt(3) / 2.000000) * childIndicatorWidth) - shadowWidthloc.y + size.h / 2);
3453             List<Point> triangle;
3454             triangle.Add(up);
3455             triangle.Add(down);
3456             triangle.Add(right);
3457             auto fillPolygonResult = graphics.FillPolygon(blackBrush3triangle.Begin().Ptr());
3458             if (fillPolygonResult.Error())
3459             {
3460                 return Result<bool>(ErrorId(fillPolygonResult.GetErrorId()));
3461             }
3462             return Result<bool>(true);
3463         }
3464         internal bool IsSameOrParentOf(MenuItem* menuItem) const
3465         {
3466             if (this == menuItem) return true;
3467             MenuItem* parent = menuItem->GetParentMenuItem();
3468             if (parent != null)
3469             {
3470                 return IsSameOrParentOf(parent);
3471             }
3472             return false;
3473         }
3474         internal inline bool Selected() const
3475         {
3476             return (flags & Flags.selected) != 0;
3477         }
3478         [nodiscard]
3479         internal Result<bool> SetSelected(MenuControl* menuControl)
3480         {
3481             if ((flags & Flags.selected) == 0)
3482             {
3483                 flags = cast<Flags>(flags | Flags.selected);
3484                 auto result = menuControl->SetMenuInvalidated();
3485                 if (result.Error()) return result;
3486             }
3487             return Result<bool>(true);
3488         }
3489         [nodiscard]
3490         internal Result<bool> ResetSelected(MenuControl* menuControl)
3491         {
3492             if ((flags & Flags.selected) != 0)
3493             {
3494                 flags = cast<Flags>(flags & ~Flags.selected);
3495                 auto result = menuControl->SetMenuInvalidated();
3496                 if (result.Error()) return result;
3497             }
3498             return Result<bool>(true);
3499         }
3500         public inline bool IsEnabled() const
3501         {
3502             return cast<Flags>(flags & Flags.disabled) == Flags.none;
3503         }
3504         public inline bool IsDisabled() const
3505         {
3506             return cast<Flags>(flags & Flags.disabled) != Flags.none;
3507         }
3508         [nodiscard]
3509         public Result<bool> Enable()
3510         {
3511             if (!IsEnabled())
3512             {
3513                 flags = cast<Flags>(flags & ~Flags.disabled);
3514                 MenuControl* menuControl = GetMenuControl();
3515                 if (menuControl != null)
3516                 {
3517                     auto result = menuControl->SetMenuInvalidated();
3518                     if (result.Error()) return result;
3519                     menuControl->SetMenuChanged();
3520                 }
3521             }
3522             return Result<bool>(true);
3523         }
3524         [nodiscard]
3525         public Result<bool> Disable()
3526         {
3527             if (IsEnabled())
3528             {
3529                 flags = cast<Flags>(flags | Flags.disabled);
3530                 MenuControl* menuControl = GetMenuControl();
3531                 if (menuControl != null)
3532                 {
3533                     auto result = menuControl->SetMenuInvalidated();
3534                     if (result.Error()) return result;
3535                     menuControl->SetMenuChanged();
3536                 }
3537             }
3538             return Result<bool>(true);
3539         }
3540         internal inline bool MouseInClient() const
3541         {
3542             return (flags & Flags.mouseInClient) != 0;
3543         }
3544         internal void SetMouseInClient()
3545         {
3546             flags = cast<Flags>(flags | Flags.mouseInClient);
3547         }
3548         internal void ResetMouseInClient()
3549         {
3550             flags = cast<Flags>(flags & ~Flags.mouseInClient);
3551         }
3552         private inline bool LButtonPressed() const
3553         {
3554             return (flags & Flags.lbuttonPressed) != 0;
3555         }
3556         private void SetLButtonPressed()
3557         {
3558             flags = cast<Flags>(flags | Flags.lbuttonPressed);
3559         }
3560         private void ResetLButtonPressed()
3561         {
3562             flags = cast<Flags>(flags & ~Flags.lbuttonPressed);
3563         }
3564         public Event<MouseEventHandlerMouseEventArgs>& MouseDownEvent()
3565         {
3566             return mouseDownEvent;
3567         }
3568         public Event<MouseEventHandlerMouseEventArgs>& MouseUpEvent()
3569         {
3570             return mouseUpEvent;
3571         }
3572         public Event<MouseEnterEventHandlerEnterLeaveEventArgs>& MouseEnterEvent()
3573         {
3574             return mouseEnterEvent;
3575         }
3576         public Event<MouseEventHandlerMouseEventArgs>& MouseMoveEvent()
3577         {
3578             return mouseMoveEvent;
3579         }
3580         public Event<MouseLeaveEventHandlerEnterLeaveEventArgs>& MouseLeaveEvent()
3581         {
3582             return mouseLeaveEvent;
3583         }
3584         public Event<ClickEventHandlerClickEventArgs>& ClickEvent()
3585         {
3586             return clickEvent;
3587         }
3588         private string text;
3589         private ComponentContainer children;
3590         private Rect childRect;
3591         private Rect unionRect;
3592         private Event<MouseEventHandlerMouseEventArgs> mouseDownEvent;
3593         private Event<MouseEventHandlerMouseEventArgs> mouseUpEvent;
3594         private Event<MouseEnterEventHandlerEnterLeaveEventArgs> mouseEnterEvent;
3595         private Event<MouseEventHandlerMouseEventArgs> mouseMoveEvent;
3596         private Event<MouseLeaveEventHandlerEnterLeaveEventArgs> mouseLeaveEvent;
3597         private Event<ClickEventHandlerClickEventArgs> clickEvent;
3598         private State state;
3599         private Flags flags;
3600         private wchar accessKey;
3601         private Keys shortcut;
3602         private int shortcutFieldWidth;
3603         private int childIndicatorFieldWidth;
3604     }
3605 
3606     public class MenuItemSeparator : MenuItemBase
3607     {
3608         [nodiscard]
3609         public override Result<bool> Draw(Graphics& graphicsconst Padding& parentPaddingconst Brush& textBrushconst Brush& disabledTextBrush
3610             const Brush& backgroundBrushconst Brush& mouseOverBrushconst Brush& menuOpenBrushconst Brush& shadowBrushconst Brush& blackBrush
3611             const Pen& blackPenconst Pen& darkPenconst Font& fontconst StringFormat& format
3612             const Color& menuOpenColorMenuControl* menuControlbool drawSubItemsconst Point& origin)
3613         {
3614             Point loc = Location();
3615             loc.x = loc.x - origin.x;
3616             loc.y = loc.y - origin.y;
3617             Rect rect(locGetSize());
3618             Padding padding = DefaultPadding();
3619             auto drawLineResult = graphics.DrawLine(darkPen
3620                 Point(rect.location.x + padding.leftrect.location.y + rect.size.h / 2)
3621                 Point(rect.location.x + rect.size.w - padding.rightrect.location.y + rect.size.h / 2));
3622             if (drawLineResult.Error())
3623             {
3624                 return Result<bool>(ErrorId(drawLineResult.GetErrorId()));
3625             }
3626             return Result<bool>(true);
3627         }
3628         public override Padding DefaultPadding() const
3629         {
3630             return Padding(32484);
3631         }
3632         public override Size MeasureItem(Graphics& graphicsconst Font& fontconst StringFormat& formatint& shortcutFieldWidthint& childIndicatorFieldWidth)
3633         {
3634             Padding padding = DefaultPadding();
3635             RectF rect;
3636             int w = cast<int>(rect.size.w);
3637             w = w + padding.Horizontal();
3638             int h = cast<int>(rect.size.h);
3639             h = h + padding.Vertical();
3640             Size size(wh);
3641             SetSize(size);
3642             return size;
3643         }
3644     }