@tool() デコレーター
クラスを LinkCAD のツールとして登録し、自動生成されるオプションダイアログとともにアプリケーションメニューに表示します。
シグネチャ
@tool( name: str, menu: str, tooltip: str = "", shortcut: str = "", icon: str = "", requires_drawing: bool = True,)class MyTool(Tool): ...パラメーター
| パラメーター | 型 | 既定値 | 説明 |
|---|---|---|---|
name | str | 必須 | メニューでの表示名 |
menu | str | 必須 | メニューパス(サブメニューは / 区切り)。例: "Tools/Analysis" |
tooltip | str | "" | ホバー時に表示されるツールチップ |
shortcut | str | "" | キーボードショートカット(例: "Ctrl+Shift+M") |
icon | str | "" | res/ からの相対アイコンファイル名 |
requires_drawing | bool | True | 図面が読み込まれていないときにツールを無効化するかどうか |
Tool 基底クラス
すべてのツールプラグインは Tool を継承し、run() を実装しなければなりません。
class Tool: def run(self, drawing) -> dict: """Override to implement the tool logic. Return a result dictionary.""" ...
def format_result(self, result: dict) -> str: """Override to control how the result is displayed.""" ...drawing 引数は linkcad.v1.db.Drawing——アプリケーションが所有するライブデータベースなので、決して破棄しないでください。requires_drawing=False の場合は None になることがあります。
run() は結果の辞書を返します。既定の format_result() は result["summary"] があればそれを表示するので、そのキーを含めてください。より充実した表示が必要な場合は format_result() をオーバーライドします。
run() の実行中、フレームワークは読み取りロックを保持しています。変更を取り消し可能にするには Transaction で包んでください。
ToolInfo
デコレーターはクラスに ToolInfo オブジェクトを付与します。
| フィールド | 説明 |
|---|---|
name | ツールの表示名 |
menu | メニューパス |
tooltip | ツールチップのテキスト |
shortcut | キーボードショートカット |
icon | アイコンのファイル名 |
requires_drawing | 図面が必要かどうか |
options | クラスから収集された Option 属性 |
メニューパス
menu パラメーターは、ツールが LinkCAD のメニューのどこに表示されるかを決めます。
"Edit/Analyze" → Edit → Analyze → <tool name>"Tools/Analysis" → Tools → Analysis → <tool name>"Tools/Drawing/Custom" → Tools → Drawing → Custom → <tool name>完全な例
from typing import Any, Dict
from linkcad.v1.plugin import tool, Tool, Option
@tool( name="Shape Counter", menu="Tools/Analysis", tooltip="Count shapes per layer", shortcut="Ctrl+Shift+C", requires_drawing=True,)class ShapeCounter(Tool): closed_only = Option.boolean("Closed shapes only", default=False)
def run(self, drawing) -> Dict[str, Any]: counts: Dict[str, int] = {} for cell in drawing.cells: for shape in cell.shapes: if self.closed_only and not shape.closed: continue layer = shape.layer if layer is not None: counts[layer.name] = counts.get(layer.name, 0) + 1
return { "layers": counts, "summary": f"{sum(counts.values())} shapes on {len(counts)} layers", }
def format_result(self, result: Dict[str, Any]) -> str: lines = [f"{name}: {n}" for name, n in sorted(result["layers"].items())] lines += ["", result["summary"]] return "\n".join(lines)