Dectivate menu entry when no glyph is selected or font is closed

I’m creating a Python General Plugin and it adds a bunch of menu entries, so should work on layers and others work on master. Right now I have to check if there are selected layers or masters and if not do nothing, but that looks like a bad UX and I’d rather have the menu entries deactivated when they can’t be used, but I have no idea how to do that.

What you are looking for is validateMenuItem:. Add this method to the object that is the target of the menu item. The method is called with the menu item. Return True, if the menu item should be enabled, or False, if not.

The Close Window plugin does this. On line 32, self is set as the target of the menu item and on line 77 it handles the menu item enabled state:

If you have multiple menu items, check for their selector in validateMenuItem: to return different results for different menu items.

Thanks for help, but that Objective-C and it is all Greek to me, I’m writing a Python plug-in.

Here is a Python version:

# Close Window
# ============
#
# Copyright 2021 Florian Pircher
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import objc
from AppKit import (
    NSEventModifierFlagCommand,
    NSEventModifierFlagShift,
    NSMenuItem,
)
from GlyphsApp import (Glyphs, FILE_MENU, VIEW_MENU)
from GlyphsApp.plugins import GeneralPlugin


class CloseWindow(GeneralPlugin):
    @objc.python_method
    def settings(self):
        self.name = Glyphs.localize({
            "ar": "إغلاق نافذ",
            "cs": "Zavřít okno",
            "de": "Fenster schließen",
            "en": "Close Window",
            "es": "Cerrar ventana",
            "fr": "Fermer la fenêtre",
            "it": "Chiudi la finestra",
            "ja": "ウインドウを閉じる",
            "ko": "창 닫기",
            "pt": "Fechar Janela",
            "ru": "Закрыть окно",
            "tr": "Pencereyi kapat",
            "zh-Hans": "关闭窗口",
            "zh-Hant": "關閉視窗",
        })

    @objc.python_method
    def start(self):
        closeWindowMenuItem = NSMenuItem.new()
        closeWindowMenuItem.setTitle_(self.name)
        closeWindowMenuItem.setTarget_(self)
        closeWindowMenuItem.setAction_(self.closeWindow_)

        if not Glyphs.defaults["com.FlorianPircher.CloseWindow.retainKeyboardEquivalent"]:
            viewMenuItem = Glyphs.menu[VIEW_MENU]
            viewMenu = viewMenuItem.submenu()
            closeTabMenuItemIndex = viewMenu.indexOfItemWithTarget_andAction_(None, "closeEditPage:")

            if closeTabMenuItemIndex != -1:
                closeTabMenuItem = viewMenu.itemAtIndex_(closeTabMenuItemIndex)
                closeTabMenuItem.setKeyEquivalent_("")
                closeTabMenuItem.setKeyEquivalentModifierMask_(0)

            closeWindowMenuItem.setKeyEquivalent_("W")
            closeWindowMenuItem.setKeyEquivalentModifierMask_(NSEventModifierFlagShift | NSEventModifierFlagCommand)

        fileMenuItem = Glyphs.menu[FILE_MENU]
        fileMenu = fileMenuItem.submenu()
        closeMenuItemIndex = fileMenu.indexOfItemWithTarget_andAction_(None, "performClose:")

        if closeMenuItemIndex != -1:
            fileMenu.insertItem_atIndex_(closeWindowMenuItem, closeMenuItemIndex + 1)
        else:
            fileMenu.addItem_(closeWindowMenuItem)

    def closeWindow_(self, sender):
        if Glyphs.font:
            Glyphs.font.close()

    def validateMenuItem_(self, menuItem):
        return Glyphs.font != None

    @objc.python_method
    def __file__(self):
        """Please leave this method unchanged"""
        return __file__
2 Likes

Looking into this, apparently validateMenuItem: has been deprecated by Apple and is no longer available per default on the upcoming Mac OS 12 (set to be released this fall). As I understand this, just adding a validateMenuItem: method will not work on macOS 12, you also have to do this:

# ...
NSMenuItemValidation = objc.protocolNamed('NSMenuItemValidation')

class CloseWindow(GeneralPlugin, protocols=[NSMenuItemValidation]):
    # ...

But changing the class definition this way only works on macOS 10.14 and later, while Glyphs runs on 10.11 and later.

I think you can ignore this added complexity for now, I just want to add a note here in case the above no longer works on macOS 12.

1 Like

Thanks! Works like charm (after a fair bit of trial and errors to get this working with my plugin class).