Exemple #1
0
        public static IView View()
        {
            var bodySelector = new ListSelectView <CelestialBody>("Planet", () => FlightGlobals.fetch == null ? null : FlightGlobals.fetch.bodies, null, Extensions.CbToString);

            bodySelector.CurrentlySelected = FlightGlobals.fetch == null ? null : FlightGlobals.ActiveVessel == null ? FlightGlobals.Bodies[1] : FlightGlobals.ActiveVessel.mainBody;
            var         lat     = new TextBoxView <double>("Lat", "Latitude of landing coordinates", 0, double.TryParse);
            var         lon     = new TextBoxView <double>("Lon", "Longitude of landing coordinates", 0, double.TryParse);
            var         alt     = new TextBoxView <double>("Alt", "Altitude of landing coordinates", 20, SiSuffix.TryParse);
            Func <bool> isValid = () => lat.Valid && lon.Valid && alt.Valid;
            Action <double, double, CelestialBody> load = (latVal, lonVal, body) =>
            {
                lat.Object = latVal;
                lon.Object = lonVal;
                bodySelector.CurrentlySelected = body;
            };

            return(new VerticalView(new IView[]
            {
                lat,
                lon,
                alt,
                bodySelector,
                new ConditionalView(() => FlightGlobals.fetch != null && FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.mainBody != bodySelector.CurrentlySelected,
                                    new LabelView("Landing on a body other than the current one is not recommended.",
                                                  "This causes lots of explosions, it's advisable to teleport to an orbit above the planet, then land on it directly")),
                new DynamicToggleView("Landing", "Land the ship (or stop landing)", Model.DoLander.IsLanding,
                                      isValid, b => Model.DoLander.ToggleLanding(lat.Object, lon.Object, alt.Object, bodySelector.CurrentlySelected)),
                new ConditionalView(() => !Model.DoLander.IsLanding(), new ButtonView("Land here", "Stops the vessel and slowly lowers it to the ground (without teleporting)", () => Model.DoLander.LandHere())),
                new ConditionalView(isValid, new ButtonView("Save", "Save the entered location", () => Model.DoLander.AddSavedCoords(lat.Object, lon.Object, bodySelector.CurrentlySelected))),
                new ButtonView("Load", "Load a previously-saved location", () => Model.DoLander.Load(load)),
                new ButtonView("Delete", "Delete a previously-saved location", Model.DoLander.Delete),
                new ButtonView("Set to current", "Set lat/lon to the current position", () => Model.DoLander.SetToCurrent(load)),
                new ListSelectView <Vessel>("Set lat/lon to", Model.DoLander.LandedVessels, select => Model.DoLander.SetToLanded(load, select), Extensions.VesselToString),
            }));
        }
        public static IView View()
        {
            // Load Auto Open status.
            ReloadConfig();

            var setAutoOpen = new DynamicToggleView("Auto Open", "Open this view when entering the Flight or Tracking Center scenes.",
                                                    () => AutoOpenLander, () => true, v => AutoOpenLander = v);
            var bodySelector = new ListSelectView <CelestialBody>("Body", () => FlightGlobals.fetch == null ? null : FlightGlobals.fetch.bodies, null, Extensions.CbToString);

            bodySelector.CurrentlySelected = FlightGlobals.fetch == null ? null : FlightGlobals.ActiveVessel == null ? Planetarium.fetch.Home : FlightGlobals.ActiveVessel.mainBody;
            var lat    = new TextBoxView <double>("Lat", "Latitude (North/South). Between +90 (North) and -90 (South).", 0.001d, latTryParse);
            var lon    = new TextBoxView <double>("Lon", "Longitude (East/West). Converts to less than 360 degrees.", 0.001d, myTryParse);
            var alt    = new TextBoxView <double>("Alt", "Altitude (Up/Down). Distance above the surface.", 20, altTryParse);
            var setRot = new ToggleView("Force Rotation",
                                        "Rotates vessel such that up on the vessel is up when landing. Otherwise, the current orientation is kept relative to the body.",
                                        true);
            Func <bool> isValid = () => lat.Valid && lon.Valid && alt.Valid;
            Action <double, double, double, CelestialBody> load = (latVal, lonVal, altVal, body) =>
            {
                lat.Object = latVal;
                lon.Object = lonVal;
                alt.Object = altVal;
                bodySelector.CurrentlySelected = body;
            };

            // Load last entered values.
            Model.DoLander.LoadLast(load);

            return(new VerticalView(new IView[]
            {
                setAutoOpen,
                bodySelector,
                new ConditionalView(() => FlightGlobals.fetch != null && FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.mainBody != bodySelector.CurrentlySelected, new LabelView("Landing on a different body is not recommended.", "This may destroy the vessel. Use the Orbit Editor to orbit the body first, then land on it.")),
                lat,
                new ConditionalView(() => !lat.Valid, new LabelView("Latitude must be a number from 0 to (+/-)89.9.", "Values too close to the poles ((+/-)90) can crash KSP, values beyond that are invalid for a latitude.")),
                lon,
                alt,
                new ConditionalView(() => alt.Object < 0, new LabelView("Altitude must be a positive number.", "This may destroy the vessel. Values less than 0 are sub-surface.")),
                setRot,
                new ConditionalView(() => !isValid(), new ButtonView("Cannot Land", "Entered location is invalid. Correct items in red.", null)),
                new ConditionalView(() => !Model.DoLander.IsLanding() && isValid(), new ButtonView("Land", "Teleport to entered location, then slowly lower to surface.", () => Model.DoLander.ToggleLanding(lat.Object, lon.Object, alt.Object, bodySelector.CurrentlySelected, setRot.Value, load))),
                new ConditionalView(() => Model.DoLander.IsLanding(), new ButtonView("Drop (CAUTION!)", "Release vessel to gravity.", () => Model.DoLander.ToggleLanding(lat.Object, lon.Object, alt.Object, bodySelector.CurrentlySelected, setRot.Value, load))),
                new ConditionalView(() => Model.DoLander.IsLanding(), new LabelView("LANDING IN PROGRESS.", "Vessel is being lowered to the surface.")),
                //Launch button here
                new ConditionalView(() => Model.DoLander.IsLanding(), new LabelView(changeHelpString(), "Change location slightly.")),
                new ConditionalView(() => !Model.DoLander.IsLanding(), new ButtonView("Land Here", "Stop at current location, then slowly lower to surface.", () => Model.DoLander.LandHere(load))),
                new ListSelectView <Vessel>("Set to vessel", Model.DoLander.LandedVessels, select => Model.DoLander.SetToLanded(load, select), Extensions.VesselToString),
                new ButtonView("Current", "Set to current location.", () => Model.DoLander.SetToCurrent(load)),
                new ConditionalView(isValid, new ButtonView("Save", "Save the entered location.", () => Model.DoLander.AddSavedCoords(lat.Object, lon.Object, alt.Object, bodySelector.CurrentlySelected))),
                new ButtonView("Load", "Load a saved location.", () => Model.DoLander.Load(load)),
                new ButtonView("Delete", "Delete a saved location.", Model.DoLander.Delete),
            }));
        }
Exemple #3
0
        public static IView View()
        {
            var bodySelector = new ListSelectView <CelestialBody>("Planet", () => FlightGlobals.fetch == null ? null : FlightGlobals.fetch.bodies, null, Extensions.CbToString);

            bodySelector.CurrentlySelected = FlightGlobals.fetch == null ? null : FlightGlobals.ActiveVessel == null ? Planetarium.fetch.Home : FlightGlobals.ActiveVessel.mainBody;
            var lat    = new TextBoxView <double>("Lat", "Latitude of landing coordinates", 0.001d, myTryParse);
            var lon    = new TextBoxView <double>("Lon", "Longitude of landing coordinates", 0.001d, myTryParse);
            var alt    = new TextBoxView <double>("Alt", "Altitude of landing coordinates", 20, Model.SiSuffix.TryParse);
            var setRot = new ToggleView("Set rotation",
                                        "If set, rotates the vessel such that up on the vessel is up when landing. Otherwise, the same orientation is kept as before teleporting, relative to the planet",
                                        false);
            Func <bool> isValid = () => lat.Valid && lon.Valid && alt.Valid;
            Action <double, double, CelestialBody> load = (latVal, lonVal, body) =>
            {
                lat.Object = latVal;
                lon.Object = lonVal;
                bodySelector.CurrentlySelected = body;
            };

            return(new VerticalView(new IView[]
            {
                lat,
                lon,
                alt,
                bodySelector,
                setRot,
                new ConditionalView(() => FlightGlobals.fetch != null && FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.mainBody != bodySelector.CurrentlySelected,
                                    new LabelView("Landing on a body other than the current one is not recommended.",
                                                  "This causes lots of explosions, it's advisable to teleport to an orbit above the planet, then land on it directly")),
                new ConditionalView(() => lat.Valid && (lat.Object <-89.9 || lat.Object> 89.9),
                                    new LabelView("Setting latitude to -90 or 90 degrees (or near it) is dangerous, try 89.9 degrees",
                                                  "(This warning also appears when latitude is past 90 degrees)")),
                new DynamicToggleView("Landing", "Land the ship (or stop landing)", Model.DoLander.IsLanding,
                                      isValid, b => Model.DoLander.ToggleLanding(lat.Object, lon.Object, alt.Object, bodySelector.CurrentlySelected, setRot.Value, load)),
                new ConditionalView(() => Model.DoLander.IsLanding(), new LabelView(HelpString(), "Moves the landing vessel's coordinates slightly")),
                new ConditionalView(() => !Model.DoLander.IsLanding(), new ButtonView("Land here", "Stops the vessel and slowly lowers it to the ground (without teleporting)", () => Model.DoLander.LandHere(load))),
                new ConditionalView(isValid, new ButtonView("Save", "Save the entered location", () => Model.DoLander.AddSavedCoords(lat.Object, lon.Object, bodySelector.CurrentlySelected))),
                new ButtonView("Load", "Load a previously-saved location", () => Model.DoLander.Load(load)),
                new ButtonView("Delete", "Delete a previously-saved location", Model.DoLander.Delete),
                new ButtonView("Set to current", "Set lat/lon to the current position", () => Model.DoLander.SetToCurrent(load)),
                new ListSelectView <Vessel>("Set lat/lon to", Model.DoLander.LandedVessels, select => Model.DoLander.SetToLanded(load, select), Extensions.VesselToString),
            }));
        }
        public static IView View()
        {
            CelestialBody body = null;

            var geeAsl     = new TextBoxView <double>("Gravity multiplier", "1.0 is kerbin, 0.5 is half of kerbin's gravity, etc.", 1, Model.SiSuffix.TryParse);
            var ocean      = new ToggleView("Has ocean", "Does weird things to the ocean if off", false);
            var atmosphere = new ToggleView("Has atmosphere", "Toggles if the planet has atmosphere or not", false);
            var atmosphereContainsOxygen      = new ToggleView("Atmosphere contains oxygen", "Whether jet engines work or not", false);
            var atmosphereDepth               = new TextBoxView <double>("Atmosphere depth", "Theoretically atmosphere height. In reality, doesn't work too well.", 1, Model.SiSuffix.TryParse);
            var atmosphereTemperatureSeaLevel = new TextBoxView <double>("atmosphereTemperatureSeaLevel", "New 1.0 field. Unknown what this does.", 1, Model.SiSuffix.TryParse);
            var atmospherePressureSeaLevel    = new TextBoxView <double>("atmospherePressureSeaLevel", "New 1.0 field. Unknown what this does.", 1, Model.SiSuffix.TryParse);
            var atmosphereMolarMass           = new TextBoxView <double>("atmosphereMolarMass", "New 1.0 field. Unknown what this does.", 1, Model.SiSuffix.TryParse);
            var atmosphereAdiabaticIndex      = new TextBoxView <double>("atmosphereAdiabaticIndex", "New 1.0 field. Unknown what this does.", 1, Model.SiSuffix.TryParse);
            var rotates         = new ToggleView("Rotates", "If the planet rotates.", false);
            var rotationPeriod  = new TextBoxView <double>("Rotation period", "Rotation period of the planet, in seconds.", 1, Model.SiSuffix.TryParse);
            var initialRotation = new TextBoxView <double>("Initial rotation", "Absolute rotation in degrees of the planet at time=0", 1, Model.SiSuffix.TryParse);
            var tidallyLocked   = new ToggleView("Tidally locked", "If the planet is tidally locked. Overrides Rotation Period.", false);

            Action <CelestialBody> onSelect = cb => {
                body             = cb;
                geeAsl.Object    = body.GeeASL;
                ocean.Value      = body.ocean;
                atmosphere.Value = body.atmosphere;
                atmosphereContainsOxygen.Value       = body.atmosphereContainsOxygen;
                atmosphereDepth.Object               = body.atmosphereDepth;
                atmosphereTemperatureSeaLevel.Object = body.atmosphereTemperatureSeaLevel;
                atmospherePressureSeaLevel.Object    = body.atmospherePressureSeaLevel;
                atmosphereMolarMass.Object           = body.atmosphereMolarMass;
                atmosphereAdiabaticIndex.Object      = body.atmosphereAdiabaticIndex;
                rotates.Value          = body.rotates;
                rotationPeriod.Object  = body.rotationPeriod;
                initialRotation.Object = body.initialRotation;
                tidallyLocked.Value    = body.tidallyLocked;
            };

            var selectBody = new ConditionalView(() => FlightGlobals.fetch != null && FlightGlobals.Bodies != null,
                                                 new ListSelectView <CelestialBody>("Selected body", () => FlightGlobals.Bodies, onSelect, Extensions.CbToString));

            var apply = new ConditionalView(() =>
                                            geeAsl.Valid &&
                                            atmosphereDepth.Valid &&
                                            atmosphereTemperatureSeaLevel.Valid &&
                                            atmospherePressureSeaLevel.Valid &&
                                            atmosphereMolarMass.Valid &&
                                            atmosphereAdiabaticIndex.Valid &&
                                            rotationPeriod.Valid &&
                                            initialRotation.Valid,
                                            new ButtonView("Apply", "Applies the changes to the body", () => {
                new Model.PlanetEditor.PlanetSettings(
                    geeAsl.Object,
                    ocean.Value,
                    atmosphere.Value,
                    atmosphereContainsOxygen.Value,
                    atmosphereDepth.Object,
                    atmosphereTemperatureSeaLevel.Object,
                    atmospherePressureSeaLevel.Object,
                    atmosphereMolarMass.Object,
                    atmosphereAdiabaticIndex.Object,
                    rotates.Value,
                    rotationPeriod.Object,
                    initialRotation.Object,
                    tidallyLocked.Value,
                    body.orbit).CopyTo(body, false);
            }));

            var editFields = new ConditionalView(() => body != null, new VerticalView(new IView[]
            {
                geeAsl,
                ocean,
                atmosphere,
                atmosphereContainsOxygen,
                atmosphereDepth,
                atmosphereTemperatureSeaLevel,
                atmospherePressureSeaLevel,
                atmosphereMolarMass,
                atmosphereAdiabaticIndex,
                rotates,
                rotationPeriod,
                initialRotation,
                tidallyLocked,
                apply,
            }));

            var resetToDefault = new ConditionalView(() => body != null,
                                                     new ButtonView("Reset to defaults", "Reset the selected planet to defaults",
                                                                    () => { Model.PlanetEditor.ResetToDefault(body); onSelect(body); }));

            var copyToKerbin = new ConditionalView(() => body != null && body != Model.PlanetEditor.Kerbin,
                                                   new ButtonView("Copy to kerbin", "Copies the selected planet's settings to kerbin",
                                                                  () => new Model.PlanetEditor.PlanetSettings(body).CopyTo(Model.PlanetEditor.Kerbin, false)));

            var savePlanet = new ConditionalView(() => body != null,
                                                 new ButtonView("Save planet to config file", "Saves the current configuration of the planet to a file, so it stays edited even after a restart. Delete the file named the planet's name in " + IoExt.GetPath(null) + " to undo.",
                                                                () => Model.PlanetEditor.SavePlanet(body)));

            var reloadDefaults = new ConditionalView(() => FlightGlobals.fetch != null && FlightGlobals.Bodies != null,
                                                     new ButtonView("Reload config files", "Reloads the planet .cfg files in " + IoExt.GetPath(null),
                                                                    Model.PlanetEditor.ApplyFileDefaults));

            return(new VerticalView(new IView[]
            {
                selectBody,
                editFields,
                resetToDefault,
                copyToKerbin,
                savePlanet,
                reloadDefaults
            }));
        }
        public static IView View()
        {
            ReloadConfig();

            Action resources = () => {
                //Using the Vertical to set the box height.
                GUILayout.BeginVertical(GUILayout.Height(100));
                scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.MinHeight(140));

                foreach (var resource in Model.MiscEditor.GetResources())
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(resource.Key);
                    var newval = (double)GUILayout.HorizontalSlider((float)resource.Value, 0, 1);
                    if (Math.Abs(newval - resource.Value) > 0.001)
                    {
                        Model.MiscEditor.SetResource(resource.Key, newval);
                    }
                    //Just trying an idea
                    //toggleRes = GUILayout.Toggle(toggleRes[resource.Key], "lock");
                    //toggleRes = GUILayout.Toggle(toggleRes, "lock");

                    /*
                     * It'd be nice to lock inf resources for specific vessels, or maybe just any vessel?
                     */

                    //GUILayout.FlexibleSpace();
                    GUILayout.Space(5);
                    GUILayout.EndHorizontal();
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndScrollView();
                GUILayout.EndVertical();
            };
            var setTimeButtonView = new TextBoxView <double>("Time", "Set time (aka UniversalTime)",
                                                             Model.MiscEditor.UniversalTime, Model.SiSuffix.TryParse, null,
                                                             v => Model.MiscEditor.UniversalTime = v);
            var timeIncrementButtonView = new TextBoxView <double>("Increment", "Set time increment (used for + and - buttons)",
                                                                   1, Model.SiSuffix.TryParse, null, null);
            Action timeButtons = () =>
            {
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("-"))
                {
                    setTimeButtonView.Object = Model.MiscEditor.DecrementYear(timeIncrementButtonView.Object);
                }
                GUILayout.Label("Year");
                if (GUILayout.Button("+"))
                {
                    setTimeButtonView.Object = Model.MiscEditor.IncrementYear(timeIncrementButtonView.Object);
                }

                GUILayout.Space(25);

                if (GUILayout.Button("-"))
                {
                    setTimeButtonView.Object = Model.MiscEditor.DecrementDay(timeIncrementButtonView.Object);
                }
                GUILayout.Label("Day");
                if (GUILayout.Button("+"))
                {
                    setTimeButtonView.Object = Model.MiscEditor.IncrementDay(timeIncrementButtonView.Object);
                }

                GUILayout.Space(25);

                if (GUILayout.Button("-"))
                {
                    setTimeButtonView.Object = Model.MiscEditor.DecrementHour(timeIncrementButtonView.Object);
                }
                GUILayout.Label("Hour");
                if (GUILayout.Button("+"))
                {
                    setTimeButtonView.Object = Model.MiscEditor.IncrementHour(timeIncrementButtonView.Object);
                }
                GUILayout.EndHorizontal();
            };

            return(new VerticalView(new IView[]
            {
                new LabelView("Resources", "Set amounts of various resources contained on the active vessel"),
                new CustomView(resources),
                setTimeButtonView,
                new CustomView(timeButtons),
                timeIncrementButtonView,
                new ButtonView("Align SMAs", "Open the semi-major axis aligner window",
                               Model.MiscEditor.AlignSemiMajorAxis),
                new ButtonView("Destroy a vessel", "Select a vessel to destroy", Model.MiscEditor.DestroyVessel),
                new TextBoxView <KeyCode[]>("Boost button key", "Sets the keybinding used for the boost button",
                                            Model.MiscEditor.BoostButtonKey, Extensions.KeyCodeTryParse, Extensions.KeyCodeToString,
                                            v => Model.MiscEditor.BoostButtonKey = v),
                new TextBoxView <double>("Boost button speed",
                                         "Sets the dV applied per frame when the boost button is held down",
                                         Model.MiscEditor.BoostButtonSpeed, Model.SiSuffix.TryParse, null,
                                         v => Model.MiscEditor.BoostButtonSpeed = v)
            }));
        }
