385 lines
14 KiB
C#
385 lines
14 KiB
C#
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
|
|
|
using System;
|
|
using FlaxEngine;
|
|
using FlaxEngine.GUI;
|
|
|
|
namespace FlaxEditor.GUI
|
|
{
|
|
/// <summary>
|
|
/// Menu strip with child buttons.
|
|
/// </summary>
|
|
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
|
|
public sealed class MainMenu : ContainerControl
|
|
{
|
|
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
|
private bool _useCustomWindowSystem;
|
|
private Image _icon;
|
|
private Label _title;
|
|
private Button _closeButton;
|
|
private Button _minimizeButton;
|
|
private Button _maximizeButton;
|
|
private LocalizedString _charChromeRestore, _charChromeMaximize;
|
|
private Window _window;
|
|
#endif
|
|
private MainMenuButton _selected;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the selected button (with opened context menu).
|
|
/// </summary>
|
|
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 Float2(0, _selected.Height));
|
|
_selected.ContextMenu.VisibleChanged += OnSelectedContextMenuVisibleChanged;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnSelectedContextMenuVisibleChanged(Control control)
|
|
{
|
|
if (_selected != null)
|
|
Selected = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="MainMenu"/> class.
|
|
/// </summary>
|
|
/// <param name="mainWindow">The main window.</param>
|
|
public MainMenu(RootControl mainWindow)
|
|
: base(0, 0, 0, 20)
|
|
{
|
|
AutoFocus = false;
|
|
AnchorPreset = AnchorPresets.HorizontalStretchTop;
|
|
|
|
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
|
_useCustomWindowSystem = !Editor.Instance.Options.Options.Interface.UseNativeWindowSystem;
|
|
if (_useCustomWindowSystem)
|
|
{
|
|
BackgroundColor = Style.Current.LightBackground;
|
|
Height = 28;
|
|
|
|
var windowIcon = FlaxEngine.Content.LoadAsyncInternal<Texture>(EditorAssets.WindowIcon);
|
|
FontAsset windowIconsFont = FlaxEngine.Content.LoadAsyncInternal<FontAsset>(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();
|
|
};
|
|
_charChromeRestore = ((char)EditorAssets.SegMDL2Icons.ChromeRestore).ToString();
|
|
_charChromeMaximize = ((char)EditorAssets.SegMDL2Icons.ChromeMaximize).ToString();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
BackgroundColor = Style.Current.LightBackground;
|
|
}
|
|
}
|
|
|
|
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
|
/// <inheritdoc />
|
|
public override void Update(float deltaTime)
|
|
{
|
|
base.Update(deltaTime);
|
|
|
|
if (_maximizeButton != null)
|
|
{
|
|
_maximizeButton.Text = _window.IsMaximized ? _charChromeRestore : _charChromeMaximize;
|
|
}
|
|
}
|
|
|
|
private void OnWindowClosed()
|
|
{
|
|
if (_window != null)
|
|
{
|
|
_window.HitTest = null;
|
|
_window = null;
|
|
}
|
|
}
|
|
|
|
private WindowHitCodes OnHitTest(ref Float2 mouse)
|
|
{
|
|
var dpiScale = _window.DpiScale;
|
|
|
|
if (_window.IsMinimized)
|
|
return WindowHitCodes.NoWhere;
|
|
|
|
if (!_window.IsMaximized)
|
|
{
|
|
var pos = _window.ScreenToClient(mouse * dpiScale); // pos is not DPI adjusted
|
|
var winSize = _window.Size;
|
|
|
|
// 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 mousePos = PointFromScreen(mouse * dpiScale);
|
|
var controlUnderMouse = GetChildAt(mousePos);
|
|
var isMouseOverSth = controlUnderMouse != null && controlUnderMouse != _title;
|
|
var rb = GetRightButton();
|
|
if (rb != null && _minimizeButton != null && new Rectangle(rb.UpperRight, _minimizeButton.BottomLeft - rb.UpperRight).Contains(ref mousePos) && !isMouseOverSth)
|
|
return WindowHitCodes.Caption;
|
|
|
|
return WindowHitCodes.Client;
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Return the rightmost button.
|
|
/// </summary>
|
|
/// <returns>Rightmost button, null if there is no <see cref="MainMenuButton"/></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the button.
|
|
/// </summary>
|
|
/// <param name="text">The button text.</param>
|
|
/// <returns>Created button control.</returns>
|
|
public MainMenuButton AddButton(string text)
|
|
{
|
|
return AddChild(new MainMenuButton(text));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the button.
|
|
/// </summary>
|
|
/// <param name="text">The button text.</param>
|
|
/// <returns>The button or null if missing.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
|
{
|
|
if (base.OnMouseDoubleClick(location, button))
|
|
return true;
|
|
|
|
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
|
var child = GetChildAtRecursive(location);
|
|
if (_useCustomWindowSystem && child is not Button && child is not MainMenuButton)
|
|
{
|
|
if (_window.IsMaximized)
|
|
_window.Restore();
|
|
else
|
|
_window.Maximize();
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override bool OnKeyDown(KeyboardKeys key)
|
|
{
|
|
if (base.OnKeyDown(key))
|
|
return true;
|
|
|
|
// Fallback to the edit window for shortcuts
|
|
var editor = Editor.Instance;
|
|
return editor.Windows.EditWin.InputActions.Process(editor, this, key);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void PerformLayoutAfterChildren()
|
|
{
|
|
float x = 0;
|
|
|
|
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
|
if (_useCustomWindowSystem)
|
|
{
|
|
// Icon
|
|
_icon.X = x;
|
|
_icon.Size = new Float2(Height);
|
|
x += _icon.Width;
|
|
}
|
|
#endif
|
|
|
|
// 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 PLATFORM_WINDOWS || PLATFORM_SDL
|
|
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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
|
/// <inheritdoc />
|
|
public override void OnDestroy()
|
|
{
|
|
base.OnDestroy();
|
|
|
|
if (_window != null)
|
|
{
|
|
_window.Closed -= OnWindowClosed;
|
|
OnWindowClosed();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|