Window Framework v1.2.4
Window Framework for Unity UI Toolkit
Loading...
Searching...
No Matches
GWG.WindowFramework.WindowFrameContextMenu Class Reference

A sophisticated context menu implementation for the Window Framework that provides dynamic menu creation with fade animations and intelligent positioning. More...

Inheritance diagram for GWG.WindowFramework.WindowFrameContextMenu:

Public Member Functions

void Show (Vector2 mousePosition, ContextMenuConfig config, VisualElement target, Action onClose, bool selfAdd=true)
 Displays the context menu at the specified position with the given configuration and event handlers.

Private Member Functions

VisualElement AddMenuItem (string text, bool isChecked, bool isDisabled, Action action=null)
 Creates a menu item element with the specified properties and behavior.
void FadeAndRemove ()
 Initiates the fade-out animation sequence and schedules menu removal.
void RemoveNow ()
 Immediately removes the context menu from the visual hierarchy and performs complete cleanup.
void SetDisabledForFade ()
 Disables all menu items to prevent interaction during the fade-out animation.

Private Attributes

float _delay
 The delay in seconds before the fade-out animation begins after the mouse leaves the menu area.
float _fadeTime
 The duration in seconds for the fade-out animation effect.
IVisualElementScheduledItem _task
 Reference to the scheduled task managing fade-out animation and menu removal.

Detailed Description

WindowFrameContextMenu is a specialized VisualElement that creates contextual menus with advanced features:

Key Features:

  • Dynamic menu item generation from configuration objects
  • Intelligent positioning with boundary detection and adjustment
  • Smooth fade-out animations with configurable timing
  • Support for menu titles, separators, and disabled items
  • Checkbox/checkmark display for toggleable options
  • Automatic cleanup and memory management
  • Integration with WindowFrameController theming system
  • Mouse and keyboard event handling for proper dismissal
  • Editor and runtime compatibility with different positioning logic

Menu Structure: The context menu consists of a wrapper container that holds:

  • Optional title label
  • Menu items with labels and optional checkmarks
  • Visual separators between logical groups
  • "No options available" fallback when no items are visible

Animation System:

  • Immediate appearance when shown
  • Configurable fade-out delay after mouse leaves menu area
  • Frame-accurate fade-out animation using Unity's scheduler
  • Automatic removal when fade completes or immediate dismissal on click

Event Handling: The menu responds to various events for natural user interaction:

  • MouseLeave/MouseLeaveWindow: Initiates fade-out sequence
  • NavigationCancel: Immediate dismissal (Escape key)
  • PointerDown: Immediate dismissal when clicking outside
  • Individual item clicks execute actions and dismiss menu

Integration: Works seamlessly with ContextMenuConfig objects and ContextMenuActivator manipulators to provide a complete context menu system.

// Basic context menu usage with ContextMenuActivator
var menuConfig = new ContextMenuConfig
{
Title = "Options"
};
menuConfig.AddItem("Copy", () => Debug.Log("Copy"), enabled: true);
menuConfig.AddItem("Paste", () => Debug.Log("Paste"), enabled: CanPaste());
menuConfig.AddSeparator();
menuConfig.AddItem("Delete", () => Debug.Log("Delete"), enabled: true);
var button = new Button("Right-click me");
button.AddManipulator(new ContextMenuActivator(menuConfig));
// Manual context menu creation and display
var contextMenu = new WindowFrameContextMenu();
var mousePos = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
contextMenu.Show(mousePos, menuConfig, targetElement, () => {
Debug.Log("Context menu closed");
});
// Advanced menu with conditional items
var advancedConfig = new ContextMenuConfig();
advancedConfig.AddItem("Edit", StartEdit, enabled: CanEdit);
advancedConfig.AddItem("Save", SaveChanges, enabled: HasChanges);
advancedConfig.AddToggleItem("Lock", ToggleLock, isChecked: IsLocked);
advancedConfig.AddSeparator();
advancedConfig.AddSubmenu("Advanced", subMenu => {
subMenu.AddItem("Reset", ResetToDefaults);
subMenu.AddItem("Export", ExportData);
});
// Context menu with dynamic content
var dynamicConfig = new ContextMenuConfig();
foreach (var tool in availableTools)
{
dynamicConfig.AddItem(tool.Name, () => SelectTool(tool),
enabled: tool.IsAvailable(),
isChecked: currentTool == tool);
}
complexElement.AddManipulator(new ContextMenuActivator(dynamicConfig));
Configuration class for a runtime context menu.
Definition ContextMenuConfig.cs:22
A sophisticated context menu implementation for the Window Framework that provides dynamic menu creat...
Definition WindowFrameContextMenu.cs:94

