唯杰地图 logo唯杰地图
VJMAP
EN

菜单与 Ribbon 扩展

vjcad/references/plugin/menu-ribbon.md 8.7 KB243 行
原文

文档:vjcad/doc/plugin/plugin-menu-ribbon.md 示例:vjcad/example/plugin/04pluginmanager.js、vjcad/example/ui/16menucustom.js

1. 默认菜单 ID

ID 名称 说明
file 文件 新建、打开、保存、导出
create 创建 直线、圆、多段线等绘图命令
edit 编辑 移动、复制、旋转等
view 显示 视图控制、显示顺序、图层
insert 插入 块、图像
dim 标注 尺寸标注
property 属性 实体属性
tool 工具 测量、统计、脚本
appearance 外观 界面外观
help 帮助 帮助、关于

2. 默认 Ribbon 标签 / 组

Tab ID Group ID 名称
default(默认) draw / modify / edit / annotation / layer / navigation 绘图、修改、编辑、注释、图层特性、导航
tools(工具) quick-tools / group / script / clip-region / purge / properties / measure / stats / help 快捷工具、组、脚本、裁剪、清理、特性、测量、统计、帮助
insert(插入) block / image / symbol / template / import 块、图像、符号、模板、导入
plugins(插件) plugin-manager 插件管理(组标题为空)
recent(最近命令) recent-commands 最近命令(动态填充,组标题为空)

以上取自 defaultRibbonConfig(vjcad@1.0.16);运行时以 RibbonConfigManager.getConfig().tabs 为准。

3. 三套写法

3.1 插件运行时(PluginContext)

context.addMenu({ id: 'my-tools', label: '我的工具', after: 'tool' });
context.addMenuItem('my-tools', { command: 'TOOL1' });
context.addRibbonTab({ id: 'my', label: '我的', groups: [] }, 'tools');
context.addRibbonGroup('my', {
    id: 'main', label: '主要',
    primaryButtons: [{ icon: 'tool1', cmd: 'TOOL1', prompt: '工具 1', type: 'large' }]
});

3.2 MainView 一次性配置(增量)

new MainView({
    // ...其他 MainViewConfig 字段
    menuBar: {
        removeMenus: ['help', 'appearance'],
        addMenus: [{
            id: 'custom-menu', label: '自定义菜单', after: 'insert',
            items: [
                { type: 'command', command: 'DRAW_STAR' },
                { type: 'separator' },
                { type: 'command', command: 'REGEN' }
            ]
        }],
        modifyMenus: {
            file: {
                removeItems: ['SWITCHWORKSPACE'],
                addItems: [{ type: 'command', command: 'DRAW_STAR', after: 'EXPORTPNG' }]
            }
        }
    },
    ribbon: {
        removeTabs: ['recent'],
        addTabs: [{
            tab: {
                id: 'custom-tab', label: '自定义',
                groups: [{
                    id: 'custom-draw', label: '自定义绘图',
                    primaryButtons: [
                        { icon: 'line', cmd: 'DRAW_STAR', prompt: '五角星', label: '五角星' }
                    ]
                }]
            },
            after: 'default'
        }],
        modifyTabs: {
            default: {
                modifyGroups: {
                    draw: {
                        addPrimaryButtons: [
                            { icon: 'circle', cmd: 'DRAW_STAR', prompt: '五角星',
                              label: '★', after: 'CIRCLE' }
                        ]
                    }
                }
            }
        }
    }
});

完整代码:vjcad/example/ui/16menucustom.js

3.3 MainView 全量替换

new MainView({
    menuBar: {
        menus: [
            { id: 'my-file', label: '文件', items: [
                { type: 'command', command: 'NEW' },
                { type: 'command', command: 'OPEN' },
                { type: 'separator' },
                { type: 'command', command: 'SAVELOCAL', shortcut: 'Ctrl+S' }
            ]},
            { id: 'my-draw', label: '绘图', items: [
                { type: 'command', command: 'LINE' },
                { type: 'command', command: 'CIRCLE' }
            ]}
        ]
    },
    ribbon: {
        config: { tabs: [ /* RibbonConfig 完整定义 */ ] }
    }
});

menus 与 config 二选一;提供它们就 忽略所有默认菜单 / Ribbon。

4. 数据结构

菜单项

