123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
- // SPDX-License-Identifier: Apache-2.0
- // SPDX-License-Identifier: MIT
- import {
- IconMenuItemOptions,
- PredefinedMenuItemOptions,
- CheckMenuItemOptions
- } from '../menu'
- import { MenuItem, type MenuItemOptions } from './menuItem'
- import { CheckMenuItem } from './checkMenuItem'
- import { IconMenuItem } from './iconMenuItem'
- import { PredefinedMenuItem } from './predefinedMenuItem'
- import { invoke } from '../core'
- import { type LogicalPosition, PhysicalPosition, type Window } from '../window'
- import { type ItemKind, MenuItemBase, newMenu } from './base'
- import { type MenuOptions } from './menu'
- function itemFromKind([rid, id, kind]: [number, string, ItemKind]):
- | Submenu
- | MenuItem
- | PredefinedMenuItem
- | CheckMenuItem
- | IconMenuItem {
- /* eslint-disable @typescript-eslint/no-unsafe-return */
- switch (kind) {
- case 'Submenu':
- // @ts-expect-error constructor is protected for external usage only, safe for us to use
- return new Submenu(rid, id)
- case 'Predefined':
- // @ts-expect-error constructor is protected for external usage only, safe for us to use
- return new PredefinedMenuItem(rid, id)
- case 'Check':
- // @ts-expect-error constructor is protected for external usage only, safe for us to use
- return new CheckMenuItem(rid, id)
- case 'Icon':
- // @ts-expect-error constructor is protected for external usage only, safe for us to use
- return new IconMenuItem(rid, id)
- case 'MenuItem':
- default:
- // @ts-expect-error constructor is protected for external usage only, safe for us to use
- return new MenuItem(rid, id)
- }
- /* eslint-enable @typescript-eslint/no-unsafe-return */
- }
- export type SubmenuOptions = Omit<MenuItemOptions, 'accelerator' | 'action'> &
- MenuOptions
- /** A type that is a submenu inside a {@linkcode Menu} or {@linkcode Submenu}. */
- export class Submenu extends MenuItemBase {
- /** @ignore */
- protected constructor(rid: number, id: string) {
- super(rid, id, 'Submenu')
- }
- /** Create a new submenu. */
- static async new(opts: SubmenuOptions): Promise<Submenu> {
- return newMenu('Submenu', opts).then(([rid, id]) => new Submenu(rid, id))
- }
- /** Returns the text of this submenu. */
- async text(): Promise<string> {
- return invoke('plugin:menu|text', { rid: this.rid, kind: this.kind })
- }
- /** Sets the text for this submenu. */
- async setText(text: string): Promise<void> {
- return invoke('plugin:menu|set_text', {
- rid: this.rid,
- kind: this.kind,
- text
- })
- }
- /** Returns whether this submenu is enabled or not. */
- async isEnabled(): Promise<boolean> {
- return invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind })
- }
- /** Sets whether this submenu is enabled or not. */
- async setEnabled(enabled: boolean): Promise<void> {
- return invoke('plugin:menu|set_enabled', {
- rid: this.rid,
- kind: this.kind,
- enabled
- })
- }
- /**
- * Add a menu item to the end of this submenu.
- *
- * ## Platform-spcific:
- *
- * - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
- */
- async append<
- T extends
- | Submenu
- | MenuItem
- | PredefinedMenuItem
- | CheckMenuItem
- | IconMenuItem
- | MenuItemOptions
- | SubmenuOptions
- | IconMenuItemOptions
- | PredefinedMenuItemOptions
- | CheckMenuItemOptions
- >(items: T | T[]): Promise<void> {
- return invoke('plugin:menu|append', {
- rid: this.rid,
- kind: this.kind,
- items: (Array.isArray(items) ? items : [items]).map((i) =>
- 'rid' in i ? [i.rid, i.kind] : i
- )
- })
- }
- /**
- * Add a menu item to the beginning of this submenu.
- *
- * ## Platform-spcific:
- *
- * - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
- */
- async prepend<
- T extends
- | Submenu
- | MenuItem
- | PredefinedMenuItem
- | CheckMenuItem
- | IconMenuItem
- | MenuItemOptions
- | SubmenuOptions
- | IconMenuItemOptions
- | PredefinedMenuItemOptions
- | CheckMenuItemOptions
- >(items: T | T[]): Promise<void> {
- return invoke('plugin:menu|prepend', {
- rid: this.rid,
- kind: this.kind,
- items: (Array.isArray(items) ? items : [items]).map((i) =>
- 'rid' in i ? [i.rid, i.kind] : i
- )
- })
- }
- /**
- * Add a menu item to the specified position in this submenu.
- *
- * ## Platform-spcific:
- *
- * - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
- */
- async insert<
- T extends
- | Submenu
- | MenuItem
- | PredefinedMenuItem
- | CheckMenuItem
- | IconMenuItem
- | MenuItemOptions
- | SubmenuOptions
- | IconMenuItemOptions
- | PredefinedMenuItemOptions
- | CheckMenuItemOptions
- >(items: T | T[], position: number): Promise<void> {
- return invoke('plugin:menu|insert', {
- rid: this.rid,
- kind: this.kind,
- items: (Array.isArray(items) ? items : [items]).map((i) =>
- 'rid' in i ? [i.rid, i.kind] : i
- ),
- position
- })
- }
- /** Remove a menu item from this submenu. */
- async remove(
- item: Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem
- ): Promise<void> {
- return invoke('plugin:menu|remove', {
- rid: this.rid,
- kind: this.kind,
- item: [item.rid, item.kind]
- })
- }
- /** Remove a menu item from this submenu at the specified position. */
- async removeAt(
- position: number
- ): Promise<
- | Submenu
- | MenuItem
- | PredefinedMenuItem
- | CheckMenuItem
- | IconMenuItem
- | null
- > {
- return invoke<[number, string, ItemKind]>('plugin:menu|remove_at', {
- rid: this.rid,
- kind: this.kind,
- position
- }).then(itemFromKind)
- }
- /** Returns a list of menu items that has been added to this submenu. */
- async items(): Promise<
- Array<
- Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem
- >
- > {
- return invoke<Array<[number, string, ItemKind]>>('plugin:menu|items', {
- rid: this.rid,
- kind: this.kind
- }).then((i) => i.map(itemFromKind))
- }
- /** Retrieves the menu item matching the given identifier. */
- async get(
- id: string
- ): Promise<
- | Submenu
- | MenuItem
- | PredefinedMenuItem
- | CheckMenuItem
- | IconMenuItem
- | null
- > {
- return invoke<[number, string, ItemKind] | null>('plugin:menu|get', {
- rid: this.rid,
- kind: this.kind,
- id
- }).then((r) => (r ? itemFromKind(r) : null))
- }
- /**
- * Popup this submenu as a context menu on the specified window.
- *
- * If the position, is provided, it is relative to the window's top-left corner.
- */
- async popup(
- at?: PhysicalPosition | LogicalPosition,
- window?: Window
- ): Promise<void> {
- let atValue = null
- if (at) {
- atValue = {} as Record<string, unknown>
- atValue[`${at instanceof PhysicalPosition ? 'Physical' : 'Logical'}`] = {
- x: at.x,
- y: at.y
- }
- }
- return invoke('plugin:menu|popup', {
- rid: this.rid,
- kind: this.kind,
- window: window?.label ?? null,
- at: atValue
- })
- }
- /**
- * Set this submenu as the Window menu for the application on macOS.
- *
- * This will cause macOS to automatically add window-switching items and
- * certain other items to the menu.
- *
- * #### Platform-specific:
- *
- * - **Windows / Linux**: Unsupported.
- */
- async setAsWindowsMenuForNSApp(): Promise<void> {
- return invoke('plugin:menu|set_as_windows_menu_for_nsapp', {
- rid: this.rid
- })
- }
- /**
- * Set this submenu as the Help menu for the application on macOS.
- *
- * This will cause macOS to automatically add a search box to the menu.
- *
- * If no menu is set as the Help menu, macOS will automatically use any menu
- * which has a title matching the localized word "Help".
- *
- * #### Platform-specific:
- *
- * - **Windows / Linux**: Unsupported.
- */
- async setAsHelpMenuForNSApp(): Promise<void> {
- return invoke('plugin:menu|set_as_help_menu_for_nsapp', {
- rid: this.rid
- })
- }
- }
|