1
2
3
4
5
6 using System;
7 using System.Collections;
8 using System.Windows.API;
9
10 namespace System.Windows
11 {
12 public nothrow Color DefaultMenuBackgroundColor()
13 {
14 return GetSystemColor(SystemColor.COLOR_MENU);
15 }
16
17 public nothrow Color DefaultMenuTextColor()
18 {
19 return GetSystemColor(SystemColor.COLOR_MENUTEXT);
20 }
21
22 public nothrow Color DefaultDisabledMenuTextColor()
23 {
24 Color color = GetSystemColor(SystemColor.COLOR_GRAYTEXT);
25 if (color == Color.Black())
26 {
27 return Color(195u, 195u, 198u);
28 }
29 return color;
30 }
31
32 public nothrow Color DefaultMenuMouseOverColor()
33 {
34 return Color(201u, 222u, 245u);
35 }
36
37 public nothrow Color DefaultMenuOpenColor()
38 {
39 return Color.White();
40 }
41
42 public nothrow ControlCreateParams& MenuControlControlCreateParams(ControlCreateParams& controlCreateParams)
43 {
44 return controlCreateParams.SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor());
45 }
46
47 public class MenuControlCreateParams
48 {
49 public nothrow MenuControlCreateParams(ControlCreateParams& controlCreateParams_) :
50 controlCreateParams(controlCreateParams_),
51 fontFamilyName("Segoe UI"),
52 fontSize(9.0f),
53 textColor(DefaultMenuTextColor()),
54 disabledTextColor(DefaultDisabledMenuTextColor()),
55 mouseOverColor(DefaultMenuMouseOverColor()),
56 menuOpenColor(DefaultMenuOpenColor())
57 {
58 }
59 public nothrow 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& windowClassName, WindowClassStyle windowClassStyle, WindowStyle style,
75 ExtendedWindowStyle exStyle,
76 const Color& backgroundColor, const string& text, const Point& location, const Size& size, Dock dock, Anchors anchors) :
77 base(windowClassName, windowClassStyle, style, exStyle, backgroundColor, text, location, size, dock, anchors),
78 font(font_), textColor(DefaultMenuTextColor()), disabledTextColor(DefaultDisabledMenuTextColor()), mouseOverColor(201u, 222u, 245u),
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.near, StringAlignment.near, HotKeyPrefix.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.near, StringAlignment.near, HotKeyPrefix.show)
97 {
98 }
99 public override nothrow Padding DefaultPadding() const
100 {
101 return Padding(6, 2, 6, 2);
102 }
103 public inline nothrow const Font& GetFont() const
104 {
105 return font;
106 }
107 public inline nothrow const Color& TextColor() const
108 {
109 return textColor;
110 }
111 public inline nothrow const Color& DisabledTextColor() const
112 {
113 return disabledTextColor;
114 }
115 public inline nothrow const Color& MouseOverColor() const
116 {
117 return mouseOverColor;
118 }
119 public inline nothrow const Color& MenuOpenColor() const
120 {
121 return menuOpenColor;
122 }
123 public inline nothrow const Color& ShadowColor() const
124 {
125 return shadowColor;
126 }
127 public inline nothrow const Brush& TextBrush() const
128 {
129 return textBrush;
130 }
131 public inline nothrow const Brush& DisabledTextBrush() const
132 {
133 return disabledTextBrush;
134 }
135 public inline nothrow const Brush& BackgroundBrush() const
136 {
137 return backgroundBrush;
138 }
139 public inline nothrow const Brush& MouseOverBrush() const
140 {
141 return mouseOverBrush;
142 }
143 public inline nothrow const Brush& MenuOpenBrush() const
144 {
145 return menuOpenBrush;
146 }
147 public inline nothrow const Brush& ShadowBrush() const
148 {
149 return shadowBrush;
150 }
151 public inline nothrow const Brush& BlackBrush() const
152 {
153 return blackBrush;
154 }
155 public inline nothrow const Pen& BlackPen() const
156 {
157 return blackPen;
158 }
159 public inline nothrow const Pen& DarkPen() const
160 {
161 return darkPen;
162 }
163 public inline nothrow const StringFormat& Format() const
164 {
165 return format;
166 }
167 internal virtual nothrow MenuItem* GetMenuItemByAccessKey(wchar accessKey)
168 {
169 return null;
170 }
171 internal virtual nothrow MenuItem* GetOpenedMenuItem() const
172 {
173 return null;
174 }
175 internal virtual nothrow MenuItem* GetSelectedMenuItem() const
176 {
177 return null;
178 }
179 internal virtual nothrow void SetSelectedMenuItem(MenuItem* selectedMenuItem_)
180 {
181 }
182 internal virtual nothrow bool IsOpen() const
183 {
184 return false;
185 }
186 public virtual nothrow void SetOpen()
187 {
188 }
189 internal virtual nothrow void SetClosed()
190 {
191 }
192 internal virtual nothrow void SetMenuInvalidated()
193 {
194 }
195 internal virtual nothrow MenuItem* GetFirstMenuItem() const
196 {
197 return null;
198 }
199 internal virtual nothrow MenuItem* GetLastMenuItem() const
200 {
201 return null;
202 }
203 internal virtual nothrow MenuItem* LatestOpenedMenuItem() const
204 {
205 return null;
206 }
207 internal virtual nothrow void SetLatestOpenedMenuItem(MenuItem* menuItem)
208 {
209 }
210 internal virtual nothrow MenuItem* GetLatestMouseDownMenuItem() const
211 {
212 return null;
213 }
214 internal virtual nothrow void SetLatestMouseDownMenuItem(MenuItem* menuItem)
215 {
216 }
217 internal virtual void InvalidateMenu()
218 {
219 }
220 internal virtual nothrow void SetMenuChanged()
221 {
222 }
223 private Font font;
224 private Color textColor;
225 private Color disabledTextColor;
226 private Color mouseOverColor;
227 private Color menuOpenColor;
228 private Color shadowColor;
229 private SolidBrush textBrush;
230 private SolidBrush disabledTextBrush;
231 private SolidBrush backgroundBrush;
232 private SolidBrush mouseOverBrush;
233 private SolidBrush menuOpenBrush;
234 private SolidBrush shadowBrush;
235 private SolidBrush blackBrush;
236 private Pen blackPen;
237 private Pen darkPen;
238 private StringFormat format;
239 }
240
241 public const int initialMenuBarHeight = 20;
242
243 public nothrow ControlCreateParams& MenuBarControlCreateParams(ControlCreateParams& controlCreateParams)
244 {
245 return controlCreateParams.SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor()).
246 SetWindowClassName("System.Windows.MenuBar").SetDock(Dock.top).SetSize(Size(0, initialMenuBarHeight));
247 }
248
249 public class MenuBarCreateParams
250 {
251 public nothrow MenuBarCreateParams(MenuControlCreateParams& menuControlCreateParams_) : menuControlCreateParams(menuControlCreateParams_)
252 {
253 }
254 public nothrow MenuBarCreateParams& Defaults()
255 {
256 return *this;
257 }
258 public MenuControlCreateParams& menuControlCreateParams;
259 }
260
261 public class MenuBar : MenuControl
262 {
263 private enum Flags : sbyte
264 {
265 none, open = 1 << 0, menuChanged = 1 << 1, menuBoxAdded = 1 << 2, menuInvalidated = 1 << 3, menuKeyDisabled = 1 << 4
266 }
267
268 internal Color ShadowColor()
269 {
270 Color shadowColor = GetSystemColor(SystemColor.COLOR_BTNSHADOW);
271 shadowColor.alpha = 196u;
272 return shadowColor;
273 }
274
275 public MenuBar(const Font& font_) : base(font_, "System.Windows.MenuBar", DefaultWindowClassStyle(), DefaultChildWindowStyle(),
276 DefaultExtendedWindowStyle(), DefaultMenuBackgroundColor(), "menuBar", Point(), Size(0, initialMenuBarHeight), Dock.top, Anchors.none),
277 flags(Flags.none), children(this), latestOpenedMenuItem(null), selectedMenuItem(null), latestMouseDownMenuItem(null)
278 {
279 SetMenuChanged();
280 }
281 public MenuBar() : this(Font(FontFamily("Segoe UI"), 9.0f))
282 {
283 }
284 public MenuBar(MenuBarCreateParams& createParams) :
285 base(createParams.menuControlCreateParams),
286 flags(Flags.none), children(this), latestOpenedMenuItem(null), selectedMenuItem(null), latestMouseDownMenuItem(null)
287 {
288 SetMenuChanged();
289 }
290 public void CloseMenu()
291 {
292 if (!IsOpen()) return;
293 SetClosed();
294 SetLatestOpenedMenuItem(null);
295 Component* child = children.FirstChild();
296 while (child != null)
297 {
298 if (child is MenuItem*)
299 {
300 MenuItem* menuItem = cast<MenuItem*>(child);
301 menuItem->SetState(MenuItem.State.closed, this);
302 }
303 child = child->NextSibling();
304 }
305 InvalidateMenu();
306 }
307 public void AddMenuItem(MenuItem* menuItem)
308 {
309 children.AddChild(menuItem);
310 SetMenuChanged();
311 }
312 public override void PrintWindowTree(int level)
313 {
314 LogView* log = Application.GetLogView();
315 if (log != null)
316 {
317 log->WriteLine(string(' ', level) + "MenuBar." + Text() + ".handle=" + ToHexString(cast<ulong>(Handle())) + " " + ParentText() + "[" + Rect(Point(), GetSize()).ToString() + "]");
318 }
319 }
320 protected override void OnPaint(PaintEventArgs& args)
321 {
322 try
323 {
324 if (Debug.Paint())
325 {
326 Rect r(Location(), GetSize());
327 LogView* log = Application.GetLogView();
328 if (log != null)
329 {
330 log->WriteLine("MenuBar.OnPaint: " + r.ToString());
331 }
332 }
333 if (!MenuBoxAdded())
334 {
335 SetMenuBoxAdded();
336 AddMenuBox();
337 }
338 args.graphics.Clear(BackgroundColor());
339 if (MenuChanged())
340 {
341 ResetMenuChanged();
342 CollectShortcuts();
343 Size size = GetSize();
344 size.h = cast<int>(GetFont().GetHeight(args.graphics));
345 size.h = size.h + DefaultPadding().Vertical();
346 SetSize(size);
347 LocateMenuItems(args.graphics, size);
348 }
349 DrawMenuItems(args, false, Location());
350 base->OnPaint(args);
351 }
352 catch (const Exception& ex)
353 {
354 MessageBox.Show(ex.Message());
355 }
356 }
357 private void LocateMenuItems(Graphics& graphics, const Size& size)
358 {
359 Rect itemRect(Location(), Size(0, size.h));
360 Padding padding = DefaultPadding();
361 PointF origin(0, 0);
362 Component* child = children.FirstChild();
363 while (child != null)
364 {
365 if (child is MenuItem*)
366 {
367 MenuItem* menuItem = cast<MenuItem*>(child);
368 Padding menuItemPadding = menuItem->DefaultPadding();
369 RectF r = graphics.MeasureStringChecked(menuItem->Text(), GetFont(), origin, Format());
370 int w = cast<int>(r.size.w) + padding.Horizontal() + menuItemPadding.Horizontal();
371 itemRect.size.w = w;
372 menuItem->SetLocation(itemRect.location);
373 menuItem->SetSize(itemRect.size);
374 menuItem->CalculateChildRect(graphics, GetFont(), Format(), Point(itemRect.location.x, itemRect.location.y + itemRect.size.h));
375 itemRect.location.x = itemRect.location.x + w;
376 }
377 child = child->NextSibling();
378 }
379 }
380 private nothrow Control* ParentControl() const
381 {
382 Container* container = GetContainer();
383 if (container != null)
384 {
385 Component* parent = container->Parent();
386 if (parent != null && (parent is Control*))
387 {
388 return cast<Control*>(parent);
389 }
390 }
391 return null;
392 }
393 private void InvalidateParentRect(const Rect& parentRect)
394 {
395 Control* parentControl = ParentControl();
396 if (parentControl != null)
397 {
398 parentControl->Invalidate(parentRect.ToWinRect());
399 }
400 }
401 internal void DrawMenuItems(PaintEventArgs& args, bool drawSubItems, const Point& origin)
402 {
403 Padding padding = DefaultPadding();
404 Size size = GetSize();
405 Component* child = children.FirstChild();
406 while (child != null)
407 {
408 if (child is MenuItem*)
409 {
410 MenuItem* menuItem = cast<MenuItem*>(child);
411 menuItem->Draw(
412 args.graphics, padding, TextBrush(), DisabledTextBrush(), BackgroundBrush(), MouseOverBrush(), MenuOpenBrush(), ShadowBrush(), BlackBrush(), BlackPen(), DarkPen(), GetFont(), Format(),
413 MenuOpenColor(), this, drawSubItems, origin);
414 }
415 child = child->NextSibling();
416 }
417 }
418 internal void DoKeyDown(KeyEventArgs& args)
419 {
420 OnKeyDown(args);
421 }
422 protected override void OnKeyDown(KeyEventArgs& args)
423 {
424 base->OnKeyDown(args);
425 if (!args.handled)
426 {
427 HashMap<Keys, MenuItem*>.ConstIterator it = shortcuts.CFind(args.key);
428 if (it != shortcuts.CEnd())
429 {
430 MenuItem* menuItem = it->second;
431 if (menuItem->IsEnabled())
432 {
433 menuItem->DoClick();
434 args.handled = true;
435 }
436 }
437 }
438 }
439 internal void MouseEnterInternal()
440 {
441 OnMouseEnter();
442 }
443 protected override void OnMouseEnter()
444 {
445 base->OnMouseEnter();
446 }
447 internal void MouseMoveInternal(MouseEventArgs& args)
448 {
449 OnMouseMove(args);
450 }
451 protected override void OnMouseMove(MouseEventArgs& args)
452 {
453 ResetMenuInvalidated();
454 base->OnMouseMove(args);
455 bool handled = false;
456 Component* child = children.FirstChild();
457 while (child != null)
458 {
459 if (child is MenuItem*)
460 {
461 MenuItem* menuItem = cast<MenuItem*>(child);
462 if (!menuItem->Contains(args.location))
463 {
464 menuItem->ResetSelected(this);
465 if (menuItem->MouseInClient())
466 {
467 menuItem->ResetMouseInClient();
468 menuItem->DoMouseLeave(this);
469 }
470 }
471 }
472 child = child->NextSibling();
473 }
474 child = children.FirstChild();
475 while (child != null)
476 {
477 if (child is MenuItem*)
478 {
479 MenuItem* menuItem = cast<MenuItem*>(child);
480 if (menuItem->Contains(args.location))
481 {
482 menuItem->SetSelected(this);
483 if (!menuItem->MouseInClient())
484 {
485 menuItem->SetMouseInClient();
486 menuItem->DoMouseEnter(IsOpen(), this);
487 }
488 else
489 {
490 menuItem->DoMouseMove(args);
491 }
492 handled = true;
493 }
494 }
495 child = child->NextSibling();
496 }
497 if (!handled)
498 {
499 if (IsOpen())
500 {
501 if (latestOpenedMenuItem != null)
502 {
503 Component* child = children.FirstChild();
504 while (child != null && !handled)
505 {
506 if (child is MenuItem*)
507 {
508 MenuItem* menuItem = cast<MenuItem*>(child);
509 if (menuItem->IsSameOrParentOf(latestOpenedMenuItem))
510 {
511 menuItem->DispatchMouseMove(args, handled, this);
512 }
513 }
514 child = child->NextSibling();
515 }
516 }
517 }
518 }
519 if (MenuInvalidated())
520 {
521 InvalidateMenu();
522 }
523 }
524 internal void MouseLeaveInternal()
525 {
526 OnMouseLeave();
527 }
528 protected override void OnMouseLeave()
529 {
530 ResetMenuInvalidated();
531 base->OnMouseLeave();
532 Component* child = children.FirstChild();
533 while (child != null)
534 {
535 if (child is MenuItem*)
536 {
537 MenuItem* menuItem = cast<MenuItem*>(child);
538 if (menuItem->MouseInClient() || menuItem->Children().IsEmpty())
539 {
540 menuItem->ResetSelected(this);
541 menuItem->ResetMouseInClient();
542 Point mousePos;
543 WinGetMessagePos(mousePos.x, mousePos.y);
544 mousePos = ScreenToClient(mousePos);
545 if (menuItem != latestOpenedMenuItem || !menuItem->UnionRectContains(mousePos))
546 {
547 menuItem->DoMouseLeave(this);
548 }
549 }
550 else
551 {
552 menuItem->ResetSelected(this);
553 menuItem->ResetMouseInClient();
554 }
555 }
556 child = child->NextSibling();
557 }
558 if (MenuInvalidated())
559 {
560 InvalidateMenu();
561 }
562 }
563 internal override void InvalidateMenu()
564 {
565 Invalidate();
566 Rect menuRect;
567 Component* child = children.FirstChild();
568 while (child != null)
569 {
570 if (child is MenuItem*)
571 {
572 MenuItem* menuItem = cast<MenuItem*>(child);
573 if (menuItem->GetState() == MenuItem.State.open)
574 {
575 menuItem->GetOpenRect(menuRect);
576 }
577 }
578 child = child->NextSibling();
579 }
580 if (IsOpen())
581 {
582 if (menuBox != null)
583 {
584 menuBox->SetPaintThisMenuBox(true);
585 menuBox->SetLocation(Point(Location().x + menuRect.location.x, Location().y + menuRect.location.y));
586 menuBox->SetSize(menuRect.size);
587 Control* parentControl = ParentControl();
588 Control* topControl = null;
589 if (parentControl != null)
590 {
591 topControl = parentControl->TopControl();
592 }
593 menuBox->BringToFront();
594 menuBox->Show();
595 menuBox->Invalidate();
596 menuBox->Update();
597 if (topControl != null)
598 {
599 topControl->BringToFront();
600 }
601 }
602 }
603 else
604 {
605 if (menuBox != null)
606 {
607 menuBox->SetPaintThisMenuBox(false);
608 menuBox->Hide();
609 }
610 InvalidateParentRect(menuRect);
611 Control* parentControl = ParentControl();
612 if (parentControl != null)
613 {
614 parentControl->Update();
615 }
616 }
617 }
618 private void CollectShortcuts()
619 {
620 shortcuts.Clear();
621 Component* child = children.FirstChild();
622 while (child != null)
623 {
624 if (child is MenuItem*)
625 {
626 MenuItem* menuItem = cast<MenuItem*>(child);
627 menuItem->CollectShortcuts(shortcuts);
628 }
629 child = child->NextSibling();
630 }
631 }
632 internal bool HandleAccessKey(wchar accessKey, Keys keyCode, bool& wantsKeys)
633 {
634 ResetMenuInvalidated();
635 LogView* logView = Application.GetLogView();
636 if (logView != null)
637 {
638 string s = "MENUBAR: access key = '" + ToString(accessKey) + "' " + ToHexString(cast<ushort>(accessKey)) + ", key code = " + string(keyCodeStr[cast<int>(keyCode)]);
639 logView->WriteLine(s);
640 }
641 if (accessKey == '\0' && keyCode == Keys.none)
642 {
643 if (!MenuKeyDisabled())
644 {
645 if (selectedMenuItem == null)
646 {
647 MenuItem* firstMenuItem = GetFirstMenuItem();
648 if (firstMenuItem != null)
649 {
650 SetOpen();
651 SetSelectedMenuItem(firstMenuItem);
652 wantsKeys = true;
653 InvalidateMenu();
654 return true;
655 }
656 }
657 else
658 {
659 SetClosed();
660 MenuItem* openedMenuItem = GetOpenedMenuItem();
661 if (openedMenuItem != null)
662 {
663 openedMenuItem->SetState(MenuItem.State.closed, this);
664 }
665 selectedMenuItem->ResetSelected(this);
666 SetSelectedMenuItem(null);
667 wantsKeys = false;
668 InvalidateMenu();
669 return true;
670 }
671 }
672 }
673 else if (accessKey != '\0' && keyCode == Keys.none)
674 {
675 MenuItem* menuItem = GetMenuItemByAccessKey(accessKey);
676 if (menuItem != null)
677 {
678 MenuItem* firstMenuItem = menuItem->GetFirstMenuItem();
679 if (firstMenuItem != null)
680 {
681 if (selectedMenuItem != null)
682 {
683 MenuItem* openedMenuItem = GetOpenedMenuItem();
684 if (openedMenuItem != null)
685 {
686 openedMenuItem->SetState(MenuItem.State.closed, this);
687 }
688 }
689 SetOpen();
690 menuItem->SetState(MenuItem.State.open, this);
691 SetSelectedMenuItem(firstMenuItem);
692 wantsKeys = true;
693 InvalidateMenu();
694 return true;
695 }
696 }
697 }
698 else if (accessKey == '\0' && keyCode != Keys.none)
699 {
700 if (keyCode == Keys.menu)
701 {
702 wantsKeys = true;
703 return true;
704 }
705 else
706 {
707 if (selectedMenuItem != null)
708 {
709 MenuItem* parentItem = selectedMenuItem->GetParentMenuItem();
710 bool handled = selectedMenuItem->HandleKey(keyCode, wantsKeys, parentItem, this);
711 if (MenuInvalidated())
712 {
713 InvalidateMenu();
714 }
715 return handled;
716 }
717 }
718 }
719 if (MenuInvalidated())
720 {
721 InvalidateMenu();
722 }
723 wantsKeys = false;
724 return false;
725 }
726 internal void MouseDownInternal(MouseEventArgs& args)
727 {
728 OnMouseDown(args);
729 }
730 protected override void OnMouseDown(MouseEventArgs& args)
731 {
732 base->OnMouseDown(args);
733 SetLatestMouseDownMenuItem(null);
734 bool handled = false;
735 Component* child = children.FirstChild();
736 while (child != null)
737 {
738 if (child is MenuItem*)
739 {
740 MenuItem* menuItem = cast<MenuItem*>(child);
741 menuItem->DoMouseDown(args, handled, this);
742 if (handled)
743 {
744 InvalidateMenu();
745 return;
746 }
747 }
748 child = child->NextSibling();
749 }
750 if (IsOpen())
751 {
752 SetClosed();
753 SetLatestOpenedMenuItem(null);
754 Component* child = children.FirstChild();
755 while (child != null)
756 {
757 if (child is MenuItem*)
758 {
759 MenuItem* menuItem = cast<MenuItem*>(child);
760 menuItem->SetState(MenuItem.State.closed, this);
761 }
762 child = child->NextSibling();
763 }
764 InvalidateMenu();
765 }
766 }
767 internal void MouseUpInternal(MouseEventArgs& args)
768 {
769 OnMouseUp(args);
770 }
771 protected override void OnMouseUp(MouseEventArgs& args)
772 {
773 base->OnMouseUp(args);
774 bool handled = false;
775 Component* child = children.FirstChild();
776 while (child != null)
777 {
778 if (child is MenuItem*)
779 {
780 MenuItem* menuItem = cast<MenuItem*>(child);
781 if (menuItem->IsEnabled())
782 {
783 menuItem->DoMouseUp(args, handled, this);
784 if (handled)
785 {
786 InvalidateMenu();
787 return;
788 }
789 }
790 }
791 child = child->NextSibling();
792 }
793 }
794 internal override nothrow void SetLatestOpenedMenuItem(MenuItem* menuItem)
795 {
796 latestOpenedMenuItem = menuItem;
797 }
798 internal override nothrow MenuItem* LatestOpenedMenuItem() const
799 {
800 return latestOpenedMenuItem;
801 }
802 internal override nothrow MenuItem* GetOpenedMenuItem() const
803 {
804 Component* child = children.FirstChild();
805 while (child != null)
806 {
807 if (child is MenuItem*)
808 {
809 MenuItem* childItem = cast<MenuItem*>(child);
810 if (childItem->GetState() == MenuItem.State.open)
811 {
812 return childItem;
813 }
814 }
815 child = child->NextSibling();
816 }
817 return null;
818 }
819 internal override nothrow MenuItem* GetFirstMenuItem() const
820 {
821 Component* child = children.FirstChild();
822 while (child != null)
823 {
824 if (child is MenuItem*)
825 {
826 MenuItem* menuItem = cast<MenuItem*>(child);
827 return menuItem;
828 }
829 child = child->NextSibling();
830 }
831 return null;
832 }
833 internal override nothrow MenuItem* GetLastMenuItem() const
834 {
835 Component* child = children.LastChild();
836 while (child != null)
837 {
838 if (child is MenuItem*)
839 {
840 MenuItem* menuItem = cast<MenuItem*>(child);
841 return menuItem;
842 }
843 child = child->PrevSibling();
844 }
845 return null;
846 }
847 internal override nothrow MenuItem* GetMenuItemByAccessKey(wchar accessKey)
848 {
849 Component* child = children.FirstChild();
850 while (child != null)
851 {
852 if (child is MenuItem*)
853 {
854 MenuItem* menuItem = cast<MenuItem*>(child);
855 if (menuItem->AccessKey() == accessKey)
856 {
857 return menuItem;
858 }
859 }
860 child = child->NextSibling();
861 }
862 return null;
863 }
864 internal override nothrow MenuItem* GetSelectedMenuItem() const
865 {
866 return selectedMenuItem;
867 }
868 internal override nothrow void SetSelectedMenuItem(MenuItem* selectedMenuItem_)
869 {
870 selectedMenuItem = selectedMenuItem_;
871 }
872 internal override nothrow MenuItem* GetLatestMouseDownMenuItem() const
873 {
874 return latestMouseDownMenuItem;
875 }
876 internal override nothrow void SetLatestMouseDownMenuItem(MenuItem* menuItem)
877 {
878 latestMouseDownMenuItem = menuItem;
879 }
880 public nothrow void DisableMenuKey()
881 {
882 flags = cast<Flags>(flags | Flags.menuKeyDisabled);
883 }
884 public inline nothrow bool MenuKeyDisabled() const
885 {
886 return (flags & Flags.menuKeyDisabled) != Flags.none;
887 }
888 private inline nothrow bool MenuChanged()
889 {
890 return (flags & Flags.menuChanged) != Flags.none;
891 }
892 internal override nothrow void SetMenuChanged()
893 {
894 flags = cast<Flags>(flags | Flags.menuChanged);
895 }
896 private inline nothrow void ResetMenuChanged()
897 {
898 flags = cast<Flags>(flags & ~Flags.menuChanged);
899 }
900 private inline nothrow bool MenuInvalidated() const
901 {
902 return (flags & Flags.menuInvalidated) != Flags.none;
903 }
904 internal override nothrow void SetMenuInvalidated()
905 {
906 flags = cast<Flags>(flags | Flags.menuInvalidated);
907 }
908 private inline nothrow void ResetMenuInvalidated()
909 {
910 flags = cast<Flags>(flags & ~Flags.menuInvalidated);
911 }
912 internal override nothrow bool IsOpen() const
913 {
914 return (flags & Flags.open) != Flags.none;
915 }
916 public override nothrow void SetOpen()
917 {
918 flags = cast<Flags>(flags | Flags.open);
919 }
920 public override nothrow void SetClosed()
921 {
922 if (IsOpen())
923 {
924 flags = cast<Flags>(flags & ~Flags.open);
925 InvalidateMenu();
926 }
927 }
928 private nothrow bool MenuBoxAdded() const
929 {
930 return (flags & Flags.menuBoxAdded) != Flags.none;
931 }
932 private nothrow void SetMenuBoxAdded()
933 {
934 flags = cast<Flags>(flags | Flags.menuBoxAdded);
935 }
936 private void AddMenuBox()
937 {
938 Control* parentControl = ParentControl();
939 if (parentControl != null && parentControl is ContainerControl*)
940 {
941 menuBox = new MenuBox(GetFont(), this, null);
942 ContainerControl* containerControl = cast<ContainerControl*>(parentControl);
943 containerControl->InsertChildAfter(menuBox, this);
944 }
945 }
946 private Flags flags;
947 private Container children;
948 private MenuItem* latestOpenedMenuItem;
949 private MenuItem* selectedMenuItem;
950 private MenuItem* latestMouseDownMenuItem;
951 private HashMap<Keys, MenuItem*> shortcuts;
952 private MenuBox* menuBox;
953 }
954
955 public nothrow ControlCreateParams& MenuBoxControlCreateParams(ControlCreateParams& controlCreateParams)
956 {
957 return controlCreateParams.SetWindowStyle(HiddenChildWindowStyle()).
958 SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor()).
959 SetWindowClassName("System.Windows.MenuBox");
960 }
961
962 public class MenuBoxCreateParams
963 {
964 public nothrow MenuBoxCreateParams(MenuControlCreateParams& menuControlCreateParams_) : menuControlCreateParams(menuControlCreateParams_)
965 {
966 }
967 public nothrow MenuBoxCreateParams& Defaults()
968 {
969 return *this;
970 }
971 public MenuControlCreateParams& menuControlCreateParams;
972 }
973
974 public class MenuBox : MenuControl
975 {
976 public MenuBox(const Font& font, MenuBar* menuBar_, MenuItem* rootItem_) :
977 base(font, "System.Windows.MenuBox", DefaultWindowClassStyle(), HiddenChildWindowStyle(), DefaultExtendedWindowStyle(),
978 Color.White(), "menuBox", Point(), Size(), Dock.none, Anchors.none), menuBar(menuBar_), rootItem(rootItem_), paintThisMenuBox(false)
979 {
980 }
981 public MenuBox(MenuBoxCreateParams& createParams, MenuBar* menuBar_, MenuItem* rootItem_) :
982 base(createParams.menuControlCreateParams), menuBar(menuBar_), rootItem(rootItem_), paintThisMenuBox(false)
983 {
984 }
985 public nothrow void SetPaintThisMenuBox(bool paintThisMenuBox_)
986 {
987 paintThisMenuBox = paintThisMenuBox_;
988 }
989 public inline nothrow bool PaintThisMenuBox() const
990 {
991 return paintThisMenuBox;
992 }
993 public override void PrintWindowTree(int level)
994 {
995 LogView* log = Application.GetLogView();
996 if (log != null)
997 {
998 log->WriteLine(string(' ', level) + "MenuBox." + Text() + ".handle=" + ToHexString(cast<ulong>(Handle())) + " " + ParentText() + "[" + Rect(Point(), GetSize()).ToString() + "]");
999 }
1000 }
1001 protected virtual Point GetBoxLocation() const
1002 {
1003 return Location();
1004 }
1005 protected override void OnPaint(PaintEventArgs& args)
1006 {
1007 try
1008 {
1009 if (Debug.Paint())
1010 {
1011 Rect r(Point(), GetSize());
1012 LogView* log = Application.GetLogView();
1013 if (log != null)
1014 {
1015 log->WriteLine("MenuBox.OnPaint: " + r.ToString());
1016 }
1017 }
1018 Point loc = Location();
1019 if (!paintMenu)
1020 {
1021 if (paintThisMenuBox)
1022 {
1023 Control* parentControl = ParentControl();
1024 if (parentControl != null)
1025 {
1026 Bitmap menuBoxBitmap(args.clipRect.size.w, args.clipRect.size.h, args.graphics);
1027 Graphics menuBoxGraphics = Graphics.FromImage(menuBoxBitmap);
1028 Rect menuBoxClipRect(Point(0, 0), Size(args.clipRect.size.w, args.clipRect.size.h));
1029 menuBoxGraphics.SetClipChecked(menuBoxClipRect);
1030 menuBoxGraphics.TranslateTransformChecked(-loc.x, -loc.y);
1031 PaintEventArgs paintMenuBoxArgs(menuBoxGraphics, menuBoxClipRect);
1032 bool prevPaintMenu = paintMenu;
1033 paintMenu = true;
1034 bool skipMenuBar = this is ContextMenu*;
1035 parentControl->PaintAll(paintMenuBoxArgs, skipMenuBar);
1036 paintMenu = prevPaintMenu;
1037 args.graphics.DrawImageChecked(menuBoxBitmap, PointF(0, 0));
1038 }
1039 }
1040 }
1041 else
1042 {
1043 if (menuBar != null)
1044 {
1045 menuBar->DrawMenuItems(args, true, loc);
1046 }
1047 else if (rootItem != null)
1048 {
1049 rootItem->Draw(args.graphics, DefaultPadding(), TextBrush(), DisabledTextBrush(), BackgroundBrush(), MouseOverBrush(), MenuOpenBrush(), ShadowBrush(), BlackBrush(), BlackPen(),
1050 DarkPen(), GetFont(), Format(), MenuOpenColor(), this, true, Point());
1051 }
1052 }
1053 }
1054 catch (const Exception& ex)
1055 {
1056 }
1057 }
1058 private nothrow Control* ParentControl() const
1059 {
1060 Container* container = GetContainer();
1061 if (container != null)
1062 {
1063 Component* parent = container->Parent();
1064 if (parent != null && (parent is Control*))
1065 {
1066 return cast<Control*>(parent);
1067 }
1068 }
1069 return null;
1070 }
1071 protected override void OnMouseEnter()
1072 {
1073 base->OnMouseEnter();
1074 if (menuBar != null)
1075 {
1076 menuBar->MouseEnterInternal();
1077 }
1078 }
1079 protected override void OnMouseMove(MouseEventArgs& args)
1080 {
1081 base->OnMouseMove(args);
1082 if (menuBar != null)
1083 {
1084 Point loc = Location();
1085 args.location.x = args.location.x + loc.x;
1086 args.location.y = args.location.y + loc.y;
1087 menuBar->MouseMoveInternal(args);
1088 }
1089 else if (rootItem != null)
1090 {
1091 bool handled = false;
1092 rootItem->DispatchMouseMove(args, handled, this);
1093 }
1094 }
1095 protected override void OnMouseLeave()
1096 {
1097 base->OnMouseLeave();
1098 if (menuBar != null)
1099 {
1100 menuBar->MouseLeaveInternal();
1101 }
1102 else if (rootItem != null)
1103 {
1104 rootItem->LeaveChildren(this);
1105 }
1106 }
1107 protected override void OnMouseDown(MouseEventArgs& args)
1108 {
1109 base->OnMouseDown(args);
1110 if (menuBar != null)
1111 {
1112 Point loc = Location();
1113 args.location.x = args.location.x + loc.x;
1114 args.location.y = args.location.y + loc.y;
1115 menuBar->MouseDownInternal(args);
1116 }
1117 else if (rootItem != null)
1118 {
1119 SetLatestMouseDownMenuItem(null);
1120 bool handled = false;
1121 rootItem->DoMouseDown(args, handled, this);
1122 if (handled)
1123 {
1124 Invalidate();
1125 }
1126 }
1127 }
1128 protected override void OnMouseUp(MouseEventArgs& args)
1129 {
1130 base->OnMouseUp(args);
1131 if (menuBar != null)
1132 {
1133 Point loc = Location();
1134 args.location.x = args.location.x + loc.x;
1135 args.location.y = args.location.y + loc.y;
1136 menuBar->MouseUpInternal(args);
1137 }
1138 else if (rootItem != null)
1139 {
1140 bool handled = false;
1141 rootItem->DoMouseUp(args, handled, this);
1142 if (handled)
1143 {
1144 Invalidate();
1145 }
1146 }
1147 }
1148 protected inline nothrow MenuItem* GetRootItem() const
1149 {
1150 return rootItem;
1151 }
1152 private MenuBar* menuBar;
1153 private MenuItem* rootItem;
1154 private bool paintThisMenuBox;
1155 private bool paintMenu;
1156 }
1157
1158 public abstract class ClickAction
1159 {
1160 public nothrow ClickAction()
1161 {
1162 clickEventHandler = Click;
1163 }
1164 public virtual default ~ClickAction();
1165 public nothrow void AddHandlerTo(MenuItem& menuItem)
1166 {
1167 menuItem.ClickEvent().AddHandler(clickEventHandler);
1168 }
1169 private void Click()
1170 {
1171 Execute();
1172 }
1173 protected abstract void Execute();
1174 private ClickEventHandler clickEventHandler;
1175 }
1176
1177 public class ClickActions
1178 {
1179 public nothrow void Add(ClickAction* action)
1180 {
1181 clickActions.Add(UniquePtr<ClickAction>(action));
1182 }
1183 private List<UniquePtr<ClickAction>> clickActions;
1184 }
1185
1186 public nothrow ControlCreateParams& ContextMenuControlCreateParams(ControlCreateParams& controlCreateParams)
1187 {
1188 return controlCreateParams.SetWindowStyle(HiddenChildWindowStyle()).
1189 SetWindowClassBackgroundColor(SystemColor.COLOR_MENU).SetBackgroundColor(DefaultMenuBackgroundColor()).
1190 SetWindowClassName("System.Windows.ContextMenu");
1191 }
1192
1193 public nothrow MenuBoxCreateParams& ContextMenuMenuBoxCreateParams(MenuBoxCreateParams& menuBoxCreateParams)
1194 {
1195 return menuBoxCreateParams;
1196 }
1197
1198 public class ContextMenuCreateParams
1199 {
1200 public nothrow ContextMenuCreateParams(MenuBoxCreateParams& menuBoxCreateParams_) : menuBoxCreateParams(menuBoxCreateParams_)
1201 {
1202 }
1203 public nothrow ContextMenuCreateParams& Defaults()
1204 {
1205 return *this;
1206 }
1207 public MenuBoxCreateParams& menuBoxCreateParams;
1208 }
1209
1210 public class ContextMenu : MenuBox
1211 {
1212 public ContextMenu(const Font& font) :
1213 base(font, null, new MenuItem("root")),
1214 rootItemPtr(GetRootItem()), latestOpenedMenuItem(null), selectedMenuItem(null), latestMouseDownMenuItem(null)
1215 {
1216 }
1217 public ContextMenu() : this(Font(FontFamily("Segoe UI"), 9.0f))
1218 {
1219 }
1220 public ContextMenu(ContextMenuCreateParams& createParams) :
1221 base(createParams.menuBoxCreateParams, null, new MenuItem("root")),
1222 rootItemPtr(GetRootItem()), latestOpenedMenuItem(null), selectedMenuItem(null), latestMouseDownMenuItem(null)
1223 {
1224 }
1225 public void AddMenuItem(MenuItemBase* menuItem)
1226 {
1227 rootItemPtr->AddMenuItem(menuItem);
1228 }
1229 public void AddMenuItemAction(MenuItem* menuItem, ClickAction* action)
1230 {
1231 rootItemPtr->AddMenuItem(menuItem);
1232 action->AddHandlerTo(*menuItem);
1233 clickActions.Add(action);
1234 }
1235 public void CalculateSize()
1236 {
1237 rootItemPtr->SetState(MenuItem.State.open, this);
1238 Graphics graphics = Graphics.FromWindowHandle(Handle());
1239 rootItemPtr->CalculateChildRect(graphics, GetFont(), Format(), Point(0, 0));
1240 Rect menuRect;
1241 rootItemPtr->GetOpenRect(menuRect);
1242 SetSize(menuRect.size);
1243 }
1244 public nothrow bool HasMenuItems()
1245 {
1246 return !rootItemPtr->Children().IsEmpty();
1247 }
1248 protected override Point GetBoxLocation() const
1249 {
1250 return Point(0, 0);
1251 }
1252 protected override void OnPaint(PaintEventArgs& args)
1253 {
1254 SetPaintThisMenuBox(true);
1255 base->OnPaint(args);
1256 }
1257 protected override void OnVisibleChanged()
1258 {
1259 base->OnVisibleChanged();
1260 if (!IsVisible())
1261 {
1262 rootItemPtr->SetState(MenuItem.State.closed, this);
1263 SetPaintThisMenuBox(false);
1264 }
1265 }
1266 internal override nothrow void SetMenuInvalidated()
1267 {
1268 Invalidate();
1269 }
1270 internal override nothrow bool IsOpen() const
1271 {
1272 return rootItemPtr->GetState() == MenuItem.State.open;
1273 }
1274 internal override nothrow MenuItem* GetSelectedMenuItem() const
1275 {
1276 return selectedMenuItem;
1277 }
1278 internal override nothrow void SetSelectedMenuItem(MenuItem* selectedMenuItem_)
1279 {
1280 selectedMenuItem = selectedMenuItem_;
1281 }
1282 internal override nothrow MenuItem* LatestOpenedMenuItem() const
1283 {
1284 return latestOpenedMenuItem;
1285 }
1286 internal override nothrow void SetLatestOpenedMenuItem(MenuItem* menuItem)
1287 {
1288 latestOpenedMenuItem = menuItem;
1289 }
1290 internal override nothrow MenuItem* GetLatestMouseDownMenuItem() const
1291 {
1292 return latestMouseDownMenuItem;
1293 }
1294 internal override nothrow void SetLatestMouseDownMenuItem(MenuItem* menuItem)
1295 {
1296 latestMouseDownMenuItem = menuItem;
1297 }
1298 internal override nothrow MenuItem* GetOpenedMenuItem() const
1299 {
1300 return rootItemPtr.Get();
1301 }
1302 private UniquePtr<MenuItem> rootItemPtr;
1303 private MenuItem* latestOpenedMenuItem;
1304 private MenuItem* selectedMenuItem;
1305 private MenuItem* latestMouseDownMenuItem;
1306 private ClickActions clickActions;
1307 }
1308
1309 public abstract class MenuItemBase : Component
1310 {
1311 public nothrow MenuItemBase() : location(), size()
1312 {
1313 }
1314 public abstract void Draw(Graphics& graphics, const Padding& parentPadding, const Brush& textBrush, const Brush& disabledTextBrush, const Brush& backgroundBrush, const Brush& mouseOverBrush,
1315 const Brush& menuOpenBrush, const Brush& shadowBrush, const Brush& blackBrush, const Pen& blackPen, const Pen& darkPen, const Font& font,
1316 const StringFormat& format, const Color& menuOpenColor, MenuControl* menuControl, bool drawSubItems, const Point& origin);
1317 internal nothrow MenuItem* GetParentMenuItem() const
1318 {
1319 Container* container = GetContainer();
1320 if (container != null)
1321 {
1322 Component* parent = container->Parent();
1323 if (parent != null)
1324 {
1325 if (parent is MenuItem*)
1326 {
1327 MenuItem* parentMenuItem = cast<MenuItem*>(parent);
1328 return parentMenuItem;
1329 }
1330 }
1331 }
1332 return null;
1333 }
1334 public virtual nothrow Padding DefaultPadding() const
1335 {
1336 return Padding(0, 0, 0, 0);
1337 }
1338 public nothrow int Level() const
1339 {
1340 MenuItem* parent = GetParentMenuItem();
1341 if (parent == null)
1342 {
1343 return 0;
1344 }
1345 else
1346 {
1347 return parent->Level() + 1;
1348 }
1349 }
1350 public nothrow const Point& Location() const
1351 {
1352 return location;
1353 }
1354 public nothrow void SetLocation(const Point& location_)
1355 {
1356 location = location_;
1357 }
1358 public nothrow const Size& GetSize() const
1359 {
1360 return size;
1361 }
1362 public nothrow void SetSize(const Size& size_)
1363 {
1364 size = size_;
1365 }
1366 public abstract Size MeasureItem(Graphics& graphics, const Font& font, const StringFormat& format, int& maxShortcutWidth, int& childIndicatorWidth);
1367 private Point location;
1368 private Size size;
1369 }
1370
1371 public class MenuItem : MenuItemBase
1372 {
1373 public enum State : sbyte
1374 {
1375 closed = 0, open = 1
1376 }
1377 private enum Flags : sbyte
1378 {
1379 none = 0, disabled = 1 << 0, selected = 1 << 1, mouseInClient = 1 << 2, lbuttonPressed = 1 << 3
1380 }
1381 public MenuItem(const string& text_) :
1382 base(), text(text_), children(this), state(State.closed), childRect(), unionRect(), flags(Flags.none), accessKey('\0'), shortcut(Keys.none), shortcutFieldWidth(0)
1383 {
1384 SetAccessKey();
1385 }
1386 public void AddMenuItem(MenuItemBase* menuItem)
1387 {
1388 children.AddChild(menuItem);
1389 }
1390 public nothrow MenuItem* GetFirstMenuItem() const
1391 {
1392 Component* child = children.FirstChild();
1393 while (child != null)
1394 {
1395 if (child is MenuItem*)
1396 {
1397 MenuItem* childMenuItem = cast<MenuItem*>(child);
1398 return childMenuItem;
1399 }
1400 child = child->NextSibling();
1401 }
1402 return null;
1403 }
1404 public nothrow MenuItem* GetLastMenuItem() const
1405 {
1406 Component* child = children.LastChild();
1407 while (child != null)
1408 {
1409 if (child is MenuItem*)
1410 {
1411 MenuItem* childMenuItem = cast<MenuItem*>(child);
1412 return childMenuItem;
1413 }
1414 child = child->PrevSibling();
1415 }
1416 return null;
1417 }
1418 public nothrow MenuItem* GetNextMenuItem() const
1419 {
1420 Component* next = NextSibling();
1421 while (next != null)
1422 {
1423 if (next is MenuItem*)
1424 {
1425 MenuItem* nextMenuItem = cast<MenuItem*>(next);
1426 return nextMenuItem;
1427 }
1428 next = next->NextSibling();
1429 }
1430 return null;
1431 }
1432 public nothrow MenuItem* GetPrevMenuItem() const
1433 {
1434 Component* prev = PrevSibling();
1435 while (prev != null)
1436 {
1437 if (prev is MenuItem*)
1438 {
1439 MenuItem* prevMenuItem = cast<MenuItem*>(prev);
1440 return prevMenuItem;
1441 }
1442 prev = prev->PrevSibling();
1443 }
1444 return null;
1445 }
1446 public nothrow MenuItem* GetParentMenuItem() const
1447 {
1448 Container* container = GetContainer();
1449 if (container != null)
1450 {
1451 Component* parent = container->Parent();
1452 if (parent != null)
1453 {
1454 if (parent is MenuItem*)
1455 {
1456 MenuItem* parentItem = cast<MenuItem*>(parent);
1457 return parentItem;
1458 }
1459 }
1460 }
1461 return null;
1462 }
1463 private nothrow MenuControl* GetMenuControl() const
1464 {
1465 Container* container = GetContainer();
1466 if (container != null)
1467 {
1468 Component* parent = container->Parent();
1469 if (parent != null)
1470 {
1471 if (parent is MenuItem*)
1472 {
1473 MenuItem* parentItem = cast<MenuItem*>(parent);
1474 return parentItem->GetMenuControl();
1475 }
1476 else if (parent is MenuControl*)
1477 {
1478 MenuControl* menuControl = cast<MenuControl*>(parent);
1479 return menuControl;
1480 }
1481 }
1482 }
1483 return null;
1484 }
1485 internal bool HandleKey(Keys key, bool& wantsKeys, MenuItem* parentMenuItem, MenuControl* menuControl)
1486 {
1487 if (key >= Keys.a && key <= Keys.z || key >= Keys.d0 && key <= Keys.d9)
1488 {
1489 wchar accessKey = cast<wchar>(cast<int>(key));
1490 MenuItem* childItem = null;
1491 if (parentMenuItem != null)
1492 {
1493 childItem = parentMenuItem->GetChildItemByAccessKey(accessKey);
1494 }
1495 else
1496 {
1497 childItem = menuControl->GetMenuItemByAccessKey(accessKey);
1498 }
1499 if (childItem != null && childItem->IsEnabled())
1500 {
1501 childItem->Execute(parentMenuItem, wantsKeys, menuControl);
1502 return true;
1503 }
1504 else
1505 {
1506 wantsKeys = true;
1507 return false;
1508 }
1509 }
1510 else
1511 {
1512 switch (key)
1513 {
1514 case Keys.enter:
1515 {
1516 if (IsEnabled())
1517 {
1518 Execute(parentMenuItem, wantsKeys, menuControl);
1519 return true;
1520 }
1521 else
1522 {
1523 wantsKeys = true;
1524 return false;
1525 }
1526 }
1527 case Keys.escape:
1528 {
1529 MenuItem* openedMenuItem = menuControl->GetOpenedMenuItem();
1530 if (openedMenuItem != null)
1531 {
1532 openedMenuItem->SetState(State.closed, menuControl);
1533 }
1534 wantsKeys = false;
1535 menuControl->SetSelectedMenuItem(null);
1536 menuControl->SetClosed();
1537 menuControl->SetMenuInvalidated();
1538 return true;
1539 }
1540 case Keys.home:
1541 {
1542 if (Level() == 0)
1543 {
1544 MenuItem* firstMenuItem = menuControl->GetFirstMenuItem();
1545 if (firstMenuItem != null)
1546 {
1547 menuControl->SetSelectedMenuItem(firstMenuItem);
1548 wantsKeys = true;
1549 menuControl->SetMenuInvalidated();
1550 return true;
1551 }
1552 }
1553 else
1554 {
1555 MenuItem* parentMenuItem = GetParentMenuItem();
1556 if (parentMenuItem != null)
1557 {
1558 MenuItem* firstMenuItem = parentMenuItem->GetFirstMenuItem();
1559 if (firstMenuItem != null)
1560 {
1561 menuControl->SetSelectedMenuItem(firstMenuItem);
1562 wantsKeys = true;
1563 menuControl->SetMenuInvalidated();
1564 return true;
1565 }
1566 }
1567 }
1568 break;
1569 }
1570 case Keys.end:
1571 {
1572 if (Level() == 0)
1573 {
1574 MenuItem* lastMenuItem = menuControl->GetLastMenuItem();
1575 if (lastMenuItem != null)
1576 {
1577 menuControl->SetSelectedMenuItem(lastMenuItem);
1578 wantsKeys = true;
1579 menuControl->SetMenuInvalidated();
1580 return true;
1581 }
1582 }
1583 else
1584 {
1585 MenuItem* parentMenuItem = GetParentMenuItem();
1586 if (parentMenuItem != null)
1587 {
1588 MenuItem* lastMenuItem = parentMenuItem->GetLastMenuItem();
1589 if (lastMenuItem != null)
1590 {
1591 menuControl->SetSelectedMenuItem(lastMenuItem);
1592 wantsKeys = true;
1593 menuControl->SetMenuInvalidated();
1594 return true;
1595 }
1596 }
1597 }
1598 break;
1599 }
1600 case Keys.down:
1601 {
1602 if (Level() == 0)
1603 {
1604 SetState(state.open, menuControl);
1605 MenuItem* firstChild = GetFirstMenuItem();
1606 if (firstChild != null)
1607 {
1608 menuControl->SetSelectedMenuItem(firstChild);
1609 wantsKeys = true;
1610 menuControl->SetMenuInvalidated();
1611 return true;
1612 }
1613 }
1614 else
1615 {
1616 MenuItem* nextMenuItem = GetNextMenuItem();
1617 if (nextMenuItem != null)
1618 {
1619 menuControl->SetSelectedMenuItem(nextMenuItem);
1620 wantsKeys = true;
1621 menuControl->SetMenuInvalidated();
1622 return true;
1623 }
1624 else
1625 {
1626 if (parentMenuItem != null)
1627 {
1628 MenuItem* firstMenuItem = parentMenuItem->GetFirstMenuItem();
1629 if (firstMenuItem != null)
1630 {
1631 menuControl->SetSelectedMenuItem(firstMenuItem);
1632 wantsKeys = true;
1633 menuControl->SetMenuInvalidated();
1634 return true;
1635 }
1636 }
1637 }
1638 }
1639 break;
1640 }
1641 case Keys.up:
1642 {
1643 if (Level() == 0)
1644 {
1645 SetState(state.open, menuControl);
1646 MenuItem* lastChild = GetLastMenuItem();
1647 if (lastChild != null)
1648 {
1649 menuControl->SetSelectedMenuItem(lastChild);
1650 wantsKeys = true;
1651 menuControl->SetMenuInvalidated();
1652 return true;
1653 }
1654 }
1655 else
1656 {
1657 MenuItem* prevMenuItem = GetPrevMenuItem();
1658 if (prevMenuItem != null)
1659 {
1660 menuControl->SetSelectedMenuItem(prevMenuItem);
1661 wantsKeys = true;
1662 menuControl->SetMenuInvalidated();
1663 return true;
1664 }
1665 else
1666 {
1667 if (parentMenuItem != null)
1668 {
1669 MenuItem* lastMenuItem = parentMenuItem->GetLastMenuItem();
1670 if (lastMenuItem != null)
1671 {
1672 menuControl->SetSelectedMenuItem(lastMenuItem);
1673 wantsKeys = true;
1674 menuControl->SetMenuInvalidated();
1675 return true;
1676 }
1677 }
1678 }
1679 }
1680 break;
1681 }
1682 case Keys.right:
1683 {
1684 if (Level() == 0)
1685 {
1686 MenuItem* nextMenuItem = GetNextMenuItem();
1687 if (nextMenuItem != null)
1688 {
1689 menuControl->SetSelectedMenuItem(nextMenuItem);
1690 wantsKeys = true;
1691 menuControl->SetMenuInvalidated();
1692 return true;
1693 }
1694 else
1695 {
1696 MenuItem* firstMenuItem = menuControl->GetFirstMenuItem();
1697 if (firstMenuItem != null)
1698 {
1699 menuControl->SetSelectedMenuItem(firstMenuItem);
1700 wantsKeys = true;
1701 menuControl->SetMenuInvalidated();
1702 return true;
1703 }
1704 }
1705 }
1706 else
1707 {
1708 MenuItem* firstChild = GetFirstMenuItem();
1709 if (firstChild != null)
1710 {
1711 SetState(State.open, menuControl);
1712 menuControl->SetSelectedMenuItem(firstChild);
1713 wantsKeys = true;
1714 menuControl->SetMenuInvalidated();
1715 return true;
1716 }
1717 else
1718 {
1719 while (parentMenuItem != null)
1720 {
1721 if (parentMenuItem->Level() == 0)
1722 {
1723 MenuItem* nextMenuItem = parentMenuItem->GetNextMenuItem();
1724 if (nextMenuItem != null)
1725 {
1726 parentMenuItem->SetState(State.closed, menuControl);
1727 nextMenuItem->SetState(State.open, menuControl);
1728 MenuItem* firstChild = nextMenuItem->GetFirstMenuItem();
1729 if (firstChild != null)
1730 {
1731 menuControl->SetSelectedMenuItem(firstChild);
1732 wantsKeys = true;
1733 menuControl->SetMenuInvalidated();
1734 return true;
1735 }
1736 }
1737 else
1738 {
1739 MenuItem* firstMenuItem = menuControl->GetFirstMenuItem();
1740 if (firstMenuItem != null)
1741 {
1742 parentMenuItem->SetState(State.closed, menuControl);
1743 firstMenuItem->SetState(State.open, menuControl);
1744 MenuItem* firstChild = firstMenuItem->GetFirstMenuItem();
1745 if (firstChild != null)
1746 {
1747 menuControl->SetSelectedMenuItem(firstChild);
1748 wantsKeys = true;
1749 menuControl->SetMenuInvalidated();
1750 return true;
1751 }
1752 }
1753 }
1754 }
1755 else
1756 {
1757 MenuItem* grandParentMenuItem = parentMenuItem->GetParentMenuItem();
1758 MenuItem* nextMenuItem = grandParentMenuItem->GetNextMenuItem();
1759 if (nextMenuItem != null)
1760 {
1761 parentMenuItem->SetState(State.closed, menuControl);
1762 grandParentMenuItem->SetState(State.closed, menuControl);
1763 nextMenuItem->SetState(State.open, menuControl);
1764 MenuItem* firstChild = nextMenuItem->GetFirstMenuItem();
1765 if (firstChild != null)
1766 {
1767 menuControl->SetSelectedMenuItem(firstChild);
1768 wantsKeys = true;
1769 menuControl->SetMenuInvalidated();
1770 return true;
1771 }
1772 }
1773 else
1774 {
1775 parentMenuItem = grandParentMenuItem;
1776 }
1777 }
1778 }
1779 }
1780 }
1781 break;
1782 }
1783 case Keys.left:
1784 {
1785 if (Level() == 0)
1786 {
1787 MenuItem* prevMenuItem = GetPrevMenuItem();
1788 if (prevMenuItem != null)
1789 {
1790 menuControl->SetSelectedMenuItem(prevMenuItem);
1791 wantsKeys = true;
1792 menuControl->SetMenuInvalidated();
1793 return true;
1794 }
1795 else
1796 {
1797 MenuItem* lastMenuItem = menuControl->GetLastMenuItem();
1798 if (lastMenuItem != null)
1799 {
1800 menuControl->SetSelectedMenuItem(lastMenuItem);
1801 wantsKeys = true;
1802 menuControl->SetMenuInvalidated();
1803 return true;
1804 }
1805 }
1806 }
1807 else
1808 {
1809 if (parentMenuItem != null)
1810 {
1811 MenuItem* prevMenuItem = parentMenuItem->GetPrevMenuItem();
1812 if (prevMenuItem != null)
1813 {
1814 parentMenuItem->SetState(State.closed, menuControl);
1815 prevMenuItem->SetState(State.open, menuControl);
1816 MenuItem* firstChild = prevMenuItem->GetFirstMenuItem();
1817 if (firstChild != null)
1818 {
1819 menuControl->SetSelectedMenuItem(firstChild);
1820 wantsKeys = true;
1821 menuControl->SetMenuInvalidated();
1822 return true;
1823 }
1824 }
1825 else
1826 {
1827 MenuItem* grandParentMenuItem = parentMenuItem->GetParentMenuItem();
1828 if (grandParentMenuItem != null)
1829 {
1830 grandParentMenuItem->SetState(State.open, menuControl);
1831 MenuItem* firstMenuItem = grandParentMenuItem->GetFirstMenuItem();
1832 if (firstMenuItem != null)
1833 {
1834 firstMenuItem->SetState(State.closed, menuControl);
1835 menuControl->SetSelectedMenuItem(firstMenuItem);
1836 }
1837 }
1838 else
1839 {
1840 MenuItem* lastMenuItem = menuControl->GetLastMenuItem();
1841 if (lastMenuItem != null)
1842 {
1843 parentMenuItem->SetState(State.closed, menuControl);
1844 lastMenuItem->SetState(State.open, menuControl);
1845 MenuItem* firstChild = lastMenuItem->GetFirstMenuItem();
1846 if (firstChild != null)
1847 {
1848 menuControl->SetSelectedMenuItem(firstChild);
1849 wantsKeys = true;
1850 menuControl->SetMenuInvalidated();
1851 return true;
1852 }
1853 }
1854 }
1855 }
1856 }
1857 }
1858 break;
1859 }
1860 }
1861 }
1862 wantsKeys = true;
1863 return false;
1864 }
1865 private void Close(MenuControl* menuControl)
1866 {
1867 SetState(State.closed, menuControl);
1868 MenuItem* parentItem = GetParentMenuItem();
1869 while (parentItem != null)
1870 {
1871 parentItem->SetState(State.closed, menuControl);
1872 parentItem = parentItem->GetParentMenuItem();
1873 }
1874 menuControl->SetSelectedMenuItem(null);
1875 menuControl->SetClosed();
1876 menuControl->SetMenuInvalidated();
1877 }
1878 private void Execute(MenuItem* parentMenuItem, bool& wantsKeys, MenuControl* menuControl)
1879 {
1880 if (children.IsEmpty())
1881 {
1882 if (IsEnabled())
1883 {
1884 Close(menuControl);
1885 wantsKeys = false;
1886 DoClick();
1887 }
1888 }
1889 else
1890 {
1891 if (IsEnabled())
1892 {
1893 SetState(State.open, menuControl);
1894 MenuItem* firstMenuItem = GetFirstMenuItem();
1895 if (firstMenuItem != null)
1896 {
1897 menuControl->SetSelectedMenuItem(firstMenuItem);
1898 wantsKeys = true;
1899 menuControl->SetMenuInvalidated();
1900 }
1901 }
1902 }
1903 }
1904 internal void DoMouseDown(MouseEventArgs& args, bool& handled, MenuControl* menuControl)
1905 {
1906 if (Level() == 0)
1907 {
1908 if (Contains(args.location))
1909 {
1910 SetMouseInClient();
1911 if (menuControl->IsOpen())
1912 {
1913 menuControl->SetClosed();
1914 menuControl->SetLatestOpenedMenuItem(null);
1915 SetState(State.closed, menuControl);
1916 DoMouseDown(args, menuControl);
1917 handled = true;
1918 }
1919 else
1920 {
1921 menuControl->SetOpen();
1922 SetState(State.open, menuControl);
1923 menuControl->SetLatestOpenedMenuItem(this);
1924 DoMouseDown(args, menuControl);
1925 handled = true;
1926 }
1927 }
1928 else
1929 {
1930 Component* child = children.FirstChild();
1931 while (child != null)
1932 {
1933 if (child is MenuItem*)
1934 {
1935 MenuItem* childItem = cast<MenuItem*>(child);
1936 childItem->DoMouseDown(args, handled, menuControl);
1937 if (handled) return;
1938 }
1939 child = child->NextSibling();
1940 }
1941 }
1942 }
1943 else
1944 {
1945 if (menuControl->IsOpen())
1946 {
1947 MenuItem* parentMenuItem = GetParentMenuItem();
1948 if (parentMenuItem != null)
1949 {
1950 if (parentMenuItem->state == State.open)
1951 {
1952 if (Contains(args.location))
1953 {
1954 if (!children.IsEmpty())
1955 {
1956 if (state == State.closed)
1957 {
1958 SetState(State.open, menuControl);
1959 menuControl->SetLatestOpenedMenuItem(this);
1960 DoMouseDown(args, menuControl);
1961 handled = true;
1962 }
1963 else if (state == State.open)
1964 {
1965 SetState(State.closed, menuControl);
1966 menuControl->SetLatestOpenedMenuItem(null);
1967 DoMouseDown(args, menuControl);
1968 handled = true;
1969 }
1970 }
1971 else
1972 {
1973 DoMouseDown(args, menuControl);
1974 if ((args.buttons & MouseButtons.lbutton) != 0)
1975 {
1976 SetLButtonPressed();
1977 }
1978 handled = true;
1979 }
1980 }
1981 }
1982 }
1983 Component* child = children.FirstChild();
1984 while (child != null)
1985 {
1986 if (child is MenuItem*)
1987 {
1988 MenuItem* childItem = cast<MenuItem*>(child);
1989 childItem->DoMouseDown(args, handled, menuControl);
1990 if (handled) return;
1991 }
1992 child = child->NextSibling();
1993 }
1994 }
1995 }
1996 }
1997 internal void DoMouseUp(MouseEventArgs& args, bool& handled, MenuControl* menuControl)
1998 {
1999 if (Level() == 0)
2000 {
2001 if (Contains(args.location))
2002 {
2003 DoMouseUp(args, menuControl);
2004 handled = true;
2005 }
2006 else
2007 {
2008 Component* child = children.FirstChild();
2009 while (child != null)
2010 {
2011 if (child is MenuItem*)
2012 {
2013 MenuItem* childItem = cast<MenuItem*>(child);
2014 if (childItem->IsEnabled())
2015 {
2016 childItem->DoMouseUp(args, handled, menuControl);
2017 if (handled) return;
2018 }
2019 }
2020 child = child->NextSibling();
2021 }
2022 }
2023 }
2024 else
2025 {
2026 if (menuControl->IsOpen())
2027 {
2028 MenuItem* parentMenuItem = GetParentMenuItem();
2029 if (parentMenuItem != null)
2030 {
2031 if (parentMenuItem->state == State.open)
2032 {
2033 if (Contains(args.location))
2034 {
2035 DoMouseUp(args, menuControl);
2036 handled = true;
2037 return;
2038 }
2039 }
2040 }
2041 Component* child = children.FirstChild();
2042 while (child != null)
2043 {
2044 if (child is MenuItem*)
2045 {
2046 MenuItem* childItem = cast<MenuItem*>(child);
2047 if (childItem->IsEnabled())
2048 {
2049 childItem->DoMouseUp(args, handled, menuControl);
2050 if (handled) return;
2051 }
2052 }
2053 child = child->NextSibling();
2054 }
2055 }
2056 }
2057 }
2058 private void DoMouseDown(MouseEventArgs& args, MenuControl* menuControl)
2059 {
2060 menuControl->SetLatestMouseDownMenuItem(this);
2061 ResetLButtonPressed();
2062 OnMouseDown(args);
2063 }
2064 protected virtual void OnMouseDown(MouseEventArgs& args)
2065 {
2066 mouseDownEvent.Fire(args);
2067 }
2068 private void DoMouseUp(MouseEventArgs& args, MenuControl* menuControl)
2069 {
2070 if (!IsEnabled()) return;
2071 OnMouseUp(args);
2072 bool isMenuBar = menuControl is MenuBar*;
2073 MenuItem* latestMouseDownMenuItem = menuControl->GetLatestMouseDownMenuItem();
2074 if ((args.buttons & MouseButtons.lbutton) != 0)
2075 {
2076 if (LButtonPressed())
2077 {
2078 ResetLButtonPressed();
2079 if (latestMouseDownMenuItem == this && children.IsEmpty())
2080 {
2081 ResetSelected(menuControl);
2082 ResetMouseInClient();
2083 this->DoMouseLeave(menuControl);
2084 LeaveChildren(menuControl);
2085 Close(menuControl);
2086 DoClick();
2087 }
2088 if (isMenuBar)
2089 {
2090 MenuItem* openedMenuItem = menuControl->GetOpenedMenuItem();
2091 if (openedMenuItem != null)
2092 {
2093 openedMenuItem->SetState(State.closed, menuControl);
2094 }
2095 menuControl->SetClosed();
2096 menuControl->SetMenuInvalidated();
2097 }
2098 }
2099 }
2100 }
2101 protected virtual void OnMouseUp(MouseEventArgs& args)
2102 {
2103 mouseUpEvent.Fire(args);
2104 }
2105 internal void DoMouseEnter(bool parentIsOpen, MenuControl* menuControl)
2106 {
2107 if (parentIsOpen)
2108 {
2109 Component* prev = PrevSibling();
2110 while (prev != null)
2111 {
2112 if (prev is MenuItem*)
2113 {
2114 MenuItem* prevItem = cast<MenuItem*>(prev);
2115 prevItem->DoMouseLeave(menuControl);
2116 }
2117 prev = prev->PrevSibling();
2118 }
2119 Component* next = NextSibling();
2120 while (next != null)
2121 {
2122 if (next is MenuItem*)
2123 {
2124 MenuItem* nextItem = cast<MenuItem*>(next);
2125 nextItem->DoMouseLeave(menuControl);
2126 }
2127 next = next->NextSibling();
2128 }
2129 Component* child = children.FirstChild();
2130 while (child != null)
2131 {
2132 if (child is MenuItem*)
2133 {
2134 MenuItem* childMenuItem = cast<MenuItem*>(child);
2135 childMenuItem->ResetSelected(menuControl);
2136 if (childMenuItem->MouseInClient())
2137 {
2138 childMenuItem->ResetMouseInClient();
2139 childMenuItem->DoMouseLeave(menuControl);
2140 }
2141 }
2142 child = child->NextSibling();
2143 }
2144 }
2145 if (parentIsOpen)
2146 {
2147 SetState(State.open, menuControl);
2148 menuControl->SetLatestOpenedMenuItem(this);
2149 }
2150 OnMouseEnter();
2151 menuControl->SetMenuInvalidated();
2152 }
2153 internal void DoMouseMove(MouseEventArgs& args)
2154 {
2155 OnMouseMove(args);
2156 }
2157 protected virtual void OnMouseEnter()
2158 {
2159 mouseEnterEvent.Fire();
2160 }
2161 internal void LeaveChildren(MenuControl* menuControl)
2162 {
2163 Component* child = children.FirstChild();
2164 while (child != null)
2165 {
2166 if (child is MenuItem*)
2167 {
2168 MenuItem* childMenuItem = cast<MenuItem*>(child);
2169 childMenuItem->ResetSelected(menuControl);
2170 childMenuItem->ResetMouseInClient();
2171 childMenuItem->DoMouseLeave(menuControl);
2172 childMenuItem->LeaveChildren(menuControl);
2173 }
2174 child = child->NextSibling();
2175 }
2176 }
2177 internal void DoMouseLeave(MenuControl* menuControl)
2178 {
2179 ResetLButtonPressed();
2180 if (state == State.open)
2181 {
2182 SetState(State.closed, menuControl);
2183 LeaveChildren(menuControl);
2184 OnMouseLeave();
2185 }
2186 else if (Level() == 0)
2187 {
2188 OnMouseLeave();
2189 }
2190 }
2191 protected virtual void OnMouseLeave()
2192 {
2193 mouseLeaveEvent.Fire();
2194 }
2195 internal void DispatchMouseMove(MouseEventArgs& args, bool& handled, MenuControl* menuControl)
2196 {
2197 if (unionRect.Contains(args.location))
2198 {
2199 if (Contains(args.location))
2200 {
2201 SetSelected(menuControl);
2202 }
2203 else
2204 {
2205 ResetSelected(menuControl);
2206 ResetMouseInClient();
2207 }
2208 Component* child = children.FirstChild();
2209 while (child != null)
2210 {
2211 if (child is MenuItem*)
2212 {
2213 MenuItem* childMenuItem = cast<MenuItem*>(child);
2214 if (childMenuItem->Contains(args.location))
2215 {
2216 childMenuItem->SetSelected(menuControl);
2217 if (!childMenuItem->MouseInClient())
2218 {
2219 childMenuItem->SetMouseInClient();
2220 childMenuItem->DoMouseEnter(true, menuControl);
2221 handled = true;
2222 }
2223 else
2224 {
2225 childMenuItem->DoMouseMove(args);
2226 }
2227 }
2228 else
2229 {
2230 childMenuItem->ResetSelected(menuControl);
2231 if (childMenuItem->MouseInClient())
2232 {
2233 childMenuItem->ResetMouseInClient();
2234 if (!childMenuItem->IsSameOrParentOf(menuControl->LatestOpenedMenuItem()))
2235 {
2236 childMenuItem->DoMouseLeave(menuControl);
2237 }
2238 }
2239 }
2240 }
2241 child = child->NextSibling();
2242 }
2243 }
2244 else
2245 {
2246 Component* child = children.FirstChild();
2247 while (child != null)
2248 {
2249 if (child is MenuItem*)
2250 {
2251 MenuItem* childMenuItem = cast<MenuItem*>(child);
2252 if (childMenuItem->IsSameOrParentOf(menuControl->LatestOpenedMenuItem()))
2253 {
2254 childMenuItem->DispatchMouseMove(args, handled, menuControl);
2255 if (handled) return;
2256 }
2257 }
2258 child = child->NextSibling();
2259 }
2260 }
2261 }
2262 protected virtual void OnMouseMove(MouseEventArgs& args)
2263 {
2264 mouseMoveEvent.Fire(args);
2265 }
2266 internal void DoClick()
2267 {
2268 LogView* logView = Application.GetLogView();
2269 if (logView != null)
2270 {
2271 logView->WriteLine("MENUITEM: " + text + " CLICK!");
2272 }
2273 OnClick();
2274 }
2275 protected virtual void OnClick()
2276 {
2277 clickEvent.Fire();
2278 }
2279 public void CalculateChildRect(Graphics& graphics, const Font& font, const StringFormat& format, const Point& location)
2280 {
2281 childRect = Rect();
2282 childRect.location = location;
2283 Component* child = children.FirstChild();
2284 shortcutFieldWidth = 0;
2285 childIndicatorFieldWidth = 0;
2286 while (child != null)
2287 {
2288 if (child is MenuItemBase*)
2289 {
2290 MenuItemBase* item = cast<MenuItemBase*>(child);
2291 Size size = item->MeasureItem(graphics, font, format, shortcutFieldWidth, childIndicatorFieldWidth);
2292 childRect.size.w = Max(childRect.size.w, size.w);
2293 childRect.size.h = childRect.size.h + size.h;
2294 }
2295 child = child->NextSibling();
2296 }
2297 childRect.size.w = childRect.size.w + shortcutFieldWidth + childIndicatorFieldWidth;
2298 Rect itemRect(childRect.location, Size(childRect.size.w, 0));
2299 child = children.FirstChild();
2300 while (child != null)
2301 {
2302 if (child is MenuItemBase*)
2303 {
2304 MenuItemBase* item = cast<MenuItemBase*>(child);
2305 item->SetLocation(itemRect.location);
2306 itemRect.size.h = item->GetSize().h;
2307 item->SetSize(itemRect.size);
2308 itemRect.location.y = itemRect.location.y + itemRect.size.h;
2309 }
2310 child = child->NextSibling();
2311 }
2312 int shadowWidth = ShadowWidth();
2313 childRect.size.h = childRect.size.h + shadowWidth;
2314 childRect.size.w = childRect.size.w + shadowWidth;
2315 child = children.FirstChild();
2316 while (child != null)
2317 {
2318 if (child is MenuItem*)
2319 {
2320 MenuItem* item = cast<MenuItem*>(child);
2321 if (!item->Children().IsEmpty())
2322 {
2323 Point itemLocation = item->Location();
2324 Size itemSize = item->GetSize();
2325 item->CalculateChildRect(graphics, font, format, Point(itemLocation.x + itemSize.w - shadowWidth, itemLocation.y));
2326 }
2327 }
2328 child = child->NextSibling();
2329 }
2330 Rect r(Location(), GetSize());
2331 unionRect = Rect.Union(r, childRect);
2332 }
2333 public override void Draw(Graphics& graphics, const Padding& parentPadding, const Brush& textBrush, const Brush& disabledTextBrush, const Brush& backgroundBrush, const Brush& mouseOverBrush,
2334 const Brush& menuOpenBrush, const Brush& shadowBrush, const Brush& blackBrush, const Pen& blackPen, const Pen& darkPen, const Font& font, const StringFormat& format,
2335 const Color& menuOpenColor, MenuControl* menuControl, bool drawSubItems, const Point& origin)
2336 {
2337 switch (state)
2338 {
2339 case State.closed:
2340 {
2341 DrawClosed(graphics, parentPadding, textBrush, disabledTextBrush, mouseOverBrush, backgroundBrush, menuOpenBrush, blackBrush, blackPen, font, format, menuOpenColor, menuControl,
2342 drawSubItems, origin);
2343 break;
2344 }
2345 case State.open:
2346 {
2347 DrawOpen(graphics, parentPadding, textBrush, disabledTextBrush, backgroundBrush, mouseOverBrush, menuOpenBrush, shadowBrush, blackBrush, blackPen, darkPen, font, format,
2348 menuOpenColor, menuControl, drawSubItems, origin);
2349 break;
2350 }
2351 }
2352 }
2353 public nothrow const string& Text() const
2354 {
2355 return text;
2356 }
2357 public nothrow void SetText(const string& text_, MenuControl* menuControl)
2358 {
2359 text = text_;
2360 SetAccessKey();
2361 menuControl->InvalidateMenu();
2362 }
2363 public inline nothrow wchar AccessKey() const
2364 {
2365 return accessKey;
2366 }
2367 private nothrow void SetAccessKey()
2368 {
2369 wstring s = ToUtf16(text);
2370 long ampPos = s.Find('&');
2371 if (ampPos != -1 && ampPos < s.Length() - 1)
2372 {
2373 accessKey = cast<wchar>(ToUpper(cast<uchar>(s[ampPos + 1])));
2374 }
2375 else
2376 {
2377 accessKey = '\0';
2378 }
2379 }
2380 public nothrow void SetShortcut(Keys shortcut_)
2381 {
2382 shortcut = shortcut_;
2383 MenuControl* menuControl = GetMenuControl();
2384 if (menuControl != null)
2385 {
2386 menuControl->SetMenuChanged();
2387 }
2388 }
2389 private nothrow MenuItem* GetChildItemByAccessKey(wchar accessKey)
2390 {
2391 Component* child = children.FirstChild();
2392 while (child != null)
2393 {
2394 if (child is MenuItem*)
2395 {
2396 MenuItem* menuItem = cast<MenuItem*>(child);
2397 if (menuItem->AccessKey() == accessKey)
2398 {
2399 return menuItem;
2400 }
2401 }
2402 child = child->NextSibling();
2403 }
2404 return null;
2405 }
2406 internal nothrow void CollectShortcuts(HashMap<Keys, MenuItem*>& shortcuts)
2407 {
2408 if (shortcut != Keys.none)
2409 {
2410 shortcuts[shortcut] = this;
2411 }
2412 Component* child = children.FirstChild();
2413 while (child != null)
2414 {
2415 if (child is MenuItem*)
2416 {
2417 MenuItem* menuItem = cast<MenuItem*>(child);
2418 menuItem->CollectShortcuts(shortcuts);
2419 }
2420 child = child->NextSibling();
2421 }
2422 }
2423 public nothrow const Container& Children() const
2424 {
2425 return children;
2426 }
2427 public override nothrow Padding DefaultPadding() const
2428 {
2429 if (Level() == 0)
2430 {
2431 return Padding(4, 0, 4, 0);
2432 }
2433 else
2434 {
2435 return Padding(32, 4, 32, 4);
2436 }
2437 }
2438 public nothrow Padding ShortcutPadding() const
2439 {
2440 if (Level() == 0)
2441 {
2442 return Padding(0, 0, 0, 0);
2443 }
2444 else
2445 {
2446 return Padding(4, 0, 4, 0);
2447 }
2448 }
2449 public virtual nothrow int ShadowWidth() const
2450 {
2451 return 3;
2452 }
2453 public virtual nothrow int ChildIndicatorIndent() const
2454 {
2455 return 9;
2456 }
2457 public virtual nothrow int ChildIndicatorWidth() const
2458 {
2459 return 6;
2460 }
2461 public nothrow bool Contains(const Point& p)
2462 {
2463 Rect r(Location(), GetSize());
2464 if (r.Contains(p))
2465 {
2466 return true;
2467 }
2468 return false;
2469 }
2470 public nothrow bool UnionRectContains(const Point& p)
2471 {
2472 return unionRect.Contains(p);
2473 }
2474 public inline nothrow const Rect& UnionRect() const
2475 {
2476 return unionRect;
2477 }
2478 public nothrow void GetOpenRect(Rect& parentRect)
2479 {
2480 if (!childRect.IsEmpty())
2481 {
2482 if (parentRect.IsEmpty())
2483 {
2484 parentRect = childRect;
2485 }
2486 else
2487 {
2488 parentRect = Rect.Union(parentRect, childRect);
2489 }
2490 }
2491 Component* child = children.FirstChild();
2492 while (child != null)
2493 {
2494 if (child is MenuItem*)
2495 {
2496 MenuItem* menuItem = cast<MenuItem*>(child);
2497 if (menuItem->GetState() == MenuItem.State.open)
2498 {
2499 menuItem->GetOpenRect(parentRect);
2500 }
2501 }
2502 child = child->NextSibling();
2503 }
2504 }
2505 public inline nothrow State GetState() const
2506 {
2507 return state;
2508 }
2509 internal void SetState(State state_, MenuControl* menuControl)
2510 {
2511 if (state != state_)
2512 {
2513 state = state_;
2514 menuControl->SetMenuInvalidated();
2515 }
2516 }
2517 public override Size MeasureItem(Graphics& graphics, const Font& font, const StringFormat& format, int& shortcutFieldWidth, int& childIndicatorFieldWidth)
2518 {
2519 Padding padding = DefaultPadding();
2520 RectF rect = graphics.MeasureStringChecked(text, font, PointF(0, 0), format);
2521 int w = cast<int>(rect.size.w);
2522 w = w + padding.Horizontal();
2523 if (shortcut != Keys.none)
2524 {
2525 string shortcutText = ToString(shortcut);
2526 RectF shortcutRect = graphics.MeasureStringChecked(shortcutText, font, PointF(0, 0), format);
2527 Padding shortcutPadding = ShortcutPadding();
2528 int shortcutWidth = cast<int>(shortcutRect.size.w + shortcutPadding.Horizontal());
2529 shortcutFieldWidth = Max(shortcutFieldWidth, shortcutWidth);
2530 }
2531 if (Level() > 0 && !children.IsEmpty())
2532 {
2533 childIndicatorFieldWidth = Max(childIndicatorFieldWidth, ChildIndicatorIndent());
2534 }
2535 int h = cast<int>(rect.size.h);
2536 h = h + padding.Vertical();
2537 Size size(w, h);
2538 SetSize(size);
2539 return size;
2540 }
2541 private void DrawClosed(Graphics& graphics, const Padding& parentPadding, const Brush& textBrush, const Brush& disabledTextBrush, const Brush& mouseOverBrush, const Brush& backgroundBrush,
2542 const Brush& menuOpenBrush, const Brush& blackBrush, const Pen& blackPen, const Font& font, const StringFormat& format, const Color& menuOpenColor,
2543 MenuControl* menuControl, bool drawSubItems, const Point& origin)
2544 {
2545 Point loc = Location();
2546 loc.x = loc.x - origin.x;
2547 loc.y = loc.y - origin.y;
2548 Size size = GetSize();
2549 Rect r(loc, size);
2550 r.size.w = r.size.w - 1;
2551 r.size.h = r.size.h - 1;
2552 MenuItem* selectedMenuItem = menuControl->GetSelectedMenuItem();
2553 if (Selected() || this == selectedMenuItem)
2554 {
2555 graphics.FillRectangleChecked(mouseOverBrush, r);
2556 graphics.DrawRectangleChecked(blackPen, r);
2557 }
2558 if (Level() == 0)
2559 {
2560 if (!drawSubItems)
2561 {
2562 if (!Selected() && this != selectedMenuItem)
2563 {
2564 graphics.FillRectangleChecked(backgroundBrush, r);
2565 }
2566 StringFormat textFormat(format);
2567 textFormat.SetAlignment(StringAlignment.center);
2568 RectF rect(PointF(loc.x, loc.y), SizeF(size.w, size.h));
2569 if (IsEnabled())
2570 {
2571 graphics.DrawStringChecked(text, font, rect, textFormat, textBrush);
2572 }
2573 else
2574 {
2575 graphics.DrawStringChecked(text, font, rect, textFormat, disabledTextBrush);
2576 }
2577 }
2578 }
2579 else
2580 {
2581 if (drawSubItems)
2582 {
2583 Padding padding = DefaultPadding();
2584 if (IsEnabled())
2585 {
2586 graphics.DrawStringChecked(text, font, PointF(loc.x + padding.left, loc.y + padding.top), format, textBrush);
2587 DrawShortcut(graphics, textBrush, font, format, origin);
2588 }
2589 else
2590 {
2591 graphics.DrawStringChecked(text, font, PointF(loc.x + padding.left, loc.y + padding.top), format, disabledTextBrush);
2592 DrawShortcut(graphics, disabledTextBrush, font, format, origin);
2593 }
2594 DrawChildIndicator(graphics, blackBrush, origin);
2595 }
2596 }
2597 }
2598 private void DrawOpen(Graphics& graphics, const Padding& parentPadding, const Brush& textBrush, const Brush& disabledTextBrush, const Brush& backgroundBrush, const Brush& mouseOverBrush,
2599 const Brush& menuOpenBrush, const Brush& shadowBrush, const Brush& blackBrush, const Pen& blackPen, const Pen& darkPen, const Font& font, const StringFormat& format,
2600 const Color& menuOpenColor, MenuControl* menuControl, bool drawSubItems, const Point& origin)
2601 {
2602 Point loc = Location();
2603 loc.x = loc.x - origin.x;
2604 loc.y = loc.y - origin.y;
2605 Size size = GetSize();
2606 Rect r(loc, size);
2607 r.size.w = r.size.w - 1;
2608 r.size.h = r.size.h - 1;
2609 int shadowWidth = ShadowWidth();
2610 if (Level() == 0)
2611 {
2612 if (!drawSubItems)
2613 {
2614 graphics.FillRectangleChecked(menuOpenBrush, r);
2615 graphics.DrawLineChecked(blackPen, r.location, Point(r.location.x + r.size.w, r.location.y));
2616
2617 graphics.DrawLineChecked(blackPen, r.location, Point(r.location.x, r.location.y + r.size.h));
2618 graphics.DrawLineChecked(blackPen, Point(r.location.x + r.size.w, r.location.y), Point(r.location.x + r.size.w, r.location.y + r.size.h));
2619 if (children.IsEmpty())
2620 {
2621 graphics.DrawLineChecked(blackPen, Point(r.location.x, r.location.y + r.size.h), Point(r.location.x + r.size.w, r.location.y + r.size.h));
2622 }
2623 StringFormat textFormat(format);
2624 textFormat.SetAlignment(StringAlignment.center);
2625 RectF rect(PointF(loc.x, loc.y), SizeF(size.w, size.h));
2626 if (IsEnabled())
2627 {
2628 graphics.DrawStringChecked(text, font, rect, textFormat, textBrush);
2629 }
2630 else
2631 {
2632 graphics.DrawStringChecked(text, font, rect, textFormat, disabledTextBrush);
2633 }
2634 }
2635 }
2636 else
2637 {
2638 if (drawSubItems)
2639 {
2640 MenuItem* selectedMenuItem = menuControl->GetSelectedMenuItem();
2641 if (Selected() || this == selectedMenuItem)
2642 {
2643 graphics.FillRectangleChecked(mouseOverBrush, r);
2644 graphics.DrawRectangleChecked(blackPen, r);
2645 }
2646 else
2647 {
2648 Rect inside = r;
2649 inside.Inflate(-1, -1);
2650 graphics.FillRectangleChecked(menuOpenBrush, inside);
2651 }
2652 Padding padding = DefaultPadding();
2653 if (IsEnabled())
2654 {
2655 graphics.DrawStringChecked(text, font, PointF(loc.x + padding.left, loc.y + padding.top), format, textBrush);
2656 DrawShortcut(graphics, textBrush, font, format, origin);
2657 }
2658 else
2659 {
2660 graphics.DrawStringChecked(text, font, PointF(loc.x + padding.left, loc.y + padding.top), format, disabledTextBrush);
2661 DrawShortcut(graphics, disabledTextBrush, font, format, origin);
2662 }
2663 DrawChildIndicator(graphics, blackBrush, origin);
2664 }
2665 }
2666 if (!childRect.IsEmpty())
2667 {
2668 if (drawSubItems)
2669 {
2670 Region prevClipRegion = graphics.GetClipChecked();
2671 Rect menuBox = childRect;
2672 menuBox.location.x = menuBox.location.x - origin.x;
2673 menuBox.location.y = menuBox.location.y - origin.y;
2674 menuBox.size.h = menuBox.size.h - shadowWidth;
2675 menuBox.size.w = menuBox.size.w - shadowWidth;
2676 graphics.SetClipChecked(menuBox);
2677 graphics.Clear(menuOpenColor);
2678 Rect cr(childRect);
2679 cr.location.x = cr.location.x - origin.x;
2680 cr.location.y = cr.location.y - origin.y;
2681 graphics.SetClipChecked(cr);
2682 Rect bottomShadowRect(
2683 Point(cr.location.x + shadowWidth, cr.location.y + cr.size.h - shadowWidth),
2684 Size(cr.size.w - shadowWidth, shadowWidth));
2685 graphics.FillRectangleChecked(shadowBrush, bottomShadowRect);
2686 Rect rightShadowRect(
2687 Point(cr.location.x + cr.size.w - shadowWidth, cr.location.y + shadowWidth),
2688 Size(shadowWidth, cr.size.h - shadowWidth));
2689 graphics.FillRectangleChecked(shadowBrush, rightShadowRect);
2690 Rect rect = childRect;
2691 rect.location.x = rect.location.x - origin.x;
2692 rect.location.y = rect.location.y - origin.y;
2693 rect.size.w = rect.size.w - 1;
2694 rect.size.h = rect.size.h - 1;
2695 if (Level() == 0)
2696 {
2697 graphics.DrawLineChecked(blackPen, rect.location, Point(rect.location.x, rect.location.y + rect.size.h - shadowWidth));
2698 graphics.DrawLineChecked(blackPen, Point(rect.location.x, rect.location.y + rect.size.h - shadowWidth),
2699 Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y + rect.size.h - shadowWidth));
2700 graphics.DrawLineChecked(blackPen, Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y + rect.size.h - shadowWidth),
2701 Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y));
2702 graphics.DrawLineChecked(blackPen,
2703 Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y), Point(r.location.x + r.size.w, rect.location.y));
2704 }
2705 else
2706 {
2707 graphics.DrawLineChecked(blackPen, rect.location, Point(rect.location.x, rect.location.y + rect.size.h - shadowWidth));
2708 graphics.DrawLineChecked(blackPen, Point(rect.location.x, r.location.y + rect.size.h - shadowWidth),
2709 Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y + rect.size.h - shadowWidth));
2710 graphics.DrawLineChecked(blackPen, Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y + rect.size.h - shadowWidth),
2711 Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y));
2712 graphics.DrawLineChecked(blackPen, Point(rect.location.x + rect.size.w - shadowWidth, rect.location.y),
2713 Point(rect.location.x, rect.location.y));
2714 }
2715 Component* child = children.FirstChild();
2716 while (child != null)
2717 {
2718 if (child is MenuItemBase*)
2719 {
2720 MenuItemBase* menuItem = cast<MenuItem*>(child);
2721 menuItem->Draw(graphics, parentPadding, textBrush, disabledTextBrush, backgroundBrush, mouseOverBrush, menuOpenBrush, shadowBrush, blackBrush, blackPen, darkPen,
2722 font, format, menuOpenColor, menuControl, drawSubItems, origin);
2723 }
2724 child = child->NextSibling();
2725 }
2726 graphics.SetClipChecked(prevClipRegion);
2727 }
2728 }
2729 }
2730 private void DrawShortcut(Graphics& graphics, const Brush& textBrush, const Font& font, const StringFormat& format, const Point& origin)
2731 {
2732 if (shortcut != Keys.none)
2733 {
2734 string shortcutText = ToString(shortcut);
2735 Padding shortcutPadding = ShortcutPadding();
2736 int shortcutFieldWidth = 0;
2737 int childIndicatorFieldWidth = 0;
2738 MenuItem* parent = GetParentMenuItem();
2739 if (parent != null)
2740 {
2741 shortcutFieldWidth = parent->shortcutFieldWidth;
2742 childIndicatorFieldWidth = parent->childIndicatorFieldWidth;
2743 }
2744 Padding padding = DefaultPadding();
2745 int shadowWidth = ShadowWidth();
2746 Point loc = Location();
2747 loc.x = loc.x - origin.x;
2748 loc.y = loc.y - origin.y;
2749 Size size = GetSize();
2750 graphics.DrawStringChecked(shortcutText, font,
2751 PointF(loc.x + size.w - shadowWidth - shortcutFieldWidth - childIndicatorFieldWidth + shortcutPadding.left, loc.y + padding.top), format, textBrush);
2752 }
2753 }
2754 private void DrawChildIndicator(Graphics& graphics, const Brush& blackBrush, const Point& origin)
2755 {
2756 if (children.IsEmpty()) return;
2757 Point loc = Location();
2758 loc.x = loc.x - origin.x;
2759 loc.y = loc.y - origin.y;
2760 Size size = GetSize();
2761 int childIndicatorIndent = ChildIndicatorIndent();
2762 int childIndicatorWidth = ChildIndicatorWidth();
2763 int shadowWidth = ShadowWidth();
2764 Point up(loc.x + size.w - childIndicatorIndent - shadowWidth, loc.y + size.h / 2 - childIndicatorWidth / 2);
2765 Point down(loc.x + size.w - childIndicatorIndent - shadowWidth, loc.y + size.h / 2 + childIndicatorWidth / 2);
2766 Point right(loc.x + size.w - childIndicatorIndent + cast<int>((Sqrt(3) / 2.0) * childIndicatorWidth) - shadowWidth, loc.y + size.h / 2);
2767 List<Point> triangle;
2768 triangle.Add(up);
2769 triangle.Add(down);
2770 triangle.Add(right);
2771 graphics.FillPolygonChecked(blackBrush, 3, triangle.Begin().Ptr());
2772 }
2773 internal nothrow bool IsSameOrParentOf(MenuItem* menuItem) const
2774 {
2775 if (this == menuItem) return true;
2776 MenuItem* parent = menuItem->GetParentMenuItem();
2777 if (parent != null)
2778 {
2779 return IsSameOrParentOf(parent);
2780 }
2781 return false;
2782 }
2783 internal inline nothrow bool Selected() const
2784 {
2785 return (flags & Flags.selected) != 0;
2786 }
2787 internal nothrow void SetSelected(MenuControl* menuControl)
2788 {
2789 if ((flags & Flags.selected) == 0)
2790 {
2791 flags = cast<Flags>(flags | Flags.selected);
2792 menuControl->SetMenuInvalidated();
2793 }
2794 }
2795 internal nothrow void ResetSelected(MenuControl* menuControl)
2796 {
2797 if ((flags & Flags.selected) != 0)
2798 {
2799 flags = cast<Flags>(flags & ~Flags.selected);
2800 menuControl->SetMenuInvalidated();
2801 }
2802 }
2803 public inline nothrow bool IsEnabled() const
2804 {
2805 return cast<Flags>(flags & Flags.disabled) == Flags.none;
2806 }
2807 public inline nothrow bool IsDisabled() const
2808 {
2809 return cast<Flags>(flags & Flags.disabled) != Flags.none;
2810 }
2811 public nothrow void Enable()
2812 {
2813 if (!IsEnabled())
2814 {
2815 flags = cast<Flags>(flags & ~Flags.disabled);
2816 MenuControl* menuControl = GetMenuControl();
2817 if (menuControl != null)
2818 {
2819 menuControl->SetMenuInvalidated();
2820 menuControl->SetMenuChanged();
2821 }
2822 }
2823 }
2824 public nothrow void Disable()
2825 {
2826 if (IsEnabled())
2827 {
2828 flags = cast<Flags>(flags | Flags.disabled);
2829 MenuControl* menuControl = GetMenuControl();
2830 if (menuControl != null)
2831 {
2832 menuControl->SetMenuInvalidated();
2833 menuControl->SetMenuChanged();
2834 }
2835 }
2836 }
2837 internal inline nothrow bool MouseInClient() const
2838 {
2839 return (flags & Flags.mouseInClient) != 0;
2840 }
2841 internal void SetMouseInClient()
2842 {
2843 flags = cast<Flags>(flags | Flags.mouseInClient);
2844 }
2845 internal void ResetMouseInClient()
2846 {
2847 flags = cast<Flags>(flags & ~Flags.mouseInClient);
2848 }
2849 private inline nothrow bool LButtonPressed() const
2850 {
2851 return (flags & Flags.lbuttonPressed) != 0;
2852 }
2853 private nothrow void SetLButtonPressed()
2854 {
2855 flags = cast<Flags>(flags | Flags.lbuttonPressed);
2856 }
2857 private nothrow void ResetLButtonPressed()
2858 {
2859 flags = cast<Flags>(flags & ~Flags.lbuttonPressed);
2860 }
2861 public nothrow Event<MouseEventHandler, MouseEventArgs>& MouseDownEvent()
2862 {
2863 return mouseDownEvent;
2864 }
2865 public nothrow Event<MouseEventHandler, MouseEventArgs>& MouseUpEvent()
2866 {
2867 return mouseUpEvent;
2868 }
2869 public nothrow Event<MouseEnterEventHandler>& MouseEnterEvent()
2870 {
2871 return mouseEnterEvent;
2872 }
2873 public nothrow Event<MouseEventHandler, MouseEventArgs>& MouseMoveEvent()
2874 {
2875 return mouseMoveEvent;
2876 }
2877 public nothrow Event<MouseLeaveEventHandler>& MouseLeaveEvent()
2878 {
2879 return mouseLeaveEvent;
2880 }
2881 public nothrow Event<ClickEventHandler>& ClickEvent()
2882 {
2883 return clickEvent;
2884 }
2885 private string text;
2886 private Container children;
2887 private Rect childRect;
2888 private Rect unionRect;
2889 private Event<MouseEventHandler, MouseEventArgs> mouseDownEvent;
2890 private Event<MouseEventHandler, MouseEventArgs> mouseUpEvent;
2891 private Event<MouseEnterEventHandler> mouseEnterEvent;
2892 private Event<MouseEventHandler, MouseEventArgs> mouseMoveEvent;
2893 private Event<MouseLeaveEventHandler> mouseLeaveEvent;
2894 private Event<ClickEventHandler> clickEvent;
2895 private State state;
2896 private Flags flags;
2897 private wchar accessKey;
2898 private Keys shortcut;
2899 private int shortcutFieldWidth;
2900 private int childIndicatorFieldWidth;
2901 }
2902
2903 public class MenuItemSeparator : MenuItemBase
2904 {
2905 public override void Draw(Graphics& graphics, const Padding& parentPadding, const Brush& textBrush, const Brush& disabledTextBrush, const Brush& backgroundBrush, const Brush& mouseOverBrush,
2906 const Brush& menuOpenBrush, const Brush& shadowBrush, const Brush& blackBrush, const Pen& blackPen, const Pen& darkPen, const Font& font, const StringFormat& format,
2907 const Color& menuOpenColor, MenuControl* menuControl, bool drawSubItems, const Point& origin)
2908 {
2909 Point loc = Location();
2910 loc.x = loc.x - origin.x;
2911 loc.y = loc.y - origin.y;
2912 Rect rect(loc, GetSize());
2913 Padding padding = DefaultPadding();
2914 graphics.DrawLineChecked(darkPen,
2915 Point(rect.location.x + padding.left, rect.location.y + rect.size.h / 2),
2916 Point(rect.location.x + rect.size.w - padding.right, rect.location.y + rect.size.h / 2));
2917 }
2918 public override nothrow Padding DefaultPadding() const
2919 {
2920 return Padding(32, 4, 8, 4);
2921 }
2922 public override Size MeasureItem(Graphics& graphics, const Font& font, const StringFormat& format, int& shortcutFieldWidth, int& childIndicatorFieldWidth)
2923 {
2924 Padding padding = DefaultPadding();
2925 RectF rect;
2926 int w = cast<int>(rect.size.w);
2927 w = w + padding.Horizontal();
2928 int h = cast<int>(rect.size.h);
2929 h = h + padding.Vertical();
2930 Size size(w, h);
2931 SetSize(size);
2932 return size;
2933 }
2934 }
2935 }