Skip to content

Commit 3bbc738

Browse files
committed
- Added "Show Add Component Button" and "Show Remove Component Button" properties to RuntimeInspector
- Changes made to UI Skins via Unity Inspector in Play mode are reflected to UI immediately - Changes made to RuntimeInspector's properties via Unity Inspector in Play mode are reflected to UI immediately - ObjectReferencePicker isn't restricted to Unity objects now, it can be used to pick any kinds of objects efficiently with search support (e.g. it is used by Add Component button). Its API is now documented - ObjectReferencePicker's searchbar automatically gains focus on desktop platforms
1 parent 60ee8e4 commit 3bbc738

File tree

13 files changed

+416
-96
lines changed

13 files changed

+416
-96
lines changed

.github/README.md

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ Note that these connections are *one-directional*, meaning that assigning the in
5252

5353
![screenshot](images/img3.png)
5454

55-
Be aware that the changes made to a skin via the Unity Inspector might not be reflected to the UI immediately. To reflect these changes to the UI, you may have to click the *cog icon* while the skin is selected and select **Refresh UI**.
56-
5755
### E.1. INSPECTOR
5856

5957
![screenshot](images/img4.png)
@@ -65,6 +63,8 @@ RuntimeInspector works similar to the editor Inspector. It can expose commonly u
6563
- **Expose Properties**: determines which properties of the inspected object should be exposed
6664
- **Array Indices Start At One**: when enabled, exposed arrays and lists start their indices at 1 instead of 0 (just a visual change)
6765
- **Use Title Case Naming**: when enabled, variable names are displayed in title case format (e.g. *m_myVariable* becomes *My Variable*)
66+
- **Show Add Component Button**: when enabled, *Add Component* button will appear while inspecting a GameObject
67+
- **Show Remove Component Button**: when enabled, *Remove Component* button will appear under inspected components
6868
- **Show Tooltips**: when enabled, hovering over a variable's name for a while will show a tooltip displaying the variable's name. Can be useful for variables whose names are partially obscured
6969
- **Tooltip Delay**: determines how long the cursor should remain static over a variable's name before the tooltip appears. Has no effect if *Show Tooltips* is disabled
7070
- **Nest Limit**: imagine exposing a linked list. This variable defines how many nodes you can expose in the inspector starting from the initial node until the inspector stops exposing any further nodes
@@ -188,7 +188,42 @@ public void DeleteAllPseudoScenes();
188188

189189
This helper component allows you to add an object's children to a pseudo-scene in the hierarchy. When a child is added to or removed from the object, this component refreshes the pseudo-scene automatically. If **HideOnDisable** is enabled, the object's children are removed from the pseudo-scene when the object is disabled.
190190

191-
### F.2. DRAGGED REFERENCE ITEMS
191+
### F.2. COLOR PICKER
192+
193+
You can access the built-in color picker via **ColorPicker.Instance** and then present it with the following function:
194+
195+
```csharp
196+
public void Show( ColorWheelControl.OnColorChangedDelegate onColorChanged, ColorWheelControl.OnColorChangedDelegate onColorConfirmed, Color initialColor, Canvas referenceCanvas );
197+
```
198+
199+
- **onColorChanged**: invoked regularly as the user changes the color. `ColorWheelControl.OnColorChangedDelegate` takes a *Color32* parameter
200+
- **onColorConfirmed**: invoked when user submits the color via *OK* button
201+
- **initialColor**: the initial value of the color picker
202+
- **referenceCanvas**: if assigned, the reference canvas' properties will be copied to the color picker canvas
203+
204+
You can change the color picker's visual appearance by assigning a *UISkin* to its **Skin** property.
205+
206+
### F.3. OBJECT REFERENCE PICKER
207+
208+
You can access the built-in object reference picker via **ObjectReferencePicker.Instance** and then present it with the following function:
209+
210+
```csharp
211+
public void Show( ReferenceCallback onReferenceChanged, ReferenceCallback onSelectionConfirmed, NameGetter referenceNameGetter, NameGetter referenceDisplayNameGetter, object[] references, object initialReference, bool includeNullReference, string title, Canvas referenceCanvas );
212+
```
213+
214+
- **onReferenceChanged**: invoked when the user selects a reference from the list. `ReferenceCallback` takes an *object* parameter
215+
- **onSelectionConfirmed**: invoked when user submits the selected reference via *OK* button
216+
- **referenceNameGetter**: `NameGetter` takes an *object* parameter and returns that object's name as string. The passed function will be used to sort the references list and compare the references' names with the search string
217+
- **referenceDisplayNameGetter**: the passed function will be used to get display names for the references. Usually, the same function is passed to this parameter and the *referenceNameGetter* parameter
218+
- **references**: array of references to pick from
219+
- **initialReference**: initially selected reference
220+
- **includeNullReference**: is set to *true*, a null reference option will be added to the top of the references list
221+
- **title**: title of the object reference picker
222+
- **referenceCanvas**: if assigned, the reference canvas' properties will be copied to the object reference picker canvas
223+
224+
You can change the object reference picker's visual appearance by assigning a *UISkin* to its **Skin** property.
225+
226+
### F.4. DRAGGED REFERENCE ITEMS
192227