type MenuItemDef =
    | { type: 'command';  command: string; label?: string; icon?: string; shortcut?: string; column?: number }
    | { type: 'separator'; column?: number }
    | { type: 'submenu';  label: string; icon?: string; column?: number; children: MenuItemDef[] };

Ribbon 按钮

type RibbonButtonType = 'large' | 'small' | 'icon-only' | 'list';

interface RibbonButtonConfig {
    icon: string;        // 图标 ID(registerIcon 名)
    cmd:  string;        // 命令名
    prompt?: string;     // 工具提示
    label?:  string;     // 紧凑模式显示文本
    type?:   RibbonButtonType;
    items?:  RibbonButtonConfig[];   // type='list' 时下拉子项
}

Ribbon 组

type RibbonGroupDisplayMode = 'large' | 'compact' | 'small-icons' | 'layer' | 'recent';

interface RibbonGroupConfig {
    id: string;
    label: string;
    pinnable?: boolean;
    displayMode?: RibbonGroupDisplayMode;
    primaryButtons: RibbonButtonConfig[];
    moreButtons?: RibbonButtonConfig[];
}

Ribbon 标签

interface RibbonTabConfig {
    id: string;
    label: string;
    groups: RibbonGroupConfig[];
}

5. 实战:完整插件示例(MYQSELECT)

const ICON = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
    <rect x="3" y="3" width="18" height="18" rx="2" stroke-width="2"/>
    <path d="M9 12l2 2 4-4" stroke-width="2"/>
</svg>`;

// 源码写法:按 URL 加载需打包成 IIFE(见 overview §3);直接用这段字符串则走 pm.loadFromContent
export default {
    manifest: { id: 'my-quick-select', name: '我的快速选择', version: '1.0.0' },

    async onActivate(context) {
        context.registerCommand('MYQSELECT', '我的快速选择', MyQuickSelectCommand);

        context.registerIcon('MYQSELECT', ICON);   // 菜单与 Ribbon 共用(键名大小写不敏感)

        context.addMenu({ id: 'plugins', label: '插件', after: 'tool' });
        context.addMenuItem('plugins', { command: 'MYQSELECT' });

        context.addRibbonTab({ id: 'plugins', label: '插件', groups: [] });
        context.addRibbonGroup('plugins', {
            id: 'my-quick-select', label: '我的快速选择', pinnable: true,
            primaryButtons: [{ icon: 'myqselect', cmd: 'MYQSELECT', prompt: '快速选择图元', type: 'large' }]
        });
    },

    async onDeactivate(context) {
        context.removeRibbonGroup('plugins', 'my-quick-select');
        context.removeMenuItem('plugins', 'MYQSELECT');
        context.unregisterCommand('MYQSELECT');
    }
};

6. 命名规范

元素 规则 例
命令名 全大写 DRAWCROSS
图标名 与命令同名;注册表统一转小写,大小写不敏感,注册一次菜单与 Ribbon 共用 DRAWCROSS ≡ drawcross
主菜单 / Ribbon ID kebab-case my-plugin

7. 三种写法对比

维度 PluginContext MainView 增量 MainView 全量
时机 运行时(激活/停用) 启动一次 启动一次
粒度 逐项 批量增量 整体替换
自动清理 是(onDeactivate) 否(生命周期跟随 MainView) 否
适合 第三方插件 应用级定制(删/改默认) 完全自定义

红旗

  • 默认主菜单 / Ribbon 的 ID 写错(如 tools ↔ tool)会让命令藏起来;记牢上面默认表
  • 增量与全量同时写时,全量赢;调试时不要混用
  • addMenu / addRibbonTab 重名是 no-op,不能用于"重置";要替换请先 remove 再 add
  • 图标键名注册与查找都转小写:菜单按命令名找图标、Ribbon 按钮按 icon 找图标,大小写都无所谓,不必为大小写各注册一份
  • 移除按钮时 removeRibbonButton(tab, group, cmd) 用的是 cmd 名,不是 button 的 id
  • 命令名不要与内置命令重名(QSELECT、FINDREPLACE 等已是内置命令):registerCommand 是直接 push、查找按首个匹配,重名会被内置命令遮蔽,且 unregisterCommand 会误删内置项

参考(官方文档 MCP)

  • 文档:vjcad/doc/plugin/plugin-menu-ribbon.md
  • 示例:vjcad/example/plugin/04pluginmanager.js、vjcad/example/ui/16menucustom.js