Member Function Documentation

◆ AddMenuItem()

VisualElement GWG.WindowFramework.WindowFrameContextMenu.AddMenuItem ( string text,
bool isChecked,
bool isDisabled,
Action action = null )
private
Parameters
textThe display text for the menu item
isCheckedWhether to display a checkmark next to the item
isDisabledWhether the item should appear disabled and non-interactive
actionThe action to execute when the item is clicked (null for disabled items)
Returns
A VisualElement representing the complete menu item with label and optional checkmark

This method creates a structured menu item with the following components:

Item Structure:

  • Wrapper container with flex row layout for horizontal arrangement
  • Label element displaying the menu item text
  • Checkbox element for visual indication of checked state

Visual States:

  • Normal: Interactive item with hover and click responses
  • Disabled: Grayed out appearance with no interaction capability
  • Checked: Visible checkmark indicator for toggle states
  • Unchecked: Hidden checkmark for normal menu items

Event Handling:

  • Registers PointerDownEvent for enabled items only
  • Executes provided action and dismisses menu on click
  • Uses TrickleDown.NoTrickleDown for precise event targeting

CSS Classes:

  • "context-menu__item": Applied to the wrapper for styling
  • "context-menu__item-disabled": Applied when item is disabled
  • "context-menu__item-label": Applied to the text label
  • "context-menu__item-checked-box": Applied to the checkmark element

The method provides a consistent visual structure while allowing flexible content and behavior through the configuration parameters.

// AddMenuItem is used internally by Show() method
// Examples of different menu item types created:
// Standard clickable item
var normalItem = AddMenuItem("Save File", false, false, () => SaveCurrentFile());
// Result: Clickable "Save File" item with no checkmark
// Checked toggle item
var checkedItem = AddMenuItem("Auto Save", true, false, () => ToggleAutoSave());
// Result: Clickable "Auto Save" item with visible checkmark
// Disabled item
var disabledItem = AddMenuItem("Undo", false, true, null);
// Result: Non-clickable "Undo" item with disabled appearance
// Complex item with conditional logic
var complexItem = AddMenuItem(
text: GetDynamicItemText(),
isChecked: IsFeatureEnabled(),
isDisabled: !CanExecuteAction(),
action: () => {
if (ConfirmAction())
{
ExecuteComplexAction();
RefreshUI();
}
}
);
// The created structure:
// ContextMenuItem (wrapper)
// ├── ContextMenuItemLabel (text)
// └── ContextMenuItemCheckedBox (checkmark, visible if checked)
VisualElement AddMenuItem(string text, bool isChecked, bool isDisabled, Action action=null)
Creates a menu item element with the specified properties and behavior.
Definition WindowFrameContextMenu.cs:441

◆ FadeAndRemove()

void GWG.WindowFramework.WindowFrameContextMenu.FadeAndRemove ( )
private

This method manages the graceful dismissal of the context menu through a two-stage process:

Stage 1 - Delay Phase:

  • Schedules the fade sequence to begin after the configured delay period
  • Allows users time to return cursor to menu if accidentally moved outside
  • Uses _delay field value (from WindowFrameController.ContextMenuFadeDelay)

Stage 2 - Fade Phase:

  • Disables menu interactions to prevent actions during fade
  • Performs frame-accurate opacity reduction using Unity's scheduler
  • Monitors opacity level and removes menu when fade completes
  • Falls back to immediate removal if fade time is zero or disabled

Animation Details:

  • Uses unscaled delta time for consistent behavior regardless of time scale
  • Executes every frame (Every(0)) for smooth visual transition
  • Continues Until opacity reaches zero, then triggers final cleanup
  • Handles edge cases where resolvedStyle.visibility is already hidden

The method ensures that users have adequate time to re-engage with the menu while providing smooth visual feedback when dismissal is inevitable.