193228
In section **E.2**, it is mentioned that you can drag&drop objects from the hierarchy to the variables in the inspector to assign these objects to those variables. However, you are not limited with just hierarchy. There are two helper components that you can use to create dragged reference items for other objects:
194229

@@ -213,7 +248,7 @@ You can also use your own scripts to create dragged reference items by calling t
213248
public static DraggedReferenceItem CreateDraggedReferenceItem( Object reference, PointerEventData draggingPointer, UISkin skin = null );
214249
```
215250

216-
### F.3. CUSTOM DRAWERS (EDITORS)
251+
## G. CUSTOM DRAWERS (EDITORS)
217252

218253
**NOTE:** if you just want to hide some fields/properties from the RuntimeInspector, simply use **Settings** asset's **Hidden Variables** list (mentioned in section **E.1**).
219254

@@ -222,7 +257,7 @@ You can introduce your own custom drawers to RuntimeInspector. These drawers wil
222257
- creating a drawer prefab and adding it to the **Settings** asset mentioned in section **E.1**. Each drawer extends from **InspectorField** base class. There is also an **ExpandableInspectorField** abstract class that allows you to create an expandable/collapsable drawer like arrays. Lastly, extending **ObjectReferenceField** class allows you to create drawers that can be assigned values via the reference picker or via drag&drop. This option provides the most flexibility because you'll be able to customize the drawer prefab as you wish. The downside is, you'll have to create a prefab asset and manually add it to RuntimeInspector's **Settings** asset. All built-in drawers use this method; they can be as simple as **BoolField** and **TransformField**, or as complex as **BoundsField**, **GameObjectField** and **ArrayField**
223258
- extending **IRuntimeInspectorCustomEditor** interface and decorating the class/struct with **RuntimeInspectorCustomEditor** attribute. This method is simpler because you won't have to create a prefab asset for the drawer. Created custom drawer will internally be used by *ObjectField* to populate its sub-drawers. This option should be sufficient for most use-cases. But imagine that you want to create a custom drawer for Matrix4x4 where the cells are displayed in a 4x4 grid. In this case, you must use the first method because you'll need a custom prefab with 16 InputFields organized in a 4x4 grid for it. But if you can represent the custom drawer you have in mind by using a combination of built-in drawers, then this second option should suffice
224259

225-
#### F.3.1. InspectorField
260+
### G.1. InspectorField
226261

227262
To have a standardized visual appearance across all the drawers, there are some common variables for each drawer:
228263

@@ -253,7 +288,7 @@ There are some special functions on drawers that are invoked on certain circumst
253288
- **void OnDepthChanged()**: called when the *Depth* property of the drawer is changed. Here, your custom drawers must add a padding to their content from left to comply with the nesting standard. This function is also called when the *Skin* changes
254289
- **void Refresh()**: called when the value of the bound object is refreshed. Drawers must refresh the values of their UI elements here. Invoked by RuntimeInspector at every **Refresh Interval** seconds
255290

256-
#### F.3.2. ExpandableInspectorField
291+
### G.2. ExpandableInspectorField
257292

258293
Custom drawers that extend **ExpandableInspectorField** have access to the following properties:
259294

@@ -281,13 +316,11 @@ There are also some helper functions in ExpandableInspectorField to easily creat
281316
- `InspectorField CreateDrawerForVariable( MemberInfo variable, string variableName = null )`: creates a drawer for the variable that the *MemberInfo* stores. This variable must be declared inside inspected object's class/struct or one of its base classes
282317
- `InspectorField CreateDrawer( Type variableType, string variableName, Getter getter, Setter setter, bool drawObjectsAsFields = true )`: similar to the *BindTo* function with the *Getter* and *Setter* parameters, allows you to use custom functions to get and set the value of the object that the sub-drawer is bound to
283318

284-
If you don't want the name of the variable to be title case formatted, you can enter an empty string as the **variableName** parameter and then set the *NameRaw* property of the returned *InspectorField* object.
285-
286-
#### F.3.3. ObjectReferenceField
319+
### G.3. ObjectReferenceField
287320

288321
Drawers that extend **ObjectReferenceField** class have access to the `void OnReferenceChanged( Object reference )` function that is called when the reference assigned to that drawer is changed.
289322

290-
#### F.3.4. Helper Classes
323+
### G.4. Helper Classes
291324

292325
**PointerEventListener**: this is a simple helper component that invokes **PointerDown** event when its UI GameObject is pressed, **PointerUp** event when it is released and **PointerClick** event when it is clicked
293326

@@ -300,7 +333,7 @@ Drawers that extend **ObjectReferenceField** class have access to the `void OnRe
300333
- **OnValueChangedDelegate OnValueSubmitted**: called when user finishes editing the value of input field. Similar to *OnValueChanged*, a function that is registered to this event should parse the **input** and return *true* only if the input is valid
301334
- **bool CacheTextOnValueChange**: determines what will happen when user stops editing the input field while its contents are invalid (i.e. its background has turned red). If this variable is set to *true*, input field's text will revert to the latest value that returned *true* for OnValueChanged. Otherwise, the text will revert to the value input field had when it was focused
302335

