// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. using System; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.GUI { /// /// Menu strip with child buttons. /// /// public sealed class MainMenu : ContainerControl { private bool _useCustomWindowSystem; private Image _icon; private Label _title; private MainMenuButton _selected; private Button _closeButton; private Button _minimizeButton; private Button _maximizeButton; private Window _window; /// /// Gets or sets the selected button (with opened context menu). /// public MainMenuButton Selected { get => _selected; set { if (_selected == value) return; if (_selected != null) { _selected.ContextMenu.VisibleChanged -= OnSelectedContextMenuVisibleChanged; _selected.ContextMenu.Hide(); } _selected = value; if (_selected != null && _selected.ContextMenu.HasChildren) { _selected.ContextMenu.Show(_selected, new Vector2(0, _selected.Height)); _selected.ContextMenu.VisibleChanged += OnSelectedContextMenuVisibleChanged; } } } private void OnSelectedContextMenuVisibleChanged(Control control) { if (_selected != null) Selected = null; } /// /// Initializes a new instance of the class. /// /// The main window. public MainMenu(RootControl mainWindow) : base(0, 0, 0, 20) { _useCustomWindowSystem = !Editor.Instance.Options.Options.Interface.UseNativeWindowSystem; AutoFocus = false; AnchorPreset = AnchorPresets.HorizontalStretchTop; if (_useCustomWindowSystem) { BackgroundColor = Style.Current.LightBackground; Height = 28; var windowIcon = FlaxEngine.Content.LoadAsyncInternal(EditorAssets.WindowIcon); FontAsset windowIconsFont = FlaxEngine.Content.LoadAsyncInternal(EditorAssets.WindowIconsFont); Font iconFont = windowIconsFont?.CreateFont(9); _window = mainWindow.RootWindow.Window; _window.HitTest += OnHitTest; _window.Closed += OnWindowClosed; ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration); _icon = new Image { Margin = new Margin(6, 6, 6, 6), Brush = new TextureBrush(windowIcon), Color = Style.Current.Foreground, KeepAspectRatio = false, TooltipText = string.Format("{0}\nVersion {1}\nConfiguration {3}\nGraphics {2}", _window.Title, Globals.EngineVersion, GPUDevice.Instance.RendererType, configuration), Parent = this, }; _title = new Label(0, 0, Width, Height) { Text = _window.Title, HorizontalAlignment = TextAlignment.Center, VerticalAlignment = TextAlignment.Center, ClipText = true, TextColor = Style.Current.ForegroundGrey, TextColorHighlighted = Style.Current.ForegroundGrey, Parent = this, }; _closeButton = new Button { Text = ((char)EditorAssets.SegMDL2Icons.ChromeClose).ToString(), Font = new FontReference(iconFont), BackgroundColor = Color.Transparent, BorderColor = Color.Transparent, BorderColorHighlighted = Color.Transparent, BorderColorSelected = Color.Transparent, TextColor = Style.Current.Foreground, Width = 46, BackgroundColorHighlighted = Color.Red, BackgroundColorSelected = Color.Red.RGBMultiplied(1.3f), Parent = this, }; _closeButton.Clicked += () => _window.Close(ClosingReason.User); _minimizeButton = new Button { Text = ((char)EditorAssets.SegMDL2Icons.ChromeMinimize).ToString(), Font = new FontReference(iconFont), BackgroundColor = Color.Transparent, BorderColor = Color.Transparent, BorderColorHighlighted = Color.Transparent, BorderColorSelected = Color.Transparent, TextColor = Style.Current.Foreground, Width = 46, BackgroundColorHighlighted = Style.Current.LightBackground.RGBMultiplied(1.3f), Parent = this, }; _minimizeButton.Clicked += () => _window.Minimize(); _maximizeButton = new Button { Text = ((char)(_window.IsMaximized ? EditorAssets.SegMDL2Icons.ChromeRestore : EditorAssets.SegMDL2Icons.ChromeMaximize)).ToString(), Font = new FontReference(iconFont), BackgroundColor = Color.Transparent, BorderColor = Color.Transparent, BorderColorHighlighted = Color.Transparent, BorderColorSelected = Color.Transparent, TextColor = Style.Current.Foreground, Width = 46, BackgroundColorHighlighted = Style.Current.LightBackground.RGBMultiplied(1.3f), Parent = this, }; _maximizeButton.Clicked += () => { if (_window.IsMaximized) { _window.Restore(); } else { _window.Maximize(); } }; } else { BackgroundColor = Style.Current.LightBackground; } } /// public override void Update(float deltaTime) { base.Update(deltaTime); if (_maximizeButton != null) { _maximizeButton.Text = ((char)(_window.IsMaximized ? EditorAssets.SegMDL2Icons.ChromeRestore : EditorAssets.SegMDL2Icons.ChromeMaximize)).ToString(); } } private void OnWindowClosed() { if (_window != null) { _window.HitTest = null; _window = null; } } private WindowHitCodes OnHitTest(ref Vector2 mouse) { var pos = _window.ScreenToClient(mouse * Platform.DpiScale); if (_window.IsMinimized) return WindowHitCodes.NoWhere; if (!_window.IsMaximized) { var dpiScale = Platform.DpiScale; var winSize = RootWindow.Size * dpiScale; // Distance from which the mouse is considered to be on the border/corner float distance = 5.0f * dpiScale; if (pos.Y > winSize.Y - distance && pos.X < distance) return WindowHitCodes.BottomLeft; if (pos.X > winSize.X - distance && pos.Y > winSize.Y - distance) return WindowHitCodes.BottomRight; if (pos.Y < distance && pos.X < distance) return WindowHitCodes.TopLeft; if (pos.Y < distance && pos.X > winSize.X - distance) return WindowHitCodes.TopRight; if (pos.X > winSize.X - distance) return WindowHitCodes.Right; if (pos.X < distance) return WindowHitCodes.Left; if (pos.Y < distance) return WindowHitCodes.Top; if (pos.Y > winSize.Y - distance) return WindowHitCodes.Bottom; } var menuPos = PointFromWindow(pos); var controlUnderMouse = GetChildAt(menuPos); var isMouseOverSth = controlUnderMouse != null && controlUnderMouse != _title; var rb = GetRightButton(); if (rb != null && _minimizeButton != null && new Rectangle(rb.UpperRight * Platform.DpiScale, (_minimizeButton.BottomLeft - rb.UpperRight) * Platform.DpiScale).Contains(ref menuPos) && !isMouseOverSth) return WindowHitCodes.Caption; return WindowHitCodes.Client; } /// /// Return the rightmost button. /// /// Rightmost button, null if there is no private MainMenuButton GetRightButton() { MainMenuButton b = null; foreach (var control in Children) { if (b == null && control is MainMenuButton) b = (MainMenuButton)control; if (control is MainMenuButton && control.Right > b.Right) b = (MainMenuButton)control; } return b; } /// /// Adds the button. /// /// The button text. /// Created button control. public MainMenuButton AddButton(string text) { return AddChild(new MainMenuButton(text)); } /// /// Gets the button. /// /// The button text. /// The button or null if missing. public MainMenuButton GetButton(string text) { MainMenuButton result = null; for (int i = 0; i < Children.Count; i++) { if (Children[i] is MainMenuButton button && string.Equals(button.Text, text, StringComparison.OrdinalIgnoreCase)) { result = button; break; } } return result; } /// public override bool OnMouseDoubleClick(Vector2 location, MouseButton button) { if (base.OnMouseDoubleClick(location, button)) return true; if (_useCustomWindowSystem) { if (_window.IsMaximized) _window.Restore(); else _window.Maximize(); } return true; } /// protected override void PerformLayoutAfterChildren() { float x = 0; if (_useCustomWindowSystem) { // Icon _icon.X = x; _icon.Size = new Vector2(Height); x += _icon.Width; } // Arrange controls MainMenuButton rightMostButton = null; for (int i = 0; i < _children.Count; i++) { var c = _children[i]; if (c is MainMenuButton b && c.Visible) { b.Bounds = new Rectangle(x, 0, b.Width, Height); if (rightMostButton == null) rightMostButton = b; else if (rightMostButton.X < b.X) rightMostButton = b; x += b.Width; } } if (_useCustomWindowSystem) { // Buttons _closeButton.Height = Height; _closeButton.X = Width - _closeButton.Width; _maximizeButton.Height = Height; _maximizeButton.X = _closeButton.X - _maximizeButton.Width; _minimizeButton.Height = Height; _minimizeButton.X = _maximizeButton.X - _minimizeButton.Width; // Title _title.Bounds = new Rectangle(x + 2, 0, _minimizeButton.Left - x - 4, Height); //_title.Text = _title.Width < 300.0f ? Editor.Instance.ProjectInfo.Name : _window.Title; } } /// public override void OnDestroy() { base.OnDestroy(); if (_window != null) { _window.Closed -= OnWindowClosed; OnWindowClosed(); } } } }