Skip to content

Commit

Permalink
Submenu contribution to editor/title and view/title not working #12706
Browse files Browse the repository at this point in the history
* add option RenderContextMenuOptions to ask renderer to no render a
menu with single submenu but to render the children instead
* add helper method to menu-model-registry to remove the parent nodes
from a menu node as described above
* adjust renderers and callers accordingly
  • Loading branch information
jfaltermeier committed Aug 8, 2023
1 parent 1e16b08 commit 4bc88f0
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 9 deletions.
5 changes: 5 additions & 0 deletions packages/core/src/browser/context-menu-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,9 @@ export interface RenderContextMenuOptions {
context?: HTMLElement;
contextKeyService?: ContextMatcher;
onHide?: () => void;
/**
* If true a single submenu in the context menu is not rendered but its children are rendered on the top level.
* Default is `false`.
*/
skipSingleRootNode?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export class BrowserContextMenuRenderer extends ContextMenuRenderer {
super();
}

protected doRender({ menuPath, anchor, args, onHide, context, contextKeyService }: RenderContextMenuOptions): ContextMenuAccess {
const contextMenu = this.menuFactory.createContextMenu(menuPath, args, context, contextKeyService);
protected doRender({ menuPath, anchor, args, onHide, context, contextKeyService, skipSingleRootNode }: RenderContextMenuOptions): ContextMenuAccess {
const contextMenu = this.menuFactory.createContextMenu(menuPath, args, context, contextKeyService, skipSingleRootNode);
const { x, y } = coordinateFromAnchor(anchor);
if (onHide) {
contextMenu.aboutToClose.connect(() => onHide!());
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/browser/menu/browser-menu-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ export class BrowserMainMenuFactory implements MenuWidgetFactory {
}
}

createContextMenu(path: MenuPath, args?: unknown[], context?: HTMLElement, contextKeyService?: ContextMatcher): MenuWidget {
const menuModel = this.menuProvider.getMenu(path);
createContextMenu(path: MenuPath, args?: unknown[], context?: HTMLElement, contextKeyService?: ContextMatcher, skipSingleRootNode?: boolean): MenuWidget {
const menuModel = skipSingleRootNode ? this.menuProvider.removeSingleRootNode(this.menuProvider.getMenu(path), path) : this.menuProvider.getMenu(path);
const menuCommandRegistry = this.createMenuCommandRegistry(menuModel, args).snapshot(path);
const contextMenu = this.createMenuWidget(menuModel, { commands: menuCommandRegistry, context, rootMenuPath: path, contextKeyService });
return contextMenu;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ export class TabBarToolbar extends ReactWidget {
args: [this.current],
anchor,
context: this.current?.node,
onHide: () => toDisposeOnHide.dispose()
onHide: () => toDisposeOnHide.dispose(),
skipSingleRootNode: true,
});
}

Expand Down
36 changes: 36 additions & 0 deletions packages/core/src/common/menu/menu-model-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,42 @@ export class MenuModelRegistry {
return this.findGroup(menuPath);
}

/**
* Checks the given menu model whether it will show a menu with a single submenu.
*
* @param fullMenuModel the menu model to analyze
* @param menuPath the menu's path
* @returns if the menu will show a single submenu this returns a menu that will show the child elements of the submenu,
* otherwise the given `fullMenuModel` is return
*/
removeSingleRootNode(fullMenuModel: MutableCompoundMenuNode, menuPath: MenuPath): CompoundMenuNode {
let menuModel: MenuNode = fullMenuModel;

// first find the menu node(s) under our menu path
const idToSkip = menuPath.length > 0 ? menuPath[menuPath.length - 1] : undefined;
if (idToSkip) {
menuModel = fullMenuModel;
while (menuModel.id === idToSkip) {
if (CompoundMenuNode.is(menuModel) && menuModel.children.length === 1) {
menuModel = menuModel.children[0];
} else {
break;
}
}
}

// inspect the node whether it is a single submenu
if (CompoundMenuNode.is(menuModel) && menuModel.children.length === 1) {
// yes -> only render the submenus children
menuModel = menuModel.children[0];
} else {
// no -> render full menu
menuModel = fullMenuModel;
}

return CompoundMenuNode.is(menuModel) ? menuModel : fullMenuModel;
}

/**
* Returns the {@link MenuPath path} at which a given menu node can be accessed from this registry, if it can be determined.
* Returns `undefined` if the `parent` of any node in the chain is unknown.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ export class ElectronContextMenuRenderer extends BrowserContextMenuRenderer {

protected override doRender(options: RenderContextMenuOptions): ContextMenuAccess {
if (this.useNativeStyle) {
const { menuPath, anchor, args, onHide, context, contextKeyService } = options;
const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args, context, contextKeyService);
const { menuPath, anchor, args, onHide, context, contextKeyService, skipSingleRootNode } = options;
const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args, context, contextKeyService, skipSingleRootNode);
const { x, y } = coordinateFromAnchor(anchor);

const menuHandle = window.electronTheiaCore.popup(menu, x, y, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
return undefined;
}

createElectronContextMenu(menuPath: MenuPath, args?: any[], context?: HTMLElement, contextKeyService?: ContextMatcher): MenuDto[] {
const menuModel = this.menuProvider.getMenu(menuPath);
createElectronContextMenu(menuPath: MenuPath, args?: any[], context?: HTMLElement, contextKeyService?: ContextMatcher, skipSingleRootNode?: boolean): MenuDto[] {
const menuModel = skipSingleRootNode ? this.menuProvider.removeSingleRootNode(this.menuProvider.getMenu(menuPath), menuPath) : this.menuProvider.getMenu(menuPath);
return this.fillMenuTemplate([], menuModel, args, { showDisabled: true, context, rootMenuPath: menuPath, contextKeyService });
}

Expand Down

0 comments on commit 4bc88f0

Please sign in to comment.