public override void OnInspectorGUI()
        {
            string currentControlName;
            bool   deselect;

            // Check for key down before drawing any fields because they might consume the event.
            bool enterKeyDown = Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return;

            // Load serialized object.
            serializedObject.Update();

            // Port field.
            EditorGUI.BeginChangeCheck();
            GUI.SetNextControlName(portControlName);
            int newPort = EditorGUILayout.IntField(_portLabel, _oscOut.port);

            if (EditorGUI.EndChangeCheck())
            {
                _portProp.intValue = newPort;
                if (_oscOut.isOpen)
                {
                    _oscOut.Close();                                  // Close socket while editing
                }
            }
            currentControlName = GUI.GetNameOfFocusedControl();
            bool enterKeyDownPort = enterKeyDown && currentControlName == portControlName;

            if (enterKeyDownPort)
            {
                UnfocusAndUpdateUI();
            }
            deselect = _prevControlName == portControlName && currentControlName != portControlName;
            if ((deselect || enterKeyDownPort) && !_oscOut.isOpen)
            {
                if (_oscOut.Open(_portProp.intValue, _remoteIpAddressProp.stringValue))
                {
                    _tempPort = _portProp.intValue;
                }
                else
                {
                    _portProp.intValue = _tempPort;                     // Undo
                    _oscOut.Open(_portProp.intValue, _remoteIpAddressProp.stringValue);
                }
            }

            // Mode field.
            EditorGUI.BeginChangeCheck();
            OscSendMode newMode = (OscSendMode)EditorGUILayout.EnumPopup(_modeLabel, _oscOut.mode);

            if (EditorGUI.EndChangeCheck() && newMode != _oscOut.mode)
            {
                switch (newMode)
                {
                case OscSendMode.UnicastToSelf:         _oscOut.Open(_oscOut.port); break;

                case OscSendMode.Unicast:                       _oscOut.Open(_oscOut.port, OscConst.unicastAddressDefault); break;

                case OscSendMode.Multicast:                     _oscOut.Open(_oscOut.port, OscConst.multicastAddressDefault); break;

                case OscSendMode.Broadcast:                     _oscOut.Open(_oscOut.port, IPAddress.Broadcast.ToString()); break;
                }
                UpdateStatusInEditMode();
            }

            // IP Address field.
            EditorGUI.BeginChangeCheck();
            GUI.SetNextControlName(ipAddressControlName);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PrefixLabel(_remoteIpAddressLabel);
            string newIp = EditorGUILayout.TextField(_oscOut.remoteIpAddress);               // Field

            if (EditorGUI.EndChangeCheck())
            {
                IPAddress ip;
                if (IPAddress.TryParse(newIp, out ip))
                {
                    _remoteIpAddressProp.stringValue = newIp;                                                       // Accept only valid ip addresses
                }
                if (_oscOut.isOpen)
                {
                    _oscOut.Close();                                  // Close socket while editing
                }
                if (!Application.isPlaying)
                {
                    if (_pingEnumerator != null)
                    {
                        _pingEnumerator = null;                                               // Don't update ping coroutine while editing
                    }
                    if (_statusInEditMode != OscRemoteStatus.Unknown)
                    {
                        _statusInEditMode = OscRemoteStatus.Unknown;
                    }
                }
            }
            GUILayout.FlexibleSpace();
            Rect rect = GUILayoutUtility.GetRect(16, 5);

            rect.width = 5;
            rect.x    += 3;
            rect.y    += 7;
            OscRemoteStatus status = Application.isPlaying ? _oscOut.remoteStatus : _statusInEditMode;

            EditorGUI.DrawRect(rect, StatusToColor(status));
            EditorGUILayout.EndHorizontal();
            GUILayoutUtility.GetRect(1, 2);               // vertical spacing
            currentControlName = GUI.GetNameOfFocusedControl();
            bool enterKeyDownIp = enterKeyDown && currentControlName == ipAddressControlName;

            if (enterKeyDownIp)
            {
                UnfocusAndUpdateUI();
            }
            deselect = _prevControlName == ipAddressControlName && currentControlName != ipAddressControlName;
            if ((deselect || enterKeyDownIp) && !_oscOut.isOpen)                 // All this mess to check for end edit, OMG!!! Not cool.
            {
                if (_oscOut.Open(_portProp.intValue, _remoteIpAddressProp.stringValue))
                {
                    _tempIPAddress = _remoteIpAddressProp.stringValue;
                    UpdateStatusInEditMode();
                }
                else
                {
                    _remoteIpAddressProp.stringValue = _tempIPAddress;                     // Undo
                }
            }

            // Is Open field.
            EditorGUI.BeginDisabledGroup(true);
            EditorGUILayout.Toggle(_isOpenLabel, _oscOut.isOpen);
            EditorGUI.EndDisabledGroup();

            // Open On Awake field.
            EditorGUI.BeginDisabledGroup(Application.isPlaying);
            EditorGUILayout.PropertyField(_openOnAwakeProp, _openOnAwakeLabel);
            EditorGUI.EndDisabledGroup();

            // Settings ...
            _settingsFoldoutProp.boolValue = EditorGUILayout.Foldout(_settingsFoldoutProp.boolValue, _settingsFoldLabel, true);
            if (_settingsFoldoutProp.boolValue)
            {
                EditorGUI.indentLevel++;

                // Udp Buffer Size field.
                EditorGUI.BeginChangeCheck();
                int newBufferSize = EditorGUILayout.IntField(_udpBufferSizeLabel, _udpBufferSizeProp.intValue);
                if (EditorGUI.EndChangeCheck())
                {
                    if (newBufferSize >= OscConst.udpBufferSizeMin)
                    {
                        _udpBufferSizeProp.intValue = newBufferSize;
                        _oscOut.udpBufferSize       = newBufferSize;                   // This will reopen OscOut
                    }
                }

                // Bundle messages automatically.
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField(_bundleMessagesAutomaticallyLabel, GUILayout.Width(220));
                GUILayout.FlexibleSpace();
                _bundleMessagesAutomaticallyProp.boolValue = EditorGUILayout.Toggle(_bundleMessagesAutomaticallyProp.boolValue, GUILayout.Width(30));
                EditorGUILayout.EndHorizontal();
                if (!_bundleMessagesAutomaticallyProp.boolValue)
                {
                    EditorGUILayout.HelpBox("Unbundled messages that are send successively are prone to be lost. Only disable this setting if your receiving end does not support OSC bundles.", MessageType.Warning);
                }

                EditorGUI.indentLevel--;
            }

            // Monitor ...
            EditorGUI.BeginDisabledGroup(!_oscOut.isOpen);
            _sb.Clear();
            _sb.Append("Messages (").Append(_oscOut.messageCountSendLastFrame).Append(',').Append(OscDebug.GetPrettyByteSize(_oscOut.byteCountSendLastFrame)).Append(')');
            GUIContent messagesFoldContent = new GUIContent(_sb.ToString(), "Messages received last update");

            _messagesFoldoutProp.boolValue = EditorGUILayout.Foldout(_messagesFoldoutProp.boolValue, messagesFoldContent, true);
            if (_messagesFoldoutProp.boolValue)
            {
                EditorGUI.indentLevel++;
                if (_messageMonitorText.Length > 0)
                {
                    _messageMonitorText.Remove(_messageMonitorText.Length - 1, 1);                                                  // Trim last new line temporarily.
                }
                EditorGUILayout.HelpBox(_messageMonitorText.ToString(), MessageType.None);
                if (_messageMonitorText.Length > 0)
                {
                    _messageMonitorText.Append('\n');
                }
                EditorGUI.indentLevel--;
            }
            EditorGUI.EndDisabledGroup();


            // Apply
            serializedObject.ApplyModifiedProperties();

            // Request OnInspectorGUI to be called every frame as long as inspector is active
            EditorUtility.SetDirty(target);

            // Update ping coroutine manually in Edit Mode. (Unity does not run coroutines in Edit Mode)
            if (!Application.isPlaying && _pingEnumerator != null)
            {
                OscHelper.UpdateCoroutineInEditMode(_pingEnumerator, ref _lastPingTime);
            }

            // Store name of focused control to detect unfocus events
            _prevControlName = GUI.GetNameOfFocusedControl();
        }
        public override void OnInspectorGUI()
        {
            Rect   rect;
            string currentControlName;

            // Check for key down before drawing any fields because they might consume the event.
            bool enterKeyDown = Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return;

            // Load serialized object
            serializedObject.Update();

            // Port field
            EditorGUI.BeginChangeCheck();
            GUI.SetNextControlName(portControlName);
            int newPort = EditorGUILayout.IntField(_portLabel, _oscIn.port);

            if (EditorGUI.EndChangeCheck())
            {
                _portProp.intValue = newPort;
                if (_oscIn.isOpen)
                {
                    _oscIn.Close();                                 // Close UDPReceiver while editing
                }
            }
            currentControlName = GUI.GetNameOfFocusedControl();
            bool enterKeyDownPort = enterKeyDown && currentControlName == portControlName;

            if (enterKeyDownPort)
            {
                UnfocusAndUpdateUI();
            }
            bool deselect = _prevControlName == portControlName && currentControlName != portControlName;

            if ((deselect || enterKeyDownPort) && !_oscIn.isOpen)
            {
                if (_oscIn.Open(_portProp.intValue))
                {
                    _tempPort = _portProp.intValue;
                }
                else
                {
                    _portProp.intValue = _tempPort;                     // undo
                    _oscIn.Open(_portProp.intValue);
                }
            }

            // Mode field
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(_modeProp, _modeLabel);
            if (EditorGUI.EndChangeCheck())
            {
                switch ((OscReceiveMode)_modeProp.enumValueIndex)
                {
                case OscReceiveMode.UnicastBroadcast:
                    _oscIn.Open(_oscIn.port, string.Empty);
                    _multicastAddressProp.stringValue = string.Empty;
                    break;

                case OscReceiveMode.UnicastBroadcastMulticast:
                    _oscIn.Open(_oscIn.port, OscConst.multicastAddressDefault);
                    _multicastAddressProp.stringValue = OscConst.multicastAddressDefault;
                    break;
                }
            }

            // Multicast field
            if (_oscIn.mode == OscReceiveMode.UnicastBroadcastMulticast)
            {
                EditorGUI.BeginChangeCheck();
                GUI.SetNextControlName(multicastAddressControlName);
                EditorGUILayout.PropertyField(_multicastAddressProp, _multicastIpAddressLabel);
                if (EditorGUI.EndChangeCheck())
                {
                    if (_oscIn.isOpen)
                    {
                        _oscIn.Close();                                     // Close socket while editing
                    }
                }
                currentControlName = GUI.GetNameOfFocusedControl();
                bool enterKeyDownMulticastIpAddress = enterKeyDown && currentControlName == multicastAddressControlName;
                if (enterKeyDownMulticastIpAddress)
                {
                    UnfocusAndUpdateUI();
                }
                deselect = _prevControlName == multicastAddressControlName && currentControlName != multicastAddressControlName;
                if ((deselect || enterKeyDownMulticastIpAddress) && !_oscIn.isOpen)
                {
                    if (_oscIn.Open(_portProp.intValue, _multicastAddressProp.stringValue))
                    {
                        _tempMulticastAddress = _multicastAddressProp.stringValue;
                    }
                    else
                    {
                        _multicastAddressProp.stringValue = _tempMulticastAddress;                         // undo
                        _oscIn.Open(_portProp.intValue, _multicastAddressProp.stringValue);
                    }
                }
            }

            // IP Address field.
            EditorGUILayout.BeginVertical();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PrefixLabel(_localIpAddressLabel);
            EditorGUILayout.LabelField(" ");
            rect = GUILayoutUtility.GetLastRect();             // UI voodoo to position the selectable label perfectly
            EditorGUI.SelectableLabel(rect, OscIn.localIpAddress);
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();

            // Alternative IP Addresses field.
            if (OscIn.localIpAddressAlternatives.Count > 0)
            {
                int i = 0;
                foreach (string ip in OscIn.localIpAddressAlternatives)
                {
                    EditorGUILayout.BeginVertical();
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.PrefixLabel(new GUIContent(_localIpAddressAlternativesLabel.text + "[" + i + "]", _localIpAddressAlternativesLabel.tooltip));
                    EditorGUILayout.LabelField(" ");
                    rect = GUILayoutUtility.GetLastRect();                     // UI voodoo to position the selectable label perfectly
                    EditorGUI.SelectableLabel(rect, ip);
                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.EndVertical();
                    i++;
                }
            }

            // Is Open field
            EditorGUI.BeginDisabledGroup(true);
            EditorGUILayout.Toggle(_isOpenLabel, _oscIn.isOpen);
            EditorGUI.EndDisabledGroup();

            // Open On Awake field
            EditorGUI.BeginDisabledGroup(Application.isPlaying);
            EditorGUILayout.PropertyField(_openOnAwakeProp, _openOnAwakeLabel);
            EditorGUI.EndDisabledGroup();


            // Settings ...
            _settingsFoldoutProp.boolValue = EditorGUILayout.Foldout(_settingsFoldoutProp.boolValue, _settingsFoldLabel, true);

            if (_settingsFoldoutProp.boolValue)
            {
                EditorGUI.indentLevel++;

                // Udp Buffer Size field.
                EditorGUI.BeginChangeCheck();
                int newBufferSize = EditorGUILayout.IntField(_udpBufferSizeLabel, _udpBufferSizeProp.intValue);
                if (EditorGUI.EndChangeCheck())
                {
                    if (newBufferSize >= OscConst.udpBufferSizeMin)
                    {
                        _udpBufferSizeProp.intValue = newBufferSize;
                        _oscIn.udpBufferSize        = newBufferSize;                  // This will reopen OscIn
                    }
                }

                // Filter Duplicates field
                BoolSettingsField(_filterDuplicatesProp, _filterDuplicatesLabel);

                // Add Time Tags To Bundled Messages field.
                BoolSettingsField(_addTimeTagsToBundledMessagesProp, _addTimeTagsToBundledMessagesLabel);

                EditorGUI.indentLevel--;
            }

            // Mappings ...
            string mappingsFoldLabel = "Mappings (" + _mappingsProp.arraySize + ")";

            _mappingsFoldoutProp.boolValue = EditorGUILayout.Foldout(_mappingsFoldoutProp.boolValue, mappingsFoldLabel, true);
            if (_mappingsFoldoutProp.boolValue)
            {
                EditorGUI.indentLevel++;
                EditorGUI.BeginDisabledGroup(Application.isPlaying);

                // Mapping elements ..
                int removeIndexRequsted = -1;

                for (int m = 0; m < _mappingsProp.arraySize; m++)
                {
                    SerializedProperty mappingProp = _mappingsProp.GetArrayElementAtIndex(m);

                    // Mapping field (using custom property drawer)
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(mappingProp);
                    if (EditorGUI.EndChangeCheck())
                    {
                        SerializedProperty addressProp = mappingProp.FindPropertyRelative(mappingAddressFieldName);
                        addressProp.stringValue = GetSanitizedAndUniqueAddress(_mappingsProp, m, addressProp.stringValue);
                    }

                    // Remove mapping button
                    rect        = GUILayoutUtility.GetLastRect();
                    rect        = EditorGUI.IndentedRect(GUILayoutUtility.GetLastRect());
                    rect.x      = rect.x + rect.width - OscMappingDrawer.removeButtonWidth - 7;
                    rect.y     += 6;
                    rect.width  = OscMappingDrawer.removeButtonWidth;
                    rect.height = OscMappingDrawer.removeButtonHeight;
                    if (GUI.Button(rect, _removeMappingButtonLabel))
                    {
                        removeIndexRequsted = m;
                    }
                }

                // Handle mapping removal ..
                if (removeIndexRequsted != -1)
                {
                    _mappingsProp.DeleteArrayElementAtIndex(removeIndexRequsted);
                }

                // Add mapping button
                rect = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 30));
                if (GUI.Button(rect, _addMappingButtonLabel))
                {
                    string            newAddress   = GetSanitizedAndUniqueAddress(_mappingsProp, -1, "/");
                    FieldInfo         meppingsInfo = serializedObject.targetObject.GetType().GetField(_mappingsProp.propertyPath, BindingFlags.Instance | BindingFlags.NonPublic);
                    List <OscMapping> mappings     = (List <OscMapping>)meppingsInfo.GetValue(serializedObject.targetObject);
                    OscMapping        mapping      = new OscMapping(newAddress, OscMessageType.OscMessage);

                    mapping.AddEmptyEntry();
                    mappings.Add(mapping);
                }
                EditorGUILayout.Space();

                EditorGUI.EndDisabledGroup();
                EditorGUI.indentLevel--;
            }

            // Messages ...
            _sb.Clear();
            _sb.Append("Messages (").Append(_oscIn.messageCountReceivedLastFrame).Append(",").Append(OscDebug.GetPrettyByteSize(_oscIn.byteCountReceivedLastFrame)).Append(")");
            GUIContent messagesFoldContent = new GUIContent(_sb.ToString(), "Messages received last update");

            _messagesFoldoutProp.boolValue = EditorGUILayout.Foldout(_messagesFoldoutProp.boolValue, messagesFoldContent, true);
            if (_messagesFoldoutProp.boolValue)
            {
                EditorGUI.indentLevel++;
                if (_messageMonitorText.Length > 0)
                {
                    _messageMonitorText.Remove(_messageMonitorText.Length - 1, 1);                                                  // Trim last new line temporarily.
                }
                EditorGUILayout.HelpBox(_messageMonitorText.ToString(), MessageType.None);
                if (_messageMonitorText.Length > 0)
                {
                    _messageMonitorText.Append('\n');
                }
                EditorGUI.indentLevel--;
            }

            // Apply
            serializedObject.ApplyModifiedProperties();

            // Request OnInspectorGUI to be called every frame as long as inspector is active
            EditorUtility.SetDirty(target);

            // Store name of focused control to detect unfocus events
            _prevControlName = GUI.GetNameOfFocusedControl();
        }