Daniel Lip
Daniel Lip

Reputation: 11317

How can I set position of a GUI.Button in Inspector?

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

[CustomEditor(typeof(ConversationTrigger))]
public class ConversationTriggerEditor : Editor
{
    private ConversationTrigger conversationtrigger;

    private void OnEnable()
    {
        conversationtrigger = FindObjectOfType<ConversationTrigger>();
    }

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        if(GUI.Button(new Rect(0.1f,0.5f,0.1f,0.1f), "Add new item"))
        {
            conversationtrigger.conversations.Add(new Conversation());
        }

        if (GUILayout.Button("Save Conversations"))
        {
            conversationtrigger.SaveConversations();
        }

        if (GUILayout.Button("Load Conversations"))
        {
            Undo.RecordObject(conversationtrigger, "Loaded conversations from JSON");
            conversationtrigger.LoadConversations();
        }
    }
}

I tried this line :

if(GUI.Button(new Rect(0.1f,0.5f,0.1f,0.1f), "Add new item"))

But that make the button vanished like deleted. If I'm using GUILayout.Button I will see the button but then I can't set the button position so I'm using GUI.Button.

I want to position the button "Add new item" before the Canvas field and always after the last conversation item, in this case the Locked Room. And if I will add a new item the button should stay after the new added item and before the Canvas field.

I guess this values of the Rect are wrong making the button to be positioned out of the window.

This is a screenshot of the Inspector :

Inspector

Upvotes: 3

Views: 8647

Answers (1)

derHugo
derHugo

Reputation: 90659

The values for the Rect are positionX, positionY, width and height and for the Inspector they are in pixels. So

new Rect(0.1f,0.5f,0.1f,0.1f)

simply results in a really tiny little 0.1 x 0.1 pixel size button on the position 0.1 ,0.5 pixels of the current Inspector. Since you can't display something with size 0.1 pixels on the screen it is invisible.


Afaik you can use GUILayoutUtility.GetLastRect in order to get the Rect of the last control before the button and then place your button using that rect like e.g.

Rect lastRect = GUILayoutUtility.GetLastRect();

Rect buttonRect = new Rect(lastRect.x, lastRect.y + EditorGUIUtility.singleLineHeight, 100, 30);

if(GUI.Button(buttonRect, "AddNewItem")
    ...

to place the button I the next line under the last control and set it's size to 100px * 30px.


I would however in general recommend to not mix GUI and GUILayout stuff. It is kind of the same like mixing static and relative in css ..


Depending on what exactly it is you want to change here you might rather want to use the optional options parameter to e.g. change the buttons height and width using

GUILayout.Button("AddNewItem", GUILayout.With(100), GUILayout.Height(30));

where the button starts in the X axis you could also change by temporarily change the EditorGUI.indentLevel e.g.

EditorGUI.indentLevel++
GUILayout.Button("AddNewItem", GUILayout.With(100), GUILayout.Height(30));
EditorGUI.indentLevel--;

For changing the position in Y direction you could either use EditorGUILayout.Space

EditorGUILayout.Space();
if(GUILayout.Button(...))

in order to have a small default space between the button and the control before or GUILayout.Space like e.g.

GUILayout.Space(30);
if(GUILayout.Button(...))

to set a fixed space in pixels.


To your actual question

If you really want to place a button in between the controls before you won't come around implementing the Editor for the entire inspector instead of using DrawDefaultInspector since it also means that you would have to make space for the button. Otherwise you might get multiple controls on top of each other.

I won't do that for you here. We can't even see the fields/types of your classes.

But since you are using a list/array there I (like I do quite often) once more strongly recommend to use the undocumented ReorderableList which not only is extremely fancy and allows you to rearrange items within the list by drag and drop but also implements Add and Remove buttons by default.


May I also ask why you do

conversationtrigger = FindObjectOfType<ConversationTrigger>();

This will fail as soon as you are dealing with an inactive GameObject, a disabled ConversationTrigger, a Prefab or simply multiple of those components in the scene.

In the Editor you already get the currently inspected component in target. All you have to do is to cast it like

conversationtrigger = (ConversationTrigger) target;

Note: Typed on smartphone so no warranty but I hope the idea gets clear

Upvotes: 3

Related Questions