diff --git a/InfernalRobotics.version b/InfernalRobotics.version index 7c0511de..d9ba6aa8 100644 --- a/InfernalRobotics.version +++ b/InfernalRobotics.version @@ -4,7 +4,7 @@ "VERSION": { "MAJOR": 0, "MINOR": 21, - "PATCH": 2 + "PATCH": 3 }, "KSP_VERSION": { "MAJOR": 1, diff --git a/InfernalRobotics/InfernalRobotics/API/IRWrapper.cs b/InfernalRobotics/InfernalRobotics/API/IRWrapper.cs index 27877953..665f8951 100644 --- a/InfernalRobotics/InfernalRobotics/API/IRWrapper.cs +++ b/InfernalRobotics/InfernalRobotics/API/IRWrapper.cs @@ -120,7 +120,7 @@ internal static bool InitWrapper() } LogFormatted("Got Instance, Creating Wrapper Objects"); - IRController = new InfernalRoboticsAPI(ActualServoController); + IRController = new InfernalRoboticsAPI(); isWrapped = true; return true; } @@ -132,22 +132,24 @@ private class InfernalRoboticsAPI : IRAPI private PropertyInfo apiReady; private object actualServoGroups; - public InfernalRoboticsAPI(object irServoController) + public InfernalRoboticsAPI() { DetermineReady(); - BuildServoGroups(irServoController); + BuildServoGroups(); } - private void BuildServoGroups(object irServoController) + private void BuildServoGroups() { - LogFormatted("Getting ServoGroups Object"); var servoGroupsField = IRServoControllerType.GetField("ServoGroups"); if (servoGroupsField == null) LogFormatted("Failed Getting ServoGroups fieldinfo"); + else if (IRWrapper.ActualServoController == null) + { + LogFormatted("ServoController Instance not found"); + } else { - actualServoGroups = servoGroupsField.GetValue(irServoController); - LogFormatted("Success: " + (actualServoGroups != null)); + actualServoGroups = servoGroupsField.GetValue(IRWrapper.ActualServoController); } } @@ -162,7 +164,7 @@ public bool Ready { get { - if (apiReady == null) + if (apiReady == null || actualServoGroups == null) return false; return (bool)apiReady.GetValue(null, null); @@ -173,6 +175,7 @@ public IList ServoGroups { get { + BuildServoGroups (); return ExtractServoGroups(actualServoGroups); } } @@ -181,7 +184,7 @@ private IList ExtractServoGroups(object servoGroups) { var listToReturn = new List(); - if(servoGroups == null) + if (servoGroups == null) return listToReturn; try diff --git a/InfernalRobotics/InfernalRobotics/Command/ServoController.cs b/InfernalRobotics/InfernalRobotics/Command/ServoController.cs index 2b70eda0..24818c24 100644 --- a/InfernalRobotics/InfernalRobotics/Command/ServoController.cs +++ b/InfernalRobotics/InfernalRobotics/Command/ServoController.cs @@ -241,6 +241,8 @@ private void Awake() GameEvents.onPartAttach.Add(OnPartAttach); GameEvents.onPartRemove.Add(OnPartRemove); GameEvents.onEditorShipModified.Add(OnEditorShipModified); + GameEvents.onEditorLoad.Add(OnEditorLoad); + GameEvents.onEditorRestart.Add(OnEditorRestart); ControllerInstance = this; } else @@ -251,6 +253,18 @@ private void Awake() Logger.Log("[ServoController] awake finished successfully", Logger.Level.Debug); } + private void OnEditorRestart() + { + ServoGroups = null; + Logger.Log ("OnEditorRestart called", Logger.Level.Debug); + } + + private void OnEditorLoad(ShipConstruct s, CraftBrowser.LoadType t) + { + OnEditorShipModified (s); + Logger.Log ("OnEditorLoad called", Logger.Level.Debug); + } + private void OnVesselWasModified(Vessel v) { if (v == FlightGlobals.ActiveVessel) @@ -270,7 +284,8 @@ private void OnDestroy() GameEvents.onPartRemove.Remove(OnPartRemove); GameEvents.onVesselWasModified.Remove(OnVesselWasModified); GameEvents.onEditorShipModified.Remove(OnEditorShipModified); - + GameEvents.onEditorLoad.Remove(OnEditorLoad); + GameEvents.onEditorRestart.Remove(OnEditorRestart); Logger.Log("[ServoController] OnDestroy finished successfully", Logger.Level.Debug); } diff --git a/InfernalRobotics/InfernalRobotics/Command/Translator.cs b/InfernalRobotics/InfernalRobotics/Command/Translator.cs index 83de12bf..08519f77 100644 --- a/InfernalRobotics/InfernalRobotics/Command/Translator.cs +++ b/InfernalRobotics/InfernalRobotics/Command/Translator.cs @@ -30,6 +30,9 @@ public void Init(bool motionLock, IServo servo, Interpolator interpolator) public bool IsMotionLock { get; set; } public float GetSpeedUnit() { + if (servo == null) + return 0f; + return servo.Mechanism.DefaultSpeed; } diff --git a/InfernalRobotics/InfernalRobotics/Control/IMechanism.cs b/InfernalRobotics/InfernalRobotics/Control/IMechanism.cs index 03bfff95..38245e97 100644 --- a/InfernalRobotics/InfernalRobotics/Control/IMechanism.cs +++ b/InfernalRobotics/InfernalRobotics/Control/IMechanism.cs @@ -111,5 +111,10 @@ public interface IMechanism /// Used in the editor to reset a parts state to Default /// void Reset(); + + /// + /// Used in the editor to apply Servo limits to symmetry counterparts + /// + void ApplyLimitsToSymmetry(); } } \ No newline at end of file diff --git a/InfernalRobotics/InfernalRobotics/Control/Servo/MechanismBase.cs b/InfernalRobotics/InfernalRobotics/Control/Servo/MechanismBase.cs index bd43986b..2b7b4cba 100644 --- a/InfernalRobotics/InfernalRobotics/Control/Servo/MechanismBase.cs +++ b/InfernalRobotics/InfernalRobotics/Control/Servo/MechanismBase.cs @@ -161,5 +161,20 @@ public void Reconfigure() } public abstract void Reset(); + + public void ApplyLimitsToSymmetry() + { + foreach (Part counterPart in RawServo.part.symmetryCounterparts) + { + var module = ((MuMechToggle)counterPart.Modules ["MuMechToggle"]); + module.rotateMin = RawServo.rotateMin; + module.rotateMax = RawServo.rotateMax; + module.translateMin = RawServo.translateMin; + module.translateMax = RawServo.translateMax; + module.minTweak = RawServo.minTweak; + module.maxTweak = RawServo.maxTweak; + } + Logger.Log ("ApplyingSymmetry, number of counterparts: " + RawServo.part.symmetryCounterparts.Count, Logger.Level.Debug); + } } } \ No newline at end of file diff --git a/InfernalRobotics/InfernalRobotics/Control/Servo/Servo.cs b/InfernalRobotics/InfernalRobotics/Control/Servo/Servo.cs index b81e7aec..32e172a9 100644 --- a/InfernalRobotics/InfernalRobotics/Control/Servo/Servo.cs +++ b/InfernalRobotics/InfernalRobotics/Control/Servo/Servo.cs @@ -35,7 +35,7 @@ public string Name } public uint UID { - get {return rawServo.part.flightID; } + get {return rawServo.part.craftID; } } public bool Highlight { diff --git a/InfernalRobotics/InfernalRobotics/Control/Servo/ServoPreset.cs b/InfernalRobotics/InfernalRobotics/Control/Servo/ServoPreset.cs index 4f63cef7..c359120a 100644 --- a/InfernalRobotics/InfernalRobotics/Control/Servo/ServoPreset.cs +++ b/InfernalRobotics/InfernalRobotics/Control/Servo/ServoPreset.cs @@ -50,12 +50,13 @@ public void Save(bool symmetry = false) rawServo.presetPositionsSerialized = rawServo.SerializePresets(); - if (symmetry && rawServo.part.symmetryCounterparts.Count > 1) + if (symmetry && rawServo.part.symmetryCounterparts.Count >= 1) { foreach (Part part in rawServo.part.symmetryCounterparts) { - ((MuMechToggle)part.Modules["MuMechToggle"]).presetPositionsSerialized = rawServo.presetPositionsSerialized; - ((MuMechToggle)part.Modules["MuMechToggle"]).ParsePresetPositions(); + var module = ((MuMechToggle)part.Modules ["MuMechToggle"]); + module.presetPositionsSerialized = rawServo.presetPositionsSerialized; + module.ParsePresetPositions(); } } } @@ -131,6 +132,14 @@ public void GetNearestPresets(out int floor, out int ceiling) floor = rawServo.PresetPositions.FindLastIndex(p => p < rawServo.Position); if (floor == -1) floor = 0; + + if(rawServo.invertAxis) + { + //if axis is inverted swap two nearest presets + var tmp = ceiling; + ceiling = floor; + floor = tmp; + } } public void RemoveAt(int presetIndex) diff --git a/InfernalRobotics/InfernalRobotics/Gui/ControlsGUI.cs b/InfernalRobotics/InfernalRobotics/Gui/ControlsGUI.cs index 70a26487..75bcdd40 100644 --- a/InfernalRobotics/InfernalRobotics/Gui/ControlsGUI.cs +++ b/InfernalRobotics/InfernalRobotics/Gui/ControlsGUI.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Collections.Generic; using UnityEngine; using File = System.IO.File; @@ -44,8 +45,6 @@ public class ControlsGUI : MonoBehaviour private bool guiGroupEditorEnabled; private bool guiPresetsEnabled; private IServo associatedServo; - private string tmpMax = ""; - private string tmpMin = ""; private bool guiPresetMode; private bool guiHidden; private string tooltipText = ""; @@ -618,31 +617,7 @@ private void DrawTooltip() private void DrawPresetSelector(IServo servo, GUILayoutOption rowHeight) { - //commented out parts are for Future experimental UI with mouse hover - /*var gc = new GUIContent (string.Format ("{0:#0.##}", servo.Mechanism.Position), "Add preset"); - - var customStyle = new GUIStyle (GUI.skin.button); - customStyle.normal.textColor = servo.Mechanism.IsAxisInverted ? Color.yellow : Color.white; - customStyle.alignment = TextAnchor.MiddleCenter; - customStyle.fontSize = 12; - customStyle.fontStyle = servo.Mechanism.IsAxisInverted ? FontStyle.Italic : FontStyle.Normal; - customStyle.padding = new RectOffset(2, 2, 2, 2); - customStyle.fixedWidth = 40; - customStyle.fixedHeight = 22; - - var isPresetPosition = false; - var presetIndex = -1; - - for (int i = 0; i < servo.Preset.Count; i++) - { - if (Math.Abs (servo.Preset [i] - servo.Mechanism.Position) < 0.00001) - { - isPresetPosition = true; - presetIndex = i; - break; - } - } - */ + int floor, ceiling; servo.Preset.GetNearestPresets(out floor, out ceiling); @@ -654,34 +629,6 @@ private void DrawPresetSelector(IServo servo, GUILayoutOption rowHeight) } SetTooltipText(); - /*var rect = GUILayoutUtility.GetRect(gc, customStyle); - if (rect.Contains(Event.current.mousePosition)) - { - if (isPresetPosition) - { - gc.image = TextureLoader.TrashIcon; - gc.text = ""; - gc.tooltip = "Delete Preset"; - tooltipText = gc.tooltip; - } - else - { - gc.text = "Add"; - } - } - - if (GUI.Button(rect, gc, customStyle)) - { - if (isPresetPosition) - { - servo.Preset.RemoveAt (presetIndex); - } - else - { - servo.Preset.Add (servo.Mechanism.Position); - } - } - */ DrawServoPosition(servo, rowHeight); if (GUILayout.Button(new GUIContent(TextureLoader.NextIcon, "Next Preset" + ((ceiling >= 0) ? ": " + servo.Preset[ceiling] : "")), @@ -691,6 +638,39 @@ private void DrawPresetSelector(IServo servo, GUILayoutOption rowHeight) } SetTooltipText(); } + /// + /// Draws the text field and returns its value + /// + /// Entered value + /// Control name. + /// Value. + /// Format. + /// Style. + /// Width. + /// Height. + private string DrawTextField(string controlName, float value, string format, GUIStyle style, GUILayoutOption width, GUILayoutOption height) + { + string focusedControlName = GUI.GetNameOfFocusedControl (); + + if (controlName == focusedControlName + && lastFocusedTextFieldValue == "") + { + lastFocusedTextFieldValue = string.Format (format, value); + } + + string tmp = (controlName == focusedControlName) + ? lastFocusedTextFieldValue + : string.Format (format, value); + + GUI.SetNextControlName(controlName); + tmp = GUILayout.TextField(tmp, style, width, height); + + if (controlName == focusedControlName + && focusedControlName == lastFocusedControlName) + lastFocusedTextFieldValue = tmp; + + return tmp; + } private void DrawServoPosition(IServo servo, GUILayoutOption rowHeight) { @@ -704,16 +684,26 @@ private void DrawServoPosition(IServo servo, GUILayoutOption rowHeight) fontStyle = servo.Mechanism.IsAxisInverted ? FontStyle.Italic : FontStyle.Normal }; var posFormat = Math.Abs(servo.Mechanism.MaxPosition - servo.Mechanism.MinPosition) > 10 ? "{0:#0.0#}" : "{0:#0.0##}"; - lastFocusedTextFieldValue = GUILayout.TextField(string.Format(posFormat, servo.Mechanism.Position), customStyle, GUILayout.Width(40), rowHeight); + + string focusedControlName = GUI.GetNameOfFocusedControl (); + string thisControlName = "Position " + servo.UID; + + string tmp = DrawTextField (thisControlName, servo.Mechanism.Position, posFormat, customStyle, GUILayout.Width (40), rowHeight); + + var valueChanged = (thisControlName == focusedControlName && + (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)); float tmpValue; - if (float.TryParse(lastFocusedTextFieldValue, out tmpValue)) + if (float.TryParse (tmp, out tmpValue) && valueChanged) { + //focus changers are handled elsewhere tmpValue = Mathf.Clamp(tmpValue, servo.Mechanism.MinPositionLimit, servo.Mechanism.MaxPositionLimit); - if (Math.Abs(servo.Mechanism.Position - tmpValue) > 0.005 && GUI.changed) + if (Math.Abs(servo.Mechanism.Position - tmpValue) > 0.005) servo.Mechanism.MoveTo(tmpValue); + + lastFocusedTextFieldValue = ""; } } @@ -959,32 +949,73 @@ private void EditorWindow(int windowID) GUILayout.BeginHorizontal(); GUILayout.Label("Range: ", GUILayout.Width(40), rowHeight); - tmpMin = GUILayout.TextField(string.Format("{0:#0.0#}", servo.Mechanism.MinPositionLimit), GUILayout.Width(40), rowHeight); + //GUI.SetNextControlName ("MinPositionLimit " + servo.UID); + + string focusedControlName = GUI.GetNameOfFocusedControl (); + string thisControlName = "MinPositionLimit " + servo.UID; + + tmp = DrawTextField (thisControlName, servo.Mechanism.MinPositionLimit, "{0:#0.0#}", + GUI.skin.textField, GUILayout.Width (40), rowHeight); + + var valueChanged = (thisControlName == focusedControlName && + (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)); + float tmpValue; - if (float.TryParse(tmpMin, out tmpValue)) + if (float.TryParse (tmp, out tmpValue) && valueChanged) { + //focus changers are handled elsewhere servo.Mechanism.MinPositionLimit = tmpValue; + lastFocusedTextFieldValue = ""; } - tmpMax = GUILayout.TextField(string.Format("{0:#0.0#}", servo.Mechanism.MaxPositionLimit), GUILayout.Width(40), rowHeight); - if (float.TryParse(tmpMax, out tmpValue)) + thisControlName = "MaxPositionLimit " + servo.UID; + + tmp = DrawTextField (thisControlName, servo.Mechanism.MaxPositionLimit, "{0:#0.0#}", + GUI.skin.textField, GUILayout.Width (40), rowHeight); + + valueChanged = (thisControlName == focusedControlName && + (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)); + + if (float.TryParse (tmp, out tmpValue) && valueChanged) { + //focus changers are handled elsewhere servo.Mechanism.MaxPositionLimit = tmpValue; + lastFocusedTextFieldValue = ""; } GUILayout.Label("Spd: ", GUILayout.Width(30), rowHeight); - tmpMin = GUILayout.TextField(string.Format("{0:#0.0##}", servo.Mechanism.SpeedLimit), GUILayout.Width(30), rowHeight); - if (float.TryParse(tmpMin, out tmpValue)) + + thisControlName = "Speed " + servo.UID; + + tmp = DrawTextField (thisControlName, servo.Mechanism.SpeedLimit, "{0:#0.0#}", + GUI.skin.textField, GUILayout.Width (30), rowHeight); + + valueChanged = (thisControlName == focusedControlName && + (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)); + + if (float.TryParse (tmp, out tmpValue) && valueChanged) { + //focus changers are handled elsewhere servo.Mechanism.SpeedLimit = tmpValue; + lastFocusedTextFieldValue = ""; } GUILayout.Label("Acc: ", GUILayout.Width(30), rowHeight); - tmpMin = GUILayout.TextField(string.Format("{0:#0.0##}", servo.Mechanism.AccelerationLimit), GUILayout.Width(30), rowHeight); - if (float.TryParse(tmpMin, out tmpValue)) + + thisControlName = "Acceleration " + servo.UID; + + tmp = DrawTextField (thisControlName, servo.Mechanism.AccelerationLimit, "{0:#0.0#}", + GUI.skin.textField, GUILayout.Width (30), rowHeight); + + valueChanged = (thisControlName == focusedControlName && + (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)); + + if (float.TryParse (tmp, out tmpValue) && valueChanged) { + //focus changers are handled elsewhere servo.Mechanism.AccelerationLimit = tmpValue; + lastFocusedTextFieldValue = ""; } bool servoInverted = servo.Mechanism.IsAxisInverted; @@ -995,6 +1026,11 @@ private void EditorWindow(int windowID) SetTooltipText(); servo.Mechanism.IsAxisInverted = servoInverted; + + if (GUILayout.Button(new GUIContent(TextureLoader.CloneIcon, "Apply Symmetry"), buttonStyle, GUILayout.Width(28), rowHeight)) + { + servo.Mechanism.ApplyLimitsToSymmetry (); + } } if (isEditor) @@ -1097,6 +1133,93 @@ internal static void SetEditorScrollYPosition(Single newY) editorScroll.y = newY; } + private void ProcessFocusChange() + { + var temp = lastFocusedControlName.Split (' '); + Logger.Log ("[GUI] Focus change, lastName = " + lastFocusedControlName + + ", lastValue = " + lastFocusedTextFieldValue + + ", temp.Length = " + temp.Length, Logger.Level.Debug); + + var servoFields = new string[6] {"Preset", "Position", "MinPositionLimit", "MaxPositionLimit", "Speed", "Acceleration"}; + + var pos = Array.IndexOf (servoFields, temp [0]); + + if (pos == 0 && temp.Length == 2 && associatedServo != null) + { + int tmpVal = -1; + if(int.TryParse(temp[1], out tmpVal)) + { + if (tmpVal >= 0 && tmpVal < associatedServo.Preset.Count) + { + float tmpValue; + + if (float.TryParse (lastFocusedTextFieldValue, out tmpValue)) + { + if (tmpValue != associatedServo.Preset [tmpVal] && associatedServo.Preset [tmpVal] == associatedServo.Mechanism.DefaultPosition) + { + associatedServo.Mechanism.DefaultPosition = tmpValue; + } + associatedServo.Preset [tmpVal] = tmpValue; + } + } + } + } + else if (temp.Length == 2 && pos > 0 && pos < 6) + { + uint servoUID = 0; + if(uint.TryParse(temp[1], out servoUID)) + { + //find servo with UID and update its position + var allServos = new List(); + foreach (var g in ServoController.Instance.ServoGroups) + { + allServos.AddRange (g.Servos); + } + var s = allServos.Find (p => p.UID == servoUID); + + if (s != null) + { + float tmpValue; + + if (float.TryParse (lastFocusedTextFieldValue, out tmpValue)) + { + if (pos == 1) + { + tmpValue = Mathf.Clamp(tmpValue, s.Mechanism.MinPositionLimit, s.Mechanism.MaxPositionLimit); + + if (Math.Abs(s.Mechanism.Position - tmpValue) > 0.005) + s.Mechanism.MoveTo(tmpValue); + } + else if (pos == 2) + { + s.Mechanism.MinPositionLimit = tmpValue; + } + else if (pos == 3) + { + s.Mechanism.MaxPositionLimit = tmpValue; + } + else if (pos == 4) + { + s.Mechanism.SpeedLimit = tmpValue; + } + else if (pos == 5) + { + s.Mechanism.AccelerationLimit = tmpValue; + } + } + } + } + } + + if (associatedServo != null) + { + associatedServo.Preset.Sort(); + } + + lastFocusedControlName = GUI.GetNameOfFocusedControl(); + lastFocusedTextFieldValue = ""; + } + private void PresetsEditWindow(int windowID) { GUILayoutOption rowHeight = GUILayout.Height(22); @@ -1107,6 +1230,7 @@ private void PresetsEditWindow(int windowID) if (GUILayout.Button("Add", buttonStyle, GUILayout.Width(30), rowHeight)) { associatedServo.Preset.Add(); + associatedServo.Preset.Sort(); } GUILayout.EndHorizontal(); @@ -1115,17 +1239,44 @@ private void PresetsEditWindow(int windowID) for (int i = 0; i < associatedServo.Preset.Count; i++) { GUILayout.BeginHorizontal(); - GUI.SetNextControlName("Preset " + i); - string tmp = GUILayout.TextField(string.Format("{0:#0.0#}", associatedServo.Preset[i]), GUILayout.ExpandWidth(true), rowHeight); + + string focusedControlName = GUI.GetNameOfFocusedControl (); + string thisControlName = "Preset " + i; + + if (thisControlName == focusedControlName + && lastFocusedTextFieldValue == "") + { + lastFocusedTextFieldValue = string.Format ("{0:#0.0#}", associatedServo.Preset [i]); + } + + string tmp = (thisControlName == focusedControlName) + ? lastFocusedTextFieldValue + : string.Format("{0:#0.0#}", associatedServo.Preset[i]); + + GUI.SetNextControlName(thisControlName); + tmp = GUILayout.TextField(tmp, GUILayout.ExpandWidth(true), rowHeight); + + if (thisControlName == focusedControlName + && focusedControlName == lastFocusedControlName) + lastFocusedTextFieldValue = tmp; + + var valueChanged = (thisControlName == focusedControlName && + (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)); float tmpValue; - if (float.TryParse(tmp, out tmpValue)) + + if (float.TryParse (tmp, out tmpValue) && valueChanged) { - if (tmpValue != associatedServo.Preset[i] && associatedServo.Preset[i] == associatedServo.Mechanism.DefaultPosition) + //focus changes are handled elsewhere + if (tmpValue != associatedServo.Preset [i] && associatedServo.Preset [i] == associatedServo.Mechanism.DefaultPosition) { associatedServo.Mechanism.DefaultPosition = tmpValue; } - associatedServo.Preset[i] = tmpValue; + associatedServo.Preset [i] = tmpValue; + associatedServo.Preset.Sort (); + //unfocus control as the list is sorted + GUIUtility.keyboardControl = 0; + lastFocusedTextFieldValue = ""; } bool isDefault = (associatedServo.Preset[i] == associatedServo.Mechanism.DefaultPosition); @@ -1152,12 +1303,6 @@ private void PresetsEditWindow(int windowID) GUILayout.EndHorizontal(); } - if (lastFocusedControlName != GUI.GetNameOfFocusedControl()) - { - associatedServo.Preset.Sort(); - lastFocusedControlName = GUI.GetNameOfFocusedControl(); - } - GUILayout.BeginHorizontal(); if (GUILayout.Button("Apply Symmetry", buttonStyle)) @@ -1165,7 +1310,7 @@ private void PresetsEditWindow(int windowID) associatedServo.Preset.Save(true); } - if (GUILayout.Button("Save&Exit", buttonStyle, GUILayout.Width(70))) + if (GUILayout.Button("Close", buttonStyle, GUILayout.Width(70))) { associatedServo.Preset.Save(); guiPresetsEnabled = false; @@ -1261,6 +1406,20 @@ private void OnGUI() if (editorWindowWidth > Screen.width * 0.7) editorWindowWidth = (int)Math.Round(Screen.width * 0.7f); + if (GUIEnabled && !guiHidden) + { + if (lastFocusedControlName != GUI.GetNameOfFocusedControl ()) + { + ProcessFocusChange (); + } + + //this code defocuses the TexFields if you click mouse elsewhere + if (GUIUtility.hotControl > 0 && GUIUtility.hotControl != GUIUtility.keyboardControl) + { + GUIUtility.keyboardControl = 0; + } + } + if (scene == GameScenes.FLIGHT) { GUILayoutOption height = GUILayout.Height(Screen.height / 2f); diff --git a/InfernalRobotics/InfernalRobotics/Module/MuMechToggle.cs b/InfernalRobotics/InfernalRobotics/Module/MuMechToggle.cs index 690a74c3..9b8d434b 100644 --- a/InfernalRobotics/InfernalRobotics/Module/MuMechToggle.cs +++ b/InfernalRobotics/InfernalRobotics/Module/MuMechToggle.cs @@ -9,11 +9,16 @@ using KSP.IO; using KSPAPIExtensions; using UnityEngine; +using TweakScale; namespace InfernalRobotics.Module { - public class MuMechToggle : PartModule + public class MuMechToggle : PartModule, IRescalable { + //these 3 are for sending messages to inform nuFAR of shape changes to the craft. + private const int shapeUpdateTimeout = 60; //it will send message every xx FixedUpdates + private int shapeUpdateCounter = 0; + private float lastPosition = 0f; private const string ELECTRIC_CHARGE_RESOURCE_NAME = "ElectricCharge"; @@ -125,6 +130,7 @@ public class MuMechToggle : PartModule [KSPField(isPersistant = false)] public string translateModel = "on"; private SoundSource motorSound; + private bool failedAttachment = false; public MuMechToggle() { @@ -346,6 +352,9 @@ public override void OnAwake() try { + Events["InvertAxisToggle"].guiName = invertAxis ? "Un-invert Axis" : "Invert Axis"; + Events["MotionLockToggle"].guiName = isMotionLock ? "Disengage Lock" : "Engage Lock"; + if (rotateJoint) { minTweak = rotateMin; @@ -354,6 +363,7 @@ public override void OnAwake() if (limitTweakable) { Events["LimitTweakableToggle"].active = true; + Events["LimitTweakableToggle"].guiName = limitTweakableFlag ? "Disengage Limits" : "Engage Limits"; } if (freeMoving) @@ -468,6 +478,8 @@ public override void OnLoad(ConfigNode config) ParsePresetPositions(); + UpdateMinMaxTweaks (); + Logger.Log("[OnLoad] End", Logger.Level.Debug); } @@ -576,8 +588,18 @@ protected void ReparentFriction(Transform obj) public void BuildAttachments() { - if (part.findAttachNodeByPart(part.parent).id.Contains(bottomNode) - || part.attachMode == AttachModes.SRF_ATTACH) + if (part.parent == null) + { + Logger.Log ("BuildAttachments: part.parent is null", Logger.Level.Warning); + if(!isMotionLock) + SetLock (true); + failedAttachment = true; + return; + } + var node = part.findAttachNodeByPart (part.parent); + if (node != null && + (node.id.Contains(bottomNode) + || part.attachMode == AttachModes.SRF_ATTACH)) { if (fixedMesh != "") { @@ -602,6 +624,7 @@ public void BuildAttachments() translateAxis *= -1; } ReparentFriction(part.transform); + failedAttachment = false; } protected void FindTransforms() @@ -655,6 +678,7 @@ public override void OnStart(StartState state) if (limitTweakable) { Events["LimitTweakableToggle"].active = rotateJoint; + Events["LimitTweakableToggle"].guiName = limitTweakableFlag ? "Disengage Limits" : "Engage Limits"; } //it seems like we do need to call this one more time as OnVesselChange was called after Awake //for some reason it was not necessary for legacy parts, but needed for rework parts. @@ -867,12 +891,6 @@ protected bool KeyUnPressed(string key) protected void CheckInputs() { - if (part.isConnected && KeyPressed(onKey)) - { - on = !on; - UpdateState(); - } - if (KeyPressed(rotateKey) || KeyPressed(translateKey)) { Translator.Move(float.PositiveInfinity, speedTweak * customSpeed); @@ -884,8 +902,7 @@ protected void CheckInputs() else if (KeyUnPressed(rotateKey) || KeyUnPressed(translateKey) || KeyUnPressed(revRotateKey) || KeyUnPressed(revTranslateKey)) { Translator.Stop(); - } - + } } protected void DoRotation() @@ -897,13 +914,14 @@ protected void DoRotation() (invertSymmetry ? ((IsSymmMaster() || (part.symmetryCounterparts.Count != 1)) ? 1 : -1) : 1)* (rotation - rotationDelta), rotateAxis); } - else if (transform != null) + else if (RotateModelTransform != null) { Quaternion curRot = Quaternion.AngleAxis( (invertSymmetry ? ((IsSymmMaster() || (part.symmetryCounterparts.Count != 1)) ? 1 : -1) : 1)* rotation, rotateAxis); - transform.FindChild("model").FindChild(rotateModel).localRotation = curRot; + RotateModelTransform.localRotation = curRot; + //transform.FindChild("model").FindChild(rotateModel).localRotation = curRot; } } @@ -922,7 +940,7 @@ protected void DoTranslation() } } - public void OnRescale(float factor) + public void OnRescale(ScalingFactor factor) { if (rotateJoint) return; @@ -933,35 +951,24 @@ public void OnRescale(float factor) //translateMin *= factor; //translateMax *= factor; - minTweak *= factor; - maxTweak *= factor; + minTweak *= factor.relative.linear; + maxTweak *= factor.relative.linear; // The part center is the origin of the moving mesh // so if translation!=0, the fixed mesh moves on rescale. // We need to move the part back so the fixed mesh stays at the same place. - transform.Translate(-translateAxis * translation * (factor-1f) ); + transform.Translate(-translateAxis * translation * (factor.relative.linear-1f) ); if (HighLogic.LoadedSceneIsEditor) - translation *= factor; + translation *= factor.relative.linear; // update the window so the new limits are applied UpdateMinMaxTweaks(); - UIPartActionWindow[] actionWindows = FindObjectsOfType(); - if (actionWindows.Length > 0) - { - foreach (UIPartActionWindow actionWindow in actionWindows) - { - if (actionWindow.part == part) - { - TweakWindow = actionWindow; - TweakIsDirty = true; - } - } - } - else - { - TweakWindow = null; - } + + TweakWindow = part.FindActionWindow (); + TweakIsDirty = true; + + Logger.Log ("OnRescale called, TweakWindow is null? = " + (TweakWindow == null), Logger.Level.Debug); } @@ -972,14 +979,17 @@ public void RefreshTweakUI() UpdateMinMaxTweaks(); - if (part.symmetryCounterparts.Count > 1) + if (part.symmetryCounterparts.Count >= 1) { foreach (Part counterPart in part.symmetryCounterparts) { - ((MuMechToggle) counterPart.Modules["MuMechToggle"]).rotateMin = rotateMin; - ((MuMechToggle) counterPart.Modules["MuMechToggle"]).rotateMax = rotateMax; - ((MuMechToggle) counterPart.Modules["MuMechToggle"]).minTweak = minTweak; - ((MuMechToggle) counterPart.Modules["MuMechToggle"]).maxTweak = maxTweak; + var module = ((MuMechToggle)counterPart.Modules ["MuMechToggle"]); + module.rotateMin = rotateMin; + module.rotateMax = rotateMax; + module.translateMin = translateMin; + module.translateMax = translateMax; + module.minTweak = minTweak; + module.maxTweak = maxTweak; } } } @@ -1021,6 +1031,32 @@ void Update() } } + /// + /// This method sends a message every shapeUpdateTimeout FixedUpdate to part and its + /// children to update the shape. This is needed for nuFAR to rebuild the voxel shape accordingly. + /// + private void ProcessShapeUpdates() + { + if (shapeUpdateCounter < shapeUpdateTimeout) + { + shapeUpdateCounter++; + return; + } + + if (Math.Abs(lastPosition - this.Position) >= 0.005) + { + part.SendMessage("UpdateShapeWithAnims"); + foreach (var p in part.children) + { + p.SendMessage("UpdateShapeWithAnims"); + } + + lastPosition = this.Position; + } + + shapeUpdateCounter = 0; + } + public void FixedUpdate() { if (HighLogic.LoadedScene != GameScenes.FLIGHT && HighLogic.LoadedScene != GameScenes.EDITOR) @@ -1081,6 +1117,8 @@ public void FixedUpdate() child.UpdateOrgPosAndRot(vessel.rootPart); } } + + ProcessShapeUpdates(); } public void HandleElectricCharge() @@ -1112,6 +1150,16 @@ public override void OnInactive() public void SetLock(bool isLocked) { + if(!isLocked && failedAttachment) + { + BuildAttachments (); + if (failedAttachment) + { + Logger.Log ("Failed rebuilding attachments, try again", Logger.Level.Debug); + return; + } + + } isMotionLock = isLocked; Events["MotionLockToggle"].guiName = isMotionLock ? "Disengage Lock" : "Engage Lock"; @@ -1205,15 +1253,6 @@ public void MoveNextPresetAction(KSPActionParam param) Translator.Stop(); else MoveNextPreset(); - /*switch (param.type) - { - case KSPActionType.Activate: - MoveNextPreset (); - break; - case KSPActionType.Deactivate: - Translator.Stop(); - break; - }*/ } [KSPAction("Move To Previous Preset")] @@ -1223,16 +1262,6 @@ public void MovePrevPresetAction(KSPActionParam param) Translator.Stop(); else MovePrevPreset(); - - /*switch (param.type) - { - case KSPActionType.Activate: - MovePrevPreset (); - break; - case KSPActionType.Deactivate: - Translator.Stop(); - break; - }*/ } @@ -1270,7 +1299,7 @@ public void MoveCenterAction(KSPActionParam param) switch (param.type) { case KSPActionType.Activate: - Translator.Move(Translator.ToExternalPos(0f), customSpeed * speedTweak); + Translator.Move(Translator.ToExternalPos(defaultPosition), customSpeed * speedTweak); break; case KSPActionType.Deactivate: Translator.Stop (); @@ -1331,8 +1360,6 @@ public void ApplyDeltaPos(float deltaPos) } } - - public void MoveLeft() { Move(-1); diff --git a/InfernalRobotics/InfernalRobotics/Properties/AssemblyInfo.cs b/InfernalRobotics/InfernalRobotics/Properties/AssemblyInfo.cs index e07eb763..f0c4e935 100644 --- a/InfernalRobotics/InfernalRobotics/Properties/AssemblyInfo.cs +++ b/InfernalRobotics/InfernalRobotics/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.19.0.0")] -[assembly: AssemblyFileVersion("0.19.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("0.21.3.0")] +[assembly: AssemblyFileVersion("0.21.3.0")] \ No newline at end of file diff --git a/InfernalRobotics/InfernalRobotics/Utility/TextureLoader.cs b/InfernalRobotics/InfernalRobotics/Utility/TextureLoader.cs index 2cd64c20..607fae3e 100644 --- a/InfernalRobotics/InfernalRobotics/Utility/TextureLoader.cs +++ b/InfernalRobotics/InfernalRobotics/Utility/TextureLoader.cs @@ -31,6 +31,7 @@ public class TextureLoader internal static Texture2D NoninvertedIcon { get; private set; } internal static Texture2D NextIcon { get; private set; } internal static Texture2D PrevIcon { get; private set; } + internal static Texture2D CloneIcon { get; private set; } protected static TextureLoader LoaderInstance; @@ -113,6 +114,9 @@ public static void InitTextures() PrevIcon = new Texture2D(32, 32, TextureFormat.ARGB32, false); LoadImageFromFile(PrevIcon, "prev.png"); + CloneIcon = new Texture2D(32, 32, TextureFormat.ARGB32, false); + LoadImageFromFile(CloneIcon, "clone.png"); + isReady = true; } } diff --git a/Resources/GameData/MagicSmokeIndustries/InfernalRobotics.version b/Resources/GameData/MagicSmokeIndustries/InfernalRobotics.version index b23f342d..d9ba6aa8 100644 --- a/Resources/GameData/MagicSmokeIndustries/InfernalRobotics.version +++ b/Resources/GameData/MagicSmokeIndustries/InfernalRobotics.version @@ -4,11 +4,11 @@ "VERSION": { "MAJOR": 0, "MINOR": 21, - "PATCH": 1 + "PATCH": 3 }, "KSP_VERSION": { "MAJOR": 1, "MINOR": 0, - "PATCH": 0 + "PATCH": 2 } } diff --git a/Resources/GameData/MagicSmokeIndustries/Textures/clone.png b/Resources/GameData/MagicSmokeIndustries/Textures/clone.png new file mode 100755 index 00000000..1829b247 Binary files /dev/null and b/Resources/GameData/MagicSmokeIndustries/Textures/clone.png differ