Developer Notes & Best Practices: JLC EDA Pro Extension Development
July 25, 2026 · View on GitHub
This document serves as a comprehensive technical guide and architecture log for the EASY EDA PCB Beautify project. It documents critical discoveries, optimization strategies, and best practices for building high-performance, idiomatic extensions in the JLC EDA Pro environment.
Background: The eda Global Object
To understand the solution, we must first understand the host environment. The extension operates within a managed runtime provided by JLC EDA Pro.
1. The eda Object as a Singleton
Every extension runtime is injected with a unique and independent eda object in its root scope.
- Isolation: This object is not shared with other extensions, ensuring that properties attached to it do not collide with other installed plugins.
- Ubiquity: This object is accessible globally in both the Main Process (Worker) and the Iframe logic (through the parent scope proxy or direct injection), making it the only guaranteed shared memory reference between these contexts.
2. Standard Usage: The Official API Pattern
According to the official documentation, the extension API module contains many specialized classes. All Classes, Enums, Interfaces, and Type Aliases are registered under the EDA base class and instantiated as the eda object, which exists in the root scope of every extension runtime.
Key Characteristics:
- Isolation: Every extension runtime generates an independent
edaobject not shared with others. - Access Pattern:
eda+Class Instance Name+Method/Variable. - Naming Rule: The system instantiates classes using a specific naming convention: the first three letters before the underscore are lowercased.
| Class Name | Instance Name |
|---|---|
SYS_I18n | sys_I18n |
SYS_ToastMessage | sys_ToastMessage |
// Example: Calling SYS_I18n.text and SYS_ToastMessage.showMessage
// Note strictly lowercase 'sys' prefix
eda.sys_ToastMessage.showMessage(eda.sys_I18n.text('Done'), ESYS_ToastMessageType.INFO);
Because of property #1 (Isolation), we can repurpose this object to store our own global state, solving the isolation problem described below.
The Problem: Module-Level Variable Isolation
When developing extensions that share state between the worker logic and the settings UI (iframe), you might encounter situations where updates in one context are not reflected in the other, even if you are accessing what seems to be the same "File" or "API".
Scenario
- Main Process (
src/lib/*.ts): Updates a module-level variable (e.g.,let globalCache = [...]). - Iframe UI (
iframe/settings.html): Calls a function exposed by the main process (viaeda.extension_api...) that tries to read that variable. - Result: The Iframe sees an stale or empty version of the variable, while the Main Process sees the updated one.
Cause
In the Javascript environment of EasyEDA Pro extensions:
- The
src/code bundles into a worker script. - The
iframe/settings.htmlruns in a separate browser context (an iframe). - While the
edaglobal object facilitates communication, Module Scoped Variables (declared withlet,constat the top level of a file) may be instantiated separately for different contexts or re-evaluated in ways that break reference equality.
The Solution: Global Object Anchoring
To ensure that both the Main Process and the Iframe logic access the exact same memory reference for shared state (like a cache), you must anchor that state to the globally shared eda object.
Implementation
Instead of:
// src/lib/state.ts
let myCache: any[] = []; // Risky: May be isolated per context
export function updateCache(data: any) {
myCache = data;
}
export function getCache() {
return myCache;
}
Use:
// src/lib/state.ts
const CACHE_KEY = '_unique_extension_id_cache';
export function updateCache(data: any) {
// Safe: Anchored to the single source of truth 'eda'
(eda as any)[CACHE_KEY] = data;
}
export function getCache() {
return (eda as any)[CACHE_KEY] || [];
}
Best Practices
- Unique Keys: Always use a unique prefix (e.g.,
_jlc_beautify_...) to avoid collisions with other extensions or system properties. - Callbacks: This applies to callbacks as well. If you need the Main Process to trigger a UI update inside the Iframe, register the callback on the
edaobject rather than a local variable. - Cleanup: Be mindful of cleaning up large objects if the extension is unloaded (though rare for this type of extension).
Case Study: Snapshot Feature
In the Easy EDA PCB Beautify extension, we encountered this with the Snapshot list.
- Symptom: Snapshots created automatically by the router were not appearing in the Settings UI list, despite the UI polling for updates.
- Fix: We moved
globalSnapshotsCachefrom a file-level variable insnapshot.tstoeda._jlc_beautify_snapshots_cache. The UI and the Main Process now read/write to the exact same array reference in memory.
Iframe Resource Inlining
When using sys_IFrame.openIFrame, external CSS (<link href="...">) and JS (<script src="...">) files referenced in the HTML may fail to load in the extension environment.
Recommendation: Always inline your CSS and JavaScript directly into the HTML file using <style> and <script> blocks to ensure the UI renders correctly.
DRC API Data Structure & Filtering
API Call
const issues = await eda.pcb_Drc.check(false, false, true);
// check(false, false, true) → returns Promise<Array<any>>
Three-Level Nesting Structure
The returned array contains Category objects, each containing Sub-category groups, each containing individual Issue items:
Level 1 — Category
│ name: "Clearance Error"
│ count: 14
│ title: ["Clearance Error", "(14)"]
│ visible: true
│ list: [...]
│
├── Level 2 — Sub-category
│ │ name: "SMD Pad to Track" ← Non-copper-pour
│ │ count: 2
│ │ title: ["SMD Pad", "to", "Track", "(2)"]
│ │ visible: true
│ │ list: [...]
│ │
│ └── Level 3 — Individual Issue
│ │ visible: true
│ │ errorType: "Clearance Error"
│ │ errorObjType: "SMD Pad to Track" ← Key field for filtering
│ │ ruleName: "copperThickness1oz" ← NOT copper-pour related!
│ │ ruleTypeName: "Safe Spacing"
│ │ layer: "Bottom Layer"
│ │ globalIndex: "err1783"
│ │ objs: ["8b3156fa...", "5d20f23f..."] ← Violated object IDs
│ │ pos: { x, y }
│ │ parentId: "DRCTab|_|Errors|_|Clearance Error|_|SMD Pad to Track"
│ │
│ │ obj1: { typeName: "Track", suffix: "(VBAT_SW): e936" }
│ │ obj2: { typeName: "SMD Pad", suffix: "(GND): C5_1" }
│ │
│ └─ explanation:
│ str: "{obj1} to {obj2} distance is {minDistance}, should be {shouldBe}"
│ param: { minDistance: "5.5mil", shouldBe: ">= 6mil", type: "ClearanceError" }
│ errData:
│ globalIndex: "err1783"
│ name: "copperThickness1oz"
│ obj1: "8b3156fa..." ← Object 1 ID
│ obj1Type: "Track" ← Object 1 type
│ obj2: "5d20f23f..." ← Object 2 ID
│ obj2Type: "SMD Pad" ← Object 2 type
│ minDistance: 0.548 (unit: 10mil, i.e. mm/0.0254/10)
│ clearance: 0.598
│ errorType: "Safe Spacing"
│ layerIds: [2]
│ position: { x, y }
│
├── Level 2 — Sub-category (Copper Pour)
│ │ name: "Copper Region(Filled) to Track" ← Copper-pour related
│ │ count: 11
│ │ list: [...]
│ │
│ └── Level 3 — Individual Issue
│ errorObjType: "Copper Region(Filled) to Track"
│ obj1: { typeName: "Copper Region(Filled)", suffix: "(GND): e15e1" }
│ obj2: { typeName: "Track", suffix: "(VBAT_SW): e936" }
│ errData.obj1Type: "Copper Region(Filled)"
│ ...
Copper Pour Filtering Strategy
Goal: Filter out copper-pour-related DRC issues (they auto-resolve after re-pouring) while keeping real violations.
Pitfall: The ruleName field is "copperThickness1oz" for ALL clearance errors (it's the rule name, not the object type). Matching the word "copper" broadly will incorrectly filter out real violations like "SMD Pad to Track" and "Track to Via".
Correct approach — Match on object type fields only:
| Field | Copper-pour issue | Real violation |
|---|---|---|
errorObjType | "Copper Region(Filled) to Track" | "SMD Pad to Track" |
name (sub-category) | "Copper Region(Filled) to Track" | "Track to Via" |
obj1.typeName | "Copper Region(Filled)" | "Track" |
obj2.typeName | "Track" | "SMD Pad" / "Via" |
errData.obj1Type | "Copper Region(Filled)" | "Track" |
errData.obj2Type | "Track" | "SMD Pad" / "Via" |
Keywords: "Copper Region" (matches "Copper Region(Filled)") plus Chinese equivalents 铜皮/覆铜/铺铜/灌铜/铜区/敷铜 for locale safety.
Filtering is applied at Level 2 (sub-category) and Level 3 (individual issue). If all issues in a sub-category are filtered, the sub-category itself is removed. If all sub-categories in a category are filtered, the category is removed.
Extracting Violated Object IDs
For DRC-based auto-rollback, we extract object IDs from the remaining (non-copper-pour) issues:
- Primary:
issue.objs[]— array of string IDs directly - Secondary:
issue.explanation.errData.obj1/.obj2— redundant but useful as fallback - Recursive: Walk
list[]arrays at each nesting level
These IDs are matched against the primitives being modified to determine which corners need radius reduction.
DRC Repair Convergence
- Treat
drcRetryCountas the maximum number of actual geometry adjustments. Run one additional DRC check after the last adjustment to verify convergence. - Medium and large boards can reveal violations in batches after earlier corners are repaired, so the production default is
60adjustment rounds and the settings UI allows1to100. - A Line and Arc generated for the same corner can both appear in one DRC result. Deduplicate by path and corner so each corner advances at most once per round.
- Do not redraw a path when every matched corner is already straight or otherwise unchanged. Stop early instead of consuming more rounds.
- A failed DRC API call is not a pass. Report that convergence could not be confirmed, and distinguish it from a valid check with zero remaining violations.
Copper Pour Rebuild API
Discovery
The IPCB_PrimitivePour class has a method rebuildCopperRegion() for rebuilding the filled copper region associated with a pour boundary.
As of @jlceda/pro-api-types@0.3.4, this method is present in the official type declarations as a @beta API:
interface IPCB_PrimitivePour {
getCopperRegion: () => Promise<IPCB_PrimitivePoured | undefined>;
rebuildCopperRegion: () => Promise<IPCB_PrimitivePoured | undefined>;
}
Older host/type combinations may still expose it only at runtime, so code that needs to support older environments should continue to guard the call.
Verification
// List all methods on a pour object
const pours = eda.pcb_PrimitivePour.getAll();
console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(pours[0])));
// → ["constructor", "rebuildCopperRegion", "getCopperRegion", "convertToFill",
// "convertToPolyline", "convertToRegion", "done", "reset", ...]
// Execute rebuild
pours[0].rebuildCopperRegion();
// Console output: "worker completed pour calculation, thermal generation, 0.282s"
Usage in Code
With current type declarations, the direct call is typed. For older SDK versions, keep a small runtime guard when compatibility matters:
export async function rebuildAllCopperPours(): Promise<number> {
const pours = eda.pcb_PrimitivePour.getAll();
if (!pours || pours.length === 0)
return 0;
for (const pour of pours) {
if (typeof pour.rebuildCopperRegion === 'function')
await pour.rebuildCopperRegion();
}
return pours.length;
}
Architecture
The feature uses a two-layer design:
rebuildAllCopperPours()— Pure execution: iterates all pours, callsrebuildCopperRegion(), returns count (0 = no pours, -1 = error).rebuildAllCopperPoursIfEnabled()— Settings-aware wrapper: readsrebuildCopperPourAfterBeautify, reuses or runs DRC to rebuild only affected layers, and falls back to all pours only if smart detection fails. Returns -2 if disabled.rebuildAllCopperPoursAfterRestoreIfEnabled()— Restore-specific wrapper: respects the same setting but rebuilds every pour because the pre-rebuild filled copper is stale after routing restoration and cannot safely drive smart DRC selection.
Selected and All beautify/width-transition entry points call the smart wrapper, then run one final DRC after all post-processing. Snapshot restore calls only the restore-specific copper wrapper after geometry verification; undo reuses the same restore path.
Notes
- The method triggers an asynchronous pour calculation in the EDA worker. The canvas updates after the worker completes.
- Each pour is rebuilt independently. For boards with many copper zones, this may take noticeable time.
- The API is marked
@beta, so host behavior and performance should still be checked after EDA updates. - Automatic per-pour rebuilding is intentionally capped by the user setting
copperPourRebuildLimit(default30) becauserebuildCopperRegion()recalculates regions one at a time. When the affected count exceeds the limit, preserve responsiveness and prompt the user to run the host's full-boardShift + Bcommand manually. - After a beautify or width-transition operation completes successfully, run one final global DRC check when DRC is enabled. The check belongs to operation finalization, not the copper helper: it must run after copper post-processing even when rebuilding is disabled, skipped, or unnecessary.
Snapshot Operation Boundaries
- Store
restoreStrategy: 'incremental'on Selected-operation Before snapshots andrestoreStrategy: 'full'on All-operation Before snapshots. - Snapshot geometry deduplication must not reuse an explicit Before snapshot across different operation names or restore strategies. Geometrically identical
Beautify (All) BeforeandBeautify (Selected) Beforestates are different undo boundaries. - Selected-operation Before snapshots use state-diff restore. All-operation Before snapshots, manual snapshots, and the automatic Before/After safety snapshots created around a manual restore use authoritative full restore and may accept only verified host-normalized geometric equivalence.
- Full restore must repeatedly enumerate and delete every live Line and Arc until both APIs report a stable empty board before recreating the target snapshot. Do not rely only on IDs captured before deletion because the host may reassign or expose primitives during mutation.
- Full-restore verification may accept an Arc count change only when bidirectional coverage proves the target and actual arcs occupy the same circles and angular intervals with matching net, layer, and width. Host splitting/merging is normalization; uncovered extra arcs remain a hard failure.
- After any successful snapshot restore, rebuild every copper pour when automatic rebuilding is enabled. This applies to both manual restore and undo because undo delegates to
restoreSnapshot().
Experimental Mutation Acceleration
@jlceda/pro-api-types 0.3.11 exposes PCB_Document.stopCanvasUpdateCalculation(), startCanvasUpdateCalculation(), getCanvasUpdateCalculationStatus(), and triggerCanvasUpdateCalculation() as Alpha APIs. It also exposes PCB_PrimitivePour.rebuildCopperRegions() for rebuilding multiple or all copper regions in one call. The current host also exposes the ratline calculation status/start/stop APIs. Canvas suspension remains implemented but is hard-disabled by ENABLE_EXPERIMENTAL_CANVAS_SUSPENSION = false until it has been validated in the host.
Production safety rules:
- Keep the experiment behind the default-on
experimentalFastRestoresetting so users can still disable it. Alpha APIs may be unavailable to a production extension even when present in the type package. - Detect every required method at runtime. Unsupported or failed optional calls must fall back to the normal restore path rather than fail the geometry restore.
- Read the current ratline status before stopping it, and restart it only when this extension actually stopped it.
- Resume ratline calculation from
finally, including when deletion, creation, or verification throws. Keep the equivalent canvas resume path intact while canvas suspension is hard-disabled. - Beautify suspends ratline calculation only after the Before snapshot and path analysis. Keep deletion, initial redraw, DRC repair redraws, and output verification inside the guard; resume before the After snapshot, copper post-processing, final DRC, or rollback.
getAllPrimitiveId()may accelerate deletion-loop enumeration, but a stable-empty decision must still be confirmed with fullgetAll()reads.- Restore may try
PCB_PrimitivePour.rebuildCopperRegions()once after geometry verification. Keep the existing per-pourrebuildCopperRegion()loop as the runtime fallback and preserve the configured copper-region count limit. - Restore and undo must run one final DRC check after copper rebuilding and before the After snapshot or completion toast. Show a progress toast when this final check starts. A failed check or remaining violations must produce a terminal warning instead of a success message.
- Do not use
PCB_Document.clearRouting('all')for snapshot restore. It can clear routing objects outside the Line/Arc snapshot model, including vias. - The experiment changes only calculation scheduling and ID enumeration. Full restore still clears all Line/Arc primitives, confirms a stable empty board, recreates the target, and performs the same geometry verification.
Field Performance Evidence
- Board: a copy of the Sipeed Lushan Pi Lite K230D CanMV development board project (“立创·庐山派 Lite-K230D-CanMV 开发板”).
- Host: JLCEDA Pro
V3.2.148. - Scale: approximately
5276–5278Line primitives; the beautified state contained approximately2258–2303Arc primitives. - Comparable full restore direction, from roughly 2300 arcs to 4 arcs:
- Alpha enabled: mutation plus verification
13.0s, copper7.2s, After snapshot0.2s, total20.3s. - Alpha disabled: mutation plus verification
21.9s, copper7.0s, After snapshot0.2s, total29.2s.
- Alpha enabled: mutation plus verification
- The measured total reduction was approximately
30%; Line creation fell from about17.4sto9.2s. Ratline suspension and fast ID enumeration were enabled together, so the data does not isolate either API's individual contribution. - Beautify was also observed at
85.1sversus31.7s, but DRC convergence changed from 29 rounds to 8 rounds. Treat that as an operational observation, not a controlled benchmark.
Copper Pour ID Spaces: Three Non-Overlapping Systems
Discovery (2026-02-12)
When implementing smart copper pour rebuild (only repouring DRC-violated regions instead of all 78 pours), we spent significant debugging time trying to match DRC-reported IDs to pcb_PrimitivePour objects. The root cause: the EDA runtime maintains three completely independent ID namespaces for copper-related objects, and none of them overlap.
The Three ID Spaces
| # | Object Type | API / Source | Example ID | Description |
|---|---|---|---|---|
| 1 | Pour boundary | eda.pcb_PrimitivePour | 2316cffa0d9f91e4 | User-drawn copper pour outline. This is what rebuildCopperRegion() operates on. |
| 2 | Poured fill | eda.pcb_PrimitivePoured | df0d4325623cd52b | Generated fill polygons created by the pour engine. Regenerated on every rebuild. |
| 3 | DRC internal | eda.pcb_Drc.check() → errData.obj1/obj2 | 296cf192d9a8e1b5 | Internal "Copper Region(Filled)" references used only within DRC error reporting. |
Diagnostic Evidence
DRC IDs (Sample): 296cf192d9a8e1b5, 7150c4091f757010, 94a2eea540594e9f
Pour IDs (Sample): 2316cffa0d9f91e4, 6ed988d76a53f6fe, ce5d6f2a975bc84c
Poured IDs (Sample): df0d4325623cd52b, 05f30e00070409b1, 3b54e96ec0519aaa
Zero intersection between any two sets across 78 pour objects and 64 DRC violations.
Additional Findings on pcb_PrimitivePoured
- The
pourPrimitiveIdfield exists on Poured objects but points to its ownprimitiveId, not to the parent Pour boundary. It is effectively a self-reference. parentPrimitiveIdisundefinedat runtime.getState_Net()andgetState_Layer()both returnundefined(the object has no net/layer accessors).- Direct property access (
.net,.layer) also returnsundefined.
This means Poured objects cannot be used as a bridge between DRC IDs and Pour IDs — they carry no usable linkage information.
Solution: Layer-Based Filtering
Since ID matching is impossible, we use layer IDs from the DRC error data as the matching dimension:
errData.layerIds: number[]— available on every DRC issue, contains the physical layer numbers where the violation occurs.pour.getState_Layer(): number— returns the layer ID of each Pour boundary.
Algorithm:
DRC issues → extract violated layer IDs → filter Pour objects by layer → rebuildCopperRegion() only on matching pours
This reduces rebuild scope from all pours to only those on affected layers (e.g., 30/78 instead of 78/78 on a typical multi-layer board).
Lesson
When working with EDA Pro's internal object model, never assume IDs from different API endpoints share the same namespace. Always verify with diagnostic logging before building ID-based matching logic.
PCB_PrimitiveLine.modify() Is Not Reliable In-Place Mutation
Runtime Discovery (2026-07-18, Host V3.2.148)
Do not treat eda.pcb_PrimitiveLine.modify() as an in-place replacement merely because of its API name or type declaration. In the tested host, using it to update rounded-track endpoints left the original Lines on the board while new output primitives were also present:
Before: 987 Lines, 12 Arcs
After: 1988 Lines, 523 Arcs
The canvas visibly showed the original sharp tracks underneath the new rounded tracks. Some calls returned results and others fell back to creation, but the key production conclusion is the same: the old primitive ID cannot be assumed to have been replaced or removed.
Required Production Pattern
- Calculate all output geometry before mutating the board.
- Batch-delete the exact original Line IDs.
- Create the replacement Line and Arc primitives with bounded concurrency.
- During DRC repair, track and delete created Line IDs and Arc IDs through their respective APIs; do not send a mixed ID list to both delete APIs.
- After drawing, verify that none of the original Line IDs remain and that the Line count does not exceed the calculated upper bound. A lower count can be legitimate because the host may normalize or coalesce geometry, so count equality alone must not trigger rollback.
- If deletion, creation, or verification fails, restore the pre-operation snapshot.
Lesson
For beta mutation APIs, validate runtime identity and post-operation object counts on the target host version. Never infer in-place semantics from a method name or TypeScript signature.
Architectural Pattern: Manifest-Driven UI
In later stages of development, we moved away from procedural UI management to a Manifest-Driven approach.
- Centralized Definition: The
extension.json(Manifest) is the single source of truth for the menu structure (headerMenus). - Elimination of Redundancy: Functions like
updateHeaderMenus()that manually injected or updated menu items were removed. - Auto-Mapping: The SDK automatically maps
registerFnin the manifest toexportfunctions in the entry file (index.ts). - Benefits: This significantly reduces code complexity, eliminates "flashing" UI during registration, and ensures better compatibility with the host application's lifecycle.
Shortcut Key Management
Critical Discovery: Key Name Case Sensitivity (2026-02-13)
The TSYS_ShortcutKeys type definition declares all keys in uppercase ('SHIFT', 'CONTROL', 'ALT', 'Q', 'F9', etc.). However, the EDA runtime is case-sensitive and requires a specific mixed-case format for shortcuts to actually trigger:
| Key Type | Type Definition | Runtime Requirement | Example |
|---|---|---|---|
| Modifier keys | 'SHIFT', 'CONTROL', 'ALT' | Title Case | 'Shift', 'Ctrl', 'Alt' |
| Letter keys | 'Q', 'W', 'Z' | Uppercase | 'Q', 'W', 'Z' |
| F-keys | 'F1' – 'F20' | Uppercase | 'F9', 'F6' |
| Special keys | 'SPACE', 'TAB', 'UP' | Uppercase | 'SPACE', 'TAB', 'UP' |
Symptom: registerShortcutKey() returns true (success) regardless of case, but callbacks registered with all-uppercase modifier keys ('SHIFT', 'CONTROL') never fire when the shortcut is pressed.
Test Evidence:
| Registration Format | Triggers? |
|---|---|
['Shift', 'Q'] | Yes |
['SHIFT', 'Q'] | No (registers OK, never fires) |
['Ctrl', 'Shift', 'Q'] | Yes |
['CONTROL', 'SHIFT', 'Q'] | No |
['F9'] | Yes (no modifier, already uppercase) |
['Shift', 'F6'] | Yes |
['SHIFT', 'F5'] | No |
Important: The modifier key Ctrl must be spelled 'Ctrl', NOT 'Control'. The type definition says 'CONTROL' but the runtime recognizes 'Ctrl'.
Fix: The normalizeKeyToken() function in shortcuts.ts must output Title Case for modifiers (Ctrl, Shift, Alt, Cmd, Win) and uppercase for everything else. The frontend settings.html already saves keys in the correct format via toFriendlyKey().
Conflict Detection
Before registering shortcuts, we use eda.sys_ShortcutKey.getShortcutKeys(true) to pull the complete list of existing bindings (including user-defined and system-defaults).
- Implementation: We sort the key arrays and join them with
+to perform a normalized string match against our targets. - Protection: If a conflict is detected, we log a warning and skip our registration rather than overriding host/user keys.
Documentation Alignment: TSYS_ShortcutKeys
Our shortcut registration logic follows the TSYS_ShortcutKeys definition. The source checkout archives that reference under EDA_EX_DOC/JLC_EDA_API/; it is intentionally excluded from the packaged extension.
- Supported Keys ONLY: The settings UI (
settings.html) filters out keys NOT found in theTSYS_ShortcutKeystype (e.g.,Escape,Enter,Delete,Backspaceare forbidden for registry). - Modifier Mapping (runtime format, NOT type-definition format):
CONTROL/CTRL→CtrlSHIFT→ShiftALT→AltCOMMAND/CMD→Cmd(macOS)WIN/META/SUPER→Win(Windows/Linux)
- Frontend-Backend Consistency: Both
settings.html(toFriendlyKey()) andshortcuts.ts(normalizeKeyToken()) must produce the same output format. The frontend saves keys directly in the runtime-compatible format.
Common EDA Shortcuts
To match user muscle memory from other EDA tools, we register the following by default (if free):
| Shortcut | Action |
|---|---|
F6 | Beautify Selected |
F9 | Beautify All |
Ctrl + Shift + Z | Undo Operation |
Host V3.2.148 can report Q-based extension shortcuts as registered while consuming them before the extension callback. Use the verified F-key defaults above; migrate only the exact legacy Q defaults and preserve user-customized bindings.
The same host cannot reliably dispatch both a base key and its modifier superset (for example
F9andShift + F9) to two extension callbacks. Treat such pairs as conflicts and use different base keys.Host V3.2.148 also reports
Shift + F-keybindings as registered without dispatching their callbacks, even when both left and right Shift are tested. Do not use Shift+F combinations for extension defaults; flag them as unsupported.
Registration Context
- DocumentType:
[4](PCB) - Ensures keys only trigger in the layout editor. - Scene:
[1, 2, 3, 4, 5, 6](All editor scenes) - Allows keys to work during all editing modes including selection, drawing, and placement.
Multi-language Support (I18n)
Automatic Translation Mechanism
嘉立创 EDA Pro SDK 提供了自动翻译机制。只需在仓库 locales/ 目录下创建对应的语言文件(如 zh-Hans.json, en.json),SDK 会在渲染 UI 时自动执行翻译。
- 适用范围:
headerMenus的title、sys_ShortcutKey注册时的title等。 - 最佳实践:
- 直接使用 Key:代码中直接书写中文或英文原文作为 Key,无需手动调用
eda.sys_I18n.text()。 - 无代码介入:移除
index.ts中所有用于手动翻译的代码。 - 简化代码:移除冗余的翻译,完全依赖
.json配置文件。 - 回退语言:确保包含
zh-Hans.json作为主语言定义。
- 直接使用 Key:代码中直接书写中文或英文原文作为 Key,无需手动调用
Created: 2026-01-31 Updated: 2026-07-25