0
votes

Is it possible for an NSMenu object to notify BEFORE it'll close, not after? Its delegate has method didClose(_:) but I want to update its items before it actually closes, since the disappearing animation is too long and the eye can see the change.

I've tried to monitor NSEvents, but it's useless because NSMenu hasn't public property containing its NSWindow object.

It's theoretically possible to achieve by creating a custom NSViews for each menu items. But I don't like this because then I'll have to draw all the drawing of the items, including selection and click animation.

UPDATE: I've tried to subclass the NSPopUpButton to track menu updates:

class CustomPopUpButton: NSPopUpButton {
    var isMenuShown: Bool = false
    var onClosingMenu: ((NSMenu)->())?
    
    override var needsDisplay: Bool {
        willSet {
            if let menu = self.menu, isMenuShown, newValue {
                onClosingMenu?(menu)
                isMenuShown = false
            }
        }
    }

    override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) {
        isMenuShown = true
        super.willOpenMenu(menu, with: event)
    }
}

I'm not proud of that piece of code but it works in general. Yet the 'onClosingMenu' method is being called just after the menu closing animation is finished. Not before.

Video of what I want to achieve: https://drive.google.com/file/d/1GAceKp-fTlurxSybdB3h0epVZrtQjthm/view?usp=sharing

1
I think you can try to do what you want in NSMenu.willSendActionNotification handler, because menu is closed once any item action sent.Asperi
That works only if user clicks ON an item. But it's possible to close menu by clicking outside the menu, or by hitting the Esc key. And I'm stuck with that :(Vitalii Vashchenko
It is not clear what do you want to achieve. NSMenu has own validation/udpate flow, so what's the problem?Asperi
I want to display the picker of fonts available in the system. Let's say, like in Apple Pages. In that app NSPopupButton with NSMenu of available fonts is changing the display options of selected items depending on the menu showing state. If the menu is shown, selected item has an NSAttrbiutedString title. But before the menu closes it removes the attributes and when the menu is closed you see the normal button font, the default one. I was able to imitate that behaviour, except the title update when closing the menu. I do that in didClose method and the change of title's font is too visibleVitalii Vashchenko
I still don't understand what you're trying to accomplish.Willeke

1 Answers

0
votes

Finally, I've found the solution. No need to fight the system and update something before the button menu closes. I've found the another way and it's pretty simple.

I've subclassed the NSPopUpButton and created another NSMenu in the subclass, called 'attributedMenu'. Overrided all properties of the NSPopUpButton that deal with menu items (insertions and removals) and redirected that actions to the 'attributedMenu' property.

The initial menu property of NSPopUpButton I'm using only for selected items, removing non-selected items right away.

I intercept the click on the button to show 'attributedMenu', not the default menu of the class.

That solution even made possible to display 'multiple values' title if I select more than one element. Like in Apple Pages' font picker when you select text written with multiple fonts. All it takes is to add an NSMenuItem with title 'Multiple Values' and call super to select it.

That's it, now it works as perfect as in Apple Pages font picker button. As long, as I'm not touching the original 'menu' property of NSPopUpButton class.

UPDATE

Uploaded the subclass to GitHub: https://github.com/CineDev/AttributedPopUpButton