Multi-menu menu, how to
-
Hi folks,
How does one go about making a multi-menu menu, like the shortcuts in the viewport:
Can I do this in my own dialog/UA?
WP.
-
Hello @WickedP,
Thank you for reaching out to us. In short - radial menus or any form of "multi-menus" are not part of the public API. There is
c4d.gui.ShowPopupDialog
but it is blocking, so trying to open two or more menus at once will not work.So, you would have to use multiple
GeDialog
instances at once to do this. And for that you will need a handler for them, something like I did in the quick sketch below. The problem with this is, that you cannot have a dialog of typeDLG_TYPE_ASYNC_POPUPEDIT
, i.e., a borderless dialog, with a menu. Which then means that you also must (re)-implement menus.I personally would not go down that rabbit hole, there is a lot of work and only little reward. Just use a dialog with one menu or
ShowPopupDialog
.Cheers,
FerdinandFYI:
ShowPopupDialog
isShowPopupMenu
in C++.Code:
"""Realizes a dialog handler which handles multiple dialogs, primarily with the feature that closing one dialog entails closing all of them. Must be run in the script manager. """ import c4d class DialogHandler: """Realizes the dialog handler object. """ def __init__(self, count=4) -> None: self._collection: dict[MyDialog, bool] = {MyDialog(self): True for i in range(count)} def Open(self): for i, dlg in enumerate(self._collection): dlg.Open(c4d.DLG_TYPE_ASYNC, xpos=400+i*100, ypos=400, defaultw=100, defaulth=24) def OnClose(self, sender: "MyDialog") -> None: self._collection[sender] = False for dlg, isOpen in self._collection.items(): if isOpen: dlg.Close() class MyDialog(c4d.gui.GeDialog): """Realizes the handled dialog. """ def __init__(self, handler: DialogHandler) -> None: self._handler: DialogHandler = handler def CreateLayout(self) -> bool: self.MenuSubBegin("Test") self.MenuAddString(1000, f"Foo&i{c4d.Ocube}&") self.MenuAddString(1001, f"Bar&i{c4d.Osphere}&") self.MenuSubEnd() return True def InitValues(self) -> bool: return True def Command(self, id: int, msg: c4d.BaseContainer) -> bool: self.Close() return True def AskClose(self) -> bool: self._handler.OnClose(self) return False handler: DialogHandler = DialogHandler(count=4) if __name__ == "__main__": handler. Open()
-
Thanks @ferdinand,
I've made a mock-up of a multi-menu system using dialogs as you suggested. Work-in-progress question:
When I close my menu system (destroy the dialogs), how can I set another dialog/window as the main focus again? Currently, if I open up my dialogs, and say, go and type something in Notepad, then come back to CInema and close the menus/dialogs, Windows switches back to Notepad as the main focus window. How can I avoid this?
WP.
-
Hello @WickedP,
hm, good question, you can grab the
HWND
of a dialog with GeDialog::GetWindowHandle, but there is neither a way to determine the focusedCDialog
(not a typo, the underlying type ofGeDialog
) nor set the focused dialog. With::GetWindowHandle
and tracking the active window handle via OS functions, you probably could fiddle things into place. But just as GUI stuff, I personally also would avoid OS backend stuff at all costs.But my main question would be: When you use
DLG_TYPE_ASYNC_POPUPEDIT
will such dialogs actually 'steal' the focus from another dialog/window? My gut feeling would be no, but I did not try.Cheers,
Ferdinand -
Thanks @ferdinand,
Agree. I've avoided using OS-specific calls up until now. But for this one I've had to make an exception. Not an ideal solution, but it seems to work:
To get around the lost window focus issue, I'm using the first dialog's Timer() to poll and check if any dialog in the menu has window focus. If none do, e.g., a user has clicked away, the system self-destructs. If a menu selection is made, it sends a Message() back to the calling object with details, and then self-destructs.
It's all a bit of a hack. But it works.
WP.
Update: I'll mark this thread as solved. If I have any further questions I'll pop back in.
-