Skip to content

Instantly share code, notes, and snippets.

@adammyhre
Created December 28, 2025 13:08
Show Gist options
  • Select an option

  • Save adammyhre/2fbf3c95228b76342487828919570ce7 to your computer and use it in GitHub Desktop.

Select an option

Save adammyhre/2fbf3c95228b76342487828919570ce7 to your computer and use it in GitHub Desktop.
Unity 6.3 Custom Main Toolbar
using UnityEditor;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.UIElements;
public class MainToolbarButtons {
[MainToolbarElement("Project/Open Project Settings", defaultDockPosition = MainToolbarDockPosition.Middle)]
public static MainToolbarElement ProjectSettingsButton() {
var icon = EditorGUIUtility.IconContent("SettingsIcon").image as Texture2D;
var content = new MainToolbarContent(icon);
return new MainToolbarButton(content, () => { SettingsService.OpenProjectSettings(); });
}
[MainToolbarElement("Timescale/Reset", defaultDockPosition = MainToolbarDockPosition.Middle)]
public static MainToolbarElement ResetTimeScaleButton() {
var icon = EditorGUIUtility.IconContent("Refresh").image as Texture2D;
var content = new MainToolbarContent(icon, "Reset");
var button = new MainToolbarButton(content, () => {
Time.timeScale = 1f;
MainToolbar.Refresh("Timescale/Slider");
});
MainToolbarElementStyler.StyleElement<UnityEditor.Toolbars.EditorToolbarButton>("Timescale/Reset", element => {
element.style.paddingLeft = 0f;
element.style.paddingRight = 0f;
element.style.marginLeft = 0f;
element.style.marginRight = 0f;
element.style.minWidth = 20f;
element.style.maxWidth = 20f;
var image = element.Q<Image>();
if (image != null) {
image.style.width = 12f;
image.style.height = 12f;
}
});
return button;
}
}
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityUtils; // https://github.com/adammyhre/Unity-Utils
public static class MainToolbarElementStyler {
public static void StyleElement<T>(string elementName, System.Action<T> styleAction) where T : VisualElement {
EditorApplication.delayCall += () => {
ApplyStyle(elementName, (element) => {
T targetElement = null;
if (element is T typedElement) {
targetElement = typedElement;
} else {
targetElement = element.Query<T>().First();
}
if (targetElement != null) {
styleAction(targetElement);
}
});
};
}
static void ApplyStyle(string elementName, System.Action<VisualElement> styleCallback) {
var element = FindElementByName(elementName);
if (element != null) {
styleCallback(element);
}
}
static VisualElement FindElementByName(string name) {
var windows = Resources.FindObjectsOfTypeAll<EditorWindow>();
foreach (var window in windows) {
var root = window.rootVisualElement;
if (root == null) continue;
VisualElement element;
if ((element = root.FindElementByName(name)) != null) return element;
if ((element = root.FindElementByTooltip(name)) != null) return element;
}
return null;
}
}
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.UIElements;
public class MainToolbarTimescaleSlider {
const float k_minTimeScale = 0f;
const float k_maxTimeScale = 5f;
[MainToolbarElement("Timescale/Slider", defaultDockPosition = MainToolbarDockPosition.Middle)]
public static MainToolbarElement TimeSlider() {
var content = new MainToolbarContent("Time Scale", "Time Scale");
var slider = new MainToolbarSlider(content, Time.timeScale, k_minTimeScale, k_maxTimeScale, OnSliderValueChanged);
slider.populateContextMenu = (menu) => {
menu.AppendAction("Reset", _ => {
Time.timeScale = 1f;
MainToolbar.Refresh("Timescale/Slider");
});
};
MainToolbarElementStyler.StyleElement<VisualElement>("Timescale/Slider", (element) => {
element.style.paddingLeft = 10f;
});
return slider;
}
static void OnSliderValueChanged(float newValue) {
Time.timeScale = newValue;
}
}
@kostarevVP
Copy link

Regarding the MainToolbarElementStyler.StyleElement method, if the element name contains spaces, unfortunately it will not work.

@kostarevVP
Copy link

  In principle, it worked quite well.
  
    static VisualElement FindElementByName(string name)
    {
        var nameWithoutSpace = name.Replace(" ", "");
        var windows = Resources.FindObjectsOfTypeAll<EditorWindow>();
        foreach (var window in windows)
        {
            var root = window.rootVisualElement;
            if (root == null) continue;

            VisualElement element;
            if ((element = root.FindElementByName(name)) != null) return element;
            if ((element = root.FindElementByName(nameWithoutSpace)) != null) return element;
            if ((element = root.FindElementByTooltip(name)) != null) return element;
        }

        return null;
    }

@kostarevVP
Copy link

kostarevVP commented Dec 29, 2025

And one more thing that wasn't in the video, if for example you need to combine a slider and a button into one tool, then you need to return not MainToolbarElement but IEnumerable'<'MainToolbarElement> where to each yield return add the desired element

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment