Skip to content

Writing a Tool Plugin

This tutorial shows how to create a Python tool that appears in LinkCAD's menu system with an auto-generated options dialog.

The Tool Framework

A tool plugin consists of:

  1. A class decorated with @tool() that extends Tool
  2. Option class attributes that define the UI dialog
  3. A run() method that implements the logic

Example: Layer Statistics

Create a file layer_stats.py in your plugins directory:

from linkcad.plugin import tool, Tool, Option

@tool(
    name="Layer Statistics",
    menu="Tools/Analysis",
    tooltip="Show shape count per layer",
)
class LayerStats(Tool):
    include_empty = Option.boolean(
        "Include empty layers",
        default=False,
        tooltip="Show layers with zero shapes",
    )

    def run(self, drawing) -> None:
        for layer_name, shapes in drawing.shapes_by_layer():
            count = sum(1 for _ in shapes)
            if count > 0 or self.include_empty:
                print(f"{layer_name}: {count} shapes")

How It Works

  1. @tool() registers the class as a LinkCAD tool
  2. name appears in the menu, menu sets the menu path
  3. Option.boolean(...) creates a checkbox in the auto-generated dialog
  4. run() is called when the user clicks OK in the dialog

Option Types

Factory UI Control Example
Option.integer() Spin box Option.integer("Count", default=1, min=0, max=100)
Option.real() Double spin box Option.real("Scale", default=1.0, decimals=4)
Option.boolean() Checkbox Option.boolean("Enable", default=True)
Option.string() Text field Option.string("Name", default="output")
Option.choice() Dropdown Option.choice("Mode", choices=["Fast", "Precise"])
Option.path() File picker Option.path("Output", file_filter="*.csv")
Option.color() Color picker Option.color("Fill", default="#FF0000")
Option.table() Editable grid See Panel Assembly
Option.cell_choice() Cell dropdown Option.cell_choice("Target Cell")

Conditional Options

Use enabled_when to show/hide options dynamically:

class MyTool(Tool):
    mode = Option.choice("Mode", choices=["Simple", "Advanced"])
    threshold = Option.real(
        "Threshold",
        default=0.5,
        enabled_when=lambda self: self.mode == "Advanced",
    )

The threshold field is only enabled when mode is "Advanced."

Keyboard Shortcut

@tool(
    name="My Tool",
    menu="Tools/Custom",
    shortcut="Ctrl+Shift+M",
)
class MyTool(Tool):
    ...

Next Steps