/// <summary> /// Add an Enter and Leave handler, notifying the user that a relaunch is required to apply the changes. /// </summary> /// <param name="option">The input TextMenu.Item option.</param> /// <param name="containingMenu">The menu containing the TextMenu.Item option.</param> /// <param name="needsRelaunch">This method does nothing if this is set to false.</param> /// <returns>The passed option.</returns> public static TextMenu.Item NeedsRelaunch(this TextMenu.Item option, TextMenu containingMenu, bool needsRelaunch = true) { if (!needsRelaunch) { return(option); } // build the "Restart is required" text menu entry TextMenuExt.EaseInSubHeaderExt needsRelaunchText = new TextMenuExt.EaseInSubHeaderExt(Dialog.Clean("MODOPTIONS_NEEDSRELAUNCH"), false, containingMenu) { TextColor = Color.OrangeRed, HeightExtra = 0f }; List <TextMenu.Item> items = containingMenu.GetItems(); if (items.Contains(option)) { // insert the text after the option that needs relaunch. containingMenu.Insert(items.IndexOf(option) + 1, needsRelaunchText); } option.OnEnter += delegate { // make the description appear. needsRelaunchText.FadeVisible = true; }; option.OnLeave += delegate { // make the description disappear. needsRelaunchText.FadeVisible = false; }; return(option); }
private static void TrySetNeedRelaunch(TextMenu textMenu, TextMenu.Item item) { if (item is TextMenu.OnOff onOffItem && needRelaunchItemLabels.Contains(onOffItem.Label)) { item.NeedsRelaunch(textMenu); } }
private void OpenExperimentDetails(int experimentIndex, TextMenu.Item experimentItem) { var experimentModule = experimentModules[experimentIndex]; var detailsMenu = new ExperimentDetailsMenu(experimentModule); OpenSubMenu(detailsMenu); }
private void RunAllScience(int id, TextMenu.Item item) { experimentModules.ForEach(exp => { RunScience(exp); }); }
/// <summary> /// Add an Enter and Leave handler, displaying a description if selected. /// </summary> /// <param name="option">The input TextMenu.Item option.</param> /// <param name="containingMenu">The menu containing the TextMenu.Item option.</param> /// <param name="description"></param> /// <returns>The passed option.</returns> public static TextMenu.Item AddDescription(this TextMenu.Item option, TextMenu containingMenu, string description) { // build the description menu entry TextMenuExt.EaseInSubHeaderExt descriptionText = new TextMenuExt.EaseInSubHeaderExt(description, false, containingMenu) { TextColor = Color.Gray, HeightExtra = 0f }; List <TextMenu.Item> items = containingMenu.GetItems(); if (items.Contains(option)) { // insert the description after the option. containingMenu.Insert(items.IndexOf(option) + 1, descriptionText); } option.OnEnter += delegate { // make the description appear. descriptionText.FadeVisible = true; }; option.OnLeave += delegate { // make the description disappear. descriptionText.FadeVisible = false; }; return(option); }
// ReSharper disable once UnusedMember.Global public void CreateMoreOptionsEntry(TextMenu textMenu, bool inGame) { textMenu.Add(moreOptionsTextMenu = new TextMenu.Button(Dialog.Clean(DialogIds.MoreOptions)).Pressed(() => { ToggleMoreOptionsMenuItem(textMenu, true); moreOptionsTextMenu.Visible = false; textMenu.Selection += 1; })); }
public void CreatePauseMenuButtons(Level level, TextMenu menu, bool minimal) { if (Everest.Flags.IsDisabled || !Settings.ShowModOptionsInGame) { return; } List <TextMenu.Item> items = menu.GetItems(); int index; // Find the options button and place our button below it. string cleanedOptions = Dialog.Clean("menu_pause_options"); index = items.FindIndex(_ => { TextMenu.Button other = (_ as TextMenu.Button); if (other == null) { return(false); } return(other.Label == cleanedOptions); }); if (index != -1) { index++; } // Otherwise, place it below the last button. else { index = items.Count; } TextMenu.Item itemModOptions = null; menu.Insert(index, itemModOptions = new TextMenu.Button(Dialog.Clean("menu_pause_modoptions")).Pressed(() => { int returnIndex = menu.IndexOf(itemModOptions); menu.RemoveSelf(); level.PauseMainMenuOpen = false; level.Paused = true; TextMenu options = OuiModOptions.CreateMenu(true, LevelExt.PauseSnapshot); options.OnESC = options.OnCancel = () => { Audio.Play(Sfxs.ui_main_button_back); options.CloseAndRun(Everest.SaveSettings(), () => level.Pause(returnIndex, minimal, false)); }; options.OnPause = () => { Audio.Play(Sfxs.ui_main_button_back); options.CloseAndRun(Everest.SaveSettings(), () => { level.Paused = false; Engine.FreezeTimer = 0.15f; }); }; level.Add(options); })); }
public static void CreateMenu(EverestModule self, TextMenu menu, bool inGame, FMOD.Studio.EventInstance snapshot) { menu.Add(new TextMenu.OnOff("Enabled", Settings.Enabled).Change((b) => { Settings.Enabled = b; foreach (TextMenu.Item item in normalOptions) { item.Visible = b; } keyConfigMenu.Visible = b; moreOptionsTextMenu.Visible = b; foreach (TextMenu.Item item in hiddenOptions) { item.Visible = false; } if (!b && Settings.ShowHitboxes) { ((TextMenu.OnOff)normalOptions.First()).LeftPressed(); } })); CreateNormalOptions(menu, inGame); foreach (TextMenu.Item item in normalOptions) { menu.Add(item); item.Visible = Settings.Enabled; TrySetNeedRelaunch(menu, item); } keyConfigMenu = new TextMenu.Button(Dialog.Clean("options_keyconfig")).Pressed(() => { menu.Focused = false; Engine.Scene.Add(new ModuleSettingsKeyboardConfigUI(self) { OnClose = () => menu.Focused = true }); Engine.Scene.OnEndOfFrame += () => Engine.Scene.Entities.UpdateLists(); }); moreOptionsTextMenu = new TextMenu.Button("modoptions_celestetas_moreoptions".DialogCleanOrNull() ?? "More Options").Pressed(() => { ToggleMoreOptionsMenuItem(menu, true); moreOptionsTextMenu.Visible = false; menu.Selection += 1; }); menu.Add(keyConfigMenu); menu.Add(moreOptionsTextMenu); keyConfigMenu.Visible = Settings.Enabled; moreOptionsTextMenu.Visible = Settings.Enabled; CreateHiddenOptions(menu, inGame); foreach (TextMenu.Item item in hiddenOptions) { menu.Add(item); item.Visible = false; TrySetNeedRelaunch(menu, item); } }
public void CreateOpenBackupFolderEntry(TextMenu textMenu, bool inGame) { TextMenu.Item item = new TextMenu.Button(DialogId.Options.OpenBackupFolder.DialogClean()) .Pressed(() => { try { string backupPath = Modules.InfiniteBackups.BackupPath; if (!Directory.Exists(backupPath)) { Directory.CreateDirectory(backupPath); } Process.Start(backupPath); } catch (Exception err) { LogUtil.Log("Open backup folder failed!", LogLevel.Warn); err.LogDetailed(); TextMenu.Item openBackupFolder = menuItems[DialogId.Options.OpenBackupFolder]; TextMenu.Item openFailed = menuItems[DialogId.Subtext.OpenBackupFolderFailed]; if (!textMenu.Items.Contains(openFailed)) { textMenu.Insert(textMenu.IndexOf(openBackupFolder) + 1, openFailed); } } }); textMenu.Add(item); menuItems.Add(DialogId.Options.OpenBackupFolder, item); // split the string into multiple lines to prevent off-screen menus caused by long path string[] descriptionLines = string.Format(DialogId.Subtext.BackupLocation.DialogGet(), Path.GetFullPath(Modules.InfiniteBackups.BackupPath)).SplitIntoFixedLength(50); TextMenuExt.EaseInSubHeaderExt backupLocationSubtext = new TextMenuExt.EaseInSubHeaderExt(string.Join("\n", descriptionLines), false, textMenu) { TextColor = Color.Gray }; // increase the height and make it vertical align backupLocationSubtext.HeightExtra = (backupLocationSubtext.Title.Split('\n').Length - 1) * ActiveFont.LineHeight * 0.6f; backupLocationSubtext.Offset = new Vector2(0f, -Math.Max(0f, -16f + backupLocationSubtext.HeightExtra) + textMenu.ItemSpacing); textMenu.Add(backupLocationSubtext); TextMenuExt.EaseInSubHeaderExt openFailedSubtext = new TextMenuExt.EaseInSubHeaderExt(DialogId.Subtext.OpenBackupFolderFailed.DialogClean(), false, textMenu) { TextColor = Color.OrangeRed, HeightExtra = 0f }; item.OnEnter += delegate { openFailedSubtext.FadeVisible = true; backupLocationSubtext.FadeVisible = true; }; item.OnLeave += delegate { openFailedSubtext.FadeVisible = false; backupLocationSubtext.FadeVisible = false; }; menuItems.Add(DialogId.Subtext.BackupLocation, backupLocationSubtext); menuItems.Add(DialogId.Subtext.OpenBackupFolderFailed, openFailedSubtext); }
// ReSharper disable once UnusedMember.Global public void CreateButtonConfigEntry(TextMenu textMenu, bool inGame) { textMenu.Add(lastTextMenu = new TextMenu.Button(Dialog.Clean(DialogIds.ButtonConfig)).Pressed(() => { textMenu.Focused = false; ButtonConfigUi buttonConfigUi = new ButtonConfigUi { OnClose = () => textMenu.Focused = true }; Engine.Scene.Add(buttonConfigUi); Engine.Scene.OnEndOfFrame += (Action)(() => Engine.Scene.Entities.UpdateLists()); })); firstTextMenu.OnValueChange(Enabled); ToggleMoreOptionsMenuItem(textMenu, false); }
public static TextMenu.Item NeedsRelaunch(this TextMenu.Item option, bool needsRelaunch) { if (!needsRelaunch) { return(option); } return(option .Enter(() => { // TODO: Show "needs relaunch" warning. }) .Leave(() => { // TODO: Hide "needs relaunch" warning. })); }
private void OpenContainerDetails(int containerIndex, TextMenu.Item containerItem) { var containerModule = containerModules[containerIndex]; var detailsMenu = new TextMenu(); detailsMenu.menuTitle = containerModule.GUIName; for (int actionIndex = 0; actionIndex < containerModule.Actions.Count; ++actionIndex) { var action = containerModule.Actions[actionIndex]; detailsMenu.Add(new TextMenu.Item(action.guiName, (id, item) => action.Invoke(activateParam))); } OpenSubMenu(detailsMenu); }
private void RefreshModules() { experimentModules = vessel.FindPartModulesImplementing <ModuleScienceExperiment>(); containerModules = vessel.FindPartModulesImplementing <ModuleScienceContainer>(); experimentsMenu.Clear(); int experimentModuleCount = experimentModules == null ? 0 : experimentModules.Count; for (int experimentIndex = 0; experimentIndex < experimentModuleCount; ++experimentIndex) { var experimentModule = experimentModules[experimentIndex]; var experimentItem = new TextMenu.Item(experimentModule.experiment.experimentTitle, OpenExperimentDetails, experimentIndex); var data = experimentModule.GetData().FirstOrDefault(); if (data != null) { var subject = ResearchAndDevelopment.GetSubjectByID(data.subjectID); if (subject != null) { var scienceValue = data.dataAmount / subject.dataScale * subject.subjectValue * subject.scientificValue; experimentItem.rightText = scienceValue.ToString("F1"); } else { DumpObject(experimentModule); } } experimentsMenu.Add(experimentItem); } containersMenu.Clear(); int containerCount = containerModules == null ? 0 : containerModules.Count; for (int containerIndex = 0; containerIndex < containerCount; ++containerIndex) { containersMenu.Add(new TextMenu.Item(containerModules[containerIndex].GetModuleDisplayName(), OpenContainerDetails, containerIndex)); } }
private static EaseInSubMenu CreateHotkeysSubMenu(EverestModule everestModule, TextMenu menu) { return(new EaseInSubMenu("Hotkeys".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.Button(Dialog.Clean("options_keyconfig")).Pressed(() => { subMenu.Focused = false; KeyboardConfigUI keyboardConfig; if (CreateKeyboardConfigUi != null) { keyboardConfig = (KeyboardConfigUI)CreateKeyboardConfigUi.Invoke(everestModule, new object[] { menu }); } else { keyboardConfig = new ModuleSettingsKeyboardConfigUI(everestModule); } keyboardConfig.OnClose = () => { subMenu.Focused = true; }; Engine.Scene.Add(keyboardConfig); Engine.Scene.OnEndOfFrame += () => Engine.Scene.Entities.UpdateLists(); })); subMenu.Add(new TextMenu.Button(Dialog.Clean("options_btnconfig")).Pressed(() => { subMenu.Focused = false; ButtonConfigUI buttonConfig; if (CreateButtonConfigUI != null) { buttonConfig = (ButtonConfigUI)CreateButtonConfigUI.Invoke(everestModule, new object[] { menu }); } else { buttonConfig = new ModuleSettingsButtonConfigUI(everestModule); } buttonConfig.OnClose = () => { subMenu.Focused = true; }; Engine.Scene.Add(buttonConfig); Engine.Scene.OnEndOfFrame += () => Engine.Scene.Entities.UpdateLists(); })); }).Apply(subMenu => hotkeysSubMenu = subMenu)); }
public static TextMenu.Item CreateSubMenu() { subMenuItem = new TextMenuExt.SubMenu("Info HUD".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.OnOff("Enabled".ToDialogText(), TasSettings.InfoHud).Change(value => TasSettings.InfoHud = value)); subMenu.Add(new TextMenu.OnOff("Info Game".ToDialogText(), TasSettings.InfoGame).Change(value => TasSettings.InfoGame = value)); subMenu.Add(new TextMenu.OnOff("Info TAS Input".ToDialogText(), TasSettings.InfoTasInput).Change(value => TasSettings.InfoTasInput = value)); subMenu.Add(new TextMenu.OnOff("Info Subpixel Indicator".ToDialogText(), TasSettings.InfoSubPixelIndicator).Change(value => TasSettings.InfoSubPixelIndicator = value)); subMenu.Add(new TextMenuExt.EnumerableSlider <HudOptions>("Info Custom".ToDialogText(), CreateHudOptions(), TasSettings.InfoCustom) .Change(value => TasSettings.InfoCustom = value)); subMenu.Add(new TextMenu.Button("Info Copy Custom Template".ToDialogText()).Pressed(() => TextInput.SetClipboardText(TasSettings.InfoCustomTemplate ?? string.Empty))); subMenu.Add(new TextMenu.Button("Info Set Custom Template".ToDialogText()).Pressed(() => { TasSettings.InfoCustomTemplate = TextInput.GetClipboardText() ?? string.Empty; CelesteTasModule.Instance.SaveSettings(); })); subMenu.Add(new TextMenuExt.EnumerableSlider <HudOptions>("Info Inspect Entity".ToDialogText(), CreateHudOptions(), TasSettings.InfoInspectEntity).Change(value => TasSettings.InfoInspectEntity = value)); subMenu.Add(new TextMenuExt.EnumerableSlider <InspectEntityTypes>("Info Inspect Entity Type".ToDialogText(), new[] { new KeyValuePair <InspectEntityTypes, string>(InspectEntityTypes.Position, "Info Inspect Entity Position".ToDialogText()), new KeyValuePair <InspectEntityTypes, string>(InspectEntityTypes.DeclaredOnly, "Info Inspect Entity Declared Only".ToDialogText()), new KeyValuePair <InspectEntityTypes, string>(InspectEntityTypes.All, "Info Inspect Entity All".ToDialogText()), }, TasSettings.InfoInspectEntityType).Change(value => TasSettings.InfoInspectEntityType = value)); subMenu.Add(new TextMenu.OnOff("Info Ignore Trigger When Click Entity".ToDialogText(), TasSettings.InfoIgnoreTriggerWhenClickEntity) .Change(value => TasSettings.InfoIgnoreTriggerWhenClickEntity = value)); subMenu.Add(new TextMenuExt.IntSlider("Info Text Size".ToDialogText(), 5, 20, TasSettings.InfoTextSize).Change(value => TasSettings.InfoTextSize = value)); subMenu.Add(new TextMenuExt.IntSlider("Info Subpixel Indicator Size".ToDialogText(), 5, 20, TasSettings.InfoSubPixelIndicatorSize) .Change(value => TasSettings.InfoSubPixelIndicatorSize = value)); subMenu.Add(new TextMenuExt.IntSlider("Info Opacity".ToDialogText(), 1, 10, TasSettings.InfoOpacity).Change(value => TasSettings.InfoOpacity = value)); subMenu.Add(new TextMenuExt.IntSlider("Info Masked Opacity".ToDialogText(), 0, 10, TasSettings.InfoMaskedOpacity).Change(value => TasSettings.InfoMaskedOpacity = value)); }); return(subMenuItem); }
public static TextMenu.Item CreateSubMenu(TextMenu menu, bool inGame) { subMenuItem = new TextMenuExt.SubMenu("Show Hitboxes".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.OnOff("Enabled".ToDialogText(), Settings.ShowHitboxes).Change(value => Settings.ShowHitboxes = value)); subMenu.Add(new TextMenu.Option <ActualCollideHitboxTypes>("Actual Collide Hitboxes".ToDialogText()).Apply(option => { Array enumValues = Enum.GetValues(typeof(ActualCollideHitboxTypes)); foreach (ActualCollideHitboxTypes value in enumValues) { option.Add(value.ToString().SpacedPascalCase().ToDialogText(), value, value.Equals(Settings.ShowActualCollideHitboxes)); } option.Change(value => Settings.ShowActualCollideHitboxes = value); })); subMenu.Add(new TextMenu.OnOff("Hide Trigger Hitboxes".ToDialogText(), Settings.HideTriggerHitboxes).Change(value => Settings.HideTriggerHitboxes = value)); subMenu.Add(new TextMenu.OnOff("Simplified Hitboxes".ToDialogText(), Settings.SimplifiedHitboxes).Change(value => Settings.SimplifiedHitboxes = value)); subMenu.Add(HitboxColor.CreateEntityHitboxColorButton(menu, inGame)); subMenu.Add(HitboxColor.CreateTriggerHitboxColorButton(menu, inGame)); subMenu.Add(HitboxColor.CreatePlatformHitboxColorButton(menu, inGame)); }); return(subMenuItem); }
/// <inheritdoc cref="patch_TextMenu.Insert(int, TextMenu.Item)"/> public static TextMenu Insert(this TextMenu self, int index, TextMenu.Item item) => ((patch_TextMenu)self).Insert(index, item);
private void UpdateLists() { switch (currentMenu) { case MenuList.Undock: UpdateUndockablesList(); activeMenu.Clear(); foreach (ModuleDockingNode thatPort in undockablesList) { var tmi = new TextMenu.Item(); tmi.action = DecouplePort; switch (thatPort.state) { case "Docked (docker)": tmi.labelText = "Undock " + thatPort.vesselInfo.name; break; case "PreAttached": tmi.labelText = string.Format("Detach {0} ({1})", thatPort.part.name, PortOrientationText(part.GetReferenceTransform(), thatPort.controlTransform)); break; } activeMenu.Add(tmi); } break; case MenuList.Celestials: foreach (Celestial body in celestialsList) body.UpdateDistance(vessel.transform.position); CelestialBody currentBody = celestialsList[activeMenu.GetCurrentIndex()].body; switch (sortMode) { case SortMode.Alphabetic: celestialsList.Sort(Celestial.AlphabeticSort); break; case SortMode.Distance: celestialsList.Sort(Celestial.DistanceSort); break; } activeMenu.Clear(); foreach (Celestial celestial in celestialsList) { var tmi = new TextMenu.Item(); tmi.action = TargetCelestial; tmi.labelText = celestial.name; tmi.rightText = String.Format(fp, distanceFormatString.UnMangleConfigText(), celestial.distance); tmi.isSelected = (selectedCelestial == celestial.body); tmi.isDisabled = (vessel.mainBody == celestial.body); activeMenu.Add(tmi); } break; case MenuList.Reference: FindReferencePoints(); activeMenu.Clear(); Part currentReference = vessel.GetReferenceTransformPart(); foreach (PartModule referencePoint in referencePoints) { var tmi = new TextMenu.Item(); tmi.action = SetReferencePoint; var thatPort = referencePoint as ModuleDockingNode; if (thatPort == null) tmi.labelText = string.Format("{0}. {1}", activeMenu.Count + 1, referencePoint.part.name); else tmi.labelText = string.Format("{0}. {1} ({2})", activeMenu.Count + 1, referencePoint.part.name, PortOrientationText(part.GetReferenceTransform(), thatPort.controlTransform)); tmi.isSelected = (currentReference == referencePoint.part); activeMenu.Add(tmi); } break; case MenuList.Vessels: vesselsList.Clear(); foreach (Vessel thatVessel in FlightGlobals.fetch.vessels) { if (vessel != thatVessel) { foreach (var filter in vesselFilter) { if (thatVessel.vesselType == filter.Key && filter.Value) { vesselsList.Add(new TargetableVessel(thatVessel, vessel.transform.position)); break; } } } } switch (sortMode) { case SortMode.Alphabetic: vesselsList.Sort(TargetableVessel.AlphabeticSort); break; case SortMode.Distance: vesselsList.Sort(TargetableVessel.DistanceSort); break; } activeMenu.Clear(); foreach (TargetableVessel targetableVessel in vesselsList) { var tmi = new TextMenu.Item(); tmi.action = TargetVessel; tmi.labelText = targetableVessel.name; tmi.rightText = String.Format(fp, distanceFormatString.UnMangleConfigText(), targetableVessel.distance); tmi.isSelected = (selectedVessel == targetableVessel.vessel); activeMenu.Add(tmi); } break; case MenuList.Ports: UpdatePortsList(); activeMenu.Clear(); foreach (ModuleDockingNode port in portsList) { var tmi = new TextMenu.Item(); tmi.action = TargetVessel; tmi.labelText = string.Format("{0} ({1})", port.name, PortOrientationText(port.vessel.ReferenceTransform, port.controlTransform)); tmi.isSelected = (selectedPort == port); tmi.action = TargetPort; activeMenu.Add(tmi); } break; } }
/// <summary> /// Create the mod menu subsection including the section header in the given menu. /// The default implementation uses reflection to attempt creating a menu. /// </summary> /// <param name="menu">Menu to add the section to.</param> /// <param name="inGame">Whether we're in-game (paused) or in the main menu.</param> /// <param name="snapshot">The Level.PauseSnapshot</param> public virtual void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot) { Type type = SettingsType; EverestModuleSettings settings = _Settings; if (type == null || settings == null) { return; } // The default name prefix. string typeName = type.Name.ToLowerInvariant(); if (typeName.EndsWith("settings")) { typeName = typeName.Substring(0, typeName.Length - 8); } string nameDefaultPrefix = $"modoptions_{typeName}_"; // Any attributes we may want to get and read from later. SettingInGameAttribute attribInGame; SettingRangeAttribute attribRange; // If the settings type has got the InGame attrib, only show it in the matching situation. if ((attribInGame = type.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { return; } // The settings subheader. string name; // We lazily reuse this field for the props later on. name = type.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}title"; name = name.DialogCleanOrNull() ?? Metadata.Name.SpacedPascalCase(); menu.Add(new TextMenu.SubHeader(name + " | v." + Metadata.VersionString)); PropertyInfo[] props; if (type == _PrevSettingsType) { props = _PrevSettingsProps; } else { _PrevSettingsProps = props = type.GetProperties(); _PrevSettingsType = type; } foreach (PropertyInfo prop in props) { MethodInfo creator = type.GetMethod( $"Create{prop.Name}Entry", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(TextMenu), typeof(bool) }, new ParameterModifier[0] ); if (creator != null) { creator.GetFastDelegate()(settings, menu, inGame); continue; } if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } name = prop.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}"; name = name.DialogCleanOrNull() ?? prop.Name.SpacedPascalCase(); bool needsRelaunch = prop.GetCustomAttribute <SettingNeedsRelaunchAttribute>() != null; TextMenu.Item item = null; Type propType = prop.PropertyType; object value = prop.GetValue(settings); // Create the matching item based off of the type and attributes. if (propType == typeof(bool)) { item = new TextMenu.OnOff(name, (bool)value) .Change(v => prop.SetValue(settings, v)) ; } else if ( propType == typeof(int) && (attribRange = prop.GetCustomAttribute <SettingRangeAttribute>()) != null ) { item = new TextMenu.Slider(name, i => i.ToString(), attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else if (propType.IsEnum) { Array enumValues = Enum.GetValues(propType); Array.Sort((int[])enumValues); string enumNamePrefix = $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}_"; item = new TextMenu.Slider(name, (i) => { string enumName = enumValues.GetValue(i).ToString(); string fullName = $"{enumNamePrefix}{enumName.ToLowerInvariant()}"; return(fullName.DialogCleanOrNull() ?? enumName); }, 0, enumValues.Length - 1, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else if (!inGame && propType == typeof(string)) { item = new TextMenu.Button(name + ": " + value) .Pressed(() => { Audio.Play(Sfxs.ui_main_savefile_rename_start); menu.SceneAs <Overworld>().Goto <OuiModOptionString>().Init <OuiModOptions>( (string)value, v => prop.SetValue(settings, v) ); }) ; } if (item == null) { continue; } if (needsRelaunch) { item = item.NeedsRelaunch(); } menu.Add(item); } }
private static void CreateOptions(EverestModule everestModule, TextMenu menu, bool inGame) { options = new List <TextMenu.Item> { HitboxTweak.CreateSubMenu(menu, inGame), SimplifiedGraphicsFeature.CreateSubMenu(), InfoHud.CreateSubMenu(), new TextMenuExt.SubMenu("Round Values".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.OnOff("Round Position".ToDialogText(), Settings.RoundPosition).Change(value => Settings.RoundPosition = value)); subMenu.Add(new TextMenu.OnOff("Round Speed".ToDialogText(), Settings.RoundSpeed).Change(value => Settings.RoundSpeed = value)); subMenu.Add(new TextMenu.OnOff("Round Velocity".ToDialogText(), Settings.RoundVelocity).Change(value => Settings.RoundVelocity = value)); subMenu.Add(new TextMenu.OnOff("Round Custom Info".ToDialogText(), Settings.RoundCustomInfo).Change(value => Settings.RoundCustomInfo = value)); }), new TextMenuExt.SubMenu("Relaunch Required".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.OnOff("Launch Studio At Boot".ToDialogText(), Settings.LaunchStudioAtBoot).Change(value => Settings.LaunchStudioAtBoot = value)); subMenu.Add(new TextMenu.OnOff("Auto Extract New Studio".ToDialogText(), Settings.AutoExtractNewStudio).Change(value => Settings.AutoExtractNewStudio = value)); // TODO need some guys who know Linux to make it actually work // subMenu.Add(new TextMenu.OnOff("Unix RTC".ToDialogText(), Settings.UnixRtc).Change(value => Settings.UnixRtc = value)); }), new TextMenuExt.SubMenu("More Options".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.OnOff("Center Camera".ToDialogText(), Settings.CenterCamera).Change(value => Settings.CenterCamera = value)); subMenu.Add(new TextMenu.OnOff("Pause After Load State".ToDialogText(), Settings.PauseAfterLoadState).Change(value => Settings.PauseAfterLoadState = value)); subMenu.Add(new TextMenu.OnOff("Restore Settings".ToDialogText(), Settings.RestoreSettings).Change(value => Settings.RestoreSettings = value)); subMenu.Add( new TextMenu.OnOff("Disable Achievements".ToDialogText(), Settings.DisableAchievements).Change(value => Settings.DisableAchievements = value)); subMenu.Add(new TextMenu.OnOff("Mod 9D Lighting".ToDialogText(), Settings.Mod9DLighting).Change(value => Settings.Mod9DLighting = value)); }), new TextMenu.Button(Dialog.Clean("options_keyconfig")).Pressed(() => { menu.Focused = false; Entity keyboardConfig; if (CreateKeyboardConfigUi != null) { keyboardConfig = CreateKeyboardConfigUi.Invoke(everestModule, new object[] { menu }) as Entity; } else { keyboardConfig = new ModuleSettingsKeyboardConfigUI(everestModule) { OnClose = () => menu.Focused = true }; } Engine.Scene.Add(keyboardConfig); Engine.Scene.OnEndOfFrame += () => Engine.Scene.Entities.UpdateLists(); }).Apply(item => keyConfigButton = item) }; }
public void Start() { // I guess I shouldn't have expected Squad to actually do something nice for a modder like that. // In 0.23, loading in non-alphabetical order is still broken. // But now we have KSPAssembly and KSPAssemblyDependency, which actually sidestep the issue, and finally // Mu told someone about it and now I can avoid this path hardlinking. // Actually, better yet. Let it check for the new canonical location instead. Because f**k installation problems. if (!JSI.InstallationPathWarning.Warn()) { return; } GameEvents.onUndock.Add(UndockCallback); if (!string.IsNullOrEmpty(itemColor)) { itemColorValue = ConfigNode.ParseColor32(itemColor); } if (!string.IsNullOrEmpty(selectedColor)) { selectedColorValue = ConfigNode.ParseColor32(selectedColor); } if (!string.IsNullOrEmpty(unavailableColor)) { unavailableColorValue = ConfigNode.ParseColor32(unavailableColor); } topMenu.labelColor = JUtil.ColorToColorTag(itemColorValue); topMenu.selectedColor = JUtil.ColorToColorTag(selectedColorValue); topMenu.disabledColor = JUtil.ColorToColorTag(unavailableColorValue); RasterPropMonitorComputer rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true); Func<bool> isMjAvailable = (Func<bool>)rpmComp.GetMethod("JSIMechJeb:GetMechJebAvailable", internalProp, typeof(Func<bool>)); if (isMjAvailable == null) { throw new NotImplementedException("isMjAvailable"); } UpdateMethods(rpmComp); // If MechJeb is installed, but not found on the craft, menu options can't be populated correctly. if (isMjAvailable()) { mjAvailable = true; smartassAvailable = GetModuleExists("MechJebModuleSmartASS"); topMenu.Add(new TextMenu.Item(JSIMechJeb.TargetTexts[(int)JSIMechJeb.Target.OFF], SmartASS_Off)); topMenu.Add(new TextMenu.Item(JSIMechJeb.TargetTexts[(int)JSIMechJeb.Target.KILLROT].Replace('\n', ' '), SmartASS_KillRot)); nodeMenuItem = new TextMenu.Item(JSIMechJeb.TargetTexts[(int)JSIMechJeb.Target.NODE], SmartASS_Node); topMenu.Add(nodeMenuItem); topMenu.Add(new TextMenu.Item(JSIMechJeb.ModeTexts[(int)JSIMechJeb.Mode.ORBITAL], OrbitalMenu)); topMenu.Add(new TextMenu.Item(JSIMechJeb.ModeTexts[(int)JSIMechJeb.Mode.SURFACE], SurfaceMenu)); targetMenuItem = new TextMenu.Item(JSIMechJeb.ModeTexts[(int)JSIMechJeb.Mode.TARGET], TargetMenu); topMenu.Add(targetMenuItem); forceRollMenuItem = new TextMenu.Item(String.Format("Force Roll: {0:f0}", GetForceRollAngle()), ToggleForceRoll); topMenu.Add(forceRollMenuItem); topMenu.Add(new TextMenu.Item("Execute Next Node", ExecuteNode, (int)MJMenu.ExecuteNodeMenu)); topMenu.Add(new TextMenu.Item("Ascent Guidance", AscentGuidance, (int)MJMenu.AscentGuidanceMenu)); topMenu.Add(new TextMenu.Item("Land Somewhere", LandingGuidance, (int)MJMenu.LandingGuidanceMenu)); topMenu.Add(new TextMenu.Item("Docking Guidance", DockingGuidance, (int)MJMenu.DockingGuidanceMenu)); //topMenu.Add(new TextMenu.Item("Hold Alt & Heading", SpaceplaneGuidance, (int)MJMenu.SpacePlaneMenu)); topMenu.Add(new TextMenu.Item("Circularize", CircularizeMenu, (int)MJMenu.CircularizeMenu)); } else { mjAvailable = false; smartassAvailable = false; } activeMenu = topMenu; }
public TextMenu CreateMenu(bool inGame, EventInstance snapshot) { menu = new TextMenu(); items.Clear(); menu.Add(new TextMenu.Header(Dialog.Clean("maplist_title"))); menu.Add(new TextMenu.SubHeader(Dialog.Clean("maplist_filters"))); menu.Add(new TextMenu.Button(Dialog.Clean("maplist_reload")).Pressed(() => { Audio.Play(SFX.ui_postgame_unlock_newchapter); Overworld.Mountain.UntiltedCamera = cameraStart; OuiHelper_ChapterSelect_Reload.Reload(); Overworld.Goto <OuiMapList>(); })); menu.Add(searchButton = new TextMenu.Button(Dialog.Clean("maplist_search")).Pressed(() => { Searching = true; MInput.Disabled = true; })); sets.Clear(); foreach (AreaData area in AreaData.Areas) { string levelSet = area.GetLevelSet(); if (string.IsNullOrEmpty(levelSet)) { continue; } if (levelSet == "Celeste") { continue; } if (sets.Contains(levelSet)) { continue; } sets.Add(levelSet); } menu.Add(new TextMenu.Slider(Dialog.Clean("maplist_type"), value => { if (value == 0) { return(Dialog.Clean("levelset_celeste")); } if (value == 1) { return(Dialog.Clean("maplist_type_allmods")); } return(DialogExt.CleanLevelSet(sets[value - 2])); }, 0, 1 + sets.Count, type).Change(value => { type = value; ReloadItems(); })); menu.Add(new TextMenu.Slider(Dialog.Clean("maplist_side"), value => ((char)('A' + value)).ToString(), 0, Enum.GetValues(typeof(AreaMode)).Length - 1, side).Change(value => { side = value; ReloadItems(); })); menu.Add(new TextMenu.SubHeader(Dialog.Clean("maplist_list"))); ReloadItems(); return(menu); }
/// <summary> /// Create the mod menu subsection including the section header in the given menu. /// The default implementation uses reflection to attempt creating a menu. /// </summary> /// <param name="menu">Menu to add the section to.</param> /// <param name="inGame">Whether we're in-game (paused) or in the main menu.</param> /// <param name="snapshot">The Level.PauseSnapshot</param> public virtual void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot) { Type type = SettingsType; EverestModuleSettings settings = _Settings; if (type == null || settings == null) { return; } // The default name prefix. string nameDefaultPrefix = $"modoptions_{type.Name.ToLowerInvariant()}_"; if (nameDefaultPrefix.EndsWith("Settings")) { nameDefaultPrefix = nameDefaultPrefix.Substring(0, nameDefaultPrefix.Length - 8); } // Any attributes we may want to get and read from later. SettingInGameAttribute attribInGame; SettingRangeAttribute attribRange; // If the settings type has got the InGame attrib, only show it in the matching situation. if ((attribInGame = type.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { return; } // The settings subheader. string name; // We lazily reuse this field for the props later on. name = type.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}title"; name = name.DialogCleanOrNull() ?? Metadata.Name.SpacedPascalCase(); menu.Add(new TextMenu.SubHeader(name)); PropertyInfo[] props; if (type == _PrevSettingsType) { props = _PrevSettingsProps; } else { _PrevSettingsProps = props = type.GetProperties(); _PrevSettingsType = type; } foreach (PropertyInfo prop in props) { if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } name = prop.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}"; name = name.DialogCleanOrNull() ?? prop.Name.SpacedPascalCase(); bool needsRelaunch = prop.GetCustomAttribute <SettingNeedsRelaunchAttribute>() != null; TextMenu.Item item = null; Type propType = prop.PropertyType; object value = prop.GetValue(settings); // Create the matching item based off of the type and attributes. if (propType == typeof(bool)) { item = new TextMenu.OnOff(name, (bool)value) .Change(v => prop.SetValue(settings, v)) .NeedsRelaunch(needsRelaunch) ; } else if ( propType == typeof(int) && (attribRange = prop.GetCustomAttribute <SettingRangeAttribute>()) != null ) { item = new TextMenu.Slider(name, i => i.ToString(), attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) .NeedsRelaunch(needsRelaunch) ; } if (item == null) { continue; } menu.Add(item); } }
private static void CreateOptions(EverestModule everestModule, TextMenu menu, bool inGame) { options = new List <TextMenu.Item> { new TextMenuExt.SubMenu("Show Hitboxes".ToDialogText(), false).Apply(subMenu => { showHitboxesSubmenu = subMenu; subMenu.Add(new TextMenu.OnOff("Enabled".ToDialogText(), Settings.ShowHitboxes).Change(value => Settings.ShowHitboxes = value)); subMenu.Add(new TextMenu.Option <ActualCollideHitboxTypes>("Actual Collide Hitboxes".ToDialogText()).Apply(option => { Array enumValues = Enum.GetValues(typeof(ActualCollideHitboxTypes)); foreach (ActualCollideHitboxTypes value in enumValues) { option.Add(value.ToString().SpacedPascalCase().ToDialogText(), value, value.Equals(Settings.ShowActualCollideHitboxes)); } option.Change(value => Settings.ShowActualCollideHitboxes = value); })); subMenu.Add(new TextMenu.OnOff("Hide Trigger Hitboxes".ToDialogText(), Settings.HideTriggerHitboxes).Change(value => Settings.HideTriggerHitboxes = value)); subMenu.Add(new TextMenu.OnOff("Simplified Hitboxes".ToDialogText(), Settings.SimplifiedHitboxes).Change(value => Settings.SimplifiedHitboxes = value)); subMenu.Add(HitboxColor.CreateEntityHitboxColorButton(menu, inGame)); subMenu.Add(HitboxColor.CreateTriggerHitboxColorButton(menu, inGame)); subMenu.Add(HitboxColor.CreateSolidTilesHitboxColorButton(menu, inGame)); }), SimplifiedGraphicsFeature.CreateSimplifiedGraphicsOption(), new TextMenuExt.SubMenu("Relaunch Required".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.OnOff("Launch Studio At Boot".ToDialogText(), Settings.LaunchStudioAtBoot).Change(value => Settings.LaunchStudioAtBoot = value)); subMenu.Add(new TextMenu.OnOff("Auto Extract New Studio".ToDialogText(), Settings.AutoExtractNewStudio).Change(value => Settings.AutoExtractNewStudio = value)); subMenu.Add(new TextMenu.OnOff("Unix RTC".ToDialogText(), Settings.UnixRtc).Change(value => Settings.UnixRtc = value)); }), new TextMenuExt.SubMenu("More Options".ToDialogText(), false).Apply(subMenu => { subMenu.Add(new TextMenu.OnOff("Center Camera".ToDialogText(), Settings.CenterCamera).Change(value => Settings.CenterCamera = value)); subMenu.Add(new TextMenu.OnOff("Round Position".ToDialogText(), Settings.RoundPosition).Change(value => Settings.RoundPosition = value)); subMenu.Add(new TextMenu.Option <InfoPositions>("Info HUD".ToDialogText()).Apply(option => { Array enumValues = Enum.GetValues(typeof(InfoPositions)); foreach (InfoPositions value in enumValues) { option.Add(value.ToString().SpacedPascalCase(), value, value.Equals(Settings.InfoHud)); } option.Change(value => Settings.InfoHud = value); })); subMenu.Add(new TextMenu.OnOff("Pause After Load State".ToDialogText(), Settings.PauseAfterLoadState).Change(value => Settings.PauseAfterLoadState = value)); subMenu.Add(new TextMenu.OnOff("Restore Settings".ToDialogText(), Settings.RestoreSettings).Change(value => Settings.RestoreSettings = value)); subMenu.Add( new TextMenu.OnOff("Disable Achievements".ToDialogText(), Settings.DisableAchievements).Change(value => Settings.DisableAchievements = value)); subMenu.Add(new TextMenu.OnOff("Mod 9D Lighting".ToDialogText(), Settings.Mod9DLighting).Change(value => Settings.Mod9DLighting = value)); }), new TextMenu.Button(Dialog.Clean("options_keyconfig")).Pressed(() => { menu.Focused = false; Entity keyboardConfig; if (CreateKeyboardConfigUi != null) { keyboardConfig = CreateKeyboardConfigUi.Invoke(everestModule, new object[] { menu }) as Entity; } else { keyboardConfig = new ModuleSettingsKeyboardConfigUI(everestModule) { OnClose = () => menu.Focused = true }; } Engine.Scene.Add(keyboardConfig); Engine.Scene.OnEndOfFrame += () => Engine.Scene.Entities.UpdateLists(); }).Apply(item => keyConfigButton = item) }; }
private void UpdateLists() { switch (currentMenu) { case MenuList.Undock: UpdateUndockablesList(); activeMenu.Clear(); foreach (PartModule thatUndockable in undockablesList) { var tmi = new TextMenu.Item(); tmi.action = DecouplePort; if (thatUndockable is ModuleDockingNode) { var thatPort = thatUndockable as ModuleDockingNode; switch (thatPort.state) { case "Docked (docker)": tmi.labelText = "Undock " + thatPort.vesselInfo.name; break; case "PreAttached": tmi.labelText = string.Format("Detach {0} {1}", GetPortName(thatPort), PortOrientationText(part.GetReferenceTransform(), thatPort.controlTransform)); break; } } if (thatUndockable is ModuleGrappleNode) { var thatClaw = thatUndockable as ModuleGrappleNode; tmi.labelText = "Claw (" + thatClaw.otherVesselInfo.name + ")"; } activeMenu.Add(tmi); } break; case MenuList.Celestials: foreach (Celestial body in celestialsList) body.UpdateDistance(vessel.transform.position); CelestialBody currentBody = celestialsList[activeMenu.GetCurrentIndex()].body; switch (sortMode) { case SortMode.Alphabetic: celestialsList.Sort(Celestial.AlphabeticSort); break; case SortMode.Distance: celestialsList.Sort(Celestial.DistanceSort); break; } activeMenu.Clear(); foreach (Celestial celestial in celestialsList) { var tmi = new TextMenu.Item(); tmi.action = TargetCelestial; tmi.labelText = celestial.name; tmi.rightText = String.Format(fp, distanceFormatString.UnMangleConfigText(), celestial.distance); tmi.isSelected = (selectedCelestial == celestial.body); tmi.isDisabled = (vessel.mainBody == celestial.body); activeMenu.Add(tmi); } break; case MenuList.Reference: FindReferencePoints(); activeMenu.Clear(); Part currentReference = vessel.GetReferenceTransformPart(); foreach (PartModule referencePoint in referencePoints) { var tmi = new TextMenu.Item(); tmi.action = SetReferencePoint; if (referencePoint is ModuleDockingNode) { var thatPort = referencePoint as ModuleDockingNode; tmi.labelText = string.Format("{0}. {1} {2}", activeMenu.Count + 1, GetPortName(thatPort), PortOrientationText(part.GetReferenceTransform(), thatPort.controlTransform)); } else if (referencePoint is ModuleGrappleNode) { var thatClaw = referencePoint as ModuleGrappleNode; tmi.labelText = string.Format("{0}. {1} {2}", activeMenu.Count + 1, referencePoint.part.partInfo.title, PortOrientationText(part.GetReferenceTransform(), thatClaw.controlTransform)); } else { tmi.labelText = string.Format("{0}. {1}", activeMenu.Count + 1, referencePoint.part.partInfo.title); } tmi.isSelected = (currentReference == referencePoint.part); activeMenu.Add(tmi); } break; case MenuList.Vessels: vesselsList.Clear(); foreach (Vessel thatVessel in FlightGlobals.fetch.vessels) { if (vessel != thatVessel) { foreach (var filter in vesselFilter) { if (thatVessel.vesselType == filter.Key && filter.Value) { vesselsList.Add(new TargetableVessel(thatVessel, vessel.transform.position)); break; } } } } switch (sortMode) { case SortMode.Alphabetic: vesselsList.Sort(TargetableVessel.AlphabeticSort); break; case SortMode.Distance: vesselsList.Sort(TargetableVessel.DistanceSort); break; } activeMenu.Clear(); foreach (TargetableVessel targetableVessel in vesselsList) { var tmi = new TextMenu.Item(); tmi.action = TargetVessel; tmi.labelText = targetableVessel.name; tmi.rightText = String.Format(fp, distanceFormatString.UnMangleConfigText(), targetableVessel.distance); tmi.isSelected = (selectedVessel == targetableVessel.vessel); activeMenu.Add(tmi); } break; case MenuList.SpaceObjects: spaceObjectsList.Clear(); foreach (Vessel thatVessel in FlightGlobals.fetch.vessels) { if (vessel != thatVessel) { // MOARdV: // Assuming DiscoveryLevels.StateVectors = "tracked object" // DL.Name is set true as well, but I suspect it // remains true after tracking ceases (not confirmed). // Note that all asteroids are VesselType.SpaceObject. if (thatVessel.vesselType == VesselType.SpaceObject && thatVessel.DiscoveryInfo.HaveKnowledgeAbout(DiscoveryLevels.StateVectors)) { spaceObjectsList.Add(new TargetableVessel(thatVessel, vessel.transform.position)); } } } switch (sortMode) { case SortMode.Alphabetic: spaceObjectsList.Sort(TargetableVessel.AlphabeticSort); break; case SortMode.Distance: spaceObjectsList.Sort(TargetableVessel.DistanceSort); break; } activeMenu.Clear(); foreach (TargetableVessel targetableVessel in spaceObjectsList) { var tmi = new TextMenu.Item(); tmi.action = TargetSpaceObject; tmi.labelText = targetableVessel.name; tmi.rightText = String.Format(fp, distanceFormatString.UnMangleConfigText(), targetableVessel.distance); tmi.isSelected = (selectedVessel == targetableVessel.vessel); activeMenu.Add(tmi); } break; case MenuList.Ports: UpdatePortsList(); activeMenu.Clear(); foreach (ModuleDockingNode port in portsList) { var tmi = new TextMenu.Item(); tmi.action = TargetVessel; tmi.labelText = GetPortName(port); tmi.rightText = PortOrientationText(port.vessel.ReferenceTransform, port.controlTransform); tmi.isSelected = (selectedPort == port); tmi.action = TargetPort; activeMenu.Add(tmi); } break; } }
private void ShowFiltersMenu(int index, TextMenu.Item ti) { currentMenu = MenuList.Filters; activeMenu = new TextMenu(); activeMenu.labelColor = nameColorTag; activeMenu.selectedColor = selectedColorTag; activeMenu.disabledColor = unavailableColorTag; activeMenu.rightTextColor = distanceColorTag; for (int i = 0; i < vesselFilter.Count; i++) { var filter = vesselFilter.ElementAt(i); var tmi = new TextMenu.Item(); tmi.labelText = filter.Key.ToString().PadRight(9) + (filter.Value ? "- On" : "- Off"); tmi.isSelected = filter.Value; tmi.action = ToggleFilter; activeMenu.Add(tmi); } }
public void Start() { if (!HighLogic.LoadedSceneIsFlight) return; // Grrrrrr. if (!string.IsNullOrEmpty(nameColor)) nameColorValue = ConfigNode.ParseColor32(nameColor); if (!string.IsNullOrEmpty(distanceColor)) distanceColorValue = ConfigNode.ParseColor32(distanceColor); if (!string.IsNullOrEmpty(selectedColor)) selectedColorValue = ConfigNode.ParseColor32(selectedColor); if (!string.IsNullOrEmpty(unavailableColor)) unavailableColorValue = ConfigNode.ParseColor32(unavailableColor); persistentVarName = "targetfilter" + internalProp.propID; persistence = new PersistenceAccessor(internalProp); // 7 is the bitmask for ship-station-probe; VesselFilterFromBitmask(persistence.GetVar(persistentVarName, defaultFilter)); nameColorTag = JUtil.ColorToColorTag(nameColorValue); distanceColorTag = JUtil.ColorToColorTag(distanceColorValue); selectedColorTag = JUtil.ColorToColorTag(selectedColorValue); unavailableColorTag = JUtil.ColorToColorTag(unavailableColorValue); distanceFormatString = distanceFormatString.UnMangleConfigText(); menuTitleFormatString = menuTitleFormatString.UnMangleConfigText(); topMenu.labelColor = nameColorTag; topMenu.selectedColor = selectedColorTag; topMenu.disabledColor = unavailableColorTag; if (!string.IsNullOrEmpty(pageTitle)) pageTitle = pageTitle.UnMangleConfigText(); foreach (CelestialBody body in FlightGlobals.Bodies) { celestialsList.Add(new Celestial(body, vessel.transform.position)); } FindReferencePoints(); UpdateUndockablesList(); var menuActions = new List<Action<int, TextMenu.Item>>(); menuActions.Add(ShowCelestialMenu); menuActions.Add(ShowVesselMenu); menuActions.Add(ShowSpaceObjectMenu); menuActions.Add(ShowReferenceMenu); menuActions.Add(ShowUndockMenu); menuActions.Add(ArmGrapple); menuActions.Add(ShowFiltersMenu); menuActions.Add(ClearTarget); for (int i = 0; i < rootMenu.Count; ++i) { var menuitem = new TextMenu.Item(); menuitem.labelText = rootMenu[i]; menuitem.action = menuActions[i]; topMenu.Add(menuitem); switch (menuitem.labelText) { case clearTargetItemText: clearTarget = topMenu[i]; break; case undockItemText: undockMenuItem = topMenu[i]; break; case armGrappleText: grappleMenuItem = topMenu[i]; break; } } activeMenu = topMenu; }
/// <inheritdoc cref="patch_TextMenu.Remove(TextMenu.Item)"/> public static TextMenu Remove(this TextMenu self, TextMenu.Item item) => ((patch_TextMenu)self).Remove(item);
/// <summary> /// Create the mod menu subsection including the section header in the given menu. /// The default implementation uses reflection to attempt creating a menu. /// </summary> /// <param name="menu">Menu to add the section to.</param> /// <param name="inGame">Whether we're in-game (paused) or in the main menu.</param> /// <param name="snapshot">The Level.PauseSnapshot</param> public virtual void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot) { Type type = SettingsType; EverestModuleSettings settings = _Settings; if (type == null || settings == null) { return; } // The default name prefix. string typeName = type.Name.ToLowerInvariant(); if (typeName.EndsWith("settings")) { typeName = typeName.Substring(0, typeName.Length - 8); } string nameDefaultPrefix = $"modoptions_{typeName}_"; // Any attributes we may want to get and read from later. SettingInGameAttribute attribInGame; SettingRangeAttribute attribRange; SettingNumberInputAttribute attribNumber; // If the settings type has got the InGame attrib, only show it in the matching situation. if ((attribInGame = type.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { return; } bool headerCreated = false; if (GetType().GetMethod("CreateModMenuSection").DeclaringType != typeof(EverestModule)) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } PropertyInfo[] props; if (type == _PrevSettingsType) { props = _PrevSettingsProps; } else { _PrevSettingsProps = props = type.GetProperties(); _PrevSettingsType = type; } foreach (PropertyInfo prop in props) { MethodInfo creator = type.GetMethod( $"Create{prop.Name}Entry", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(TextMenu), typeof(bool) }, new ParameterModifier[0] ); if (creator != null) { if (!headerCreated) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } creator.GetFastDelegate()(settings, menu, inGame); continue; } if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } string name = prop.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}"; name = name.DialogCleanOrNull() ?? prop.Name.SpacedPascalCase(); bool needsRelaunch = prop.GetCustomAttribute <SettingNeedsRelaunchAttribute>() != null; string description = prop.GetCustomAttribute <SettingSubTextAttribute>()?.Description; TextMenu.Item item = null; Type propType = prop.PropertyType; object value = prop.GetValue(settings); // Create the matching item based off of the type and attributes. if (propType == typeof(bool)) { item = new TextMenu.OnOff(name, (bool)value) .Change(v => prop.SetValue(settings, v)) ; } else if ( propType == typeof(int) && (attribRange = prop.GetCustomAttribute <SettingRangeAttribute>()) != null ) { if (attribRange.LargeRange) { item = new TextMenuExt.IntSlider(name, attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else { item = new TextMenu.Slider(name, i => i.ToString(), attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) ; } } else if ((propType == typeof(int) || propType == typeof(float)) && (attribNumber = prop.GetCustomAttribute <SettingNumberInputAttribute>()) != null) { float currentValue; Action <float> valueSetter; if (propType == typeof(int)) { currentValue = (int)value; valueSetter = v => prop.SetValue(settings, (int)v); } else { currentValue = (float)value; valueSetter = v => prop.SetValue(settings, v); } int maxLength = attribNumber.MaxLength; bool allowNegatives = attribNumber.AllowNegatives; item = new TextMenu.Button(name + ": " + currentValue.ToString($"F{maxLength}").TrimEnd('0').TrimEnd('.')) .Pressed(() => { Audio.Play(SFX.ui_main_savefile_rename_start); menu.SceneAs <Overworld>().Goto <OuiNumberEntry>().Init <OuiModOptions>( currentValue, valueSetter, maxLength, propType == typeof(float), allowNegatives ); }) ; } else if (propType.IsEnum) { Array enumValues = Enum.GetValues(propType); Array.Sort((int[])enumValues); string enumNamePrefix = $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}_"; item = new TextMenu.Slider(name, (i) => { string enumName = enumValues.GetValue(i).ToString(); return ($"{enumNamePrefix}{enumName.ToLowerInvariant()}".DialogCleanOrNull() ?? $"modoptions_{propType.Name.ToLowerInvariant()}_{enumName.ToLowerInvariant()}".DialogCleanOrNull() ?? enumName); }, 0, enumValues.Length - 1, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else if (!inGame && propType == typeof(string)) { int maxValueLength = prop.GetCustomAttribute <SettingMaxLengthAttribute>()?.Max ?? 12; int minValueLength = prop.GetCustomAttribute <SettingMinLengthAttribute>()?.Min ?? 1; item = new TextMenu.Button(name + ": " + value) .Pressed(() => { Audio.Play(SFX.ui_main_savefile_rename_start); menu.SceneAs <Overworld>().Goto <OuiModOptionString>().Init <OuiModOptions>( (string)value, v => prop.SetValue(settings, v), maxValueLength, minValueLength ); }) ; } if (item == null) { continue; } if (!headerCreated) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } menu.Add(item); if (needsRelaunch) { item = item.NeedsRelaunch(menu); } if (description != null) { item = item.AddDescription(menu, description.DialogCleanOrNull() ?? description); } } foreach (PropertyInfo prop in type.GetProperties()) { if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } if (!typeof(ButtonBinding).IsAssignableFrom(prop.PropertyType)) { continue; } if (!headerCreated) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } CreateModMenuSectionKeyBindings(menu, inGame, snapshot); break; } }
public void Start() { if (!HighLogic.LoadedSceneIsFlight) return; rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true); // Grrrrrr. if (!string.IsNullOrEmpty(nameColor)) nameColorValue = ConfigNode.ParseColor32(nameColor); if (!string.IsNullOrEmpty(distanceColor)) distanceColorValue = ConfigNode.ParseColor32(distanceColor); if (!string.IsNullOrEmpty(selectedColor)) selectedColorValue = ConfigNode.ParseColor32(selectedColor); if (!string.IsNullOrEmpty(unavailableColor)) unavailableColorValue = ConfigNode.ParseColor32(unavailableColor); persistentVarName = "targetfilter" + internalProp.propID; // 7 is the bitmask for ship-station-probe; VesselFilterFromBitmask(rpmComp.GetPersistentVariable(persistentVarName, defaultFilter, false).MassageToInt()); nameColorTag = JUtil.ColorToColorTag(nameColorValue); distanceColorTag = JUtil.ColorToColorTag(distanceColorValue); selectedColorTag = JUtil.ColorToColorTag(selectedColorValue); unavailableColorTag = JUtil.ColorToColorTag(unavailableColorValue); distanceFormatString = distanceFormatString.UnMangleConfigText(); menuTitleFormatString = menuTitleFormatString.UnMangleConfigText(); topMenu.labelColor = nameColorTag; topMenu.selectedColor = selectedColorTag; topMenu.disabledColor = unavailableColorTag; if (!string.IsNullOrEmpty(pageTitle)) pageTitle = pageTitle.UnMangleConfigText(); foreach (CelestialBody body in FlightGlobals.Bodies) { celestialsList.Add(new Celestial(body, vessel.transform.position)); } FindReferencePoints(); UpdateUndockablesList(); var menuActions = new List<Action<int, TextMenu.Item>>(); menuActions.Add(ShowCelestialMenu); menuActions.Add(ShowVesselMenu); menuActions.Add(ShowSpaceObjectMenu); menuActions.Add(ShowReferenceMenu); menuActions.Add(ShowUndockMenu); menuActions.Add(ArmGrapple); menuActions.Add(ShowFiltersMenu); menuActions.Add(ClearTarget); menuActions.Add(ShowCrewEVA); for (int i = 0; i < rootMenu.Count; ++i) { var menuitem = new TextMenu.Item(); menuitem.labelText = rootMenu[i]; menuitem.action = menuActions[i]; topMenu.Add(menuitem); switch (menuitem.labelText) { case clearTargetItemText: clearTarget = topMenu[i]; break; case undockItemText: undockMenuItem = topMenu[i]; break; case armGrappleText: grappleMenuItem = topMenu[i]; break; case crewEvaText: float acLevel = ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex); bool evaUnlocked = GameVariables.Instance.UnlockedEVA(acLevel); menuitem.isDisabled = !GameVariables.Instance.EVAIsPossible(evaUnlocked, vessel); break; } } activeMenu = topMenu; }
public void CreatePauseMenuButtons(Level level, TextMenu menu, bool minimal) { if (Everest.Flags.IsDisabled || !Settings.ShowModOptionsInGame) { return; } List <TextMenu.Item> items = menu.GetItems(); int index; // Find the options button and place our button below it. string cleanedOptions = Dialog.Clean("menu_pause_options"); index = items.FindIndex(_ => { TextMenu.Button other = (_ as TextMenu.Button); if (other == null) { return(false); } return(other.Label == cleanedOptions); }); if (index != -1) { index++; } // Otherwise, place it below the last button. else { index = items.Count; } TextMenu.Item itemModOptions = null; menu.Insert(index, itemModOptions = new TextMenu.Button(Dialog.Clean("menu_pause_modoptions")).Pressed(() => { int returnIndex = menu.IndexOf(itemModOptions); menu.RemoveSelf(); level.PauseMainMenuOpen = false; level.Paused = true; TextMenu options = OuiModOptions.CreateMenu(true, LevelExt.PauseSnapshot); options.OnESC = options.OnCancel = () => { Audio.Play(SFX.ui_main_button_back); options.CloseAndRun(Everest.SaveSettings(), () => { level.Pause(returnIndex, minimal, false); // adjust the Mod Options menu position, in case it moved (pause menu entries added/removed after changing mod options). TextMenu textMenu = level.Entities.GetToAdd().FirstOrDefault((Entity e) => e is TextMenu) as TextMenu; TextMenu.Button modOptionsButton = textMenu?.GetItems().OfType <TextMenu.Button>() .FirstOrDefault(button => button.Label == Dialog.Clean("menu_pause_modoptions")); if (modOptionsButton != null) { textMenu.Selection = textMenu.IndexOf(modOptionsButton); } }); }; options.OnPause = () => { Audio.Play(SFX.ui_main_button_back); options.CloseAndRun(Everest.SaveSettings(), () => { level.Paused = false; Engine.FreezeTimer = 0.15f; }); }; level.Add(options); })); }
private void ShowCrewEVA(int index, TextMenu.Item ti) { currentMenu = MenuList.CrewEVA; activeMenu = new TextMenu(); activeMenu.labelColor = nameColorTag; activeMenu.selectedColor = selectedColorTag; activeMenu.disabledColor = unavailableColorTag; activeMenu.rightTextColor = distanceColorTag; var vesselCrew = vessel.GetVesselCrew(); for (int crewIdx = 0; crewIdx < vesselCrew.Count; ++crewIdx) { if (vesselCrew[crewIdx] != null) { var tmi = new TextMenu.Item(); tmi.action = CrewEVA; tmi.labelText = vesselCrew[crewIdx].name; tmi.rightText = vesselCrew[crewIdx].experienceTrait.Title; tmi.isSelected = false; tmi.id = crewIdx; activeMenu.Add(tmi); } } }