/** * @file ac_manager.hpp * @brief Reconstructed header for Toon Boom AC_Manager class hierarchy * * This header was reverse-engineered from ToonBoomActionManager.dll * IDA Database: RE/ToonBoomActionManager.dll.i64 * * AC_Manager is the central action/command management system for Toon Boom * applications. It handles: * - Responder chain management (first responder, selection responder) * - Menu creation and management * - Toolbar creation and registration * - Shortcut/keyboard handling * - Action triggering and validation * * @note All offsets and structures derived from decompilation analysis. * This is NOT official Toon Boom code. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include // Forward declarations class AC_Manager; class AC_ManagerImpl; class AC_Responder; class AC_Menu; class AC_Toolbar; class AC_ToolbarImpl; class AC_ToolbarItemGenerator; class AC_ShortcutManager; class AC_ActionData; class AC_ActionInfo; class AC_Object; class AC_Item; class AC_Container; class AC_ContainerImpl; class AC_ToolbarMultiButton; /** * @brief Result code for action command handling * * Used as return value from perform(), trigger(), and validation methods. */ enum class AC_Result : int { Handled = 0, ///< Action was successfully handled NotHandled = 1, ///< Action was not handled by any responder Error = 2 ///< An error occurred during handling }; /** * @brief Manager options for AC_Manager configuration */ enum class AC_ManagerOption : int { TrimShortcuts = 0 ///< Whether to trim whitespace from shortcut strings // Additional options may exist }; /** * @brief Action-state payload passed to responders during trigger/validation * * In Toon Boom's binaries, responder slots typically accept an `AC_ActionInfo*` * (e.g. `onActionFooValidate(AC_ActionInfo*)`). RTTI in * `ToonBoomActionManager.dll` shows the concrete objects passed are * implementations of `AC_ActionInfoImpl` / `AC_ActionValidateImpl`, and that * `AC_ActionInfo` inherits from `AC_ActionData` (single inheritance, offset 0). * * This framework only declares the exported, non-virtual methods that are safe * to call from plugins. Do not instantiate these types (size/layout is opaque). */ class AC_ActionData { public: AC_ActionData() = delete; AC_ActionData(const AC_ActionData &) = delete; AC_ActionData &operator=(const AC_ActionData &) = delete; // Polymorphic base (vtable) in ToonBoomActionManager.dll. // Vtable for `AC_ActionData` has 10 entries: dtor + 9 pure virtuals. virtual ~AC_ActionData() = 0; virtual void _reserved1() = 0; virtual void _reserved2() = 0; virtual void _reserved3() = 0; virtual void _reserved4() = 0; virtual void _reserved5() = 0; virtual void _reserved6() = 0; virtual void _reserved7() = 0; virtual void _reserved8() = 0; virtual void _reserved9() = 0; // Exported from ToonBoomActionManager.dll (non-virtual). bool isValidation() const; void setEnabled(bool enabled); void setVisible(bool visible); }; inline AC_ActionData::~AC_ActionData() = default; /** * @brief Public type used in Qt slot signatures (`AC_ActionInfo*`) * * This type exists to match Toon Boom's Qt metaobject signatures. The runtime * objects passed are `AC_ActionInfoImpl`/`AC_ActionValidateImpl` instances. */ class AC_ActionInfo : public AC_ActionData { public: // IDA-verified: `AC_ActionInfoImpl_invokeOnQObject` is vtable slot 10 // (offset +0x50), returns 0 on success and 1 when the slot signature is // missing or not found on the target QObject. virtual AC_Result invokeOnQObject(QObject *target) = 0; protected: ~AC_ActionInfo() override = default; }; /** * @brief Abstract interface for objects that can respond to actions * * AC_Responder defines the responder chain pattern used by Toon Boom. * Responders receive actions from toolbar buttons, menus, and shortcuts, * and can either handle them or pass them up the chain. * * To create a custom responder: * 1. Inherit from AC_Responder (and QObject if you need Qt signals/slots) * 2. Implement all pure virtual methods * 3. Register with AC_Manager::registerResponder() * * Example: * @code * class MyResponder : public QObject, public AC_Responder { * Q_OBJECT * public: * MyResponder(const QString& id, AC_Manager* mgr) * : m_identity(id), m_manager(mgr) { * mgr->registerResponder(this, nullptr); * } * * // Implement AC_Responder interface... * const QString& responderIdentity() const override { return m_identity; } * AC_Manager* actionManager() const override { return m_manager; } * // ... other methods * * public slots: * void onActionMyAction() { // handle action } * }; * @endcode */ // Legacy (grouped) declaration kept for reference only (NOT ABI-accurate). #if 0 class AC_Responder { public: virtual ~AC_Responder() = default; // ========================================================================= // Identity // ========================================================================= /** * @brief Get the unique identity string for this responder * @return Reference to identity QString (must remain valid) */ virtual const QString& responderIdentity() const = 0; /** * @brief Get the human-readable description * @return Reference to description QString */ virtual const QString& responderDescription() const = 0; /** * @brief Set the description * @param description New description */ virtual void setResponderDescription(const QString& description) = 0; // ========================================================================= // Responder Chain Navigation // ========================================================================= /** * @brief Get the parent responder in the chain * @return Parent responder or nullptr if this is the root */ virtual AC_Responder* parentResponder() = 0; /** * @brief Get proxy responder that should handle actions instead * @return Proxy responder or nullptr */ virtual AC_Responder* proxyResponder() = 0; // ========================================================================= // First Responder (Keyboard Focus) // ========================================================================= /** * @brief Check if this responder can become first responder * @return true if this responder accepts first responder status */ virtual bool acceptsFirstResponder() = 0; /** * @brief Called when becoming first responder * @return true if successfully became first responder */ virtual bool becomeFirstResponder() = 0; /** * @brief Called when resigning first responder status * @return true if successfully resigned */ virtual bool resignFirstResponder() = 0; // ========================================================================= // Selection Responder // ========================================================================= /** * @brief Check if this responder can become selection responder * @return true if this responder accepts selection responder status */ virtual bool acceptsSelectionResponder() = 0; /** * @brief Called when becoming selection responder * @return true if successfully became selection responder */ virtual bool becomeSelectionResponder() = 0; /** * @brief Called when resigning selection responder status * @return true if successfully resigned */ virtual bool resignSelectionResponder() = 0; // ========================================================================= // Action Handling // ========================================================================= /** * @brief Perform an action * * This is called when an action targets this responder. The implementation * should invoke the appropriate slot based on AC_ActionInfo::slot(). * * @param info Action information including slot name and parameters * @return AC_Result::Handled if action was handled, NotHandled to pass up chain */ virtual AC_Result perform(AC_ActionInfo* info) = 0; /** * @brief Perform action on child responders * @param info Action information * @return Result from children */ virtual AC_Result performDownToChildren(AC_ActionInfo* info) = 0; /** * @brief Check if this responder should receive messages * @return true if responder is active and should receive messages */ virtual bool shouldReceiveMessages() const = 0; /** * @brief Check if this responder handles keyboard shortcuts * @return true if shortcuts should be processed by this responder */ virtual bool handleShortcuts() const = 0; // ========================================================================= // Event Handling // ========================================================================= /** * @brief Handle a Qt event * @param event Event to handle * @return AC_Result indicating if event was handled */ virtual AC_Result handleEvent(QEvent* event) = 0; // ========================================================================= // Manager Access // ========================================================================= /** * @brief Get the action manager * @return AC_Manager instance or nullptr */ virtual AC_Manager* actionManager() const = 0; }; #endif /** * @brief ABI-accurate AC_Responder interface (Harmony Premium) * * Virtual method order verified in `ToonBoomActionManager.dll.i64`: * - `??_7AC_Responder@@6B@` at `0x18004cd28` * * Slot indices below are 0-based (slot 0 is the destructor). Do not reorder. */ class AC_Responder { public: virtual ~AC_Responder() = default; // Vtable slot 1: Action manager back-pointer virtual AC_Manager *actionManager() const = 0; // slot 1 // Vtable slots 2-3: Messaging / shortcut behavior virtual bool shouldReceiveMessages() const = 0; // slot 2 virtual bool handleShortcuts() const = 0; // slot 3 // Vtable slots 4-6: First responder (keyboard focus) virtual bool resignFirstResponder() = 0; // slot 4 virtual bool becomeFirstResponder() = 0; // slot 5 virtual bool acceptsFirstResponder() = 0; // slot 6 // Vtable slots 7-9: Selection responder virtual bool resignSelectionResponder() = 0; // slot 7 virtual bool becomeSelectionResponder() = 0; // slot 8 virtual bool acceptsSelectionResponder() = 0; // slot 9 // Vtable slots 10-12: Identity / description virtual const QString &responderIdentity() const = 0; // slot 10 virtual const QString &responderDescription() const = 0; // slot 11 virtual void setResponderDescription(const QString &description) = 0; // slot 12 // Vtable slot 13: Responder chain parent virtual AC_Responder *parentResponder() = 0; // slot 13 // Vtable slot 14: Unknown/reserved (default implementation is a no-op in this // build) virtual void reserved0() {} // slot 14 // Vtable slots 15-16: Action execution virtual AC_Result perform(AC_ActionInfo *info) = 0; // slot 15 virtual AC_Result performDownToChildren(AC_ActionInfo *info) = 0; // slot 16 // Vtable slot 17: Event handling virtual AC_Result handleEvent(QEvent *event) = 0; // slot 17 // Vtable slot 18: Proxy responder (redirect actions to another responder) virtual AC_Responder *proxyResponder() = 0; // slot 18 }; /** * @brief Simple base class for implementing AC_Responder * * Provides default implementations for most AC_Responder methods. * Subclass this for simpler responder creation. * * @note This is a convenience class for users creating custom responders. * It is NOT the same as Toon Boom's internal AC_ResponderTemplate. */ class AC_ResponderBase : public AC_Responder { public: AC_ResponderBase(const QString &identity, QObject* obj, AC_Manager *manager = nullptr) : m_identity(identity), m_object(obj), m_manager(manager) { } virtual ~AC_ResponderBase() = default; AC_Manager *actionManager() const override { return m_manager; } bool shouldReceiveMessages() const override { return true; } bool handleShortcuts() const override { return true; } bool resignFirstResponder() override { return true; } bool becomeFirstResponder() override { return false; } bool acceptsFirstResponder() override { return false; } bool resignSelectionResponder() override { return true; } bool becomeSelectionResponder() override { return false; } bool acceptsSelectionResponder() override { return false; } const QString &responderIdentity() const override { return m_identity; } const QString &responderDescription() const override { return m_description; } void setResponderDescription(const QString &desc) override { m_description = desc; } AC_Responder *parentResponder() override { return nullptr; } AC_Responder *proxyResponder() override { return this; } AC_Result perform(AC_ActionInfo *info) override { return info->invokeOnQObject(m_object); } AC_Result performDownToChildren(AC_ActionInfo *info) override { return AC_Result::Handled; } AC_Result handleEvent(QEvent * /*event*/) override { return AC_Result::Handled; } void setActionManager(AC_Manager *manager) { m_manager = manager; } protected: QString m_identity; QString m_description; AC_Manager *m_manager; private: QObject* m_object; }; /** * @brief Initialization parameters for AC_ManagerImpl constructor * * sizeof(AC_ManagerInitParams) = 0x20 (32 bytes) on x64 */ struct AC_ManagerInitParams { void *keywords; ///< +0x00: Pointer to keywords QList void *keywordsEnd; ///< +0x08: End pointer for keywords void *keywordsCapacity; ///< +0x10: Capacity pointer for keywords bool trimShortcuts; ///< +0x18: Initial value for TrimShortcuts option }; /** * @brief Abstract base class for action/command management * * AC_Manager is a pure virtual interface that defines the contract for * the action management system. The concrete implementation is AC_ManagerImpl. * * Key responsibilities: * - Responder chain management for first responder and selection responder * - Menu and toolbar creation from XML definitions * - Action triggering and validation * - Shortcut/keyboard event handling * - Image/icon loading for UI elements * * ABI note (MSVC x64, Harmony Premium): * - Abstract base vtable: `??_7AC_Manager@@6B@` at `0x18004e508` (72 entries * incl. dtor) * - Concrete vtable used by `AC_Manager*` calls: * `??_7AC_ManagerImpl@@6BAC_Manager@@@` at `0x18004e7c8` * * IMPORTANT: `AC_Manager` is a vtable interface; virtual method order is ABI. */ // Legacy (grouped) declaration kept for reference only (NOT ABI-accurate). #if 0 class AC_Manager { public: virtual ~AC_Manager() = 0; // ========================================================================= // Image/Icon Management // ========================================================================= /** * @brief Add a directory to search for images * @param dir Directory path to add */ virtual void addImageDir(const QString& dir) = 0; /** * @brief Add multiple image directories from a path string * @param dirs Semicolon-separated directory paths */ virtual void addImageDirs(const QString& dirs) = 0; /** * @brief Find an image file by name * @param name Image name to find * @return Full path to the image, or empty string if not found */ virtual QString findImage(const QString& name) = 0; /** * @brief Load an icon with optional color blending * @param name Icon name to load * @param blendColor Color to blend with the icon * @param useGeneric If true, fall back to generic image if not found * @return Loaded QIcon */ virtual QIcon loadImage(const QString& name, const QColor& blendColor, bool useGeneric) = 0; /** * @brief Create a QAction-compatible icon * @param icon Source icon * @return Icon suitable for use with QAction */ virtual QIcon createQActionCompatibleIcon(const QIcon& icon) = 0; /** * @brief Set the generic/fallback image name * @param name Name of the generic image */ virtual void setGenericImage(const QString& name) = 0; // ========================================================================= // Identity and Options // ========================================================================= /** * @brief Generate a unique identity string * @return Unique identifier in format "__uuid_%1_%2__" */ virtual QString generateIdentity() = 0; /** * @brief Get hover ID for current UI element * @return Current hover identifier */ virtual QString hoverId() const = 0; /** * @brief Set hover ID * @param id New hover identifier */ virtual void setHoverId(const QString& id) = 0; /** * @brief Get string option value * @param name Option name * @return Option value as string */ virtual QString option(const QString& name) const = 0; /** * @brief Get integer option value * @param option Option enum value * @return Option value as integer */ virtual int option(AC_ManagerOption option) const = 0; /** * @brief Set string option * @param name Option name * @param value Option value * @return true if option was set successfully */ virtual bool setOption(const QString& name, const QString& value) = 0; /** * @brief Set integer option * @param option Option enum value * @param value Option value * @return true if option was set successfully */ virtual bool setOption(AC_ManagerOption option, int value) = 0; // ========================================================================= // Responder Management // ========================================================================= /** * @brief Get the application-level responder * @return Application responder or nullptr */ virtual AC_Responder* applicationResponder() const = 0; /** * @brief Set the application-level responder * @param responder New application responder */ virtual void setApplicationResponder(AC_Responder* responder) = 0; /** * @brief Get the current first responder * @return First responder at top of stack, or nullptr */ virtual AC_Responder* firstResponder() const = 0; /** * @brief Set the first responder * @param responder New first responder * @return true if successfully set */ virtual bool setFirstResponder(AC_Responder* responder) = 0; /** * @brief Get the selection responder * @return Current selection responder or nullptr */ virtual AC_Responder* selectionResponder() const = 0; /** * @brief Set the selection responder * @param responder New selection responder * @return true if successfully set */ virtual bool setSelectionResponder(AC_Responder* responder) = 0; /** * @brief Get the mouse responder (responder under mouse cursor) * @return Mouse responder or nullptr */ virtual AC_Responder* mouseResponder() const = 0; /** * @brief Find responder by identity string * @param identity Responder identity to find * @return Responder or nullptr if not found */ virtual AC_Responder* responder(const QString& identity) const = 0; /** * @brief Find responder by C-string identity * @param identity Responder identity to find * @return Responder or nullptr if not found */ virtual AC_Responder* responder(const char* identity) const = 0; /** * @brief Find responder by identity list with fallback * @param identities List of identities to try * @param fallback Fallback responder if none found * @return Found responder or fallback */ virtual AC_Responder* responder(const QList& identities, AC_Responder* fallback) const = 0; /** * @brief Get responder associated with a widget * @param widget Widget to find responder for * @return Associated responder or nullptr */ virtual AC_Responder* responderForWidget(QWidget* widget) const = 0; /** * @brief Register a responder * @param responder Responder to register * @param widget Associated widget (may be nullptr) * @return true if successfully registered */ virtual bool registerResponder(AC_Responder* responder, QWidget* widget) = 0; /** * @brief Unregister a responder * @param responder Responder to unregister */ virtual void unregisterResponder(AC_Responder* responder) = 0; /** * @brief Register a factory function to create responders for widgets * @param widget Widget class to register factory for * @param factory Function that creates AC_Responder for the widget */ virtual void registerResponderFactoryFnc(QWidget* widget, AC_Responder* (*factory)(AC_Manager*, QWidget*)) = 0; /** * @brief Push a responder up the responder chain * @param responder Responder to push */ virtual void pushUp(AC_Responder* responder) = 0; /** * @brief Push a responder out of the chain * @param responder Responder to remove */ virtual void pushOut(AC_Responder* responder) = 0; /** * @brief Notify that selection was cleared on a responder * @param responder Responder whose selection was cleared */ virtual void selectionCleared(AC_Responder* responder) = 0; /** * @brief Ignore a widget for responder purposes * @param widget Widget to ignore */ virtual void ignoreWidget(QWidget* widget) = 0; /** * @brief Check if a widget is ignored * @param widget Widget to check * @param checkParents If true, also check parent widgets * @return true if widget is ignored */ virtual bool isWidgetIgnored(QWidget* widget, bool checkParents) const = 0; /** * @brief Get all responder identities * @return List of all registered responder identities */ virtual QList allResponderIdentities() const = 0; /** * @brief Get slot list for a responder * @param identity Responder identity * @param includeInherited Include inherited slots * @return List of slot names */ virtual QList responderSlotList(const QString& identity, bool includeInherited) const = 0; // ========================================================================= // Menu Management // ========================================================================= /** * @brief Get the main menu bar * @return Main menu bar or nullptr */ virtual AC_Menu* menuBar() const = 0; /** * @brief Set the main menu bar * @param menu New main menu bar */ virtual void setMenuBar(AC_Menu* menu) = 0; /** * @brief Create a menu bar from XML element * @param element XML element defining the menu * @param menuBar QMenuBar to populate * @return Created AC_Menu */ virtual AC_Menu* createMenuBar(const QDomElement& element, QMenuBar* menuBar) = 0; /** * @brief Create a menu bar from XML element on a widget * @param element XML element defining the menu * @param parent Parent widget * @return Created AC_Menu */ virtual AC_Menu* createMenuBar(const QDomElement& element, QWidget* parent) = 0; /** * @brief Create a menu bar from menu name * @param name Menu name to load * @param menuBar QMenuBar to populate * @return Created AC_Menu */ virtual AC_Menu* createMenuBar(const QString& name, QMenuBar* menuBar) = 0; /** * @brief Create a menu bar from menu name on a widget * @param name Menu name to load * @param parent Parent widget * @return Created AC_Menu */ virtual AC_Menu* createMenuBar(const QString& name, QWidget* parent) = 0; /** * @brief Create a popup menu from XML element * @param element XML element defining the menu * @param parent Parent widget * @param owner Owner QObject for signal connections * @return Created AC_Menu */ virtual AC_Menu* createPopupMenu(const QDomElement& element, QWidget* parent, QObject* owner) = 0; /** * @brief Create a popup menu from name * @param name Menu name to load * @param parent Parent widget * @param owner Owner QObject * @return Created AC_Menu */ virtual AC_Menu* createPopupMenu(const QString& name, QWidget* parent, QObject* owner) = 0; /** * @brief Create a popup menu with icons * @param name Menu name to load * @param parent Parent widget * @param owner Owner QObject * @return Created AC_Menu with icons */ virtual AC_Menu* createPopupMenuWithIcons(const QString& name, QWidget* parent, QObject* owner) = 0; /** * @brief Load menus from XML element * @param element Root XML element containing menu definitions */ virtual void loadMenus(const QDomElement& element) = 0; /** * @brief Load menus from XML element with flags * @param element Root XML element * @param flags Loading flags */ virtual void loadMenus(const QDomElement& element, int flags) = 0; /** * @brief Load menus from file * @param path Path to menu definition file */ virtual void loadMenus(const QString& path) = 0; /** * @brief Load plugin menus * @param name Plugin name * @param placeholders List of placeholder names * @param element XML element with menu definitions */ virtual void loadPluginMenus(const QString& name, QList& placeholders, const QDomElement& element) = 0; /** * @brief Get menu element by name * @param name Menu name * @return XML element for the menu */ virtual QDomElement menuElement(const QString& name) = 0; // ========================================================================= // Toolbar Management // ========================================================================= /** * @brief Create a toolbar from XML element * @param element XML element defining the toolbar * @param ids Output list of item IDs (may be nullptr) * @param mainWindow Main window to add toolbar to * @param area Toolbar area (Qt::ToolBarArea) * @param objectName Object name for the toolbar (may be nullptr) * @param owner Owner QObject * @return Created AC_Toolbar */ virtual AC_Toolbar* createToolbar(const QDomElement& element, QList* ids, QMainWindow* mainWindow, int area, const char* objectName, QObject* owner) = 0; /** * @brief Create a toolbar from name * @param name Toolbar name to load * @param ids Output list of item IDs * @param mainWindow Main window * @param area Toolbar area * @param objectName Object name * @param owner Owner QObject * @return Created AC_Toolbar */ virtual AC_Toolbar* createToolbar(const QString& name, QList* ids, QMainWindow* mainWindow, int area, const char* objectName, QObject* owner) = 0; /** * @brief Create a multi-button toolbar item * @param element XML element defining the multi-button * @param container Container for the button * @param parent Parent widget * @return Created AC_ToolbarMultiButton */ virtual AC_ToolbarMultiButton* createToolbarMultiButton(const QDomElement& element, AC_ContainerImpl* container, QWidget* parent) = 0; /** * @brief Load toolbars from XML element * @param element Root XML element * @param ids Output list of loaded toolbar IDs */ virtual void loadToolbars(const QDomElement& element, QList& ids) = 0; /** * @brief Load toolbars from file * @param path Path to toolbar definition file * @param ids Output list of loaded toolbar IDs */ virtual void loadToolbars(const QString& path, QList& ids) = 0; /** * @brief Get toolbar element by name * @param name Toolbar name * @return XML element for the toolbar */ virtual QDomElement toolbarElement(const QString& name) = 0; /** * @brief Get toolbar item generator * @return Current item generator or nullptr */ virtual AC_ToolbarItemGenerator* itemGenerator() const = 0; /** * @brief Set toolbar item generator * @param generator New item generator */ virtual void setItemGenerator(AC_ToolbarItemGenerator* generator) = 0; /** * @brief Register a toolbar with the manager * @param toolbar Toolbar to register */ virtual void registerToolbar(AC_ToolbarImpl* toolbar) = 0; /** * @brief Get toolbar customize button image name * @return Image name for customize button */ virtual QString toolbarCustomizeImage() const = 0; /** * @brief Set toolbar customize button image * @param name Image name */ virtual void setToolbarCustomizeImage(const QString& name) = 0; /** * @brief Update all toolbar states */ virtual void updateToolbars() = 0; /** * @brief Update toolbar tooltip text */ virtual void updateToolbarText() = 0; // ========================================================================= // Shortcut/Keyboard Management // ========================================================================= /** * @brief Get the shortcut manager * @return Shortcut manager or nullptr */ virtual AC_ShortcutManager* shortcutManager() const = 0; /** * @brief Set the shortcut manager * @param manager New shortcut manager */ virtual void setShortcutManager(AC_ShortcutManager* manager) = 0; /** * @brief Load shortcuts from XML element * @param element XML element with shortcut definitions */ virtual void loadShortcuts(const QDomElement& element) = 0; /** * @brief Load shortcuts from file * @param path Path to shortcut definition file */ virtual void loadShortcuts(const QString& path) = 0; /** * @brief Get key code for a shortcut * @param shortcut Shortcut name * @return Qt key code */ virtual int keyCodeForShortcut(const QString& shortcut) const = 0; /** * @brief Get key sequence for a shortcut * @param shortcut Shortcut name * @return QKeySequence for the shortcut */ virtual QKeySequence keySequenceForShortcut(const QString& shortcut) const = 0; /** * @brief Check if a key event matches a shortcut * @param shortcut Shortcut name * @param event Key event to check * @return true if event matches shortcut */ virtual bool isShortcut(const char* shortcut, QKeyEvent* event) const = 0; /** * @brief Handle a key event * @param event Key event to handle * @param isRelease true if this is a key release event * @return Result indicating if event was handled */ virtual AC_Result handleKeyEvent(QKeyEvent* event, bool isRelease) = 0; // ========================================================================= // Action Triggering and Validation // ========================================================================= /** * @brief Trigger an action by name * @param responderIdentity Target responder identity * @param actionName Action name to trigger * @param forEachResponder If true, trigger on each matching responder * @return Result of the action */ virtual AC_Result trigger(const QString& responderIdentity, const QString& actionName, bool forEachResponder) = 0; /** * @brief Trigger an action with arguments * @param responderIdentity Target responder identity * @param actionName Action name to trigger * @param args Action arguments * @param forEachResponder If true, trigger on each matching responder * @return Result of the action */ virtual AC_Result trigger(const QString& responderIdentity, const QString& actionName, const std::vector& args, bool forEachResponder) = 0; /** * @brief Trigger an action on each matching responder * @param responderIdentity Target responder identity * @param actionName Action name to trigger * @param forEachResponder Iteration flag * @return Result of the action */ virtual AC_Result triggerForEach(const QString& responderIdentity, const QString& actionName, bool forEachResponder) = 0; /** * @brief Trigger an action on each responder with arguments * @param responderIdentity Target responder identity * @param actionName Action name to trigger * @param args Action arguments * @param forEachResponder Iteration flag * @return Result of the action */ virtual AC_Result triggerForEach(const QString& responderIdentity, const QString& actionName, const std::vector& args, bool forEachResponder) = 0; /** * @brief Perform validation for an action * @param responderIdentity Target responder identity * @param actionName Action name to validate * @param enabled Output: whether action is enabled * @param checked Output: whether action is checked * @return Result of validation */ virtual AC_Result performValidation(const QString& responderIdentity, const QString& actionName, bool* enabled, bool* checked) = 0; // ========================================================================= // Static Factory // ========================================================================= /** * @brief Create a responder for a widget * @param manager AC_Manager instance * @param widget Widget to create responder for * @return Created responder or nullptr */ static AC_Responder* createResponderForWidget(AC_Manager* manager, QWidget* widget); }; #endif /** * @brief ABI-accurate AC_Manager interface (Harmony Premium) * * Virtual method order verified in `ToonBoomActionManager.dll.i64`: * - `??_7AC_ManagerImpl@@6BAC_Manager@@@` at `0x18004e7c8` * * Slot indices below are 0-based (slot 0 is the destructor). Do not reorder. */ class AC_Manager { public: virtual ~AC_Manager() = 0; // Vtable slots 1-6: Options / Hover ID virtual QString option(const QString &name) const = 0; // slot 1 virtual int option(AC_ManagerOption option) const = 0; // slot 2 virtual bool setOption(const QString &name, const QString &value) = 0; // slot 3 virtual bool setOption(AC_ManagerOption option, int value) = 0; // slot 4 virtual void setHoverId(const QString &id) = 0; // slot 5 virtual QString hoverId() const = 0; // slot 6 // Vtable slots 7-17: Menu definitions / creation virtual void loadMenus(const QString &path) = 0; // slot 7 virtual void loadMenus(const QDomElement &element) = 0; // slot 8 virtual void loadPluginMenus(const QString &name, QList &placeholders, const QDomElement &element) = 0; // slot 9 virtual AC_Menu *createPopupMenu(const QString &name, QWidget *parent, QObject *owner) = 0; // slot 10 virtual AC_Menu *createPopupMenu(const QDomElement &element, QWidget *parent, QObject *owner) = 0; // slot 11 virtual AC_Menu *createPopupMenuWithIcons(const QString &name, QWidget *parent, QObject *owner) = 0; // slot 12 virtual AC_Menu *createMenuBar(const QString &name, QMenuBar *menuBar) = 0; // slot 13 virtual AC_Menu *createMenuBar(const QDomElement &element, QMenuBar *menuBar) = 0; // slot 14 virtual AC_Menu *createMenuBar(const QString &name, QWidget *parent) = 0; // slot 15 virtual AC_Menu *createMenuBar(const QDomElement &element, QWidget *parent) = 0; // slot 16 virtual QDomElement menuElement(const QString &name) = 0; // slot 17 (returns by value; MSVC x64 // uses sret out buffer) // Vtable slot 18: Identity virtual QString generateIdentity() = 0; // slot 18 // Vtable slots 19-35: Responder chain virtual bool registerResponder(AC_Responder *responder, QWidget *widget) = 0; // slot 19 virtual void unregisterResponder(AC_Responder *responder) = 0; // slot 20 virtual AC_Responder *applicationResponder() const = 0; // slot 21 virtual void setApplicationResponder(AC_Responder *responder) = 0; // slot 22 virtual AC_Responder *selectionResponder() const = 0; // slot 23 virtual void selectionCleared(AC_Responder *responder) = 0; // slot 24 virtual bool setSelectionResponder(AC_Responder *responder) = 0; // slot 25 virtual AC_Responder *firstResponder() const = 0; // slot 26 virtual bool setFirstResponder(AC_Responder *responder) = 0; // slot 27 virtual AC_Responder *responder(const QList &identities, AC_Responder *fallback) const = 0; // slot 28 virtual AC_Responder *responder(const QString &identity) const = 0; // slot 29 virtual AC_Responder *responder(const char *identity) const = 0; // slot 30 virtual AC_Responder * responderForWidget(QWidget *widget) const = 0; // slot 31 virtual AC_Responder *mouseResponder() const = 0; // slot 32 virtual QList allResponderIdentities() const = 0; // slot 33 (returns by value; sret) virtual QList responderSlotList( const QString &identity, bool includeInherited) const = 0; // slot 34 (returns by value; sret) virtual void pushUp(AC_Responder *responder) = 0; // slot 35 // Vtable slots 36-43: Shortcuts / keyboard virtual AC_ShortcutManager *shortcutManager() const = 0; // slot 36 virtual void setShortcutManager(AC_ShortcutManager *manager) = 0; // slot 37 virtual void loadShortcuts(const QDomElement &element) = 0; // slot 38 virtual void loadShortcuts(const QString &path) = 0; // slot 39 virtual AC_Result handleKeyEvent(QKeyEvent *event, bool isRelease) = 0; // slot 40 virtual bool isShortcut(const char *shortcut, QKeyEvent *event) const = 0; // slot 41 virtual int keyCodeForShortcut(const QString &shortcut) const = 0; // slot 42 virtual QKeySequence keySequenceForShortcut( const QString &shortcut) const = 0; // slot 43 (returns by value; sret) // Vtable slots 44-45: Widget ignore virtual void ignoreWidget(QWidget *widget) = 0; // slot 44 virtual bool isWidgetIgnored(QWidget *widget, bool checkParents) const = 0; // slot 45 // Vtable slots 46-52: Toolbars virtual void loadToolbars(const QString &path, QList &ids) = 0; // slot 46 virtual void loadToolbars(const QDomElement &element, QList &ids) = 0; // slot 47 virtual AC_Toolbar *createToolbar(const QString &name, QList *ids, QMainWindow *mainWindow, int area, const char *objectName, QObject *owner) = 0; // slot 48 virtual AC_Toolbar *createToolbar(const QDomElement &element, QList *ids, QMainWindow *mainWindow, int area, const char *objectName, QObject *owner) = 0; // slot 49 virtual void registerToolbar(AC_ToolbarImpl *toolbar) = 0; // slot 50 virtual AC_ToolbarMultiButton * createToolbarMultiButton(const QDomElement &element, AC_ContainerImpl *container, QWidget *parent) = 0; // slot 51 virtual QDomElement toolbarElement(const QString &name) = 0; // slot 52 (returns by value; sret) // Vtable slots 53-56: Toolbar refresh + main menu bar accessors virtual void updateToolbars() = 0; // slot 53 virtual void updateToolbarText() = 0; // slot 54 virtual AC_Menu *menuBar() const = 0; // slot 55 virtual void setMenuBar(AC_Menu *menu) = 0; // slot 56 // Vtable slots 57-62: Images / icons virtual QString findImage(const QString &name) = 0; // slot 57 (returns by value; sret) virtual void addImageDir(const QString &dir) = 0; // slot 58 virtual void addImageDirs(const QString &dirs) = 0; // slot 59 virtual QIcon loadImage(const QString &name, const QColor &blendColor, bool useGeneric) = 0; // slot 60 (returns by value; sret) virtual QIcon createQActionCompatibleIcon( const QIcon &icon) = 0; // slot 61 (returns by value; sret) virtual void setGenericImage(const QString &name) = 0; // slot 62 // Vtable slots 63-67: Toolbar customize image + item generator virtual void setToolbarCustomizeImage(const QString &name) = 0; // slot 63 virtual QString toolbarCustomizeImage() const = 0; // slot 64 (returns by value; sret) virtual void registerResponderFactoryFnc( QWidget *widget, AC_Responder *(*factory)(AC_Manager *, QWidget *)) = 0; // slot 65 virtual AC_ToolbarItemGenerator *itemGenerator() const = 0; // slot 66 virtual void setItemGenerator(AC_ToolbarItemGenerator *generator) = 0; // slot 67 // Vtable slots 68-71: Actions / validation virtual AC_Result trigger(const QString &responderIdentity, const QString &actionName, const std::vector &args, bool forEachResponder) = 0; // slot 68 virtual AC_Result trigger(const QString &responderIdentity, const QString &actionName, bool forEachResponder) = 0; // slot 69 virtual AC_Result triggerForEach(const QString &responderIdentity, const QString &actionName, bool forEachResponder) = 0; // slot 70 virtual AC_Result performValidation(const QString &responderIdentity, const QString &actionName, bool *enabled, bool *checked) = 0; // slot 71 // Static Factory (not part of the vtable) static AC_Responder *createResponderForWidget(AC_Manager *manager, QWidget *widget); }; /** * @brief Concrete implementation of AC_Manager * * AC_ManagerImpl inherits from QObject and AC_Manager, providing the * actual implementation of the action management system. * * sizeof(AC_ManagerImpl) = 0x158 (344 bytes) on x64 * * Memory layout: * - +0x00: QObject (vptr + members) * - +0x10: AC_Manager vptr * - +0x18: QList* m_keywords (shared with init params) * - +0x20: (keywords internal) * - +0x28: (keywords internal) * - +0x30: bool m_trimShortcuts * - +0x38: Internal tree for responder name->list mapping * - +0x48: Internal tree (continued) * - +0x60: Internal tree for menus * - +0x70: (menus continued) * - +0x78: AC_ShortcutManager* m_shortcutManager * - +0x80: (shortcut internal) * - +0x88: QString m_hoverId * - +0xA0: QString m_genericImage * - +0xB8: QString m_toolbarCustomizeImage * - +0xC8: Internal tree for toolbars * - +0xD8: (toolbars continued) * - +0xE0: std::vector m_registeredResponders * - +0xF8: std::vector m_responderStack * - +0x110: (responder stack continued) * - +0x118: AC_Menu* m_menuBar * - +0x120: AC_Responder* m_firstResponder (via stack) * - +0x128: AC_Responder* m_applicationResponder * - +0x130: AC_Responder* m_selectionResponder * - +0x138: AC_ToolbarItemGenerator* m_itemGenerator * - +0x140: int m_uniqueIdCounter * - +0x144: int m_flags * - +0x148: void* m_internalData * - +0x150: bool m_option_trimShortcuts (at offset 304 from AC_Manager base) * * Signals: * - firstResponderChanged() * - selectionResponderChanged() * - updateToolbarsSignal() * - updateToolbarsText() */ class AC_ManagerImpl : public QObject, public AC_Manager { Q_OBJECT public: /** * @brief Construct AC_ManagerImpl with initialization parameters * @param params Initialization parameters */ explicit AC_ManagerImpl(const AC_ManagerInitParams ¶ms); virtual ~AC_ManagerImpl() override; // All AC_Manager virtual methods are implemented... // See AC_Manager for documentation // Additional non-virtual methods /** * @brief Get the keywords list * @return Reference to keywords list */ const QList &keywords() const; /** * @brief Check if shortcuts should be trimmed * @return true if trimming is enabled */ bool trimShortcuts() const; /** * @brief Check if a responder is registered * @param responder Responder to check * @return true if registered */ bool isRegistred(AC_Responder *responder) const; /** * @brief Get all responders matching identity list * @param identities Identity list to match * @param fallback Fallback responder * @return Vector of matching responders */ std::vector responders(const QList &identities, AC_Responder *fallback) const; /** * @brief Get all responders matching single identity * @param identity Identity to match * @return Vector of matching responders */ std::vector responders(const QString &identity) const; /** * @brief Normalize a string for comparison * @param str String to normalize * @return Normalized string */ static QString normalize(const QString &str); signals: /** * @brief Emitted when the first responder changes */ void firstResponderChanged(); /** * @brief Emitted when the selection responder changes */ void selectionResponderChanged(); /** * @brief Emitted to signal toolbar update needed */ void updateToolbarsSignal(); /** * @brief Emitted to signal toolbar text update needed */ void updateToolbarsText(); protected: /** * @brief Fire the first responder changed signal */ void fireFirstResponderChanged(); /** * @brief Fire the selection responder changed signal */ void fireSelectionResponderChanged(); /** * @brief Fire toolbar update signal */ void fireUpdateToolbars(); /** * @brief Fire toolbar text update signal */ void fireUpdateToolbarText(); /** * @brief Fire toolbar button clicked notification * @param identity Button identity */ void fireToolbarButtonClicked(const QString &identity); protected slots: /** * @brief Handle ignored widget destruction * @param object Destroyed object */ void ignoredWidgetDestroyed(QObject *object); }; // ============================================================================ // Offset Constants (for reference/debugging) // ============================================================================ namespace AC_ManagerImpl_Offsets { // Offsets from AC_Manager base (this + 16 from QObject base) constexpr size_t Keywords = 0x08; // 8 - QList* to keywords constexpr size_t TrimShortcutsInit = 0x18; // 24 - Initial trimShortcuts value constexpr size_t ResponderNameMap = 0x28; // 40 - Internal tree for name->responders constexpr size_t MenuTree = 0x50; // 80 - Internal tree for menus constexpr size_t ShortcutManager = 0x68; // 104 - AC_ShortcutManager* constexpr size_t HoverId = 0x78; // 120 - QString m_hoverId constexpr size_t GenericImage = 0x90; // 144 - QString m_genericImage constexpr size_t ToolbarCustomizeImage = 0xA8; // 168 - QString m_toolbarCustomizeImage constexpr size_t ToolbarTree = 0xB8; // 184 - Internal tree for toolbars constexpr size_t RegisteredResponders = 0xD0; // 208 - std::vector constexpr size_t ResponderStack = 0xE8; // 232 - std::vector constexpr size_t MenuBar = 0x108; // 264 - AC_Menu* constexpr size_t ApplicationResponder = 0x118; // 280 - AC_Responder* constexpr size_t SelectionResponder = 0x120; // 288 - AC_Responder* constexpr size_t ItemGenerator = 0x128; // 296 - AC_ToolbarItemGenerator* constexpr size_t TrimShortcutsOption = 0x130; // 304 - bool (option value) } // namespace AC_ManagerImpl_Offsets