1
2
3
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* windowPtr, uint keyCode, bool shift, bool control, bool alt, bool keyDown, bool& handled);
17
18 public delegate void ModelessWindowKeyPreviewFunction(uint keyCode, bool shift, bool control, bool alt, bool keyDown, bool& handled);
19
20 public class delegate void KeyPreviewMethod(Keys key, bool shift, bool control, bool alt, bool keyDown, bool& 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& windowClassName, const string& caption, const Point& location, const 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& controlCreateParams, const string& caption)
59 {
60 return WindowControlCreateParams(controlCreateParams, "System.Windows.Window", caption, Point.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 = 0, mainWindow = 1 << 0, showingDialog = 1 << 1
109 }
110 public Window(const string& windowClassName, WindowClassStyle classStyle, WindowStyle style, ExtendedWindowStyle exStyle,
111 const Color& backgroundColor, const string& text, const Point& location, const Size& size, Dock dock, Anchors anchors,
112 const string& fontFamilyName_, float fontSize_, FontStyle fontStyle_, WindowState state_) :
113 base(windowClassName, classStyle, style, exStyle, backgroundColor, text, location, size, dock, anchors), 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& windowClassName, WindowClassStyle classStyle, WindowStyle style, ExtendedWindowStyle exStyle,
124 const Color& backgroundColor, const string& text, const Point& location, const Size& size, Dock dock, Anchors anchors, WindowState state) :
125 this(windowClassName, classStyle, style, exStyle, backgroundColor, text, location, size, dock, anchors,
126 DefaultWindowFontFamilyName(), DefaultWindowFontSize(), FontStyle.regular, state)
127 {
128 }
129 public Window(const string& windowClassName, WindowStyle style, ExtendedWindowStyle exStyle, const string& text, const Point& location,
130 const Size& size, Dock dock, Anchors anchors,
131 const string& fontFamilyName_, float fontSize_, FontStyle fontStyle_, WindowState state) :
132 this(windowClassName, cast<WindowClassStyle>(WindowClassStyle.CS_VREDRAW | WindowClassStyle.CS_HREDRAW), style, exStyle,
133 DefaultWindowBackgroundColor(), text, location, size, dock, anchors, fontFamilyName_, fontSize_, fontStyle_, state)
134 {
135 }
136 public Window(const string& windowClassName, WindowStyle style, ExtendedWindowStyle exStyle, const string& text, const Point& location,
137 const Size& size, Dock dock, Anchors anchors, WindowState state) :
138 this(windowClassName, style, exStyle, text, location, size, dock, anchors, DefaultWindowFontFamilyName(), DefaultWindowFontSize(),
139 FontStyle.regular, state)
140 {
141 }
142 public Window(const string& caption, const string& fontFamilyName_, float fontSize_, FontStyle fontStyle_) :
143 this("System.Windows.Window", WindowStyle.WS_OVERLAPPEDWINDOW, DefaultExtendedWindowStyle(),
144 caption, Point.Default(), Size.Default(), Dock.none, Anchors.none, fontFamilyName_, fontSize_, fontStyle_, WindowState.normal)
145 {
146 }
147 public Window(const string& caption) :
148 this(caption, DefaultWindowFontFamilyName(), 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), fontSize, fontStyle, Unit.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_CLOSE, 0u, 0);
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 key, bool shift, bool control, bool alt, bool keyDown, bool& 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.w, windowLoc.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.w, 0);
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<WindowClosingEventHandler, bool>& 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_HICON, cast<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_HICONSM, cast<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<WindowClosingEventHandler, bool> 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* dialogWindowPtr, uint keyCode, bool shift, bool control, bool alt, bool keyDown, bool& 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(key, shift, control, alt, keyDown, handled);
1090 }
1091 }
1092
1093 internal void ModelessWindowKeyPreview(uint keyCode, bool shift, bool control, bool alt, bool keyDown, bool& 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(key, shift, control, alt, keyDown, handled);
1103 }
1104 }
1105 }