////FIXME: some of the state in here doesn't get refreshed when it's changed on the device
        private void InitializeWith(InputDevice device)
        {
            m_Device             = device;
            m_DeviceId           = device.id;
            m_DeviceIdString     = device.id.ToString();
            m_DeviceUsagesString = string.Join(", ", device.usages.Select(x => x.ToString()).ToArray());

            var flags = new List <string>();

            if ((m_Device.m_DeviceFlags & InputDevice.DeviceFlags.Native) == InputDevice.DeviceFlags.Native)
            {
                flags.Add("Native");
            }
            if ((m_Device.m_DeviceFlags & InputDevice.DeviceFlags.Remote) == InputDevice.DeviceFlags.Remote)
            {
                flags.Add("Remote");
            }
            if ((m_Device.m_DeviceFlags & InputDevice.DeviceFlags.UpdateBeforeRender) == InputDevice.DeviceFlags.UpdateBeforeRender)
            {
                flags.Add("UpdateBeforeRender");
            }
            if ((m_Device.m_DeviceFlags & InputDevice.DeviceFlags.HasStateCallbacks) == InputDevice.DeviceFlags.HasStateCallbacks)
            {
                flags.Add("HasStateCallbacks");
            }
            if ((m_Device.m_DeviceFlags & InputDevice.DeviceFlags.Disabled) == InputDevice.DeviceFlags.Disabled)
            {
                flags.Add("Disabled");
            }
            m_DeviceFlagsString = string.Join(", ", flags.ToArray());

            // Set up event trace. The default trace size of 1mb fits a ton of events and will
            // likely bog down the UI if we try to display that many events. Instead, come up
            // with a more reasonable sized based on the state size of the device.
            if (m_EventTrace == null)
            {
                m_EventTrace = new InputEventTrace((int)device.stateBlock.alignedSizeInBytes * kMaxNumEventsInTrace)
                {
                    deviceId = device.id
                }
            }
            ;
            m_EventTrace.onEvent += _ =>
            {
                ////FIXME: this is very inefficient
                m_EventTree.Reload();
            };
            if (!m_EventTraceDisabled)
            {
                m_EventTrace.Enable();
            }

            // Set up event tree.
            m_EventTree = InputEventTreeView.Create(m_Device, m_EventTrace, ref m_EventTreeState, ref m_EventTreeHeaderState);

            // Set up control tree.
            m_ControlTree = InputControlTreeView.Create(m_Device, 1, ref m_ControlTreeState, ref m_ControlTreeHeaderState);
            m_ControlTree.Reload();
            m_ControlTree.ExpandAll();

            AddToList();
            InputSystem.onDeviceChange += OnDeviceChange;
        }
        public void OnGUI()
        {
            if (m_Control == null)
            {
                m_ShowRawBytes = true;
            }

            GUILayout.BeginHorizontal(EditorStyles.toolbar);
            m_ShowRawBytes = GUILayout.Toggle(m_ShowRawBytes, Contents.showRawMemory, EditorStyles.toolbarButton,
                                              GUILayout.Width(150));

            if (m_CompareStateBuffers)
            {
                var showDifferentOnly = GUILayout.Toggle(m_ShowDifferentOnly, Contents.showDifferentOnly,
                                                         EditorStyles.toolbarButton, GUILayout.Width(150));
                if (showDifferentOnly != m_ShowDifferentOnly && m_ControlTree != null)
                {
                    m_ControlTree.showDifferentOnly = showDifferentOnly;
                    m_ControlTree.Reload();
                }

                m_ShowDifferentOnly = showDifferentOnly;
            }

            // If we have multiple state buffers to choose from and we're not comparing them to each other,
            // add dropdown that allows selecting which buffer to display.
            if (m_StateBuffers.Length > 1 && !m_CompareStateBuffers)
            {
                var selectedBuffer = EditorGUILayout.IntPopup(m_SelectedStateBuffer, m_BufferChoices,
                                                              m_BufferChoiceValues, EditorStyles.toolbarPopup);
                if (selectedBuffer != m_SelectedStateBuffer)
                {
                    m_SelectedStateBuffer = selectedBuffer;
                    m_ControlTree         = null;
                }
            }

            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();

            if (m_ShowRawBytes)
            {
                DrawHexDump();
            }
            else
            {
                if (m_ControlTree == null)
                {
                    if (m_CompareStateBuffers)
                    {
                        m_ControlTree = InputControlTreeView.Create(m_Control, m_StateBuffers.Length, ref m_ControlTreeState, ref m_ControlTreeHeaderState);
                        m_ControlTree.multipleStateBuffers = m_StateBuffers;
                        m_ControlTree.showDifferentOnly    = m_ShowDifferentOnly;
                    }
                    else
                    {
                        m_ControlTree             = InputControlTreeView.Create(m_Control, 1, ref m_ControlTreeState, ref m_ControlTreeHeaderState);
                        m_ControlTree.stateBuffer = m_StateBuffers[m_SelectedStateBuffer];
                    }
                    m_ControlTree.Reload();
                    m_ControlTree.ExpandAll();
                }

                var rect = EditorGUILayout.GetControlRect(GUILayout.ExpandHeight(true));
                m_ControlTree.OnGUI(rect);
            }
        }