1 // =================================
   2 // Copyright (c) 2024 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 using System;
   7 
   8 namespace System.Windows
   9 {
  10     public class delegate void WindowClosingEventHandler(bool& cancelClose);
  11 
  12     public class delegate void WindowClosedEventHandler();
  13 
  14     public delegate int GetDialogResultFunction(void* dialogWindowPtr);
  15 
  16     public delegate void DialogWindowKeyPreviewFunction(void* windowPtruint keyCodebool shiftbool controlbool altbool keyDownbool& handled);
  17 
  18     public delegate void ModelessWindowKeyPreviewFunction(uint keyCodebool shiftbool controlbool altbool keyDownbool& handled);
  19 
  20     public class delegate void KeyPreviewMethod(Keys keybool shiftbool controlbool altbool keyDownbool& handled);
  21 
  22     public Color DefaultWindowBackgroundColor()
  23     {
  24         return GetSystemColor(SystemColor.COLOR_WINDOW);
  25     }
  26 
  27     public string DefaultWindowFontFamilyName()
  28     {
  29         return "Microsoft Sans Serif";
  30     }
  31 
  32     public float DefaultWindowFontSize()
  33     {
  34         return 8.250000f;
  35     }
  36 
  37     internal class DialogGuard
  38     {
  39         public DialogGuard(Window* window_) : window(window_)
  40         {
  41             window->SetShowingDialog();
  42         }
  43         public ~DialogGuard()
  44         {
  45             window->ResetShowingDialog();
  46         }
  47         private Window* window;
  48     }
  49 
  50     public ControlCreateParams& WindowControlCreateParams(ControlCreateParams& controlCreateParams
  51         const string& windowClassNameconst string& captionconst Point& locationconst Size& size)
  52     {
  53         return controlCreateParams.SetWindowClassName(windowClassName).
  54             SetWindowClassStyle(cast<WindowClassStyle>(WindowClassStyle.CS_VREDRAW | WindowClassStyle.CS_HREDRAW)).
  55             SetWindowStyle(WindowStyle.WS_OVERLAPPEDWINDOW).SetText(caption).SetLocation(location).SetSize(size);
  56     }
  57 
  58     public ControlCreateParams& WindowControlCreateParams(ControlCreateParams& controlCreateParamsconst string& caption)
  59     {
  60         return WindowControlCreateParams(controlCreateParams"System.Windows.Window"captionPoint.Default()Size.Default());
  61     }
  62 
  63     public class WindowCreateParams
  64     {
  65         public WindowCreateParams(ControlCreateParams& controlCreateParams_) : 
  66             controlCreateParams(controlCreateParams_)
  67             fontFamilyName(DefaultWindowFontFamilyName())
  68             fontSize(DefaultWindowFontSize())
  69             fontStyle(FontStyle.regular)
  70             state(WindowState.normal)
  71         {
  72         }
  73         public WindowCreateParams& Defaults()
  74         {
  75             return *this;
  76         }
  77         public WindowCreateParams& SetFontFamilyName(const string& fontFamilyName_)
  78         {
  79             fontFamilyName = fontFamilyName_;
  80             return *this;
  81         }
  82         public WindowCreateParams& SetFontSize(float fontSize_)
  83         {
  84             fontSize = fontSize_;
  85             return *this;
  86         }
  87         public WindowCreateParams& SetFontStyle(FontStyle fontStyle_)
  88         {
  89             fontStyle = fontStyle_;
  90             return *this;
  91         }
  92         public WindowCreateParams& SetWindowState(WindowState state_)
  93         {
  94             state = state_;
  95             return *this;
  96         }
  97         public ControlCreateParams& controlCreateParams;
  98         public string fontFamilyName;
  99         public float fontSize;
 100         public FontStyle fontStyle;
 101         public WindowState state;
 102     }
 103 
 104     public class Window : ContainerControl
 105     {
 106         private enum Flags : sbyte
 107         {
 108             none = 0mainWindow = 1 << 0showingDialog = 1 << 1
 109         }
 110         public Window(const string& windowClassNameWindowClassStyle classStyleWindowStyle styleExtendedWindowStyle exStyle
 111             const Color& backgroundColorconst string& textconst Point& locationconst Size& sizeDock dockAnchors anchors
 112             const string& fontFamilyName_float fontSize_FontStyle fontStyle_WindowState state_) : 
 113             base(windowClassNameclassStylestyleexStylebackgroundColortextlocationsizedockanchors)flags(Flags.none)state(state_)
 114             menuBar(null)contextMenu(null)defaultButton(null)cancelButton(null)focusedControl(null)dialogResult(DialogResult.none)
 115             keyPreviewMethod()fontFamilyName(fontFamilyName_)fontSize(fontSize_)fontStyle(fontStyle_)
 116         {
 117             auto initResult = Init();
 118             if (initResult.Error())
 119             {
 120                 SetErrorId(initResult.GetErrorId());
 121             }
 122         }
 123         public Window(const string& windowClassNameWindowClassStyle classStyleWindowStyle styleExtendedWindowStyle exStyle
 124             const Color& backgroundColorconst string& textconst Point& locationconst Size& sizeDock dockAnchors anchorsWindowState state) : 
 125             this(windowClassNameclassStylestyleexStylebackgroundColortextlocationsizedockanchors
 126                 DefaultWindowFontFamilyName()DefaultWindowFontSize()FontStyle.regularstate)
 127         {
 128         }
 129         public Window(const string& windowClassNameWindowStyle styleExtendedWindowStyle exStyleconst string& textconst Point& location
 130             const Size& sizeDock dockAnchors anchors
 131             const string& fontFamilyName_float fontSize_FontStyle fontStyle_WindowState state) : 
 132             this(windowClassNamecast<WindowClassStyle>(WindowClassStyle.CS_VREDRAW | WindowClassStyle.CS_HREDRAW)styleexStyle
 133             DefaultWindowBackgroundColor()textlocationsizedockanchorsfontFamilyName_fontSize_fontStyle_state)
 134         {
 135         }
 136         public Window(const string& windowClassNameWindowStyle styleExtendedWindowStyle exStyleconst string& textconst Point& location
 137             const Size& sizeDock dockAnchors anchorsWindowState state) : 
 138             this(windowClassNamestyleexStyletextlocationsizedockanchorsDefaultWindowFontFamilyName()DefaultWindowFontSize()
 139             FontStyle.regularstate)
 140         {
 141         }
 142         public Window(const string& captionconst string& fontFamilyName_float fontSize_FontStyle fontStyle_) : 
 143             this("System.Windows.Window"WindowStyle.WS_OVERLAPPEDWINDOWDefaultExtendedWindowStyle()
 144             captionPoint.Default()Size.Default()Dock.noneAnchors.nonefontFamilyName_fontSize_fontStyle_WindowState.normal)
 145         {
 146         }
 147         public Window(const string& caption) : 
 148             this(captionDefaultWindowFontFamilyName()DefaultWindowFontSize()FontStyle.regular)
 149         {
 150         }
 151         public Window(WindowCreateParams& createParams) : 
 152             base(createParams.controlCreateParams)
 153             flags(Flags.none)state(createParams.state)
 154             menuBar(null)contextMenu(null)defaultButton(null)cancelButton(null)focusedControl(null)dialogResult(DialogResult.none)
 155             keyPreviewMethod()fontFamilyName(createParams.fontFamilyName)fontSize(createParams.fontSize)fontStyle(createParams.fontStyle)
 156         {
 157             auto initResult = Init();
 158             if (initResult.Error())
 159             {
 160                 SetErrorId(initResult.GetErrorId());
 161             }
 162         }
 163         private Result<bool> Init()
 164         {
 165             SetKeyPreviewMethod(DefaultKeyPreview);
 166             if (Handle() != null)
 167             {
 168                 auto createResult = OnCreated();
 169                 if (createResult.Error())
 170                 {
 171                     return Result<bool>(ErrorId(createResult.GetErrorId()));
 172                 }
 173             }
 174             if (!fontFamilyName.IsEmpty())
 175             {
 176                 FontFamily fontFamily = FontFamily(fontFamilyName);
 177                 if (fontFamily.Error())
 178                 {
 179                     return Result<bool>(ErrorId(fontFamily.GetErrorId()));
 180                 }
 181                 Font font = Font(Rvalue(fontFamily)fontSizefontStyleUnit.point);
 182                 if (font.Error())
 183                 {
 184                     return Result<bool>(ErrorId(font.GetErrorId()));
 185                 }
 186                 SetFont(Rvalue(font));
 187             }
 188             return Result<bool>(true);
 189         }
 190         [nodiscard]
 191         public Result<DialogResult> ShowDialog(Window& parentWindow)
 192         {
 193             DialogGuard guard(this);
 194             auto parentLocResult = parentWindow.Location();
 195             if (parentLocResult.Error())
 196             {
 197                 return Result<DialogResult>(ErrorId(parentLocResult.GetErrorId()));
 198             }
 199             Point parentLoc = parentLocResult.Value();
 200             Size parentSize = parentWindow.GetSize();
 201             Size size = GetSize();
 202             auto boolResult = SetLocation(Point(Max(cast<int>(0)parentLoc.x + (parentSize.w - size.w) / 2)
 203                 Max(cast<int>(0)parentLoc.y + (parentSize.h - size.h) / 2)));
 204             if (boolResult.Error())
 205             {
 206                 return Result<DialogResult>(ErrorId(boolResult.GetErrorId()));
 207             }
 208             SetDialogResult(DialogResult.none);
 209             GetDialogResultFunction dialogResultFunction = System.Windows.GetDialogResult;
 210             DialogWindowKeyPreviewFunction keyPreviewFunction = System.Windows.DialogWindowKeyPreview;
 211             int result = WinDialogWindowMessageLoop(Handle()parentWindow.Handle()cast<void*>(dialogResultFunction)cast<void*>(keyPreviewFunction)this);
 212             return cast<DialogResult>(result);
 213         }
 214         protected override Result<bool> OnCreated()
 215         {
 216             if (!BaseOnCreatedCalled())
 217             {
 218                 SetBaseOnCreatedCalled();
 219                 auto result = base->OnCreated();
 220                 if (result.Error())
 221                 {
 222                     return Result<bool>(ErrorId(result.GetErrorId()));
 223                 }
 224             }
 225             if (!ScreenMetrics.Calculated())
 226             {
 227                 auto graphicsResult = Graphics.FromWindowHandle(Handle());
 228                 if (graphicsResult.Error())
 229                 {
 230                     return Result<bool>(ErrorId(graphicsResult.GetErrorId()));
 231                 }
 232                 Graphics& graphics = graphicsResult.Value();
 233                 ScreenMetrics.Calculate(graphics);
 234             }
 235             return Result<bool>(true);
 236         }
 237         [nodiscard]
 238         public override Result<bool> PrintWindowTree(int level)
 239         {
 240             LogView* log = Application.GetLogView();
 241             if (log != null)
 242             {
 243                 auto handleResult = ToHexString(cast<ulong>(Handle()));
 244                 if (handleResult.Error())
 245                 {
 246                     return Result<bool>(ErrorId(handleResult.GetErrorId()));
 247                 }
 248                 const string& handleStr = handleResult.Value();
 249                 auto parentTextResult = ParentText();
 250                 if (parentTextResult.Error())
 251                 {
 252                     return Result<bool>(ErrorId(parentTextResult.GetErrorId()));
 253                 }
 254                 const string& parentText = parentTextResult.Value();
 255                 auto result = log->WriteLine(string(' 'level) + "Window." + Text() + ".handle=" + handleStr + " " + parentText + 
 256                     "[" + Rect(Point()GetSize()).ToString() + "]");
 257                 if (result.Error()) return result;
 258             }
 259             Component* child = Children().FirstChild();
 260             while (child != null)
 261             {
 262                 if (child is Control*)
 263                 {
 264                     Control* childControl = cast<Control*>(child);
 265                     auto childResult = childControl->PrintWindowTree(level + 1);
 266                     if (childResult.Error())
 267                     {
 268                         return Result<bool>(ErrorId(childResult.GetErrorId()));
 269                     }
 270                 }
 271                 child = child->NextSibling();
 272             }
 273             return Result<bool>(true);
 274         }
 275         protected override Result<bool> ProcessMessage(Message& message)
 276         {
 277             switch (message.msg)
 278             {
 279                 case WM_CLOSE:
 280                 {
 281                     bool cancelClose = false;
 282                     auto result = OnWindowClosing(cancelClose);
 283                     if (result.Error()) return result;
 284                     if (cancelClose)
 285                     {
 286                         message.result = 0;
 287                         return Result<bool>(true);
 288                     }
 289                     break;
 290                 }
 291                 case WM_DESTROY:
 292                 {
 293                     bool processed = false;
 294                     OnWindowClosed(processed);
 295                     if (processed)
 296                     {
 297                         message.result = 0;
 298                         return Result<bool>(true);
 299                     }
 300                     break;
 301                 }
 302                 case WM_COMMAND: case WM_MOVE: case WM_SIZE: case WM_PAINT: case WM_MOUSEMOVE: case WM_MOUSELEAVE: case WM_LBUTTONDOWN:
 303                 case WM_LBUTTONUP: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONUP:
 304                 case WM_CHAR: case WM_KEYDOWN: case WM_KEYUP: case WM_SYSCOMMAND: case WM_HSCROLL: case WM_VSCROLL: case WM_MOUSEWHEEL:
 305                 case WM_TIMER: case WM_SETFOCUS: case WM_KILLFOCUS:
 306                 case WM_SHOWWINDOW: case WM_CLIPBOARDUPDATE:
 307                 {
 308                     return base->ProcessMessage(message);
 309                 }
 310             }
 311             return Result<bool>(false);
 312         }
 313         [nodiscard]
 314         public Result<bool> Close()
 315         {
 316             return PostMessage(Handle()WM_CLOSE0u0);
 317         }
 318         protected virtual Result<bool> OnWindowClosing(bool& cancelClose)
 319         {
 320             windowClosingEvent.Fire(cancelClose);
 321             return Result<bool>(true);
 322         }
 323         protected virtual void OnWindowClosed(bool& processed)
 324         {
 325             if (windowClosedEvent.Handlers().IsEmpty())
 326             {
 327                 if (IsMainWindow())
 328                 {
 329                     Application.Exit();
 330                     processed = true;
 331                 }
 332             }
 333             else
 334             {
 335                 windowClosedEvent.Fire();
 336                 processed = true;
 337             }
 338         }
 339         [nodiscard]
 340         protected override Result<bool> OnControlAdded(ControlEventArgs& args)
 341         {
 342             auto result = base->OnControlAdded(args);
 343             if (result.Error()) return result;
 344             Control* control = args.control;
 345             if (control is MenuBar*)
 346             {
 347                 menuBar = cast<MenuBar*>(control);
 348             }
 349             else if (control is Button*)
 350             {
 351                 Button* button = cast<Button*>(control);
 352                 if (button->IsDefault())
 353                 {
 354                     SetDefaultButton(button);
 355                 }
 356             }
 357             return Result<bool>(true);
 358         }
 359         [nodiscard]
 360         protected override Result<bool> OnControlRemoved(ControlEventArgs& args)
 361         {
 362             auto result = base->OnControlRemoved(args);
 363             if (result.Error()) return result;
 364             Control* control = args.control;
 365             if (control == menuBar)
 366             {
 367                 menuBar = null;
 368             }
 369             else if (control == defaultButton)
 370             {
 371                 defaultButton = null;
 372             }
 373             else if (control == cancelButton)
 374             {
 375                 cancelButton = null;
 376             }
 377             return Result<bool>(true);
 378         }
 379         public void DefaultKeyPreview(Keys keybool shiftbool controlbool altbool keyDownbool& handled)
 380         {
 381             if (keyDown)
 382             {
 383                 Keys modifierKeys = Keys.none;
 384                 if (shift)
 385                 {
 386                     modifierKeys = cast<Keys>(modifierKeys | Keys.shiftModifier);
 387                 }
 388                 if (control)
 389                 {
 390                     modifierKeys = cast<Keys>(modifierKeys | Keys.controlModifier);
 391                 }
 392                 if (alt)
 393                 {
 394                     modifierKeys = cast<Keys>(modifierKeys | Keys.altModifier);
 395                 }
 396                 key = cast<Keys>(key | modifierKeys);
 397                 switch (key)
 398                 {
 399                     case Keys.enter:
 400                     {
 401                         if (ShowingDialog())
 402                         {
 403                             if (focusedControl != null)
 404                             {
 405                                 if (focusedControl is TextBox*)
 406                                 {
 407                                     TextBox* textBox = cast<TextBox*>(focusedControl);
 408                                     if (textBox->IsMultiline())
 409                                     {
 410                                         return;
 411                                     }
 412                                 }
 413                             }
 414                             if (focusedControl != null)
 415                             {
 416                                 if (focusedControl is Button*)
 417                                 {
 418                                     Button* button = cast<Button*>(focusedControl);
 419                                     auto result = button->OnClickInternal();
 420                                     if (result.Error())
 421                                     {
 422                                         SetErrorId(result.GetErrorId());
 423                                         return;
 424                                     }
 425                                     handled = true;
 426                                 }
 427                             }
 428                             if (!handled)
 429                             {
 430                                 if (defaultButton != null && defaultButton->IsEnabled())
 431                                 {
 432                                     auto result = defaultButton->OnClickInternal();
 433                                     if (result.Error())
 434                                     {
 435                                         SetErrorId(result.GetErrorId());
 436                                         return;
 437                                     }
 438                                     handled = true;
 439                                 }
 440                             }
 441                         }
 442                         break;
 443                     }
 444                     case Keys.escape:
 445                     {
 446                         if (ShowingDialog())
 447                         {
 448                             if (cancelButton != null)
 449                             {
 450                                 auto result = cancelButton->OnClickInternal();
 451                                 if (result.Error())
 452                                 {
 453                                     SetErrorId(result.GetErrorId());
 454                                     return;
 455                                 }
 456                                 handled = true;
 457                             }
 458                         }
 459                         break;
 460                     }
 461                     case Keys.tab:
 462                     {
 463                         auto result = FocusNext();
 464                         if (result.Error())
 465                         {
 466                             SetErrorId(result.GetErrorId());
 467                             return;
 468                         }
 469                         handled = true;
 470                         break;
 471                     }
 472                     case cast<Keys>(Keys.shiftModifier | Keys.tab):
 473                     {
 474                         auto result = FocusPrev();
 475                         if (result.Error())
 476                         {
 477                             SetErrorId(result.GetErrorId());
 478                             return;
 479                         }
 480                         handled = true;
 481                         break;
 482                     }
 483                 }
 484             }
 485         }
 486         [nodiscard]
 487         protected override Result<bool> OnKeyDown(KeyEventArgs& args)
 488         {
 489             auto result = base->OnKeyDown(args);
 490             if (result.Error()) return result;
 491             if (!args.handled)
 492             {
 493                 switch (args.key)
 494                 {
 495                     case Keys.enter:
 496                     {
 497                         if (ShowingDialog())
 498                         {
 499                             if (focusedControl != null)
 500                             {
 501                                 if (focusedControl is Button*)
 502                                 {
 503                                     Button* button = cast<Button*>(focusedControl);
 504                                     result = button->OnClickInternal();
 505                                     if (result.Error()) return result;
 506                                     args.handled = true;
 507                                 }
 508                             }
 509                             if (!args.handled)
 510                             {
 511                                 if (defaultButton != null && defaultButton->IsEnabled())
 512                                 {
 513                                     result = defaultButton->OnClickInternal();
 514                                     if (result.Error()) return result;
 515                                     args.handled = true;
 516                                 }
 517                             }
 518                         }
 519                         break;
 520                     }
 521                     case Keys.escape:
 522                     {
 523                         if (ShowingDialog())
 524                         {
 525                             if (cancelButton != null)
 526                             {
 527                                 result = cancelButton->OnClickInternal();
 528                                 if (result.Error()) return result;
 529                                 args.handled = true;
 530                             }
 531                         }
 532                         break;
 533                     }
 534                     case Keys.tab:
 535                     {
 536                         auto result = FocusNext();
 537                         if (result.Error()) return result;
 538                         args.handled = true;
 539                         break;
 540                     }
 541                     case cast<Keys>(Keys.shiftModifier | Keys.tab):
 542                     {
 543                         auto result = FocusPrev();
 544                         if (result.Error()) return result;
 545                         args.handled = true;
 546                         break;
 547                     }
 548                 }
 549             }
 550             return Result<bool>(true);
 551         }
 552         [nodiscard]
 553         protected override Result<bool> OnMouseMove(MouseEventArgs& args)
 554         {
 555             auto result = base->OnMouseMove(args);
 556             if (result.Error()) return result;
 557             if (menuBar != null)
 558             {
 559                 result = menuBar->MouseMoveInternal(args);
 560                 if (result.Error()) return result;
 561             }
 562             return Result<bool>(true);
 563         }
 564         [nodiscard]
 565         protected override Result<bool> OnMouseDown(MouseEventArgs& args)
 566         {
 567             auto result = base->OnMouseDown(args);
 568             if (result.Error()) return result;
 569             if (menuBar != null)
 570             {
 571                 result = menuBar->MouseDownInternal(args);
 572                 if (result.Error()) return result;
 573             }
 574             return Result<bool>(true);
 575         }
 576         [nodiscard]
 577         protected override Result<bool> OnMouseUp(MouseEventArgs& args)
 578         {
 579             auto result = base->OnMouseUp(args);
 580             if (result.Error()) return result;
 581             if (menuBar != null)
 582             {
 583                 result = menuBar->MouseUpInternal(args);
 584                 if (result.Error()) return result;
 585             }
 586             return Result<bool>(true);
 587         }
 588         [nodiscard]
 589         protected override Result<bool> OnPaint(PaintEventArgs& args)
 590         {
 591             if (Debug.Paint())
 592             {
 593                 Rect r(Point()GetSize());
 594                 LogView* log = Application.GetLogView();
 595                 if (log != null)
 596                 {
 597                     auto result = log->WriteLine("Window.OnPaint: " + r.ToString());
 598                     if (result.Error()) return result;
 599                 }
 600             }
 601             auto clearResult = args.graphics.Clear(BackgroundColor());
 602             if (clearResult.Error())
 603             {
 604                 return Result<bool>(ErrorId(clearResult.GetErrorId()));
 605             }
 606             return base->OnPaint(args);
 607         }
 608         [nodiscard]
 609         protected override Result<bool> OnGotFocus()
 610         {
 611             LogView* log = Application.GetLogView();
 612             if (log != null)
 613             {
 614                 auto result = log->WriteLine("Window.OnGotFocus: " + Text());
 615                 if (result.Error()) return result;
 616             }
 617             auto result = base->OnGotFocus();
 618             if (result.Error()) return result;
 619             Application.SetActiveWindow(this);
 620             result = FocusNext();
 621             if (result.Error()) return result;
 622             return Result<bool>(true);
 623         }
 624         protected override Result<bool> OnLostFocus()
 625         {
 626             LogView* log = Application.GetLogView();
 627             if (log != null)
 628             {
 629                 auto result = log->WriteLine("Window.OnLostFocus: " + Text());
 630                 if (result.Error()) return result;
 631             }
 632             auto result = base->OnLostFocus();
 633             if (result.Error()) return result;
 634             Application.SetActiveWindow(null);
 635             return Result<bool>(true);
 636         }
 637         public WindowState GetWindowState() const
 638         {
 639             return state;
 640         }
 641         [nodiscard]
 642         public Result<bool> SetWindowState(WindowState newState)
 643         {
 644             if (state != newState)
 645             {
 646                 switch (state)
 647                 {
 648                     case WindowState.normal:
 649                     {
 650                         switch (newState)
 651                         {
 652                             case WindowState.minimized:
 653                             {
 654                                 auto result = ShowWindow(ShowCommand.SW_MINIMIZE);
 655                                 if (result.Error()) return result;
 656                                 break;
 657                             }
 658                             case WindowState.maximized:
 659                             {
 660                                 auto result = ShowWindow(ShowCommand.SW_MAXIMIZE);
 661                                 if (result.Error()) return result;
 662                                 break;
 663                             }
 664                         }
 665                         break;
 666                     }
 667                     case WindowState.minimized: case WindowState.maximized:
 668                     {
 669                         switch (newState)
 670                         {
 671                             case WindowState.normal:
 672                             {
 673                                 auto result = ShowWindow(ShowCommand.SW_RESTORE);
 674                                 if (result.Error()) return result;
 675                                 break;
 676                             }
 677                             case WindowState.minimized:
 678                             {
 679                                 auto result = ShowWindow(ShowCommand.SW_MINIMIZE);
 680                                 if (result.Error()) return result;
 681                                 break;
 682                             }
 683                             case WindowState.maximized:
 684                             {
 685                                 auto result = ShowWindow(ShowCommand.SW_MAXIMIZE);
 686                                 if (result.Error()) return result;
 687                                 break;
 688                             }
 689                         }
 690                         break;
 691                     }
 692                 }
 693                 state = newState;
 694             }
 695             return Result<bool>(true);
 696         }
 697         public MenuBar* GetMenuBar() const
 698         {
 699             return menuBar;
 700         }
 701         public ContextMenu* GetContextMenu() const
 702         {
 703             return contextMenu;
 704         }
 705         [nodiscard]
 706         public Result<bool> SetContextMenu(ContextMenu* contextMenu_)
 707         {
 708             auto result = RemoveContextMenu();
 709             if (result.Error()) return result;
 710             contextMenu = contextMenu_;
 711             return AddChild(contextMenu);
 712         }
 713         [nodiscard]
 714         public Result<bool> RemoveContextMenu()
 715         {
 716             if (contextMenu != null)
 717             {
 718                 auto result = HideContextMenu();
 719                 if (result.Error()) return result;
 720                 Result<UniquePtr<Control>> removeResult = RemoveChild(contextMenu);
 721                 if (removeResult.Error())
 722                 {
 723                     return Result<bool>(ErrorId(removeResult.GetErrorId()));
 724                 }
 725                 contextMenu = null;
 726             }
 727             return Result<bool>(true);
 728         }
 729         [nodiscard]
 730         public Result<bool> ShowContextMenu(ContextMenu* contextMenu_const Point& ptInScreenCoords)
 731         {
 732             auto result = SetContextMenu(contextMenu_);
 733             if (result.Error())
 734             {
 735                 return Result<bool>(ErrorId(result.GetErrorId()));
 736             }
 737             auto windowLocResult = Location();
 738             if (windowLocResult.Error())
 739             {
 740                 return Result<bool>(ErrorId(windowLocResult.GetErrorId()));
 741             }
 742             Point windowLoc = windowLocResult.Value();
 743             Size windowSize = GetSize();
 744             Point windowEdgeLoc(windowLoc.x + windowSize.wwindowLoc.y + windowSize.h);
 745             auto clientToScreenResult = ClientToScreen(windowEdgeLoc);
 746             if (clientToScreenResult.Error())
 747             {
 748                 return Result<bool>(ErrorId(clientToScreenResult.GetErrorId()));
 749             }
 750             Point screenWindowEdgeLoc = clientToScreenResult.Value();
 751             result = contextMenu->CalculateSize();
 752             if (result.Error()) return result;
 753             Size contextMenuSize = contextMenu->GetSize();
 754             if (ptInScreenCoords.x + contextMenuSize.w >= screenWindowEdgeLoc.x)
 755             {
 756                 ptInScreenCoords.Offset(-contextMenuSize.w0);
 757             }
 758             if (ptInScreenCoords.y + contextMenuSize.h >= screenWindowEdgeLoc.y)
 759             {
 760                 ptInScreenCoords.Offset(0-contextMenuSize.h);
 761             }
 762             auto screenToClientResult = ScreenToClient(ptInScreenCoords);
 763             if (screenToClientResult.Error())
 764             {
 765                 return Result<bool>(ErrorId(screenToClientResult.GetErrorId()));
 766             }
 767             Point loc = screenToClientResult.Value();
 768             result = contextMenu->SetLocation(loc);
 769             if (result.Error()) return result;
 770             result = contextMenu->BringToFront();
 771             if (result.Error()) return result;
 772             result = contextMenu->Show();
 773             if (result.Error()) return result;
 774             result = contextMenu->Invalidate();
 775             if (result.Error()) return result;
 776             contextMenu->Update();
 777             return Result<bool>(true);
 778         }
 779         [nodiscard]
 780         public Result<bool> HideContextMenu()
 781         {
 782             if (contextMenu != null)
 783             {
 784                 auto locationResult = contextMenu->Location();
 785                 if (locationResult.Error())
 786                 {
 787                     return Result<bool>(ErrorId(locationResult.GetErrorId()));
 788                 }
 789                 Rect rect(locationResult.Value()contextMenu->GetSize());
 790                 auto result = contextMenu->Hide();
 791                 if (result.Error()) return result;
 792                 result = Invalidate(rect);
 793                 if (result.Error()) return result;
 794             }
 795             return Result<bool>(true);
 796         }
 797         public Event<WindowClosingEventHandlerbool>& WindowClosingEvent()
 798         {
 799             return windowClosingEvent;
 800         }
 801         public Event<WindowClosedEventHandler>& WindowClosedEvent()
 802         {
 803             return windowClosedEvent;
 804         }
 805         [nodiscard]
 806         public Result<bool> SetIcon(const Icon& icon)
 807         {
 808             auto result = SetClassLong(Handle()ClassLongIndex.GCL_HICONcast<long>(cast<ulong>(icon.Handle())));
 809             if (result.Error())
 810             {
 811                 return Result<bool>(ErrorId(result.GetErrorId()));
 812             }
 813             return Result<bool>(true);
 814         }
 815         [nodiscard]
 816         public Result<bool> SetSmallIcon(const Icon& icon)
 817         {
 818             auto result = SetClassLong(Handle()ClassLongIndex.GCL_HICONSMcast<long>(cast<ulong>(icon.Handle())));
 819             if (result.Error())
 820             {
 821                 return Result<bool>(ErrorId(result.GetErrorId()));
 822             }
 823             return Result<bool>(true);
 824         }
 825         internal inline int GetDialogResult() const
 826         {
 827             return cast<int>(dialogResult);
 828         }
 829         public inline void SetDialogResult(DialogResult dialogResult_)
 830         {
 831             dialogResult = dialogResult_;
 832         }
 833         [nodiscard]
 834         public Result<bool> FocusNext()
 835         {
 836             LogView* logView = Application.GetLogView();
 837             if (focusedControl == null)
 838             {
 839                 Component* child = Children().FirstChild();
 840                 while (child != null)
 841                 {
 842                     if (child is Control*)
 843                     {
 844                         Control* control = cast<Control*>(child);
 845                         Control* tabStopChild = control->GetFirstEnabledTabStopControl();
 846                         if (tabStopChild != null)
 847                         {
 848                             tabStopChild->SetFocus();
 849                             focusedControl = tabStopChild;
 850                             if (logView != null)
 851                             {
 852                                 auto result = logView->WriteLine("focused: " + string(typename(*focusedControl)) + ": " + focusedControl->Text());
 853                                 if (result.Error()) return result;
 854                             }
 855                             return Result<bool>(true);
 856                         }
 857                     }
 858                     child = child->NextSibling();
 859                 }
 860             }
 861             else
 862             {
 863                 Component* parent = null;
 864                 Component* child = focusedControl;
 865                 ComponentContainer* container = child->GetContainer();
 866                 if (container != null)
 867                 {
 868                     parent = container->Parent();
 869                 }
 870                 while (child != null)
 871                 {
 872                     child = child->NextSibling();
 873                     while (child != null)
 874                     {
 875                         if (child is Control*)
 876                         {
 877                             Control* control = cast<Control*>(child);
 878                             Control* tabStopChild = control->GetFirstEnabledTabStopControl();
 879                             if (tabStopChild != null)
 880                             {
 881                                 tabStopChild->SetFocus();
 882                                 focusedControl = tabStopChild;
 883                                 return Result<bool>(true);
 884                             }
 885                         }
 886                         child = child->NextSibling();
 887                     }
 888                     child = parent;
 889                     if (parent != null)
 890                     {
 891                         container = parent->GetContainer();
 892                         if (container != null)
 893                         {
 894                             parent = container->Parent();
 895                         }
 896                         else
 897                         {
 898                             parent = null;
 899                         }
 900                     }
 901                 }
 902                 focusedControl = null;
 903                 auto result = FocusNext();
 904                 if (result.Error()) return result;
 905             }
 906             return Result<bool>(true);
 907         }
 908         [nodiscard]
 909         public Result<bool> FocusPrev()
 910         {
 911             LogView* logView = Application.GetLogView();
 912             if (focusedControl == null)
 913             {
 914                 Component* child = Children().LastChild();
 915                 while (child != null)
 916                 {
 917                     if (child is Control*)
 918                     {
 919                         Control* control = cast<Control*>(child);
 920                         Control* tabStopChild = control->GetLastEnabledTabStopControl();
 921                         if (tabStopChild != null)
 922                         {
 923                             tabStopChild->SetFocus();
 924                             focusedControl = tabStopChild;
 925                             if (logView != null)
 926                             {
 927                                 auto result = logView->WriteLine("focused: " + string(typename(*focusedControl)) + ": " + focusedControl->Text());
 928                                 if (result.Error()) return result;
 929                             }
 930                             return Result<bool>(true);
 931                         }
 932                     }
 933                     child = child->PrevSibling();
 934                 }
 935             }
 936             else
 937             {
 938                 Component* parent = null;
 939                 Component* child = focusedControl;
 940                 ComponentContainer* container = child->GetContainer();
 941                 if (container != null)
 942                 {
 943                     parent = container->Parent();
 944                 }
 945                 while (child != null)
 946                 {
 947                     child = child->PrevSibling();
 948                     while (child != null)
 949                     {
 950                         if (child is Control*)
 951                         {
 952                             Control* control = cast<Control*>(child);
 953                             Control* tabStopChild = control->GetLastEnabledTabStopControl();
 954                             if (tabStopChild != null)
 955                             {
 956                                 tabStopChild->SetFocus();
 957                                 focusedControl = tabStopChild;
 958                                 return Result<bool>(true);
 959                             }
 960                         }
 961                         child = child->PrevSibling();
 962                     }
 963                     child = parent;
 964                     if (parent != null)
 965                     {
 966                         container = parent->GetContainer();
 967                         if (container != null)
 968                         {
 969                             parent = container->Parent();
 970                         }
 971                         else
 972                         {
 973                             parent = null;
 974                         }
 975                     }
 976                 }
 977                 focusedControl = null;
 978                 auto result = FocusPrev();
 979                 if (result.Error()) return result;
 980             }
 981             return Result<bool>(true);
 982         }
 983         public inline Control* GetFocusedControl() const
 984         {
 985             return focusedControl;
 986         }
 987         public void ResetFocusedControl()
 988         {
 989             focusedControl = null;
 990         }
 991         internal inline void SetFocusedControl(Control* focusedControl_)
 992         {
 993             focusedControl = focusedControl_;
 994         }
 995         public inline const KeyPreviewMethod& GetKeyPreviewMethod() const
 996         {
 997             return keyPreviewMethod;
 998         }
 999         public void SetKeyPreviewMethod(const KeyPreviewMethod& keyPreviewMethod_)
1000         {
1001             keyPreviewMethod = keyPreviewMethod_;
1002         }
1003         public inline bool IsMainWindow() const
1004         {
1005             return (flags & Flags.mainWindow) != Flags.none;
1006         }
1007         public inline void SetAsMainWindow()
1008         {
1009             flags = cast<Flags>(flags | Flags.mainWindow);
1010         }
1011         public inline Button* DefaultButton() const
1012         {
1013             return defaultButton;
1014         }
1015         public void SetDefaultButton(Button* defaultButton_)
1016         {
1017             if (defaultButton != defaultButton_)
1018             {
1019                 if (defaultButton != null)
1020                 {
1021                     defaultButton->ResetDefault();
1022                 }
1023                 defaultButton = defaultButton_;
1024                 if (defaultButton != null)
1025                 {
1026                     defaultButton->SetDefault();
1027                 }
1028             }
1029         }
1030         public inline Button* CancelButton() const
1031         {
1032             return cancelButton;
1033         }
1034         public void SetCancelButton(Button* cancelButton_)
1035         {
1036             cancelButton = cancelButton_;
1037         }
1038         [nodiscard]
1039         internal Result<bool> MouseUpNotificationInternal(MouseEventArgs& args)
1040         {
1041             return MouseUpNotification(args);
1042         }
1043         [nodiscard]
1044         protected virtual Result<bool> MouseUpNotification(MouseEventArgs& args)
1045         {
1046             return Result<bool>(true);
1047         }
1048         private inline bool ShowingDialog() const
1049         {
1050             return (flags & Flags.showingDialog) != Flags.none;
1051         }
1052         internal inline void SetShowingDialog()
1053         {
1054             flags = cast<Flags>(flags | Flags.showingDialog);
1055         }
1056         internal inline void ResetShowingDialog()
1057         {
1058             flags = cast<Flags>(flags & ~Flags.showingDialog);
1059         }
1060         private Flags flags;
1061         private WindowState state;
1062         private MenuBar* menuBar;
1063         private ContextMenu* contextMenu;
1064         private Button* defaultButton;
1065         private Button* cancelButton;
1066         private Control* focusedControl;
1067         private string fontFamilyName;
1068         private float fontSize;
1069         private FontStyle fontStyle;
1070         private Event<WindowClosingEventHandlerbool> windowClosingEvent;
1071         private Event<WindowClosedEventHandler> windowClosedEvent;
1072         private DialogResult dialogResult;
1073         private KeyPreviewMethod keyPreviewMethod;
1074     }
1075 
1076     internal int GetDialogResult(void* dialogWindowPtr)
1077     {
1078         Window* dialogWindow = cast<Window*>(dialogWindowPtr);
1079         return dialogWindow->GetDialogResult();
1080     }
1081 
1082     internal void DialogWindowKeyPreview(void* dialogWindowPtruint keyCodebool shiftbool controlbool altbool keyDownbool& handled)
1083     {
1084         Window* dialogWindow = cast<Window*>(dialogWindowPtr);
1085         Keys key = cast<Keys>(cast<int>(keyCode));
1086         KeyPreviewMethod keyPreview = dialogWindow->GetKeyPreviewMethod();
1087         if (keyPreview != KeyPreviewMethod())
1088         {
1089             keyPreview(keyshiftcontrolaltkeyDownhandled);
1090         }
1091     }
1092 
1093     internal void ModelessWindowKeyPreview(uint keyCodebool shiftbool controlbool altbool keyDownbool& handled)
1094     {
1095         Window* activeWindow = Application.GetActiveWindow();
1096         if (activeWindow != null)
1097         {
1098             Keys key = cast<Keys>(cast<int>(keyCode));
1099             KeyPreviewMethod keyPreview = activeWindow->GetKeyPreviewMethod();
1100             if (keyPreview != KeyPreviewMethod())
1101             {
1102                 keyPreview(keyshiftcontrolaltkeyDownhandled);
1103             }
1104         }
1105     }