コード例 #1
0
ファイル: Extensions.cs プロジェクト: max4805/Everest
        /// <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);
        }
コード例 #2
0
 private static void TrySetNeedRelaunch(TextMenu textMenu, TextMenu.Item item)
 {
     if (item is TextMenu.OnOff onOffItem && needRelaunchItemLabels.Contains(onOffItem.Label))
     {
         item.NeedsRelaunch(textMenu);
     }
 }
コード例 #3
0
        private void OpenExperimentDetails(int experimentIndex, TextMenu.Item experimentItem)
        {
            var experimentModule = experimentModules[experimentIndex];
            var detailsMenu      = new ExperimentDetailsMenu(experimentModule);

            OpenSubMenu(detailsMenu);
        }
コード例 #4
0
 private void RunAllScience(int id, TextMenu.Item item)
 {
     experimentModules.ForEach(exp =>
     {
         RunScience(exp);
     });
 }
コード例 #5
0
ファイル: Extensions.cs プロジェクト: max4805/Everest
        /// <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);
        }
コード例 #6
0
 // 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;
     }));
 }
コード例 #7
0
        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);
            }));
        }
コード例 #8
0
        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);
            }
        }
コード例 #9
0
        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);
        }
コード例 #10
0
 // 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);
 }
コード例 #11
0
 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.
     }));
 }
コード例 #12
0
        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);
        }
コード例 #13
0
        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));
            }
        }
コード例 #14
0
        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));
        }
コード例 #15
0
 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);
 }
コード例 #16
0
        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);
        }
コード例 #17
0
 /// <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);
コード例 #18
0
        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;
            }
        }
コード例 #19
0
ファイル: EverestModule.cs プロジェクト: skyarkhangel/Everest
        /// <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);
            }
        }
コード例 #20
0
        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)
            };
        }
コード例 #21
0
        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;
        }
コード例 #22
0
ファイル: OuiMapList.cs プロジェクト: oatmealine/Everest
        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);
        }
コード例 #23
0
        /// <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);
            }
        }
コード例 #24
0
        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)
            };
        }
コード例 #25
0
        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;
            }
        }
コード例 #26
0
        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);
            }
        }
コード例 #27
0
        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;
        }
コード例 #28
0
 /// <inheritdoc cref="patch_TextMenu.Remove(TextMenu.Item)"/>
 public static TextMenu Remove(this TextMenu self, TextMenu.Item item)
 => ((patch_TextMenu)self).Remove(item);
コード例 #29
0
        /// <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;
            }
        }
コード例 #30
0
        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;
        }
コード例 #31
0
        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);
            }));
        }
コード例 #32
0
        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);
                }
            }
        }