The actions package

The action package is used to register actions and menus in PCB and to execute existing actions. In PCB actions are generated when the user selects a menu, presses a key or issues a command on the PCB command line.

Registration of new actions

The script may register new actions using arbitrary action names. If any of the registered actions is detected, an ACTE_action event is sent to the script. If multiple actions are used in a script, argument name of the event handler can be used to identify the triggering action. (This may be time consuming in scripting languages (a series of string comparison) - those scripts binding to frequent actions should not bind to too many different actions.) pcb-gpmi guarantees that the event handler of a script is triggered only when an action is caught that previously was registered by the same script.

The process of binding an action:

  1. create an event handler for event ACTE_action
  2. register one or more actions using function action_register
  3. optional: when the event handler is triggered, check argument name (for scripts with multiple actions registered)
  4. optional: use argument argc and function action_arg to fetch action arguments
  5. optional: use arguments x, y to learn the cursor position on the layout.
Example (written in lua):
-- load the package
PkgLoad("pcb-gpmi/actions", 0);

-- action callback
function ev_action(id, name, argc, x, y)
	if name == "cake" then
		size = action_arg(1);
		-- put cake drawing code here
	else
		-- must be candy
		amount = action_arg(1);
		-- put candy drawing code here
	end
end

-- register and bind action
action_register("cake",  "cake center xy?", "cake service", "cake(size)", "");
action_register("candy", "candy cloud center xy?", "cake service", "candy(amount)", "");
Bind("ACTE_action", "ev_action");

When the script is unloaded all actions the script registered are removed from pcb-rnd automatically.

Executing actions

An existing action can be executed using the action() call. The only one argument is a command line string. The syntax is the same as in pcb command line. Example (written in lua):
PkgLoad("pcb-rnd-gpmi/actions", 0);

function ev_action1(id, name, argc, x, y)
	action("undo()")
	action("undo()")
end

-- register and bind action
action_register("untwo", "", "undo twice", "untwo()", "CONTEXT!");

The above script registers a new action called untwo(). When untwo() is executed, it executes action undo() twice.

Creating menus

It is possible to insert menus and submenus runtime, using the call create_menu(). The script should do this only after the gui has been initialized. The most common way is to create all menus from the ACTE_gui_init event, which is called after the gui finished setting up.

The first argument of create_menu() is the menu path. The path is a list of visible menu names separated by slashes (e.g. "/main_menu/File/Save as..." means "File" menu, "Save as..." submenu).

Paths are interpreted as menu paths, which are a slightly simplified version of lihata paths found in menu.lht. Basically there's a main directory directly under root that determines the type of the menu:

The simplification compared to lihata paths is that only menu and submenu names are on the path, so lihata nodes like "li:submenu" should be ignored. In other words, the path represents how the menus can be reached from the user interface, plus a "main menu type prefix" as discussed above.

By convention, scripts should create new menu items under the "/main_menu/Plugins/" menu.

The following example lua script registers a new menu item

PkgLoad("pcb-rnd-gpmi/actions", 0);

function ev_gui_init(argc, argv)
	create_menu("/main_menu/Plugins/foo", "undo()", "o", "Ctrl<Key>o", "tooltip for foo");
end

-- register and bind action
Bind("ACTE_gui_init", "ev_gui_init");

When the user clicks on the menu, the action script specified in the second argument of create_menu() is executed. Thus the script usually registers a new action first then registers one or more menu items executing those actions.