303-
#### F.3.5. RuntimeInspectorCustomEditor Attribute
336+
### G.5. RuntimeInspectorCustomEditor Attribute
304337

305338
To create drawers without having to create a prefab for it, you can declara a class/struct that extends **IRuntimeInspectorCustomEditor** and has one or more **RuntimeInspectorCustomEditor** attributes.
306339

@@ -341,6 +374,8 @@ public class ColliderEditor : IRuntimeInspectorCustomEditor
341374
}
342375
```
343376

377+
---
378+
344379
![screenshot](images/CustomMeshRendererEditor.png)
345380

346381
```csharp
@@ -365,6 +400,8 @@ public class MeshRendererEditor : IRuntimeInspectorCustomEditor
365400
}
366401
```
367402

403+
---
404+
368405
![screenshot](images/CustomCameraEditor.png)
369406

370407
```csharp

Plugins/RuntimeInspector/Scripts/RuntimeInspector.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,36 @@ public bool UseTitleCaseNaming
8383
}
8484
}
8585

86+
[SerializeField]
87+
private bool m_showAddComponentButton = true;
88+
public bool ShowAddComponentButton
89+
{
90+
get { return m_showAddComponentButton; }
91+
set
92+
{
93+
if( m_showAddComponentButton != value )
94+
{
95+
m_showAddComponentButton = value;
96+
isDirty = true;
97+
}
98+
}
99+
}
100+
101+
[SerializeField]
102+
private bool m_showRemoveComponentButton = true;
103+
public bool ShowRemoveComponentButton
104+
{
105+
get { return m_showRemoveComponentButton; }
106+
set
107+
{
108+
if( m_showRemoveComponentButton != value )
109+
{
110+
m_showRemoveComponentButton = value;
111+
isDirty = true;
112+
}
113+
}
114+
}
115+
86116
[SerializeField]
87117
private bool m_showTooltips;
88118
public bool ShowTooltips { get { return m_showTooltips; } }
@@ -183,6 +213,9 @@ public RuntimeHierarchy ConnectedHierarchy
183213
private Canvas m_canvas;
184214
public Canvas Canvas { get { return m_canvas; } }
185215

216+
// Used to make sure that the scrolled content always remains within the scroll view's boundaries
217+
private PointerEventData nullPointerEventData;
218+
186219
public InspectedObjectChangingDelegate OnInspectedObjectChanging;
187220

188221
private ComponentFilterDelegate m_componentFilter;
@@ -211,6 +244,7 @@ private void Initialize()
211244

212245
drawArea = scrollView.content;
213246
m_canvas = GetComponentInParent<Canvas>();
247+
nullPointerEventData = new PointerEventData( null );
214248

215249
GameObject poolParentGO = GameObject.Find( POOL_OBJECT_NAME );
216250
if( poolParentGO == null )
@@ -272,6 +306,16 @@ private void OnTransformParentChanged()
272306
m_canvas = GetComponentInParent<Canvas>();
273307
}
274308

309+
#if UNITY_EDITOR
310+
protected override void OnValidate()
311+
{
312+
base.OnValidate();
313+
314+
if( UnityEditor.EditorApplication.isPlaying )
315+
isDirty = true;
316+
}
317+
#endif
318+
275319
protected override void Update()
276320
{
277321
base.Update();
@@ -358,6 +402,16 @@ public void RefreshDelayed()
358402
nextRefreshTime = 0f;
359403
}
360404

405+
// Makes sure that scroll view's contents are within scroll view's bounds
406+
public void EnsureScrollViewIsWithinBounds()
407+
{
408+
// When scrollbar is snapped to the very bottom of the scroll view, sometimes OnScroll alone doesn't work
409+
if( scrollView.normalizedPosition.y <= Mathf.Epsilon )
410+
scrollView.normalizedPosition = new Vector2( scrollView.normalizedPosition.x, 0.001f );
411+
412+
scrollView.OnScroll( nullPointerEventData );
413+
}
414+
361415
protected override void RefreshSkin()
362416
{
363417
background.color = Skin.BackgroundColor;

Plugins/RuntimeInspector/Scripts/RuntimeInspector/Fields/ColorField.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private void ShowColorPicker( PointerEventData eventData )
4343
Color value = isColor32 ? (Color) (Color32) Value : (Color) Value;
4444

4545
ColorPicker.Instance.Skin = Inspector.Skin;
46-
ColorPicker.Instance.Show( OnColorChanged, value, Inspector.Canvas );
46+
ColorPicker.Instance.Show( OnColorChanged, null, value, Inspector.Canvas );
4747
}
4848

4949
private void OnColorChanged( Color32 color )

0 commit comments

Comments
 (0)