Advice on approach to "menu editor"

I’m looking to build what is essentially a menu editor – the user should be able to add items, submenus, separators, etc to a menu that’s displayed in the main body of the app. I’m perfectly content to hand-roll the various controls to do the addition / deletion / renaming / etc of menu items. What I’m wanting a little guidance on is actually showing the menu.

What I’d really like to do is have a FlatMenu in a panel that would just stay there always visible, updating as the user edits it. My initial stabs at that make me think that this might not be easy since FlatMenu is a child of PopupWindow which seems to have deep innards that make it modal when it’s visible and disappear when it loses focus.

Does anyone have any thoughts on the most direct and simplest route to victory as far as showing a non-disappearing menu inside a panel? I’m starting to fear I just need to roll my own menu-like implementation by hand with lots of little rectangular boxes, and I’ll go down that path if I have to.

But I was hoping someone might have some ideas that haven’t occurred to me, or some thoughts on how to get one of the existing Menu / FlatMenu / etc classes to work embedded inside a panel.

Thanks in advance for any guidance y’all have.

Perhaps, use a format as follows. metamenus

Ah thanks for that pointer. I didn’t actually end up using it directly but yeah the design of it is influencing how I’m structuring the innards of my menu builder. Quite helpful, thanks again.

I have a follow-up question for anyone versed in FlatMenu:

FlatMenuItems have a SetContextMenu() method where you can assign another FlatMenu as a context menu that automagically does the right-mouse bindings and popping up in the right place and so forth.

That much is working well, but I can’t for the life of me figure out how to get back to the FlatMenuItem inside the ContextMenu’s handlers. That is, if my ContextMenu has a “Delete” entry, and I have bound an event handler to that entry which fires as expected, how do I get the object or ID or index of the menu item I’ve right-clicked on to pop up the menu in the first place? I feel like it’s right there, but I can’t work it out.

Anyone have any experience with context menus in FlatMenu?

No experience at all with FlatMenu. I assume you can access evt.GetId to get to the FlatMenuItem from the handler that is bound to a FM.EVT_FLAT_MENU_SELECTED event.

For another perspective on a menu editor try SPyE and check the src/gui folder.

I’d gone down the GetId() path; turns out EVT_FLAT_MENU_SELECTED doesn’t fire on the right-mouse click that pops up the context menu.

I cobbled together a solution that works, which consisted of overriding the ProcessMouseRClick method on the origin flatmenu, using self.HitTest() on it to get the menu item’s index, and then using that to index into self.GetMenuItems().

This seems a little overengineered but I’ve started to see that FlatMenu is 90% of the way there and missing a layer of basic stuff around the edges. Still, I got it working reliably, finally.

I’m going to take a look at SPyE, thanks – still needing some UI guidance and sample code can’t but help.

Actually, I don’t see the need for displaying the ‘real’ menu while editing.
I find the usability much more important.
In wxGlade I have a menu editor which just displays the menu structure in a list control. Indentation is used to visualize submenus etc.

I’d mulled that for a while, but some of the menus that might be edited (these are data files for a game, already existing in the wild) have -thousands- of entries deeply-nested. I initially was working with a tree control but that quickly got too long vertically with even a moderate-sized existing menu, and a hassle to twiddle each expand/collapse control to get where you were going. So my current least-terrible solution is just the actual menu with a context menu with “edit” “delete” “insert” etc.

My current issue is that with FlatMenu, loading the largest menu I know of, several thousand entries, I run out of GDI handles on Windows 10 while building it. Gonna try to fall back to plain’ol’ wx.Menu etc and see if that helps, though then I’m going to have to roll my own context menu logic. Might just have to be, though. (This also argues for using some sort of virtual list-style control, I know. It’s not completely off the table yet.)

And yeah, using wx.Menu / wx.MenuItem fixes the GDI thing perfectly well and speeds up the process drastically. But there seems to be no way to hook right-click on a normal wx.Menu / wx.MenuItem. Hmm.

I believe this PR:

Will solve your GDI issue.

1 Like

That did it! My giant menu that was running out of handles 25% into loading it now idles there with only 700 handles open. That’s awesome, thank you so much!

Also want to add, for future Googlers that might find this, in addition to solving the GDI starvation, applying the patch in that pull request sped up the creation of my menu -dramatically-, and might have eliminated a crash-on-exit I was experiencing. Very pleased with this turn of events.

1 Like