1389 lines
50 KiB
C++

/**
* @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 <QtCore/qtmetamacros.h>
#include <QtCore/QList>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include <QtGui/QIcon>
#include <QtGui/QKeySequence>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QWidget>
#include <QtXml/QDomElement>
#include <vector>
// 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<QString>
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<QString>& 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<QString> 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<QString> 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<QString>& 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<QString>* 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<QString>* 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<QString>& 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<QString>& 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<QVariant>& 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<QVariant>& 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<QString> &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<QString> &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<QString>
allResponderIdentities() const = 0; // slot 33 (returns by value; sret)
virtual QList<QString> 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<QString> &ids) = 0; // slot 46
virtual void loadToolbars(const QDomElement &element,
QList<QString> &ids) = 0; // slot 47
virtual AC_Toolbar *createToolbar(const QString &name, QList<QString> *ids,
QMainWindow *mainWindow, int area,
const char *objectName,
QObject *owner) = 0; // slot 48
virtual AC_Toolbar *createToolbar(const QDomElement &element,
QList<QString> *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<QVariant> &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<QString>* 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<AC_Responder*> m_registeredResponders
* - +0xF8: std::vector<AC_Responder*> 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 &params);
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<QString> &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<AC_Responder *> responders(const QList<QString> &identities,
AC_Responder *fallback) const;
/**
* @brief Get all responders matching single identity
* @param identity Identity to match
* @return Vector of matching responders
*/
std::vector<AC_Responder *> 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<QString>* 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<AC_Responder*>
constexpr size_t ResponderStack = 0xE8; // 232 - std::vector<AC_Responder*>
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