// FadeAndRemove is called automatically by event handlers
// No direct invocation required in normal usage
// Automatic triggering scenarios:
// 1. User moves mouse outside menu area
// → MouseLeaveEvent → FadeAndRemove()
// → Delay period → Fade animation → Menu removal
// 2. User moves mouse outside application window
// → MouseLeaveWindowEvent → FadeAndRemove()
// → Same fade sequence as mouse leave
// Fade behavior examples based on settings:
// Fast fade configuration
// _delay = 0.2f, _fadeTime = 0.3f
// Result: 200ms delay, then 300ms fade-out
// Slow fade configuration
// _delay = 1.0f, _fadeTime = 0.8f
// Result: 1000ms delay, then 800ms fade-out
// Immediate dismissal configuration
// _delay = 0.0f, _fadeTime = 0.0f
// Result: Instant removal without fade
// The fade progression:
// Time 0: Mouse leaves menu, delay timer starts
// Time _delay: Fade animation begins, interactions disabled
// Time _delay + _fadeTime: Menu fully transparent and removed

◆ RemoveNow()

void GWG.WindowFramework.WindowFrameContextMenu.RemoveNow ( )
private

This method provides instant menu dismissal with comprehensive cleanup operations:

Animation Cleanup:

  • Pauses any active fade animation tasks to prevent continued execution
  • Clears the task reference to prevent memory leaks
  • Stops all scheduled operations related to menu timing

Event Cleanup:

  • Unregisters all event callbacks to prevent orphaned event handlers
  • Clears MouseLeave, MouseLeaveWindow, NavigationCancel, and PointerDown events
  • Ensures proper cleanup for memory management

Hierarchy Management:

  • Removes the menu from its parent container immediately
  • Cleans up visual tree references and parent-child relationships
  • Prevents visual artifacts or lingering UI elements

Window Management Integration:

  • Updates WindowFrameController active window state when in play mode
  • Ensures proper window focus management after menu dismissal
  • Maintains consistent UI state across the application

This method is used for immediate dismissal scenarios such as menu item clicks, Escape key presses, or outside clicks where fade animations would be inappropriate.

// RemoveNow is called automatically in several scenarios:
// Immediate dismissal scenarios:
// 1. User clicks a menu item
// → Item action executes → RemoveNow() → Menu disappears instantly
// 2. User presses Escape key
// → NavigationCancelEvent → RemoveNow() → Menu disappears instantly
// 3. User clicks outside menu area
// → PointerDownEvent → RemoveNow() → Menu disappears instantly
// 4. Fade animation completes
// → FadeAndRemove() fade complete → RemoveNow() → Final cleanup
// Manual usage for custom dismissal logic:
void OnCustomCondition()
{
if (shouldDismissImmediately)
{
contextMenu.RemoveNow(); // If method were public
}
}
// Comparison with fade dismissal:
// Graceful dismissal (mouse leave):
// 1. Mouse leaves menu area
// 2. Delay period (user can return)
// 3. Fade animation (visual feedback)
// 4. RemoveNow() (final cleanup)
// Immediate dismissal (item click):
// 1. User clicks menu item
// 2. RemoveNow() immediately (no delay or fade)
// 3. Clean removal for responsive interaction

◆ SetDisabledForFade()

void GWG.WindowFramework.WindowFrameContextMenu.SetDisabledForFade ( )
private

This method ensures that users cannot accidentally trigger menu actions while the menu is fading out, preventing unintended operations and maintaining clean visual feedback:

Disabling Process:

  • Iterates through all child elements of the context menu
  • Adds "context-menu__item-disabled" CSS class for visual feedback
  • Calls SetEnabled(false) to disable UI interaction capability

Visual Effect:

  • Menu items appear grayed out or dimmed during fade
  • Cursor changes to indicate non-interactive state
  • Maintains visual hierarchy while preventing input

Scope:

  • Applies to all menu items, separators, and labels
  • Does not affect the fade animation itself
  • Prevents both mouse and keyboard interactions

This ensures a professional fade-out experience where visual feedback clearly indicates that the menu is no longer interactive.

// SetDisabledForFade is called automatically during fade sequence
// No manual invocation required
// Effect on different menu elements:
// Before fade (interactive):
// ├── "Copy" item - clickable, normal appearance
// ├── "Paste" item - clickable, normal appearance
// ├── Separator - visual divider
// └── "Delete" item - clickable, normal appearance
// After SetDisabledForFade (during fade):
// ├── "Copy" item - non-clickable, disabled appearance
// ├── "Paste" item - non-clickable, disabled appearance
// ├── Separator - disabled appearance
// └── "Delete" item - non-clickable, disabled appearance
// CSS classes applied during fade:
// .context-menu__item-disabled {
// opacity: 0.5;
// cursor: not-allowed;
// pointer-events: none;
// }
// The disabling prevents scenarios like:
// - User rapidly clicking during fade accidentally triggering actions
// - Keyboard navigation selecting items during fade animation
// - Hover effects interfering with fade visual progression

◆ Show()

void GWG.WindowFramework.WindowFrameContextMenu.Show ( Vector2 mousePosition,
ContextMenuConfig config,
VisualElement target,
Action onClose,
bool selfAdd = true )
Parameters
mousePositionThe screen coordinates where the context menu should appear
configConfiguration object containing menu structure, items, and behaviors
targetThe VisualElement that triggered the context menu display
onCloseCallback function executed when the menu is dismissed
selfAddIf true, automatically adds the menu to the WindowFrameController's root element

This method orchestrates the complete context menu display process with sophisticated positioning and configuration logic:

Container Management:

  • Determines appropriate root container (WindowFrameController.UIRoot or target panel)
  • Removes any existing context menu to prevent duplicates
  • Optionally adds itself to the container hierarchy

Event Registration:

  • MouseLeave/MouseLeaveWindow: Triggers fade-out sequence
  • NavigationCancel: Immediate dismissal (Escape key support)
  • PointerDown: Immediate dismissal on outside clicks

Menu Structure Creation:

  • Creates wrapper container with appropriate styling classes
  • Adds optional title if specified in configuration
  • Processes all menu items with visibility, state, and action handling
  • Adds separators and handles empty menu scenarios

Theming and Positioning:

  • Applies current theme stylesheets from WindowFrameController
  • Calculates optimal position considering target bounds and screen boundaries
  • Adjusts position to ensure menu remains fully visible
  • Handles both runtime and editor positioning scenarios

The method provides intelligent defaults while allowing full customization through the configuration object and callback parameters.

// Basic context menu display
var menu = new WindowFrameContextMenu();
var config = new ContextMenuConfig();
config.AddItem("Option 1", () => Debug.Log("Selected Option 1"));
menu.Show(Input.mousePosition, config, targetButton, () => {
Debug.Log("Menu closed");
});
// Advanced context menu with custom positioning
var advancedMenu = new WindowFrameContextMenu();
var advancedConfig = new ContextMenuConfig { Title = "Advanced Options" };
advancedConfig.AddItem("Edit", EditItem, enabled: CanEdit());
advancedConfig.AddItem("Delete", DeleteItem, enabled: CanDelete());
advancedConfig.AddSeparator();
advancedConfig.AddItem("Properties", ShowProperties);
// Show at specific screen coordinates
Vector2 customPosition = new Vector2(200, 300);
advancedMenu.Show(customPosition, advancedConfig, sourceElement,
onClose: () => RefreshUI(),
selfAdd: true);
// Context menu with dynamic content based on selection
var dynamicMenu = new WindowFrameContextMenu();
var dynamicConfig = new ContextMenuConfig();
if (selectedItems.Count == 1)
{
dynamicConfig.AddItem("Rename", RenameItem);
dynamicConfig.AddItem("Duplicate", DuplicateItem);
}
else if (selectedItems.Count > 1)
{
dynamicConfig.AddItem($"Delete {selectedItems.Count} items", DeleteSelected);
dynamicConfig.AddItem("Group", GroupSelected);
}
dynamicMenu.Show(eventPosition, dynamicConfig, selectionPanel, UpdateSelection);
// Menu positioning relative to UI elements
var relativeMenu = new WindowFrameContextMenu();
var elementBounds = triggerElement.worldBound;
var menuPosition = new Vector2(elementBounds.xMax, elementBounds.yMin);
relativeMenu.Show(menuPosition, menuConfig, triggerElement, null, false);
customContainer.Add(relativeMenu); // Manual container management

Member Data Documentation

◆ _delay

float GWG.WindowFramework.WindowFrameContextMenu._delay
private

This value is retrieved from WindowFrameController.ContextMenuFadeDelay during menu display and provides users time to return their cursor to the menu before it starts fading away. This prevents accidental menu dismissal during cursor movements between menu items.

◆ _fadeTime

float GWG.WindowFramework.WindowFrameContextMenu._fadeTime
private

This value is retrieved from WindowFrameController.ContextMenuFadeTime during menu display and cached for consistent animation behavior throughout the menu's lifecycle. A value of 0 results in instant disappearance without fade animation.

◆ _task

IVisualElementScheduledItem GWG.WindowFramework.WindowFrameContextMenu._task
private

This task handles the timing and execution of fade-out effects and final menu removal. It can be paused or canceled when immediate menu dismissal is required, such as when the user clicks a menu item or presses the Escape key.