Commands & menus¶
Commands¶
ICommandRegistry is the single execution funnel for every user-invocable action
— menu items, toolbar buttons, shortcuts, and (later) Python scripts.
struct CommandDescriptor {
std::string id; // "helloworld.sayHi"
std::string title; // "Say Hi"
std::string shortcut; // portable: "Ctrl+Alt+H"
std::string category; // "Hello"
};
using CommandHandler = std::function<void()>;
class ICommandRegistry {
public:
virtual CommandToken registerCommand(CommandDescriptor, CommandHandler) = 0;
virtual void invoke(std::string_view commandId) = 0;
virtual bool exists(std::string_view commandId) const = 0;
};
registerCommand returns a CommandToken (RAII). Destroying it removes the
command, its menu entries, and its shortcut. Hold every token as a member so the
whole plugin tears down automatically in shutdown().
Menus¶
Menu paths use / as the separator; the host creates intermediate submenus on
demand:
class IMenuRegistry {
public:
virtual MenuToken addItem(std::string menuPath, std::string commandId) = 0;
virtual MenuToken addSeparator(std::string menuPath) = 0;
};
MenuToken is RAII like CommandToken.
Menu placement (plugin.json)¶
Where a plugin's top-level menu sits is data-driven via the menus array in
plugin.json — the host never hard-codes plugin menu names:
title— the top-level menu; matches the first/-separated segment of yourmenuPath.barPriority— horizontal position on the menu bar (lower = further left). Core menus are fixed: File 10, Edit 20, View 40, Language 60, Window 80; plugins fill the gaps (Search 30, Encoding 50, Plugins 70).itemPriority— vertical rank of this plugin's block withintitle(lower = higher up; default 1000). Items inside one plugin's block keep the order they are added in code.
Note
Because plugin.json is embedded as Qt plugin metadata, edits to it take
effect only after a rebuild.