Exemple #6
0
        // Also known as "closure hell"
        public static IView View()
        {
            ListSelectView <OrbitDriver> currentlyEditing         = null;
            Action <OrbitDriver>         onCurrentlyEditingChange = null;

            var setToCurrentOrbit = new ButtonView("Set to current orbit", "Sets all the fields of the editor to reflect the orbit of the currently selected vessel",
                                                   () => onCurrentlyEditingChange(currentlyEditing.CurrentlySelected));

            var referenceSelector = new ListSelectView <CelestialBody>("Reference body", () => FlightGlobals.fetch == null ? null : FlightGlobals.fetch.bodies, null, Extensions.CbToString);

            #region Simple
            var simpleAltitude = new TextBoxView <double>("Altitude", "Altitude of circular orbit", 110000, Model.SiSuffix.TryParse);
            var simpleApply    = new ConditionalView(() => simpleAltitude.Valid && referenceSelector.CurrentlySelected != null,
                                                     new ButtonView("Apply", "Sets the orbit", () => {
                Model.OrbitEditor.Simple(currentlyEditing.CurrentlySelected, simpleAltitude.Object, referenceSelector.CurrentlySelected);

                currentlyEditing.ReInvokeOnSelect();
            }));
            var simple = new VerticalView(new IView[]
            {
                simpleAltitude,
                referenceSelector,
                simpleApply,
                setToCurrentOrbit
            });
            #endregion

            #region Complex
            var complexInclination            = new TextBoxView <double>("Inclination", "How close to the equator the orbit plane is", 0, double.TryParse);
            var complexEccentricity           = new TextBoxView <double>("Eccentricity", "How circular the orbit is (0=circular, 0.5=elliptical, 1=parabolic)", 0, double.TryParse);
            var complexSemiMajorAxis          = new TextBoxView <double>("Semi-major axis", "Mean radius of the orbit (ish)", 10000000, Model.SiSuffix.TryParse);
            var complexLongitudeAscendingNode = new TextBoxView <double>("Lon. of asc. node", "Longitude of the place where you cross the equator northwards", 0, double.TryParse);
            var complexArgumentOfPeriapsis    = new TextBoxView <double>("Argument of periapsis", "Rotation of the orbit around the normal", 0, double.TryParse);
            var complexMeanAnomalyAtEpoch     = new TextBoxView <double>("Mean anomaly at epoch", "Position along the orbit at the epoch", 0, double.TryParse);
            var complexEpoch    = new TextBoxView <double>("Epoch", "Epoch at which mEp is measured", 0, Model.SiSuffix.TryParse);
            var complexEpochNow = new ButtonView("Set epoch to now", "Sets the Epoch field to the current time", () => complexEpoch.Object = Planetarium.GetUniversalTime());
            var complexApply    = new ConditionalView(() => complexInclination.Valid &&
                                                      complexEccentricity.Valid &&
                                                      complexSemiMajorAxis.Valid &&
                                                      complexLongitudeAscendingNode.Valid &&
                                                      complexArgumentOfPeriapsis.Valid &&
                                                      complexMeanAnomalyAtEpoch.Valid &&
                                                      complexEpoch.Valid &&
                                                      referenceSelector.CurrentlySelected != null,
                                                      new ButtonView("Apply", "Sets the orbit", () => {
                Model.OrbitEditor.Complex(currentlyEditing.CurrentlySelected,
                                          complexInclination.Object,
                                          complexEccentricity.Object,
                                          complexSemiMajorAxis.Object,
                                          complexLongitudeAscendingNode.Object,
                                          complexArgumentOfPeriapsis.Object,
                                          complexMeanAnomalyAtEpoch.Object,
                                          complexEpoch.Object,
                                          referenceSelector.CurrentlySelected);

                currentlyEditing.ReInvokeOnSelect();
            }));
            var complex = new VerticalView(new IView[]
            {
                complexInclination,
                complexEccentricity,
                complexSemiMajorAxis,
                complexLongitudeAscendingNode,
                complexArgumentOfPeriapsis,
                complexMeanAnomalyAtEpoch,
                complexEpoch,
                complexEpochNow,
                referenceSelector,
                complexApply,
                setToCurrentOrbit
            });
            #endregion

            #region Graphical
            SliderView graphicalInclination            = null;
            SliderView graphicalEccentricity           = null;
            SliderView graphicalPeriapsis              = null;
            SliderView graphicalLongitudeAscendingNode = null;
            SliderView graphicalArgumentOfPeriapsis    = null;
            SliderView graphicalMeanAnomaly            = null;
            double     graphicalEpoch = 0;

            Action <double> graphicalOnChange = ignored => {
                Model.OrbitEditor.Graphical(currentlyEditing.CurrentlySelected,
                                            graphicalInclination.Value,
                                            graphicalEccentricity.Value,
                                            graphicalPeriapsis.Value,
                                            graphicalLongitudeAscendingNode.Value,
                                            graphicalArgumentOfPeriapsis.Value,
                                            graphicalMeanAnomaly.Value,
                                            graphicalEpoch);

                currentlyEditing.ReInvokeOnSelect();
            };

            graphicalInclination            = new SliderView("Inclination", "How close to the equator the orbit plane is", graphicalOnChange);
            graphicalEccentricity           = new SliderView("Eccentricity", "How circular the orbit is", graphicalOnChange);
            graphicalPeriapsis              = new SliderView("Periapsis", "Lowest point in the orbit", graphicalOnChange);
            graphicalLongitudeAscendingNode = new SliderView("Lon. of asc. node", "Longitude of the place where you cross the equator northwards", graphicalOnChange);
            graphicalArgumentOfPeriapsis    = new SliderView("Argument of periapsis", "Rotation of the orbit around the normal", graphicalOnChange);
            graphicalMeanAnomaly            = new SliderView("Mean anomaly", "Position along the orbit", graphicalOnChange);

            var graphical = new VerticalView(new IView[]
            {
                graphicalInclination,
                graphicalEccentricity,
                graphicalPeriapsis,
                graphicalLongitudeAscendingNode,
                graphicalArgumentOfPeriapsis,
                graphicalMeanAnomaly,
                setToCurrentOrbit
            });
            #endregion

            #region Velocity
            var velocitySpeed     = new TextBoxView <double>("Speed", "dV to apply", 0, Model.SiSuffix.TryParse);
            var velocityDirection = new ListSelectView <Model.OrbitEditor.VelocityChangeDirection>("Direction", () => Model.OrbitEditor.AllVelocityChanges);
            var velocityApply     = new ConditionalView(() => velocitySpeed.Valid,
                                                        new ButtonView("Apply", "Adds the selected velocity to the orbit", () => {
                Model.OrbitEditor.Velocity(currentlyEditing.CurrentlySelected, velocityDirection.CurrentlySelected, velocitySpeed.Object);
            }));
            var velocity = new VerticalView(new IView[]
            {
                velocitySpeed,
                velocityDirection,
                velocityApply
            });
            #endregion

            #region Rendezvous
            var rendezvousLeadTime = new TextBoxView <double>("Lead time", "How many seconds off to rendezvous at (zero = on top of each other, bad)", 1, Model.SiSuffix.TryParse);
            var rendezvousVessel   = new ListSelectView <Vessel>("Target vessel", () => FlightGlobals.fetch == null ? null : FlightGlobals.fetch.vessels, null, Extensions.VesselToString);
            var rendezvousApply    = new ConditionalView(() => rendezvousLeadTime.Valid && rendezvousVessel.CurrentlySelected != null,
                                                         new ButtonView("Apply", "Rendezvous", () => {
                Model.OrbitEditor.Rendezvous(currentlyEditing.CurrentlySelected, rendezvousLeadTime.Object, rendezvousVessel.CurrentlySelected);
            }));
            // rendezvous gets special ConditionalView to force only editing of planets
            var rendezvous = new ConditionalView(() => currentlyEditing.CurrentlySelected != null && currentlyEditing.CurrentlySelected.vessel != null,
                                                 new VerticalView(new IView[]
            {
                rendezvousLeadTime,
                rendezvousVessel,
                rendezvousApply
            }));
            #endregion

            #region CurrentlyEditing
            onCurrentlyEditingChange = newEditing => {
                if (newEditing == null)
                {
                    return;
                }
                {
                    double        altitude;
                    CelestialBody body;
                    Model.OrbitEditor.GetSimple(newEditing, out altitude, out body);
                    simpleAltitude.Object = altitude;
                    referenceSelector.CurrentlySelected = body;
                }
                {
                    double        inclination;
                    double        eccentricity;
                    double        semiMajorAxis;
                    double        longitudeAscendingNode;
                    double        argumentOfPeriapsis;
                    double        meanAnomalyAtEpoch;
                    double        epoch;
                    CelestialBody body;
                    Model.OrbitEditor.GetComplex(newEditing,
                                                 out inclination,
                                                 out eccentricity,
                                                 out semiMajorAxis,
                                                 out longitudeAscendingNode,
                                                 out argumentOfPeriapsis,
                                                 out meanAnomalyAtEpoch,
                                                 out epoch,
                                                 out body);
                    complexInclination.Object            = inclination;
                    complexEccentricity.Object           = eccentricity;
                    complexSemiMajorAxis.Object          = semiMajorAxis;
                    complexLongitudeAscendingNode.Object = longitudeAscendingNode;
                    complexArgumentOfPeriapsis.Object    = argumentOfPeriapsis;
                    complexMeanAnomalyAtEpoch.Object     = meanAnomalyAtEpoch;
                    complexEpoch.Object = epoch;
                    referenceSelector.CurrentlySelected = body;
                }
                {
                    double inclination;
                    double eccentricity;
                    double periapsis;
                    double longitudeAscendingNode;
                    double argumentOfPeriapsis;
                    double meanAnomaly;
                    Model.OrbitEditor.GetGraphical(newEditing,
                                                   out inclination,
                                                   out eccentricity,
                                                   out periapsis,
                                                   out longitudeAscendingNode,
                                                   out argumentOfPeriapsis,
                                                   out meanAnomaly,
                                                   out graphicalEpoch);
                    graphicalInclination.Value            = inclination;
                    graphicalEccentricity.Value           = eccentricity;
                    graphicalPeriapsis.Value              = periapsis;
                    graphicalLongitudeAscendingNode.Value = longitudeAscendingNode;
                    graphicalArgumentOfPeriapsis.Value    = argumentOfPeriapsis;
                    graphicalMeanAnomaly.Value            = meanAnomaly;
                }
                {
                    Model.OrbitEditor.VelocityChangeDirection direction;
                    double speed;
                    Model.OrbitEditor.GetVelocity(newEditing, out direction, out speed);
                    velocityDirection.CurrentlySelected = direction;
                    velocitySpeed.Object = speed;
                }
            };

            currentlyEditing = new ListSelectView <OrbitDriver>("Currently editing", Model.OrbitEditor.OrderedOrbits, onCurrentlyEditingChange, Extensions.OrbitDriverToString);

            if (FlightGlobals.fetch != null && FlightGlobals.fetch.activeVessel != null && FlightGlobals.fetch.activeVessel.orbitDriver != null)
            {
                currentlyEditing.CurrentlySelected = FlightGlobals.fetch.activeVessel.orbitDriver;
            }
            #endregion

            var savePlanet = new ButtonView("Save planet", "Saves the current orbit of the planet to a file, so it stays edited even after a restart. Delete the file named the planet's name in " + IoExt.GetPath(null) + " to undo.",
                                            () => Model.PlanetEditor.SavePlanet(currentlyEditing.CurrentlySelected.celestialBody));
            var resetPlanet = new ButtonView("Reset to defaults", "Reset the selected planet to defaults",
                                             () => Model.PlanetEditor.ResetToDefault(currentlyEditing.CurrentlySelected.celestialBody));

            var planetButtons = new ConditionalView(() => currentlyEditing.CurrentlySelected?.celestialBody != null,
                                                    new VerticalView(new IView[]
            {
                savePlanet,
                resetPlanet
            }));

            var tabs = new TabView(new List <KeyValuePair <string, IView> >()
            {
                new KeyValuePair <string, IView>("Simple", simple),
                new KeyValuePair <string, IView>("Complex", complex),
                new KeyValuePair <string, IView>("Graphical", graphical),
                new KeyValuePair <string, IView>("Velocity", velocity),
                new KeyValuePair <string, IView>("Rendezvous", rendezvous),
            });

            return(new VerticalView(new IView[]
            {
                currentlyEditing,
                planetButtons,
                new ConditionalView(() => currentlyEditing.CurrentlySelected != null, tabs)
            }));
        }