Editor/GlobalPieMenu.cs
using System;
using System.Linq;
using System.Threading.Tasks;
using static Editor.EditorEvent;
namespace Editor;
/// <summary>
/// Global pie menu helper for mesh editing modes
/// </summary>
public static class GlobalPieMenu
{
static PieMenu _currentMenu;
static bool _wasButtonPressed = false;
static bool _wasMappingButtonPressed = false;
[EditorEvent.Hotload]
public static void ShowPieMenu()
{
Log.Info( "ShowPieMenu called" );
// If menu is already open, close it
if ( _currentMenu != null && _currentMenu.IsValid() )
{
_currentMenu.Close();
_currentMenu = null;
return;
}
_currentMenu = new PieMenu();
_currentMenu.TriggerButton = MappingToolSettings.PieMenuButton;
_currentMenu.Radius = MappingToolSettings.PieMenuSize;
BuildDefaultPieMenu( _currentMenu );
_currentMenu.OpenAtCursor();
}
[EditorEvent.Hotload]
public static void ShowMappingPieMenu()
{
Log.Info( "ShowMappingPieMenu called" );
// If menu is already open, close it
if ( _currentMenu != null && _currentMenu.IsValid() )
{
_currentMenu.Close();
_currentMenu = null;
return;
}
_currentMenu = new PieMenu();
_currentMenu.TriggerButton = MappingToolSettings.MappingPieMenuButton;
_currentMenu.Radius = MappingToolSettings.MappingPieMenuSize;
BuildMappingPieMenu( _currentMenu );
_currentMenu.OpenAtCursor();
}
[EditorEvent.Frame]
public static void OnFrame()
{
// Render Pie Menu
var configuredButton = MappingToolSettings.PieMenuButton;
bool isButtonPressed = Application.MouseButtons.HasFlag( configuredButton );
bool modifierRequirementMet = true;
if ( MappingToolSettings.PieMenuUseModifier )
{
var modifierKey = MappingToolSettings.PieMenuModifierKey;
modifierRequirementMet = Application.IsKeyDown( modifierKey );
}
if ( isButtonPressed && !_wasButtonPressed && !Game.IsPlaying && modifierRequirementMet )
{
ShowPieMenu();
}
else if ( !isButtonPressed && _wasButtonPressed )
{
if ( _currentMenu != null && _currentMenu.IsValid() )
{
_currentMenu = null;
}
}
_wasButtonPressed = isButtonPressed;
// Mapping Pie Menu
var mappingButton = MappingToolSettings.MappingPieMenuButton;
bool isMappingButtonPressed = Application.MouseButtons.HasFlag( mappingButton );
bool mappingModifierMet = true;
if ( MappingToolSettings.MappingPieMenuUseModifier )
{
var mappingModifierKey = MappingToolSettings.MappingPieMenuModifierKey;
mappingModifierMet = Application.IsKeyDown( mappingModifierKey );
}
if ( isMappingButtonPressed && !_wasMappingButtonPressed && !Game.IsPlaying && mappingModifierMet )
{
ShowMappingPieMenu();
}
else if ( !isMappingButtonPressed && _wasMappingButtonPressed )
{
if ( _currentMenu != null && _currentMenu.IsValid() )
{
_currentMenu = null;
}
}
_wasMappingButtonPressed = isMappingButtonPressed;
}
static void BuildDefaultPieMenu( PieMenu menu )
{
// Get active scene viewport if available
var viewport = GetActiveSceneViewport();
if ( viewport != null )
{
// Scene viewport options
menu.AddOption( "Normal View", "visibility", () =>
{
if ( viewport.State.RenderMode != SceneCameraDebugMode.Normal )
viewport.State.RenderMode = SceneCameraDebugMode.Normal;
} );
menu.AddOption( "Full Bright", "lightbulb", () =>
{
viewport.State.RenderMode = viewport.State.RenderMode != SceneCameraDebugMode.FullBright
? SceneCameraDebugMode.FullBright
: SceneCameraDebugMode.Normal;
} );
menu.AddOption( "Diffuse", "wb_sunny", () =>
{
viewport.State.RenderMode = viewport.State.RenderMode != SceneCameraDebugMode.Diffuse
? SceneCameraDebugMode.Diffuse
: SceneCameraDebugMode.Normal;
} );
menu.AddOption( "Albedo", "texture", () =>
{
viewport.State.RenderMode = viewport.State.RenderMode != SceneCameraDebugMode.Albedo
? SceneCameraDebugMode.Albedo
: SceneCameraDebugMode.Normal;
} );
menu.AddOption( "AO", "blur_circular", () =>
{
viewport.State.RenderMode = viewport.State.RenderMode != SceneCameraDebugMode.AmbientOcclusion
? SceneCameraDebugMode.AmbientOcclusion
: SceneCameraDebugMode.Normal;
} );
menu.AddOption( "Post-Processing", "photo_filter", () =>
{
viewport.State.EnablePostProcessing = !viewport.State.EnablePostProcessing;
} );
menu.AddOption( "Align To Scene Camera", "three_d_rotation", () =>
{
if ( !SceneViewWidget.Current.Session.Scene.IsValid() )
return;
var sceneCam = SceneViewWidget.Current.Session.Scene.Scene.Camera;
if ( !sceneCam.IsValid() )
return;
viewport.State.CameraPosition = sceneCam.WorldPosition;
viewport.State.CameraRotation = sceneCam.WorldRotation;
} );
}
}
static void BuildMappingPieMenu( PieMenu menu )
{
// Object Mode (MeshSelection)
menu.AddOption( "Mesh", "view_in_ar", () =>
{
_ = SwitchToModeAsync( "MeshSelection", "Object" );
} );
// Vertex Mode
menu.AddOption( "Vertex", "push_pin", () =>
{
_ = SwitchToModeAsync( "VertexTool", "Vertex" );
} );
// Edge Mode
menu.AddOption( "Edge", "timeline", () =>
{
_ = SwitchToModeAsync( "EdgeTool", "Edge" );
} );
// Face Mode
menu.AddOption( "Face", "crop_square", () =>
{
_ = SwitchToModeAsync( "FaceTool", "Face" );
} );
}
static async Task SwitchToModeAsync( string toolName, string displayName )
{
var meshTool = GetActiveMeshTool();
bool toolWasActivated = false;
// Activate mesh tool if not active
if ( meshTool == null )
{
EditorToolManager.SetTool( "MeshTool" );
toolWasActivated = true;
// Wait a bit for tool initialization
await Task.Delay( 50 );
meshTool = GetActiveMeshTool();
if ( meshTool == null )
{
Log.Warning( "Failed to activate Mesh Tool" );
return;
}
}
// Get the subtools
var tools = meshTool.Tools.ToList();
// If tools list is empty and we just activated, wait a bit longer
if ( tools.Count == 0 && toolWasActivated )
{
await Task.Delay( 50 );
tools = meshTool.Tools.ToList();
}
// Find the target tool
var targetTool = tools.FirstOrDefault( t => t.GetType().Name == toolName );
if ( targetTool != null )
{
meshTool.CurrentTool = targetTool;
}
else
{
Log.Warning( $"Could not find {toolName} in mesh tool subtools" );
}
}
static SceneViewportWidget GetActiveSceneViewport()
{
// Try to find the currently focused scene viewport
var focusedWidget = Application.FocusWidget;
// Walk up the parent chain to find a SceneViewportWidget
var widget = focusedWidget;
while ( widget != null )
{
if ( widget is SceneViewportWidget viewport )
return viewport;
widget = widget.Parent;
}
return null;
}
static Editor.MeshEditor.MeshTool GetActiveMeshTool()
{
var sceneView = SceneViewWidget.Current;
if ( sceneView?.Tools?.CurrentTool is Editor.MeshEditor.MeshTool meshTool )
{
return meshTool;
}
return null;
}
}