- Home /
(Editor) How to add Checkmarks to MenuItems
Trying to write an Editor script that uses toggle-able MenuItems. If you look at "Edit->Graphics Emulation". You'll see group of items, but only 1 can be checked on at a time. I would like to simulate the same behavior. But I don't know how, is there an undocumented attribute I'm missing?
Couldn't find anything about checkmarks here: http://docs.unity3d.com/ScriptReference/MenuItem.html
Haven't resolved this yet, but as a temporary workaround, I'm using the PreferenceItem attribute. http://docs.unity3d.com/412/Documentation/ScriptReference/PreferenceItem.html
Answer by Ziugy · Feb 25, 2016 at 08:27 AM
Was searching for this answer too. Here's what I found:
Menu.SetChecked gives you the ability to mark menu items with the checkmark seen in Edit > Graphics Emulation. Wrote a small example of this that also leverages EditorPrefs, since there's a little gotcha when setting the checked state on load.
using UnityEditor;
[InitializeOnLoad]
public static class CheckmarkMenuItem {
private const string MENU_NAME = "Example/Toggle";
private static bool enabled_;
/// Called on load thanks to the InitializeOnLoad attribute
static CheckmarkMenuItem() {
CheckmarkMenuItem.enabled_ = EditorPrefs.GetBool(CheckmarkMenuItem.MENU_NAME, false);
/// Delaying until first editor tick so that the menu
/// will be populated before setting check state, and
/// re-apply correct action
EditorApplication.delayCall += () => {
PerformAction(CheckmarkMenuItem.enabled_);
};
}
[MenuItem(CheckmarkMenuItem.MENU_NAME)]
private static void ToggleAction() {
/// Toggling action
PerformAction( !CheckmarkMenuItem.enabled_);
}
public static void PerformAction(bool enabled) {
/// Set checkmark on menu item
Menu.SetChecked(CheckmarkMenuItem.MENU_NAME, enabled);
/// Saving editor state
EditorPrefs.SetBool(CheckmarkMenuItem.MENU_NAME, enabled);
CheckmarkMenuItem.enabled_ = enabled;
/// Perform your logic here...
}
}
@Ziugy Your little gotcha doesn't work when you switch to play mode, any idea ?
Good question. I didn't see this kind of issue before, but it is presenting itself now. $$anonymous$$y assumptions are this was either overlooked when I created this, $$anonymous$$ac vs Windows (I wrote this originally on $$anonymous$$ac), or the latest version of Unity is presenting this issue (I was using the latest at the time, 4.6 or 4.7). I wasn't able to find a work-around with my brief investigation: EditorApplication.update ins$$anonymous$$d of delayCall, removing InitializeOnLoad, skipping delayCall if going into play mode.
Using EditorPrefs in a (static) constructor is a race condition which has been cleared up with errors in v5.4 since June of 2016: https://blogs.unity3d.com/2016/06/06/serialization-monobehaviour-constructors-and-unity-5-4/
The static constructor should be as such:
static Checkmark$$anonymous$$enuItem() {
/// Delaying until first editor tick so that the menu
/// will be populated before setting check state, and
/// re-apply correct action.
/// The same goes for getting the preference from EditorPrefs
/// as it might not be initialized during the constructor call time
EditorApplication.delayCall += () => {
Checkmark$$anonymous$$enuItem.enabled_ = EditorPrefs.GetBool(
Checkmark$$anonymous$$enuItem.$$anonymous$$ENU_NA$$anonymous$$E, false);
PerformAction(Checkmark$$anonymous$$enuItem.enabled_);
};
}
I$$anonymous$$O it's more consistent to call EditorPrefs.GetBool()
in every local scope ins$$anonymous$$d of storing it in a static variable. But that's a bit of a personal choice.
Answer by JanWosnitzaSAS · Jul 04, 2018 at 02:05 PM
@Mikeysee 's approach is nice, but can be improved a little imho:
public static class MyMenu
{
private const string MenuName = "My Menu Item";
private const string SettingName = "MySetting";
public static bool IsEnabled
{
get { return EditorPrefs.GetBool(SettingName, true); }
set { EditorPrefs.SetBool(SettingName, value); }
}
[MenuItem(MenuName)]
private static void ToggleAction()
{
IsEnabled = !IsEnabled;
}
[MenuItem(MenuName, true)]
private static bool ToggleActionValidate()
{
Menu.SetChecked(MenuName, IsEnabled);
return true;
}
}
Well done! and more over it's not improvement it's more proper way to handle $$anonymous$$enu.SetChecked. Only in my way I moved SetChecked to the IsEnable setter. This answer have to be at first position here.
Agreed--this is the only way to maintain the check mark appropriately in the editor on first load.
Answer by rickomax · Jul 04, 2017 at 10:49 PM
For anyone that still having issues with this, the correct way to check/unchek a menu is having a function to do the actual menu action, and another to do the menu validation, where you can check or uncheck it, like in this example:
This is the only method that will keep your menu checking state even after you hit the "play" button.
Been trying to solve this one for some time, whilst the underlying value appears to work, the visible state of the menu item does not seem to persist when first navigating to the menu item. Does the $$anonymous$$enu.SetChecked method actually set the appearance to checked?
[InitializeOnLoad]
public class Options$$anonymous$$enu
{
private const string $$anonymous$$enuName = "Options/Toggle";
private static bool isToggled;
static Options$$anonymous$$enu()
{
EditorApplication.delayCall += () =>
{
isToggled = EditorPrefs.GetBool($$anonymous$$enuName, true);
Set$$anonymous$$ode(isToggled);
$$anonymous$$enu.SetChecked($$anonymous$$enuName, isToggled); // This doesn't appear to work
};
}
[$$anonymous$$enuItem($$anonymous$$enuName)]
private static void Toggle$$anonymous$$ode()
{
isToggled = !isToggled;
Set$$anonymous$$ode(isToggled);
$$anonymous$$enu.SetChecked($$anonymous$$enuName, isToggled);
EditorPrefs.SetBool($$anonymous$$enuName, isToggled);
}
private static void Set$$anonymous$$ode(bool value)
{
// $$anonymous$$ode set up here...
}
}
Answer by Mikeysee · May 01, 2018 at 01:33 AM
@rickomax has the correct solution.
Here is a simplified working version of his code:
[InitializeOnLoad]
public static class MyMenu
{
private const string MenuName = "My Menu Item";
public static bool isEnabled;
static MyMenu()
{
isEnabled = EditorPrefs.GetBool(MenuName, true);
}
[MenuItem(MenuName)]
private static void ToggleAction()
{
isEnabled = !isEnabled;
EditorPrefs.SetBool(MenuName, isEnabled);
}
[MenuItem(MenuName, true)]
private static bool ToggleActionValidate()
{
Menu.SetChecked(MenuName, isEnabled);
return true;
}
}
Your answer
Follow this Question
Related Questions
Menu Items as checkboxes/radio buttons 4 Answers
A node in a childnode? 1 Answer
Player damage stops working over time 0 Answers
Debug the Scene loading time? 0 Answers
Equivalent of OpenFilePanel without using UnityEditor? 5 Answers