void CheckMenuColliderOverlaps(IMenu menu, MenuHideData menuHideData) { var menuBounds = menu.localBounds; if (menuBounds.extents == Vector3.zero) { return; } Array.Clear(k_ColliderOverlaps, 0, k_ColliderOverlaps.Length); var hoveringCollider = false; var menuTransform = menu.menuContent.transform; var menuRotation = menuTransform.rotation; var viewerScale = this.GetViewerScale(); var center = menuTransform.position + menuRotation * menuBounds.center * viewerScale; if (Physics.OverlapBoxNonAlloc(center, menuBounds.extents * viewerScale, k_ColliderOverlaps, menuRotation) > 0) { foreach (var overlap in k_ColliderOverlaps) { if (overlap) { k_WorkspaceComponents.Clear(); overlap.GetComponents(k_WorkspaceComponents); if (k_WorkspaceComponents.Count > 0) { hoveringCollider = true; } if (menu is MainMenu) { k_ButtonComponents.Clear(); overlap.GetComponents(k_ButtonComponents); if (k_ButtonComponents.Count > 0) { hoveringCollider = true; } } } } } // Only set if hidden--value is reset every frame if (hoveringCollider) { menuHideData.hideFlags |= MenuHideFlags.OverWorkspace; } }
void AddAlternateMenu(IAlternateMenu alternateMenu, Transform rayOrigin) { if (m_ToolModule == null) { return; } foreach (var device in m_ToolModule.deviceData) { if (device.rayOrigin != rayOrigin) { continue; } device.alternateMenus.Add(alternateMenu); var menuHideData = new MenuHideData(); device.menuHideData[alternateMenu] = menuHideData; // Alternate menus must be visible the first frame or they are ignored in the priority list menuHideData.hideFlags = 0; break; } }
internal void SpawnDefaultTools(IProxy proxy) { var defaultTools = EditorXR.DefaultTools; if (defaultTools == null) { return; } var moduleLoaderCore = ModuleLoaderCore.instance; var menuModule = moduleLoaderCore.GetModule <EditorXRMenuModule>(); var lockModule = moduleLoaderCore.GetModule <LockModule>(); var deviceInputModule = moduleLoaderCore.GetModule <DeviceInputModule>(); var vacuumablesModule = moduleLoaderCore.GetModule <EditorXRVacuumableModule>(); var vacuumables = vacuumablesModule != null ? vacuumablesModule.vacuumables : new List <IVacuumable>(); foreach (var device in deviceData) { var inputDevice = device.inputDevice; ToolData selectionToolData = null; if (device.proxy != proxy) { continue; } var rayOrigin = device.rayOrigin; foreach (var toolType in defaultTools) { HashSet <InputDevice> devices; var toolData = SpawnTool(toolType, out devices, inputDevice, rayOrigin, deviceInputModule); AddToolToDeviceData(toolData, devices); var tool = toolData.tool; var selectionTool = tool as SelectionTool; if (selectionTool) { selectionToolData = toolData; if (lockModule != null) { selectionTool.hovered += lockModule.OnHovered; } } var vacuumTool = tool as VacuumTool; if (vacuumTool) { vacuumTool.defaultOffset = WorkspaceModule.DefaultWorkspaceOffset; vacuumTool.defaultTilt = WorkspaceModule.DefaultWorkspaceTilt; vacuumTool.vacuumables = vacuumables; } } IMainMenu mainMenu; var menuHideData = device.menuHideData; if (EditorXR.DefaultMenu != null) { mainMenu = (IMainMenu)menuModule.SpawnMenu(EditorXR.DefaultMenu, rayOrigin); device.mainMenu = mainMenu; menuHideData[mainMenu] = new MenuHideData(); } if (EditorXR.DefaultAlternateMenu != null) { var alternateMenu = (IAlternateMenu)menuModule.SpawnMenu(EditorXR.DefaultAlternateMenu, rayOrigin); menuHideData[alternateMenu] = new MenuHideData(); var radialMenu = alternateMenu as RadialMenu; if (radialMenu) { radialMenu.itemWasSelected += menuModule.UpdateAlternateMenuOnSelectionChanged; } } var undoMenu = menuModule.SpawnMenu <UndoMenu>(rayOrigin); var hideData = new MenuHideData(); menuHideData[undoMenu] = hideData; hideData.hideFlags = 0; // Setup ToolsMenu ToolsMenu toolsMenu = null; var toolsMenus = gameObject.GetComponents <ToolsMenu>(); foreach (var m in toolsMenus) { if (!m.enabled) { toolsMenu = m; break; } } if (!toolsMenu) { toolsMenu = EditorXRUtils.AddComponent <ToolsMenu>(gameObject); } toolsMenu.enabled = true; this.ConnectInterfaces(toolsMenu, rayOrigin); this.InjectFunctionalitySingle(toolsMenu); device.toolsMenu = toolsMenu; toolsMenu.rayOrigin = rayOrigin; toolsMenu.setButtonForType(typeof(IMainMenu), null); toolsMenu.setButtonForType(typeof(SelectionTool), selectionToolData != null ? selectionToolData.icon : null); var spatialMenu = EditorXRUtils.AddComponent <SpatialMenu>(gameObject); this.ConnectInterfaces(spatialMenu, rayOrigin); this.InjectFunctionalitySingle(spatialMenu); spatialMenu.Setup(); device.spatialMenu = spatialMenu; } if (deviceInputModule != null) { deviceInputModule.UpdatePlayerHandleMaps(); } }
internal void UpdateMenuVisibilities() { k_ActiveDeviceData.Clear(); m_RayModule.ForEachProxyDevice(deviceData => { k_ActiveDeviceData.Add(deviceData); }); foreach (var deviceData in k_ActiveDeviceData) { IAlternateMenu alternateMenu = null; var menuHideData = deviceData.menuHideData; // Always display the highest-priority alternate menu, and hide all others. var alternateMenus = deviceData.alternateMenus; foreach (var menu in alternateMenus) { var hideData = menuHideData[menu]; if ((hideData.hideFlags & MenuHideFlags.Hidden) == 0 && (alternateMenu == null || menu.priority >= alternateMenu.priority)) { alternateMenu = menu; } hideData.hideFlags |= MenuHideFlags.OtherMenu; } deviceData.alternateMenu = alternateMenu; menuHideData[alternateMenu].hideFlags = 0; var mainMenu = deviceData.mainMenu; var customMenu = deviceData.customMenu; MenuHideData customMenuHideData = null; var mainMenuVisible = mainMenu != null && menuHideData[mainMenu].hideFlags == 0; var mainMenuSuppressed = mainMenu != null && ((menuHideData[mainMenu].hideFlags & MenuHideFlags.Occluded) != 0); var alternateMenuData = menuHideData[alternateMenu]; var alternateMenuVisible = alternateMenuData.hideFlags == 0; var customMenuVisible = false; if (customMenu != null) { customMenuHideData = menuHideData[customMenu]; customMenuVisible = customMenuHideData.hideFlags == 0; } // Temporarily hide customMenu if other menus are visible or should be if (customMenuVisible && (mainMenuVisible || mainMenuSuppressed)) { customMenuHideData.hideFlags |= MenuHideFlags.OtherMenu; } // Kick the alternate menu to the other hand if a main menu or custom menu is visible if (alternateMenuVisible && (mainMenuVisible || customMenuVisible) && alternateMenu is RadialMenu) { foreach (var otherDeviceData in k_ActiveDeviceData) { if (otherDeviceData == deviceData) { continue; } SetAlternateMenuVisibility(otherDeviceData.rayOrigin, true); break; } } // Check if menu bounds overlap with any workspace colliders foreach (var kvp in menuHideData) { CheckMenuColliderOverlaps(kvp.Key, kvp.Value); } // Check if there are currently any held objects, or if the other hand is in proximity for scaling CheckDirectSelection(deviceData, menuHideData, alternateMenuVisible); } // Set show/hide timings foreach (var deviceData in k_ActiveDeviceData) { foreach (var kvp in deviceData.menuHideData) { var hideFlags = kvp.Value.hideFlags; if ((hideFlags & ~MenuHideFlags.Hidden & ~MenuHideFlags.OtherMenu) == 0) { kvp.Value.autoHideTime = Time.time; } if (hideFlags != 0) { var menuHideData = kvp.Value; menuHideData.lastHideFlags = menuHideData.hideFlags; kvp.Value.autoShowTime = Time.time; } } } // Apply MenuHideFlags to UI visibility foreach (var deviceData in k_ActiveDeviceData) { var mainMenu = deviceData.mainMenu; if (mainMenu != null) { var mainMenuHideData = deviceData.menuHideData[mainMenu]; var mainMenuHideFlags = mainMenuHideData.hideFlags; var lastMainMenuHideFlags = mainMenuHideData.lastHideFlags; var permanentlyHidden = (mainMenuHideFlags & MenuHideFlags.Hidden) != 0; var wasPermanentlyHidden = (lastMainMenuHideFlags & MenuHideFlags.Hidden) != 0; //Temporary states take effect after a delay var temporarilyHidden = (mainMenuHideFlags & MenuHideFlags.Temporary) != 0 && Time.time > mainMenuHideData.autoHideTime + k_MainMenuAutoHideDelay; var wasTemporarilyHidden = (lastMainMenuHideFlags & MenuHideFlags.Temporary) != 0 && Time.time > mainMenuHideData.autoShowTime + k_MainMenuAutoShowDelay; // If the menu is focused, only hide if Hidden is set (e.g. not temporary) in order to hide the selected tool if (permanentlyHidden || wasPermanentlyHidden || !mainMenu.focus && (temporarilyHidden || wasTemporarilyHidden)) { mainMenu.menuHideFlags = mainMenuHideFlags; } // Disable the main menu activator if any temporary states are set deviceData.toolsMenu.mainMenuActivatorInteractable = (mainMenuHideFlags & MenuHideFlags.Temporary) == 0 && mainMenu.menuContent; } // Show/hide custom menu, if it exists var customMenu = deviceData.customMenu; if (customMenu != null) { customMenu.menuHideFlags = deviceData.menuHideData[customMenu].hideFlags; } var alternateMenus = deviceData.alternateMenus; foreach (var menu in alternateMenus) { menu.menuHideFlags = deviceData.menuHideData[menu].hideFlags; } UpdateAlternateMenuForDevice(deviceData); m_RayModule.UpdateRayForDevice(deviceData, deviceData.rayOrigin); } foreach (var deviceData in k_ActiveDeviceData) { foreach (var kvp in deviceData.menuHideData) { kvp.Value.hideFlags &= ~MenuHideFlags.Temporary; } } m_DeviceInputModule.UpdatePlayerHandleMaps(); }