Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Drive a command from the selection

Selection is UI state the shell pushes into the facade, and a command reads it when the shell asks whether it is enabled. This page runs a command with no selection, selects an object, opens a dialog and accepts it, and deletes the selection.

Generated page. tools/userdocs.py writes it from tools/workflows/05_selection_and_commands.py. Edit the workflow, not this page; python3 tools/userdocs.py --check fails when the two disagree.

Requires: the ferrocad_toy app script (it registers on import); no window: the shell’s pushes are ordinary function calls.

1. Boot the edition

import json
import ferrocad_shell
import ferrocad_toy

ferrocad_toy.bootstrap("Toy")
Read backValue
Objects[“Params”, “Derived”, “Group”, “Slab”]

2. Enablement follows the selection

The shell pushes its selection into FreeCADGui.Selection; a command answers IsActive against it. Nothing is enabled or disabled by hand.

ferrocad_shell.set_selection('[]')
def delete_state():
    for command in json.loads(ferrocad_shell.commands()):
        if command["id"] == "App_Delete":
            return command["enabled"]
Read backValue
App_Delete, nothing selectedfalse
ferrocad_shell.set_selection('[{"object": "Slab"}]')
Read backValue
Selection[“Slab”]
App_Delete, one object selectedtrue

3. A command that asks for input

Toy_MakeSlab does not act immediately. It returns a dialog description and a token; the shell renders the fields natively and sends the typed values back to that token.

request = json.loads(ferrocad_shell.run_command("Toy_MakeSlab"))

Dialog request

{
  "accept": "Create",
  "fields": [
    {
      "kind": "quantity",
      "label": "Width",
      "min": 0.1,
      "name": "Width",
      "value": 40.0
    },
    {
      "kind": "quantity",
      "label": "Depth",
      "min": 0.1,
      "name": "Depth",
      "value": 40.0
    },
    {
      "kind": "quantity",
      "label": "Height",
      "min": 0.1,
      "name": "Height",
      "value": 20.0
    }
  ],
  "title": "Create Slab"
}

Accepting runs the command’s callback, which owns its transaction.

accepted = json.loads(
    ferrocad_shell.dialog_accept(
        json.dumps(
            {
                "token": request["token"],
                "values": {"Width": 50.0, "Depth": 25.0, "Height": 12.0},
            }
        )
    )
)
Read backValue
Accept response{“ok”: true, “status”: “created Slab001”}
Objects[“Params”, “Derived”, “Group”, “Slab”, “Slab001”]

4. Cancelling instead

A token is single-use. Cancelling drops it without running the callback, so a cancelled dialog leaves no transaction behind.

cancelled = json.loads(ferrocad_shell.run_command("Toy_MakeSlab"))
cancel_response = json.loads(
    ferrocad_shell.dialog_cancel(cancelled["token"])
)
Read backValue
Cancel response{“ok”: true}
Objects[“Params”, “Derived”, “Group”, “Slab”, “Slab001”]

5. Act on the selection

App_Delete is the shell’s own edit command. It reads the same selection snapshot and deletes what it names.

ferrocad_shell.set_selection('[{"object": "Slab"}]')
deleted = json.loads(ferrocad_shell.run_command("App_Delete"))
Read backValue
Delete response{“ok”: true, “status”: “deleted 1 object(s)”}
Objects[“Params”, “Derived”, “Group”, “Slab001”]

Every call above is a plain function on the shell’s Python module. The same functions are what the window calls while you click, which is why these pages run with no window at all.

6. Close the document

FreeCAD.closeDocument('Toy')
Read backValue
Open documents[]