命令、菜单和对话框
扩展包可以向 ParametriQ CAD 的窗口添加内容:使用绘图 API 运行、并作为一个步骤撤销的命令,运行这些命令的菜单项和工具栏按钮,命令所要求的表单和图纸中的拾取,以及隐藏了部分应用自带项目的精简工作区。扩展包只是描述这些内容;控件由应用按自己的样式创建,因此应用外观改变时,扩展包仍能继续工作。
扩展包
扩展包是您的 Extensions 文件夹(文件 › 扩展 › 打开扩展文件夹)或应用的 Extensions 文件夹中的一个文件夹,其中包含 manifest.json:
QuickBox/
manifest.json
main.js what it declares
strings/en.json its text in English (es.json, zh-Hans.json for Spanish and Chinese)
icons/quickbox.svg its icons
{
"id": "quickBox",
"name": "Quick box",
"version": "1.0",
"main": "main.js",
"description": "A regular slotted box from three sizes.",
"permissions": ["commands", "menus", "dialogs", "pick", "drawing", "designs"],
"enabled": true
}
| 属性 | 含义 |
|---|---|
id |
其 id:字母、数字、_ 和 -。其命令的 id 应以它开头(quickBox.box)。您的扩展包如果与应用自带的某个扩展包 id 相同,会取代后者。 |
name、version、description、author |
显示在 文件 › 扩展 › 管理扩展… 中。 |
main |
声明其所添加内容的脚本(省略时为 main.js)。 |
permissions |
它可以做的事情(见下文)。它尝试做的其他任何事情都会被拒绝,并显示一条消息,说明所需的权限。 |
enabled |
false:在 管理扩展… 中开启之前,它处于关闭状态(用于特殊设置,例如操作员工作区)。 |
Extensions 文件夹中单独的 .js 文件可以声明后处理器、设计规则、模板、报表和保存扩展,但不能声明命令、菜单或对话框:这些需要扩展包。
权限
| 权限 | 允许它 |
|---|---|
commands |
使用 command({…}) 声明命令。 |
menus |
添加菜单项、子菜单、工具栏按钮和工具栏组。 |
customise |
隐藏和移动应用自带的菜单项、工具栏按钮和组。 |
dialogs |
使用 ui.form、ui.message、ui.confirm 进行询问,以及显示 ui.progress。 |
pick |
使用 ui.pick 要求用户在图纸中拾取。 |
drawing |
从命令中修改图纸(没有此权限时,命令只能读取图纸)。 |
designs |
使用 ui.runDesign 将库中的参数化设计作为新图纸打开。 |
开启和关闭扩展包
文件 › 扩展 › 管理扩展… 列出各扩展包及其使用的权限;分别开启或关闭每个扩展包,然后选择 应用:扩展会被重新读取,窗口立即随之改变。您的选择保存在您 Extensions 文件夹中的 packages.json 里。
字符串
t("key") 按应用当前显示的语言给出扩展包中某个键的文本:西班牙语取自 strings/es.json,中文取自 strings/zh-Hans.json,英语或该语言的表中没有的键取自 strings/en.json。t("count", n) 用键后面的参数填充文本中的 {0}(以及 {1}……)。
{ "boxTitle": "_Quick Box…", "pickCentre": "Click the middle of the hand hole" }
图标
图标是扩展包文件夹中的 SVG 文件,按其路径命名("icons/quickbox.svg"),或者是按名称引用的应用自带图标("tuckflaptool")。请在正方形的 viewBox 中绘制,线条使用 currentColor:应用会像对待自己的图标一样,按浅色或深色主题为其着色。
命令
command({
id: "quickBox.handHole",
title: t("handHoleTitle"), // "_Hand Hole…"
description: t("handHoleDescription"),
icon: "icons/handhole.svg",
shortcut: "Ctrl+Shift+H",
industries: ["Packaging"],
enabledWhen: "drawing",
async run(state) {
const centre = await ui.pick({ kind: "point", prompt: t("pickCentre") });
if (!centre) return; // Esc
circle(centre, 15);
}
});
| 属性 | 含义 |
|---|---|
id |
其 id,在已安装的命令中唯一:菜单项和按钮通过它引用该命令。 |
title |
其标签;_ 放在其访问键之前。 |
description |
显示为其提示。 |
icon |
其图标。 |
shortcut |
快捷键(Ctrl+Shift+B)。应用或其他命令已在使用的快捷键会被省略,并在读取扩展时给出提示。 |
industries |
提供该命令的行业(省略时:所有行业)。只有当图纸属于其中某个行业时(或为通用图纸,或开启了 显示所有工具),才会显示其菜单项和按钮。 |
enabledWhen |
"drawing"(有打开的图纸:默认值)、"selection"(有选中的内容)、"always",或一个函数,该函数获得下面的状态,在命令可以运行时返回 true。 |
run(state) |
命令执行的操作。state 为 {hasDrawing, industry, selected}(selected:所选图元的 id)。 |
run 与模板一样,使用绘图 API(line、newPoint、setVariable、command……)处理当前正在处理的图纸。它所做的一切修改都作为一个步骤撤销(编辑 › 撤销 会显示该命令的名称)。如果出错(出现它未捕获的错误),它所做的修改会被撤回,消息会说明原因,并给出文件和行号。
命令可以通过引用它们的菜单项和按钮、通过其快捷键,以及从 运行命令… 运行。
运行命令…
文件 › 扩展 › 运行命令…(Ctrl+Shift+P)打开命令面板(视图 › 命令面板…,Ctrl+K),通过输入名称的一部分查找任何命令:扩展的命令、当前可以使用的所有菜单项(显示其所在的菜单:文件 › 导出)、工具、设置、最近的图纸和帮助页面。输入的每个词都必须出现在名称或其所在的菜单中;用箭头键选择,按 Enter 运行。
菜单和工具栏
uiExtension({…}) 描述扩展包向菜单和工具栏添加的内容,以及它要隐藏或移动的应用自带内容:
uiExtension({
name: "Quick box menus and toolbar",
menus: [
{ menu: "Tool/Packaging", command: "quickBox.box" },
{ menu: "File/Export", command: "quickBox.export" },
{ menu: "Extensions", submenu: "quickBox", title: "_Quick Box" },
{ menu: "Extensions/quickBox", command: "quickBox.handHole" },
{ menu: "File", separator: true, after: "ExportForPalletSoftware" }
],
toolbar: [
{ group: "Packaging", command: "quickBox.box", after: "CreaseOffset" },
{ group: "quickBox", title: "Quick box", after: "Packaging", industries: ["Packaging"],
commands: ["quickBox.box", "quickBox.handHole"] }
]
});
菜单项
| 属性 | 含义 |
|---|---|
menu |
放置的位置:菜单的路径(File、Extensions、Tool/Packaging)。以某个菜单项结尾的路径将其放在该项之后(File/Export);以某个标题结尾的路径将其放在该标题所在部分的末尾(Tool/Packaging:工具 › 包装工具 中的包装工具)。 |
command |
它运行的命令。 |
submenu、title |
代替命令:一个子菜单,及其 id 和标签。之后的项目通过其路径放入其中(Extensions/quickBox)。 |
separator |
true:一条分隔线,而不是一个菜单项。 |
before、after |
它放在其前面或后面的那个菜单项(位于同一菜单中)的 id。 |
title |
其标签,如果与其命令的标签不同。 |
industries |
仅对这些行业显示(省略时:取其命令的设置;在某个行业的部分中,则为该行业)。 |
工具栏按钮和组
| 属性 | 含义 |
|---|---|
group |
按钮所在组的 id:应用自带的组之一(见下文),或一个新组。 |
command、commands |
要添加其按钮的一个或多个命令,按顺序排列。 |
title |
新组:其名称(显示为其提示)。 |
before、after |
它放在其前面或后面的、组中某个按钮的 id;对于新组,则为某个组的 id。两者都未给出时,新组放在工具栏的末尾。 |
industries |
仅对这些行业显示(新组;否则取其命令的设置)。 |
id
菜单、菜单项、按钮和组都以 id 命名,无论应用以何种语言显示,id 都相同;在路径中用 / 书写:File/Export、Draw/Bezier。第一步不是菜单栏中某个菜单的路径,会在任何位置查找(Bezier:所有贝塞尔曲线按钮;Tool/Packaging:“工具”子菜单中的标题)。Extensions 即 文件 › 扩展。
| 对象 | 其 id | 示例 |
|---|---|---|
| 菜单栏中的菜单 | 其英文名称 | File、Edit、Production、3D、View、Help(工具 位于 编辑 中:Tool 或 Edit/Tool) |
| 菜单项和子菜单 | 其英文名称,去掉空格和标点 | File/NewFromTemplate、File/Export、File/SendToMachine、File/Extensions、Edit/Constrain、Edit/CheckParametric、Tool/Line |
| 菜单项分组所在的子菜单 | 其英文名称;“文件”和“3D”中的 导入 和 导出 为 ImportMenu 和 ExportMenu,“工具”中的 拼版 为 ToolLayout(菜单项使用不带后缀的名称)。指向其中某个菜单项的路径会在子菜单中找到它(File/Export、Tool/Line) |
Tool/Draw、Tool/Modify、Tool/Dimensions、Tool/Insert、Tool/MeasureAndInspect、Tool/ToolLayout、File/ImportMenu、File/ExportMenu、3D/Display、3D/Folding、3D/MeasureAndAnnotate、3D/ModelsAndProducts、3D/ExportMenu |
| 工具 › 行业工具 | IndustryTools;其标题按行业命名 |
Tool/IndustryTools、Tool/Production、Tool/Packaging、Tool/Cutting、Tool/SheetMetal |
| 工具的菜单项或按钮 | 工具的名称 | Line、Fillet、TuckFlap、FlapOrSeam、RegistrationMark |
| 工具栏组 | 其所含内容 | Select、Draw、Modify、Annotate、Insert、Inquiry;在行业工具(IndustryTools)中:Production、Cutting 以及各个行业(Packaging、SheetMetal……) |
共享工具的按钮(FlapOrSeam、Holes、BridgeOrTab……:参见工具)位于其所属各行业的组中:Packaging/FlapOrSeam 是包装组中的那个按钮,FlapOrSeam 则是所有这些按钮。
隐藏和移动应用自带的内容
具有 customise 权限的扩展包可以隐藏菜单项、整个菜单、工具栏按钮和组,也可以移动它们:例如,供只需打开、检查图纸并将其发送到机器的操作员使用。
uiExtension({
name: "Operator workspace",
hide: {
menus: ["File/NewFromTemplate", "File/SendByEmail", "Edit/Constrain", "3D"],
toolbar: ["Draw/Bezier", "Draw/Spline", "Annotate"]
},
move: {
menus: [{ item: "File/SendToMachine", after: "Save" }],
toolbar: [{ item: "Inquiry", before: "Draw" }]
}
});
移动指定项目及其去处:同一菜单或组中某个 id 的 before 或 after,或任何位置的路径。因隐藏内容而留在菜单开头或末尾、或与另一条分隔线相邻的分隔线会被移除。隐藏内容的快捷键仍然有效。应用自带此扩展包(Operator workspace),默认关闭。
访问键
菜单项的访问键是其标题中 _ 后面的字母。如果同一菜单中的另一项已在使用该字母(就其显示的行业而言:在 工具 › 包装工具 中,即包装图纸所显示的那些项),应用会为它分配标题中某个单词的第一个未被占用的首字母,否则分配标题中任意一个未被占用的字母;如果所有字母都已被占用,则保留其自身的访问键,与他项共用。重新加载扩展 会说明它做了哪些更改。
出错时
不存在的 id 或菜单、没有扩展包声明的命令,或已被使用的快捷键,会在读取扩展时给出提示(与无法读取的扩展文件相同),并注明扩展包的名称;它所添加的其余内容仍会被添加。
对话框和拾取
命令的 run 可以用 ui 的函数进行询问。每个函数都返回一个 promise:run 是一个 async 函数,用 await 等待它,而在用户回答期间,应用继续正常工作(绘图、移动视图)。与任何扩展调用一样,命令中两个 await 之间的每一段最多可运行十秒和一百万条语句。
| 函数 | 返回 | 权限 |
|---|---|---|
ui.form({ title, fields, … }) |
按字段 id 给出的值,取消时为 null。 |
dialogs |
ui.pick({ kind, prompt, filter }) |
拾取的内容,取消时(Esc)为 null。 |
pick |
ui.message(text, { title, kind }) |
(关闭时。)kind:"information"、"warning" 或 "error"。 |
dialogs |
ui.confirm(text, { title }) |
选择 是 时为 true。 |
dialogs |
ui.progress({ title, cancellable }) |
一个进度窗口:await p.update(fraction, text) 显示进度,选择 取消 后返回 false;p.cancelled();p.close()(命令结束时无论如何都会关闭)。 |
dialogs |
ui.runDesign(name, values) |
用给出的值将库中的设计作为新图纸打开,与 文件 › 运行参数化 相同:成功时为 true。name:"Packaging/FEFCO 0201 Regular slotted container",如果只有一个设计使用该名称,也可以只用其自身名称;选择项按其文本给出。 |
designs |
它们只能在命令运行期间使用。
表单
const sizes = await ui.form({
title: "Quick box",
description: "The box's inside sizes.",
ok: "Make Box",
fields: [
{ id: "L", label: "Length", type: "length", default: 300, min: 10, max: 2000 },
{ id: "W", label: "Width", type: "length", default: 200, min: 10 },
{ id: "board", label: "Board", type: "choice", choices: ["E flute", "B flute"], default: "B flute" },
{ id: "lid", label: "Lid", type: "check", default: true },
{ id: "at", label: "Corner", type: "point", default: { x: 0, y: 0 } }
],
validate: v => v.W > v.L ? "The width is longer than the length." : null
});
if (!sizes) return;
表单的显示方式与应用的选项对话框相同,每个字段一行。
| 字段属性 | 含义 |
|---|---|
id |
返回其值时所用的名称。 |
label、description |
其所在行显示的文字,以及该行下方的文字。 |
type |
"number"、"integer"、"length"(以图纸的单位表示)、"angle"(度)、"text"、"choice"、"check"(是或否)或 "point"({x, y})。省略时:根据 default 确定(如果有 choices,则为 "choice")。 |
default |
初始值。 |
choices |
选择项的各个选项。 |
min、max |
数字的上下限。 |
unit |
显示在数字之后。 |
required |
true:文本不能留空。 |
表单关闭前,每个值都会按其字段进行检查(数字在上下限之内、为整数、选择项来自其列表、已输入文本),如果表单有 validate(values),再由它检查:返回一条消息(或 false)说明错误所在,表单会连同该消息重新显示。下次显示该表单时会记住这些值(remember: false:每次都从默认值开始)。
拾取
const at = await ui.pick({ kind: "point", prompt: "Click the middle of the hole" });
const edge = await ui.pick({ kind: "element", filter: { kinds: ["LINE", "ARC"], cutting: true } });
const outlines = await ui.pick({ kind: "elements", filter: { closed: true } });
| 类型 | 用户 | 返回 |
|---|---|---|
"point" |
单击一个位置。 | {x, y};如果单击在某个点上,还有 id,这样在其上创建的内容会随之移动。 |
"element" |
单击一个图元。 | 该图元,按 drawingInfo() 的描述(id、kind、layer、length……)。 |
"elements" |
单击多个图元(再次单击:移除),然后右键单击。 | 这些图元的列表。 |
filter 限定会高亮显示并可被拾取的图元:kinds("LINE"、"ARC"、"CIRCLE"……)、layers(其编号)、closed 和 cutting(true 或 false)。提示显示在交互窗口和状态栏中。
等待的工作方式
引擎自己运行 JavaScript 的 promise 和 async 函数。当 run 等待某个 ui 函数时,命令在此暂停,应用显示对话框;应用窗口继续正常工作。用户回答后,命令带着答案从 await 处继续,在应用自己的线程上运行,因此它绝不会与图纸中的其他任何操作同时运行。同一时间只运行一个命令:在它结束之前,无法选择其他命令。从不等待的命令会一次运行完毕,与任何扩展调用相同。
示例:Quick box
应用自带 Quick box 扩展包(位于其 Extensions 文件夹中):Quick Box… 询问盒子的长度、宽度、深度和纸板,并用这些值打开库中的 FEFCO 0201 设计;Hand Hole… 询问一个点和一个尺寸,并在切割线图层上在该处绘制一个圆角长槽,其宽度和高度为变量(HH1W、HH1H),因此保持参数化。两者都位于 工具 › 包装工具 中,以及包装组之后它们自己的工具栏组中,对包装图纸显示。将其文件夹复制到您的文件夹中,为它指定新的 id,然后修改它,即可创建您自己的扩展包。