/// <inheritdoc/> public override bool DrawBody(Rect position) { bool guiChangedWas = GUI.changed; GUI.changed = false; var renderer = Target as Renderer; var materials = renderer.sharedMaterials; int instanceIdWas = InstanceId; bool dirty = base.DrawBody(position); if (GUI.changed && !inactive && instanceIdWas == InstanceId && !materials.ContentsMatch(renderer.sharedMaterials)) { // If the materials on the renderer changed then rebuild members of parent // in order to update the MaterialDrawers embedded on the GameObjectDrawer parent.RebuildMemberBuildListAndMembers(); Inspector.RebuildPreviews(); ExitGUIUtility.ExitGUI(); } else { GUI.changed = guiChangedWas; } return(dirty); }
/// <inheritdoc/> protected override void OnSelectedInternal(ReasonSelectionChanged reason, IDrawer previous, bool isMultiSelection) { #if DEV_MODE && DEBUG_ON_SELECTED Debug.Log(ToString() + ".OnSelectedInternal(" + reason + "," + StringUtils.ToString(previous) + ")"); #endif bool wasUnfolded = false; bool isClick = false; switch (reason) { case ReasonSelectionChanged.PrefixClicked: isClick = true; if (DrawGUI.LastInputEvent().control) { ComponentDrawerUtility.singleInspectedInstance = this; } break; case ReasonSelectionChanged.ControlClicked: if (DrawGUI.LastInputEvent().control) { ComponentDrawerUtility.singleInspectedInstance = this; } return; case ReasonSelectionChanged.ThisClicked: isClick = true; break; } #if UNFOLD_ON_SELECT_IN_SINGLE_ACTIVE_MODE if (UserSettings.EditComponentsOneAtATime && !inspector.HasFilter) { if (ComponentDrawerUtility.singleInspectedInstance != null && ComponentDrawerUtility.singleInspectedInstance != this) { ComponentDrawerUtility.singleInspectedInstance.SetUnfolded(false); } ComponentDrawerUtility.singleInspectedInstance = this; // if Component was clicked, let the click event handle the unfolding if (!Unfolded && (!isClick || (MouseoveredHeaderPart != HeaderPart.FoldoutArrow && !inspector.Preferences.changeFoldedStateOnFirstClick))) { wasUnfolded = true; // allow bypassing EditComponentsOneAtATime functionality by holding down control when clicking the Component header bool collapseAllOthers = !Event.current.control || reason != ReasonSelectionChanged.PrefixClicked; SetUnfolded(true, collapseAllOthers, false); } } #endif base.OnSelectedInternal(reason, previous, isMultiSelection); if (wasUnfolded) { ExitGUIUtility.ExitGUI(); } }
protected override void DrawHeaderBase(Rect position) { HandlePrefixHighlightingForFilter(position, 55f, 4f); if (editor == null) { Editors.GetEditor(ref editor, Target); } Rect drawnRect; bool setHeaderHeightDetermined = headerHeightDetermined; try { drawnRect = EditorGUIDrawer.AssetHeader(position, editor, ref headerHeightDetermined); } #if DEV_MODE catch (MissingReferenceException e) // asset has probably been moved or destroyed { Debug.LogError(e); #else catch (MissingReferenceException) { #endif inspector.ForceRebuildDrawers(); ExitGUIUtility.ExitGUI(); return; } if (!headerHeightDetermined && setHeaderHeightDetermined) { headerHeightDetermined = true; if (headerHeight != drawnRect.height) { if (drawnRect.height >= DrawGUI.SingleLineHeight) { #if DEV_MODE Debug.Log(ToString() + ".headerHeight = " + drawnRect.height); #endif headerHeight = drawnRect.height; } else { #if DEV_MODE Debug.Log(ToString() + ".headerHeight = " + DrawGUI.Active.AssetTitlebarHeight(HeaderHasTwoRowsOfButtons)); #endif headerHeight = DrawGUI.Active.AssetTitlebarHeight(HeaderHasTwoRowsOfButtons); } } } }
/// <inheritdoc /> public override object GetValue(int index) { #if DEV_MODE if (hasParameters) { var vDrawer = IndexParameterDrawer.Value; var vMemberInfo = memberInfo.IndexParameters; Debug.Assert(vDrawer.ContentsMatch(vMemberInfo), "IndexParameterDrawer.Value " + StringUtils.ToString(vDrawer) + " != memberInfo.IndexParameters " + StringUtils.ToString(vMemberInfo)); } #endif #if DEV_MODE && DEBUG_INVOKE Debug.Log("Invoking " + memberInfo + " with " + (hasParameters ? "params " + StringUtils.ToString((object)IndexParameterDrawer.Value) : "0 parameters")); #endif if (memberInfo != null && memberInfo.CanRead && !getValueCausedException) { using (var logCatcher = new LogCatcher()) { try { var result = memberInfo.GetValue(index); if (logCatcher.HasMessage && logCatcher.LogType != LogType.Log) { OnErrorOrWarningWhenCallingGetter(logCatcher.Message, logCatcher.LogType); } return(result); } catch (Exception e) { if (ExitGUIUtility.ShouldRethrowException(e)) { throw; } OnExceptionWhenCallingGetter(e); Debug.LogError(ToString() + ".GetValue " + e); return(base.Value); } } } #if DEV_MODE Debug.LogWarning(ToString() + ".GetValue(" + index + ") called but memberInfo.CanRead=" + StringUtils.False); #endif return(base.Value); }
/// <summary> /// Invokes the Method, messages the user about it and updates results member if method has a return value. /// </summary> /// <param name="pingIfUnityObject"> True if should "ping" the return value, if the method has one, and it's of type UnityEngine.Object or UnityEngine.Object[], and not null or empty. </param> /// <param name="displayDialogIfNotUnityObject"> True if should display a popup dialog to the user about the results, if method has a return type, and it's not of type UnityEngine.Object or UnityEngine.Object[]. </param> /// <param name="copyToClipboardIfNotPingedOrDialogShown"> True if should copy the method return value to clipboard, if it has one, and if value was not pinged and popup was not displayed. </param> /// <param name="pingIfUnityObject"> True if should select the return value(s), if the method has one, and it's of type UnityEngine.Object or UnityEngine.Object[], and not null or empty. </param> private void Invoke(bool pingIfUnityObject, bool displayDialogIfNotUnityObject, bool copyToClipboardIfNotPingedOrDialogShown, bool selectIfUnityObject) { Inspector.RefreshView(); // make sure repaint gets called immediately string error; bool suppressMessages = pingIfUnityObject || displayDialogIfNotUnityObject || copyToClipboardIfNotPingedOrDialogShown || selectIfUnityObject; Invoke(out error, suppressMessages); if (!hasReturnValue) { #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(!suppressMessages); #endif return; } if (pingIfUnityObject) { var list = new List <Object>(0); if (UnityObjectExtensions.TryExtractObjectReferences(results, ref list)) { DrawGUI.Ping(list.ToArray()); } } if (selectIfUnityObject) { var list = new List <Object>(0); if (UnityObjectExtensions.TryExtractObjectReferences(results, ref list)) { Inspector.Select(list.ToArray()); } } if (displayDialogIfNotUnityObject && !isCoroutine) { TryDisplayDialogForResult(); } else if (copyToClipboardIfNotPingedOrDialogShown) { Clipboard.Copy(result); } if (Event.current != null) { ExitGUIUtility.ExitGUI(); // avoid ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint } }
//private Rect? assetHeaderDetectedHeight; #if UNITY_EDITOR protected override void DrawHeaderBase(Rect position) { HandlePrefixHighlightingForFilter(position, 55f, 4f); if (editor == null) { Editors.GetEditor(ref editor, Target); } Rect drawnRect; try { drawnRect = EditorGUIDrawer.AssetHeader(position, editor); } #if DEV_MODE catch (MissingReferenceException e) // asset has probably been moved or destroyed { Debug.LogError(e); #else catch (MissingReferenceException) { #endif inspector.ForceRebuildDrawers(); ExitGUIUtility.ExitGUI(); return; } if (!headerHeightDetermined && Event.current.type == EventType.Repaint) { if (headerHeight != drawnRect.height) { #if DEV_MODE Debug.Log(GetType().Name + " header GetLastRect " + drawnRect + " vs position " + position); #endif OnNextLayout(() => { if (drawnRect.height >= DrawGUI.SingleLineHeight) { headerHeight = drawnRect.height; } else { headerHeight = DrawGUI.Active.AssetTitlebarHeight(false); } }); } headerHeightDetermined = true; } }
public static void ShowInSplitView(this ISplittableInspectorDrawer inspectorDrawer, Object target, bool throwExitGUIException) { #if DEV_MODE Debug.Log("ShowInSplitView(" + StringUtils.ToString(target) + ")"); #endif if (target != null) { var component = target as Component; if (component != null) { #if DEV_MODE Debug.Log("ShowInSplitView(" + StringUtils.TypeToString(target) + ") - was a Component"); #endif var gameObject = component.gameObject; inspectorDrawer.ShowInSplitView(ArrayPool <Object> .CreateWithContent(gameObject)); var splitBottom = inspectorDrawer.SplitView; // Wait one frame so that there's been time to cache all layout data during the next OnGUI call, // so that ScrollToShow can scroll to the correct position splitBottom.OnNextLayout(() => { var show = splitBottom.State.drawers.FindDrawer(component); if (show != null) { splitBottom.Manager.Select(splitBottom, InspectorPart.Viewport, show, ReasonSelectionChanged.Peek); splitBottom.ScrollToShow(show); show.SetUnfolded(true, false, false); ExitGUIUtility.ExitGUI(); } }); } else //GameObjects and Assets are okay to be shown as standalone { #if DEV_MODE Debug.Log("ShowInSplitView(" + StringUtils.TypeToString(target) + ") was not a Component"); #endif inspectorDrawer.ShowInSplitView(ArrayPool <Object> .CreateWithContent(target)); } if (throwExitGUIException) { ExitGUIUtility.ExitGUI(); } } }
private void ToggleShowMethods() { var setValue = Value; setValue.ShowMethods = !setValue.ShowMethods; SetValue(setValue, false, false); var unityObjectDrawer = (IDebuggable)parent; #if DEV_MODE Debug.Log("Calling ApplyDebugModeSettings"); #endif unityObjectDrawer.ApplyDebugModeSettings(setValue); ExitGUIUtility.ExitGUI(); }
/// <inheritdoc/> public override bool OnClick(Event inputEvent) { #if DEV_MODE Debug.Log(ToString() + ".OnClick with mouseIsOverButton=" + mouseIsOverButton); #endif if (mouseIsOverButton) { DrawGUI.Use(inputEvent); Invoke(); GUI.changed = true; ExitGUIUtility.ExitGUI(); return(true); } return(base.OnClick(inputEvent)); }
private void ConfirmRestoreDefaults() { if (DrawGUI.Active.DisplayDialog("Reset All Preferences To Default Values?", "Are you sure you want to restore all preference items to their default values?\n\nThis affects all items, and not just the ones in the currently open view.", "Reset All", "Cancel")) { for (int n = targets.Length - 1; n >= 0; n--) { var target = (InspectorPreferences)targets[n]; target.ResetToDefaults(); } RebuildMemberBuildListAndMembers(); if (Event.current != null) { ExitGUIUtility.ExitGUI(); } } }
/// <inheritdoc/> public override bool OnClick(Event inputEvent) { #if DEV_MODE Debug.Log(ToString() + ".OnClick with mouseIsOverButton=" + mouseIsOverButton); #endif if (mouseIsOverButton) { HandleOnClickSelection(inputEvent, ReasonSelectionChanged.ControlClicked); DrawGUI.Use(inputEvent); GUI.changed = true; Invoke(); ExitGUIUtility.ExitGUI(); return(true); } return(base.OnClick(inputEvent)); }
/// <inheritdoc cref="IDrawer.ApplyInVisibleChildren" /> public override void ApplyInVisibleChildren(Action <IDrawer> action) { for (int n = visibleMembers.Length - 1; n >= 0; n--) { try { visibleMembers[n].ApplyInVisibleChildren(action); } catch (Exception e) { #if DEV_MODE Debug.LogError(ToString() + " ApplyInVisibleChildren - visibleMembers[" + n + "] " + e); #endif if (ExitGUIUtility.ShouldRethrowException(e)) { throw; } } } action(this); }
/// <inheritdoc /> protected override void DoGenerateMemberBuildList() { #if SAFE_MODE // temp fix for strange issue with LinkedMemberInfo.MemberData being null after interface is set to be null if (memberInfo != null && memberInfo.Data == null) { #if DEV_MODE Debug.LogError(ToString() + " memberInfo.Data was null! Calling parent.RebuildMemberBuildListAndMembers()"); #endif parent.RebuildMemberBuildListAndMembers(); ExitGUIUtility.ExitGUI(); } #endif #if DEV_MODE && DEBUG_GENERATE_MEMBER_BUILD_LIST Debug.Log(StringUtils.ToColorizedString(ToString(), ".DoGenerateMemberBuildList called with IsNull=", IsNull, ", memberInfo=", memberInfo, ", HasExplicitType=", HasExplicitType, ", TypeForValue=", TypeForValue, ", InstanceType=", InstanceType, ", UserSelectedType=", UserSelectedType)); #endif if (HasExplicitType) { memberBuildList.Add(memberInfo); } }
/// <inheritdoc cref="IDrawer.Draw" /> public override bool Draw(Rect position) { #if SAFE_MODE || DEV_MODE var targets = memberInfo.UnityObjects; int targetCount = targets.Length; if (targetCount == 0) { #if DEV_MODE Debug.LogWarning(ToString() + ".Draw() - target count was zero, rebuilding drawer"); #endif InspectorUtility.ActiveInspector.RebuildDrawersIfTargetsChanged(); return(false); } if (targets.ContainsNullObjects()) { #if DEV_MODE Debug.LogWarning(ToString() + ".Draw() - target was null, rebuilding drawer"); #endif InspectorUtility.ActiveInspector.RebuildDrawersIfTargetsChanged(); return(false); } #endif var positionWithoutMargins = position; bool dirty = false; GenerateControlId(); if (Event.current.type == EventType.Layout) { OnLayoutEvent(position); } #if !DRAW_LABEL_RESIZE_CONTROL DrawGUI.Active.ColorRect(position, DrawGUI.Active.InspectorBackgroundColor); #endif position.height -= 2f; position.y += 1f; position.width -= DrawGUI.RightPadding; float labelWidthWas = EditorGUIUtility.labelWidth; float fieldWidthWas = EditorGUIUtility.fieldWidth; float leftPadding = DrawGUI.LeftPadding; int labelRightPadding = (int)(DrawGUI.MiddlePadding + DrawGUI.MiddlePadding); position.x += leftPadding; position.width -= leftPadding; //always use wide mode for properties because it works better with the prefix width control #if ALWAYS_USE_WIDEMODE bool wideModeWas = EditorGUIUtility.wideMode; EditorGUIUtility.wideMode = true; #endif EditorStyles.label.padding.right = labelRightPadding; GUILayout.BeginArea(positionWithoutMargins); { position.y -= positionWithoutMargins.y; position.x -= positionWithoutMargins.x; EditorGUI.BeginChangeCheck(); { DrawerUtility.BeginInputField(this, controlId, ref editField, ref focusField, memberInfo == null ? false : memberInfo.MixedContent); { var serializedProperty = SerializedProperty; if (serializedProperty == null) { // NOTE: This can happen during Remove Component for some reason #if DEV_MODE Debug.LogError(ToString() + ".Draw - SerializedProperty was null (parent=" + StringUtils.ToString(parent) + ") so can't use EditorGUI.PropertyField"); #endif EditorGUI.PrefixLabel(position, label); } else { bool editingTextFieldWas; EventType eventType; KeyCode keyCode; CustomEditorUtility.BeginPropertyDrawer(out editingTextFieldWas, out eventType, out keyCode); { // fix needed or foldouts will be drawn at incorrect positions var leftMarginWas = EditorStyles.foldout.margin.left; EditorStyles.foldout.margin.left = -12; try { EditorGUI.PropertyField(position, serializedProperty, label, serializedProperty.isExpanded); } catch (Exception e) { if (ExitGUIUtility.ShouldRethrowException(e)) { EditorStyles.foldout.margin.left = leftMarginWas; throw; } #if DEV_MODE Debug.LogWarning(ToString() + " " + e); #endif } EditorStyles.foldout.margin.left = leftMarginWas; } CustomEditorUtility.EndPropertyDrawer(editingTextFieldWas, eventType, keyCode); bool editingTextFieldIs = EditorGUIUtility.editingTextField; if (editingTextFieldIs != editingTextFieldWas) { DrawGUI.EditingTextField = editingTextFieldIs; } } } DrawerUtility.EndInputField(); } if (EditorGUI.EndChangeCheck()) { GUI.changed = true; SerializedProperty.serializedObject.ApplyModifiedProperties(); dirty = true; } } GUILayout.EndArea(); #if ALWAYS_USE_WIDEMODE EditorGUIUtility.wideMode = wideModeWas; #endif EditorStyles.label.padding.right = 2; EditorGUIUtility.labelWidth = labelWidthWas; EditorGUIUtility.fieldWidth = fieldWidthWas; return(dirty); }
/// <inheritdoc cref="IDrawer.OnMouseUpAfterDownOverControl" /> public override void OnMouseUpAfterDownOverControl(Event inputEvent, bool isClick) { #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(!isClick || Inspector.MouseoveredPart != InspectorPart.None, "IsClick was true but MouseoveredPart was None!"); #endif #if DEV_MODE && DEBUG_ON_MOUSE_UP Debug.Log(ToString() + ".OnMouseUpAfterDownOverControl with inputEvent=" + StringUtils.ToString(inputEvent) + ", isClick=" + StringUtils.ToColorizedString(isClick) + ", CursorMovedAfterMouseDown=" + !Inspector.Manager.MouseDownInfo.CursorMovedAfterMouseDown); #endif // DragExited event can caused click input to be ignored, due to the fact that it's possible to // drag Object references from the icons. However here we want to treat those as clicks. if (!isClick && !Inspector.Manager.MouseDownInfo.CursorMovedAfterMouseDown) { isClick = true; } if (isClick) { #if DEV_MODE if (!isClick) { Debug.LogWarning("OnMouseUpAfterDownOverControl isClick was false but CursorMovedAfterMouseDown was false."); } #endif DrawGUI.Use(inputEvent); bool wasUnfolded = Unfolded; if (mouseoveredIconIndex != -1) { if (!wasUnfolded) { SetUnfolded(true, false); } var targetMember = members[mouseoveredIconIndex] as IParentDrawer; if (targetMember != null && targetMember.Foldable) { targetMember.SetUnfolded(!wasUnfolded || !targetMember.Unfolded); } return; } else { SetUnfolded(!wasUnfolded, Event.current.alt); } // clear Drag N Drop references Inspector.Manager.MouseDownInfo.Clear(true); DrawGUI.Active.DragAndDropVisualMode = DragAndDropVisualMode.None; ExitGUIUtility.ExitGUI(); return; } else if (!Mouseovered) { // helps with issue where label can get stuck in selected / mouseovered color SetLabelGUIStyleColor(labelIdleColor); } base.OnMouseUpAfterDownOverControl(inputEvent, isClick); }
/// <summary> This should be called by the IInspectorDrawer of the inspector during every OnGUI event. </summary> /// <param name="inspectorDimensions"> The position and bounds for where the inspecto should be drawn. </param> /// <param name="anyInspectorPartMouseovered"> True if any inspector part is currently mouseovered. </param> public override void OnGUI(Rect inspectorDimensions, bool anyInspectorPartMouseovered) { UnityEngine.Profiling.Profiler.BeginSample("OnGUI"); #if DEV_MODE && DEBUG_CLICK var e = Event.current; if (e.rawType == EventType.MouseDown) { Debug.Log(StringUtils.ToColorizedString(ToString() + " Event=", e, ", e.type=", e.type, ", button=", e.button, ", mousePos=", e.mousePosition, ", GUIUtility.hotControl=", GUIUtility.hotControl)); } #endif //this can happen e.g. if the preferences file gets reimported due to being altered outside of Unity if (Preferences == null) { Preferences = GetPreferences(); } #if DEV_MODE && DEBUG_MOUSEOVERED_PART if (State.drawer.VisibleMembers.Length > 0 && DrawGUI.IsUnityObjectDrag) { Debug.Log(StringUtils.ToColorizedString(ToString(), ".OnGUI with mouseoveredPart=", MouseoveredPart, ", Event=" + StringUtils.ToString(Event.current), ", ignoreAllMouseInputs=", InspectorDrawer.Manager.IgnoreAllMouseInputs, "´, ObjectPickerIsOpen=", ObjectPicker.IsOpen, ", anyInspectorPartMouseovered=", anyInspectorPartMouseovered, ", InspectorDrawer.MouseIsOver=", InspectorDrawer.MouseIsOver, ", DrawGUI.CanRequestMousePosition=", Cursor.CanRequestLocalPosition)); } #endif InspectorUtility.BeginInspector(this, ref anyInspectorPartMouseovered); Rect toolbarRect; Rect viewportRect; Rect previewAreaRect; GetDrawPositions(inspectorDimensions, out toolbarRect, out viewportRect, out previewAreaRect); // trying to fix a bug where the default inspector layout gets wacky if both it and this window are open // by making sure all values that could affect it are restored back to normal // var indentLevelWas = EditorGUI.indentLevel; #if UNITY_EDITOR var labelWidthWas = EditorGUIUtility.labelWidth; #endif var matrixWas = GUI.matrix; var currentEvent = Event.current; switch (currentEvent.type) { case EventType.Layout: State.nextUpdateCachedValues--; if (State.nextUpdateCachedValues <= 0) { UpdateCachedValuesFromFields(); } OnCursorPositionOrLayoutChanged(); break; case EventType.MouseMove: case EventType.MouseDrag: case EventType.DragUpdated: if (IgnoreViewportMouseInputs()) { #if DEV_MODE //Debug.Log("ignoring "+ currentEvent.type+"..."); #endif break; } OnCursorPositionOrLayoutChanged(); InspectorDrawer.RefreshView(); break; } bool dirty; try { dirty = DrawViewport(viewportRect); } catch (Exception e) { if (ExitGUIUtility.ShouldRethrowException(e)) { NowDrawingPart = InspectorPart.None; DrawGUI.IndentLevel = 0; #if UNITY_EDITOR EditorGUIUtility.labelWidth = labelWidthWas; #endif GUI.skin = null; GUI.matrix = matrixWas; throw; } #if DEV_MODE Debug.LogWarning(ToString() + " " + e); #endif dirty = true; } #if !POWER_INSPECTOR_LITE NowDrawingPart = InspectorPart.Toolbar; { Toolbar.Draw(toolbarRect); } #endif NowDrawingPart = InspectorPart.Other; //TO DO: Move to EndInspector if these are needed? //trying to fix a bug where the default inspector layout gets wacky if both it and this window are open //by making sure all values that could affect it are restored back to normal DrawGUI.IndentLevel = 0; #if UNITY_EDITOR EditorGUIUtility.labelWidth = labelWidthWas; #endif GUI.skin = null; GUI.matrix = matrixWas; if (dirty) { InspectorDrawer.RefreshView(); } InspectorUtility.EndInspector(this); UnityEngine.Profiling.Profiler.EndSample(); }
/// <summary> This should be called by the IInspectorDrawer of the inspector during every OnGUI event. </summary> /// <param name="inspectorDimensions"> The position and bounds for where the inspecto should be drawn. </param> /// <param name="anyInspectorPartMouseovered"> True if any inspector part is currently mouseovered. </param> public override void OnGUI(Rect inspectorDimensions, bool anyInspectorPartMouseovered) { UnityEngine.Profiling.Profiler.BeginSample("OnGUI"); #if DEV_MODE && DEBUG_CLICK var ev = Event.current; if (ev.rawType == EventType.MouseDown) { Debug.Log(StringUtils.ToColorizedString(ToString() + " Event=", ev, ", e.type=", ev.type, ", button=", ev.button, ", mousePos=", ev.mousePosition, ", GUIUtility.hotControl=", GUIUtility.hotControl)); } #endif #if DEV_MODE && PI_ASSERTATIONS if (inspectorDimensions.width <= 0f) { Debug.LogError(GetType().Name + ".OnGUI inspectorDimensions.width <= 0f: " + inspectorDimensions); } #endif //this can happen e.g. if the preferences file gets reimported due to being altered outside of Unity if (Preferences == null) { Preferences = GetPreferences(); } #if DEV_MODE && DEBUG_MOUSEOVERED_PART if (State.drawer.VisibleMembers.Length > 0 && DrawGUI.IsUnityObjectDrag) { Debug.Log(StringUtils.ToColorizedString(ToString(), ".OnGUI with mouseoveredPart=", MouseoveredPart, ", Event=" + StringUtils.ToString(Event.current), ", ignoreAllMouseInputs=", InspectorDrawer.Manager.IgnoreAllMouseInputs, "´, ObjectPickerIsOpen=", ObjectPicker.IsOpen, ", anyInspectorPartMouseovered=", anyInspectorPartMouseovered, ", InspectorDrawer.MouseIsOver=", InspectorDrawer.MouseIsOver, ", DrawGUI.CanRequestMousePosition=", Cursor.CanRequestLocalPosition)); } #endif InspectorUtility.BeginInspector(this, ref anyInspectorPartMouseovered); Rect toolbarRect; Rect viewportRect; Rect previewAreaRect; GetDrawPositions(inspectorDimensions, out toolbarRect, out viewportRect, out previewAreaRect); // trying to fix a bug where the default inspector layout gets wacky if both it and this window are open // by making sure all values that could affect it are restored back to normal // var indentLevelWas = EditorGUI.indentLevel; var labelWidthWas = EditorGUIUtility.labelWidth; var matrixWas = GUI.matrix; var currentEvent = Event.current; switch (currentEvent.type) { case EventType.Layout: State.nextUpdateCachedValues--; if (State.nextUpdateCachedValues <= 0) { UpdateCachedValuesFromFields(); } OnCursorPositionOrLayoutChanged(); break; case EventType.MouseMove: case EventType.MouseDrag: case EventType.DragUpdated: if (IgnoreViewportMouseInputs()) { #if DEV_MODE //Debug.Log("ignoring "+ currentEvent.type+"..."); #endif break; } OnCursorPositionOrLayoutChanged(); InspectorDrawer.RefreshView(); break; } bool dirty; try { dirty = DrawViewport(viewportRect); } catch (Exception e) { if (ExitGUIUtility.ShouldRethrowException(e)) { NowDrawingPart = InspectorPart.None; DrawGUI.IndentLevel = 0; EditorGUIUtility.labelWidth = labelWidthWas; GUI.skin = null; GUI.matrix = matrixWas; throw; } #if DEV_MODE Debug.LogWarning(ToString() + " " + e); #endif // Always throw ExitGUI exception if exceptions were caught to avoid GUI Layout warnings. ExitGUIUtility.ExitGUI(); return; } #if !POWER_INSPECTOR_LITE NowDrawingPart = InspectorPart.Toolbar; { Toolbar.Draw(toolbarRect); #if UNITY_2019_3_OR_NEWER Color lineColor; if (DrawGUI.IsProSkin) { lineColor = Preferences.theme.ComponentSeparatorLine; } else { lineColor = new Color32(153, 153, 153, 255); } var lineRect = toolbarRect; lineRect.height = 1f; lineRect.y = toolbarRect.height; DrawGUI.DrawLine(lineRect, lineColor); #endif } #endif NowDrawingPart = InspectorPart.Other; try { if (DrawPreviewArea) { NowDrawingPart = InspectorPart.PreviewArea; { previewDrawer.Draw(previewAreaRect); } NowDrawingPart = InspectorPart.Other; } } #if DEV_MODE catch (ArgumentException e) // GUILayout: Mismatched LayoutGroup.repaint { Debug.LogError(StringUtils.ToString(Event.current) + " " + e + "\nEvent=" + StringUtils.ToString(Event.current)); #else catch (ArgumentException) { #endif // new test to avoid GUI Error: You are pushing more GUIClips than you are popping. Make sure they are balanced. NowDrawingPart = InspectorPart.None; ExitGUIUtility.ExitGUI(); } //TO DO: Move to EndInspector if these are needed? //trying to fix a bug where the default inspector layout gets wacky if both it and this window are open //by making sure all values that could affect it are restored back to normal DrawGUI.IndentLevel = 0; EditorGUIUtility.labelWidth = labelWidthWas; GUI.skin = null; GUI.matrix = matrixWas; if (dirty) { InspectorDrawer.RefreshView(); } InspectorUtility.EndInspector(this); UnityEngine.Profiling.Profiler.EndSample(); }
/// <inheritdoc /> public override bool Draw(Rect position) { for (int n = targets.Length - 1; n >= 0; n--) { if (targets[n] == null) { #if DEV_MODE Debug.LogWarning(this + ".Draw() - target was null, rebuilding"); #endif inspector.RebuildDrawersIfTargetsChanged(); return(false); } } if (DebugMode) { if (Event.current.type == EventType.Layout) { UpdateHeight(); } return(base.Draw(position)); } bool dirty = false; if (Event.current.type == EventType.Layout) { OnLayoutEvent(position); } var guiColorWas = GUI.color; if (DrawGreyedOut) { var color = GUI.color; color.a = 0.5f; GUI.color = color; } if (!HeadlessMode && DrawPrefix(labelLastDrawPosition)) { dirty = true; if (DebugMode) { ExitGUIUtility.ExitGUI(); } } float unfoldedness = Unfoldedness; if (unfoldedness > 0f) { var pos = position; pos.y += HeaderHeight; pos.height = Height - HeaderHeight; HandlePrefixColumnResizing(); pos.height = DrawGUI.SingleLineHeight; #if UNITY_EDITOR var serializedObject = MemberHierarchy.SerializedObject; serializedObject.Update(); #endif if (unfoldedness >= 1f) { DrawFoldableContent(pos); } else { #if DEV_MODE && PI_ASSERTATIONS var assertColor = GUI.color; #endif using (new MemberScaler(bodyLastDrawPosition.min, unfoldedness)) { DrawFoldableContent(pos); } #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(GUI.color == assertColor, ToString() + " - After DrawFoldableContent"); #endif } #if UNITY_EDITOR serializedObject.ApplyModifiedProperties(); #endif } GUI.color = guiColorWas; if (!DataIsValid) { var pos = position; pos.y += Height - 57f; pos.height = 50f; DrawGUI.Active.HelpBox(pos, "Due to floating-point precision limitations, it is recommended to bring the world coordinates of the GameObject within a smaller range.", MessageType.Warning); pos.y += pos.height; } DrawGUI.LayoutSpace(Height); return(dirty); }
/// <inheritdoc/> public void OnLayout() { // Swap onNextLayoutDelayed with an empty list before invoking actions in onNextLayout or // onNextLayoutDelayed. This is to avoid possible infinite loops and other problems if an // invoked action should add new actions to onNextLayoutDelayed. var applyTargeted = onNextLayoutDelayed; onNextLayoutDelayed = onNextLayoutDelayedSwapTarget; onNextLayoutDelayedSwapTarget = applyTargeted; #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(onNextLayoutDelayed.Count == 0); #endif if (onNextLayout != null) { #if DEV_MODE && DEBUG_ON_NEXT_LAYOUT_DETAILED Debug.Log("Applying OnNextLayout Action: " + StringUtils.ToString(onNextLayout)); #endif // Copy onNextLayout to method-level variable and set it to null // before invoking the action. This is to avoid possible infinite loops // and other problems if an invoked action should add new actions to onNextLayout. //var apply = onNextLayout; //onNextLayout = null; //apply(); var invocationList = onNextLayout.GetInvocationList(); onNextLayout = null; Exception exception = null; for (int n = 0, count = invocationList.Length; n < count; n++) { try { var invoke = invocationList[n] as Action; invoke(); } catch (Exception e) { #if DEV_MODE if (!ExitGUIUtility.IsExitGUIException(exception)) { Debug.LogError(e); } #endif exception = e; } } if (exception != null && ExitGUIUtility.ShouldRethrowException(exception)) { throw exception; } } int applyTargetedCount = applyTargeted.Count; if (applyTargetedCount > 0) { for (int n = 0; n < applyTargetedCount; n++) { var apply = applyTargeted.Dequeue(); #if DEV_MODE && DEBUG_ON_NEXT_LAYOUT_DETAILED Debug.Log("Applying OnNextLayout DelayedAction: " + StringUtils.ToString(apply)); #endif // Only invoke targeted action if target drawers instance still exist. apply.InvokeIfInstanceReferenceIsValid(); } #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(applyTargeted.Count == 0); #endif } if (keyHeldDown != KeyCode.None) { GUI.changed = true; if (Platform.Time > sendNextHoldEventAt) { sendNextHoldEventAt = Platform.Time + KeyHoldSendEventInterval; OnKeyDown(Event.KeyboardEvent(keyHeldDownName)); } } }
/// <summary> /// Invokes the Method, returns method return value and outputs possible error descriptions encountered. /// </summary> /// <param name="index"> Index of target on which to invoke method. </param> /// <param name="error"> [out] True if should display message to user about invoking or possible exceptions. </param> protected object GetValue(int index, [NotNull] out string error) { // generics and parameter info is needed from members // so build them if they have not yet been built // (i.e. if MethodDrawer has yet to be unfolded) if (memberBuildState == MemberBuildState.BuildListGenerated) { BuildMembers(); } bool runAsCoroutine; MethodInfo methodInfo; if (isGeneric) { runAsCoroutine = false; try { var genericTypes = GenericsDrawer.Value; #if DEV_MODE && DEBUG_INVOKE Debug.Log("Making generic method of " + MethodInfo.Name + " from " + genericTypes.Length + " generic types: " + StringUtils.ToString(genericTypes)); #endif //needed? if (genericTypes.Length == 1) { methodInfo = MethodInfo.MakeGenericMethod(genericTypes[0]); } //needed? else if (genericTypes.Length == 2) { methodInfo = MethodInfo.MakeGenericMethod(genericTypes[0], genericTypes[1]); } else { methodInfo = MethodInfo.MakeGenericMethod(genericTypes); } } catch (Exception e) { if (ExitGUIUtility.ShouldRethrowException(e)) { throw; } error = e.ToString(); return(DefaultValue()); } } else { try { methodInfo = MethodInfo; } catch (Exception e) { error = e.ToString(); return(DefaultValue()); } if (isCoroutine) { if (!Inspector.Preferences.askAboutStartingCoroutines) { runAsCoroutine = true; } else { switch (DrawGUI.Active.DisplayDialog("Invoke as coroutine?", "The method return type is IEnumerable. Would you like to start it as a coroutine?", "Start As Coroutine", "Invoke As Normal Method", "Cancel")) { case 0: runAsCoroutine = true; break; case 1: runAsCoroutine = false; break; case 2: ExitGUIUtility.ExitGUI(); error = ""; return(result); default: #if DEV_MODE throw new IndexOutOfRangeException(); #else runAsCoroutine = false; break; #endif } } } else { runAsCoroutine = false; } } object returnValue; var parameters = hasParameters ? ParameterDrawer.Value : null; #if DEV_MODE && PI_ASSERTATIONS if (hasParameters && (parameters == null || parameters.Length == 0)) { Debug.LogError("hasParameters was " + StringUtils.True + " but params was " + StringUtils.ToString(parameters)); } #endif try { #if DEV_MODE && DEBUG_INVOKE Debug.Log("Invoking method " + methodInfo.Name + " with " + (parameters == null ? "" : parameters.Length + " ") + "params=" + StringUtils.ToString(parameters) + ", hasParameters=" + StringUtils.ToColorizedString(hasParameters) + ", runAsCoroutine=" + runAsCoroutine); #endif // this can be null for static methods var fieldOwner = memberInfo.GetFieldOwner(index); //get return value by invoking method with current parameter values returnValue = methodInfo.Invoke(fieldOwner, parameters); if (runAsCoroutine) { #if UNITY_EDITOR if (!Application.isPlaying) { StaticCoroutine.StartCoroutineInEditMode((IEnumerator)returnValue); } else if (monoBehaviour != null) #else if (monoBehaviour != null) #endif { monoBehaviour.StartCoroutine((IEnumerator)returnValue); } else { StaticCoroutine.StartCoroutine((IEnumerator)returnValue); } } if (hasParameters) { //update parameter Drawer with values of parameters so that changes made to parameters //(e.g. via ref and out) get shown in the ParameterDrawer var paramMembers = ParameterDrawer.Members; int paramMembersCount = paramMembers.Length; for (int n = ParameterDrawer.parameterInfos.Length - 1; n >= 0; n--) { var paramInfo = ParameterDrawer.parameterInfos[n]; if (paramInfo.ParameterType.IsByRef && paramMembersCount > n) { var memb = ParameterDrawer.Members[n]; if (memb.Type == paramInfo.ParameterType.GetElementType()) { #if DEV_MODE && DEBUG_INVOKE Debug.Log("param #" + n + " \"" + memb.Name + "\" value: " + StringUtils.ToString(parameters[n])); #endif memb.SetValue(parameters[n]); } } } } } catch (Exception e) { if (Inspector.Preferences.messageDisplayMethod == MessageDisplayMethod.None) { Debug.LogError(e); } else { InspectorUtility.ActiveInspector.Message(e.ToString(), null, MessageType.Error); } returnValue = DefaultValue(); } #if CALL_ON_VALIDATE if (!methodInfo.IsStatic && methodInfo.GetCustomAttributes(typeof(PureAttribute), false).Length == 0) { OnValidateHandler.CallForTargets(UnityObjects); } #endif error = ""; return(returnValue); }
public static void OnKeyDown(this IInspectorDrawer inspectorDrawer, Event e) { #if DEV_MODE && DEBUG_KEYBOARD_INPUT Debug.Log(StringUtils.ToColorizedString(inspectorDrawer.ToString(), ".OnKeyDown(", e.keyCode, ") with HasFocus=", inspectorDrawer.HasFocus, ", selectedControl=", StringUtils.ToString(inspectorDrawer.SelectedOrDefaultView().FocusedDrawer), ", SelectedPart=", inspectorDrawer.Manager.SelectedInspectorPart)); #endif if (!inspectorDrawer.HasFocus) { return; } var view = inspectorDrawer.SelectedOrDefaultView(); var keys = view.Preferences.keyConfigs; #if !POWER_INSPECTOR_LITE if (keys.stepBackInSelectionHistory.DetectAndUseInput(e)) { view.StepBackInSelectionHistory(); return; } if (keys.stepForwardInSelectionHistory.DetectAndUseInput(e)) { view.StepForwardInSelectionHistory(); return; } #endif inspectorDrawer.Repaint(); DrawGUI.RegisterInputEvent(e); var activeView = inspectorDrawer.SelectedOrDefaultView(); // give controls time to react to selection changes, editing text field changes etc. // before cached values are updated. (e.g. unapplied changes in delayed fields are // not discarded before they have time to get applied activeView.ResetNextUpdateCachedValues(); #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(!inspectorDrawer.HasFocus || activeView.Selected); #endif #if DEV_MODE && DEBUG_KEYBOARD_INPUT Debug.Log(StringUtils.ToColorizedString("OnKeyDown activeView.Selected=", activeView.Selected, ", activeView.FocusedDrawer=", activeView.FocusedDrawer + ", Manager.SelectedInspector=", inspectorDrawer.Manager.SelectedInspector, ", inspectorDrawer.HasFocus=", inspectorDrawer.HasFocus)); #endif if (activeView.Toolbar.OnKeyboardInputGivenWhenNotSelected(e, activeView.Preferences.keyConfigs)) { if (e.type != EventType.Used) { DrawGUI.Use(e); ExitGUIUtility.ExitGUI(); } } IDrawer selectedControl = null; if (activeView.Selected) { selectedControl = activeView.FocusedDrawer; if (selectedControl != null) { var onKeyboardInputBeingGiven = selectedControl.OnKeyboardInputBeingGiven; if (onKeyboardInputBeingGiven != null) { #if DEV_MODE && DEBUG_KEYBOARD_INPUT Debug.Log("onKeyboardInputBeingGiven(" + StringUtils.ToString(e) + "): " + StringUtils.ToString(onKeyboardInputBeingGiven)); #endif if (onKeyboardInputBeingGiven(selectedControl, e, selectedControl.Inspector.Preferences.keyConfigs)) { return; } } if (selectedControl.OnKeyboardInputGiven(e, selectedControl.Inspector.Preferences.keyConfigs)) { return; } } else if (inspectorDrawer.Manager.SelectedInspectorPart == InspectorPart.Toolbar) { activeView.Toolbar.OnKeyboardInputGiven(e, activeView.Preferences.keyConfigs); } else if (inspectorDrawer.Manager.SelectedInspectorPart == InspectorPart.Viewport || inspectorDrawer.Manager.SelectedInspectorPart == InspectorPart.None) { bool fieldChangeInputGiven; if (keys.DetectNextField(e, true) || keys.DetectPreviousField(e, true) || keys.nextFieldLeft.DetectAndUseInput(e) || keys.nextFieldRight.DetectAndUseInput(e) || keys.nextFieldDown.DetectAndUseInput(e) || keys.nextFieldUp.DetectAndUseInput(e)) { fieldChangeInputGiven = true; } else if (e.modifiers == EventModifiers.FunctionKey) { switch (e.keyCode) { case KeyCode.DownArrow: case KeyCode.UpArrow: case KeyCode.LeftArrow: case KeyCode.RightArrow: fieldChangeInputGiven = true; break; default: fieldChangeInputGiven = false; break; } } else { fieldChangeInputGiven = false; } if (fieldChangeInputGiven) { var drawers = activeView.State.drawers; if (drawers.Length == 0) { if (activeView.Toolbar != null) { activeView.Toolbar.OnFindCommandGiven(); } else { KeyboardControlUtility.SetKeyboardControl(0, 3); } } else { var first = drawers[0]; var select = first.GetNextSelectableDrawerRight(true, null); #if DEV_MODE && DEBUG_NEXT_FIELD Debug.Log(first + ".GetNextSelectableDrawerRight: " + StringUtils.ToString(select)); #endif if (select != null) { activeView.Select(select, ReasonSelectionChanged.SelectNextControl); } } } } } if (DrawGUI.EditingTextField && keys.DetectTextFieldReservedInput(e, TextFieldType.TextRow)) { #if DEV_MODE && DEBUG_KEYBOARD_INPUT Debug.Log(StringUtils.ToColorizedString("OnKeyboardInputGiven( ", StringUtils.ToString(e), ") DetectTextFieldReservedInput: ", true, " with selectedControl=", selectedControl)); #endif return; } if (keys.addComponent.DetectInput(e)) { #if DEV_MODE Debug.Log("AddComponent shortcut detected"); #endif if (AddComponentButtonDrawer.OpenSelectedOrFirstFoundInstance(activeView)) { DrawGUI.Use(e); } } if (keys.toggleSplitView.DetectInput(e)) { var splittable = inspectorDrawer as ISplittableInspectorDrawer; if (splittable != null && splittable.CanSplitView) { DrawGUI.Use(e); bool setSplitView = !splittable.ViewIsSplit; splittable.MainView.OnNextLayout(() => splittable.SetSplitView(setSplitView)); } } if (keys.refresh.DetectAndUseInput(e)) { var selectedInspector = inspectorDrawer.Manager.SelectedInspector; if (selectedInspector != null && selectedInspector.InspectorDrawer == inspectorDrawer) { selectedInspector.ForceRebuildDrawers(); } else { var mainView = inspectorDrawer.MainView; mainView.ForceRebuildDrawers(); var splittable = inspectorDrawer as ISplittableInspectorDrawer; if (splittable != null && splittable.ViewIsSplit) { splittable.SplitView.ForceRebuildDrawers(); } } } var keyCode = e.keyCode; switch (keyCode) { case KeyCode.Menu: if (selectedControl != null) { selectedControl.OpenContextMenu(e, selectedControl.RightClickArea, false, selectedControl.SelectedPart); } break; case KeyCode.Space: inspectorDrawer.Manager.RegisterKeyHeldDown(keyCode, "space"); break; case KeyCode.F2: inspectorDrawer.Repaint(); if (!DrawGUI.EditingTextField) { DrawGUI.Use(e); DrawGUI.EditingTextField = true; } break; case KeyCode.Escape: #if DEV_MODE Debug.Log("!!! ESCAPE !!!"); #endif //when dragging a control, allow aborting using the escape key if (inspectorDrawer.Manager.MouseDownInfo.MouseDownOverDrawer != null) { inspectorDrawer.Manager.MouseDownInfo.Clear(); } if (DrawGUI.EditingTextField) { DrawGUI.Use(e); DrawGUI.EditingTextField = false; } break; case KeyCode.AltGr: case KeyCode.RightAlt: KeyConfig.OnAltGrDown(); break; #if DEV_MODE case KeyCode.I: if (e.control && e.alt) { Debug.Log("INFO: FocusedDrawer=" + StringUtils.ToString(inspectorDrawer.SelectedOrDefaultView().FocusedDrawer) + ", EditingTextField=" + DrawGUI.EditingTextField); } break; #endif } }
/// <inheritdoc cref="IDrawer.Draw" /> public override bool Draw(Rect position) { var positionWithoutMargins = position; if (Event.current.type == EventType.Layout) { OnLayoutEvent(position); } #if !DRAW_LABEL_RESIZE_CONTROL DrawGUI.Active.ColorRect(position, DrawGUI.Active.InspectorBackgroundColor); #endif position.height -= 2f; position.y += 1f; position.width -= DrawGUI.RightPadding; float labelWidthWas = EditorGUIUtility.labelWidth; float fieldWidthWas = EditorGUIUtility.fieldWidth; float leftPadding = DrawGUI.LeftPadding; int labelRightPadding = (int)(DrawGUI.MiddlePadding + DrawGUI.MiddlePadding); position.x += leftPadding; position.width -= leftPadding; //always use wide mode for properties because it works better with the prefix width control #if ALWAYS_USE_WIDEMODE bool wideModeWas = EditorGUIUtility.wideMode; EditorGUIUtility.wideMode = true; #endif EditorStyles.label.padding.right = labelRightPadding; GUILayout.BeginArea(positionWithoutMargins); { position.y = position.y - positionWithoutMargins.y; position.x = position.x - positionWithoutMargins.x; try { decoratorDrawer.OnGUI(position); } catch (Exception e) { if (ExitGUIUtility.ShouldRethrowException(e)) { throw; } #if DEV_MODE Debug.LogWarning(ToString() + " " + e); #endif } } GUILayout.EndArea(); #if ALWAYS_USE_WIDEMODE EditorGUIUtility.wideMode = wideModeWas; #endif EditorStyles.label.padding.right = 2; EditorGUIUtility.labelWidth = labelWidthWas; EditorGUIUtility.fieldWidth = fieldWidthWas; return(false); }