diff --git a/framework/include/toon_boom/ac_manager.hpp b/framework/include/toon_boom/ac_manager.hpp new file mode 100644 index 0000000..317d6fc --- /dev/null +++ b/framework/include/toon_boom/ac_manager.hpp @@ -0,0 +1,1129 @@ +/** + * @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 + +// 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_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 { + NotHandled = 0, ///< Action was not handled by any responder + Handled = 1, ///< Action was successfully handled + 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 information passed to responders + * + * Contains information about the action being performed, including + * the slot name, parameters, and enabled/checked state. + * + * This is an opaque class - the actual implementation is in Toon Boom DLLs. + * The interface is provided for type safety in method signatures. + */ +class AC_ActionInfo : public QObject { + Q_OBJECT +public: + virtual ~AC_ActionInfo() = default; + + // State accessors - implemented in Toon Boom DLLs + virtual bool isEnabled() const = 0; + virtual void setEnabled(bool enabled) = 0; + virtual bool isChecked() const = 0; + virtual void setChecked(bool checked) = 0; + virtual bool isVisible() const = 0; + virtual void setVisible(bool visible) = 0; + + // Action info + virtual const QString& slot() const = 0; + virtual const QString& text() const = 0; + virtual QVariant itemParameter() const = 0; + + // Responder + virtual AC_Responder* responder() const = 0; + virtual void setResponder(AC_Responder* responder) = 0; +}; + +/** + * @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 + */ +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; +}; + +/** + * @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, AC_Manager* manager = nullptr) + : m_identity(identity), m_manager(manager) {} + + virtual ~AC_ResponderBase() = default; + + // Identity + 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; } + + // Chain - override in subclasses if needed + AC_Responder* parentResponder() override { return nullptr; } + AC_Responder* proxyResponder() override { return nullptr; } + + // First responder - typically not needed for simple responders + bool acceptsFirstResponder() override { return false; } + bool becomeFirstResponder() override { return false; } + bool resignFirstResponder() override { return true; } + + // Selection responder - typically not needed for simple responders + bool acceptsSelectionResponder() override { return false; } + bool becomeSelectionResponder() override { return false; } + bool resignSelectionResponder() override { return true; } + + // Action handling - override perform() in subclasses + AC_Result perform(AC_ActionInfo* /*info*/) override { return AC_Result::NotHandled; } + AC_Result performDownToChildren(AC_ActionInfo* /*info*/) override { return AC_Result::NotHandled; } + + // Messages + bool shouldReceiveMessages() const override { return true; } + bool handleShortcuts() const override { return true; } + + // Events + AC_Result handleEvent(QEvent* /*event*/) override { return AC_Result::NotHandled; } + + // Manager + AC_Manager* actionManager() const override { return m_manager; } + void setActionManager(AC_Manager* manager) { m_manager = manager; } + +protected: + QString m_identity; + QString m_description; + AC_Manager* m_manager; +}; + +/** + * @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 + * + * vtable at 0x18004e508 (76 virtual methods) + */ +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); +}; + +/** + * @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& 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& 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); + +private 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) +} + diff --git a/framework/include/toon_boom/toolbar.hpp b/framework/include/toon_boom/toolbar.hpp new file mode 100644 index 0000000..a0bfff3 --- /dev/null +++ b/framework/include/toon_boom/toolbar.hpp @@ -0,0 +1,945 @@ +/** + * @file toolbar.hpp + * @brief Reconstructed header for Toon Boom AC_Toolbar class hierarchy + * + * This header was reverse-engineered from ToonBoomActionManager.dll + * IDA Database: RE/ToonBoomActionManager.dll.i64 + * + * AC_Toolbar provides customizable toolbar functionality for Toon Boom + * applications. It supports: + * - Dynamic item insertion (buttons, multi-buttons, comboboxes, separators) + * - Placeholder-based customization + * - Configuration save/restore + * - Integration with AC_Manager for action handling + * + * @note All offsets and structures derived from decompilation analysis. + * This is NOT official Toon Boom code. + */ + +#pragma once + +#include "./ac_manager.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +// Forward declarations +class AC_Object; +class AC_Item; +class AC_Separator; +class AC_Container; +class AC_ContainerImpl; +class AC_Toolbar; +class AC_ToolbarImpl; +class AC_ToolbarItemGenerator; +class AC_Help; + +/** + * @brief Abstract base class for toolbar objects (items, separators, etc.) + * + * AC_Object is the base interface for all items that can be contained + * within an AC_Container (toolbar, menu, etc.). + * + * vtable at 0x18004ed88 (16 virtual methods, most pure virtual) + */ +class AC_Object { +public: + virtual ~AC_Object() = 0; + + /** + * @brief Get the identity string for this object + * @return Reference to identity QString + */ + virtual const QString& identity() const = 0; + + /** + * @brief Check if this object is visible + * @return true if visible + */ + virtual bool isVisible() const = 0; + + /** + * @brief Set visibility of this object + * @param visible New visibility state + */ + virtual void setVisible(bool visible) = 0; + + /** + * @brief Check if this object is enabled + * @return true if enabled + */ + virtual bool isEnabled() const = 0; + + /** + * @brief Set enabled state of this object + * @param enabled New enabled state + */ + virtual void setEnabled(bool enabled) = 0; + + /** + * @brief Cast to AC_Item if this is an item + * @return Pointer to AC_Item or nullptr + */ + virtual const AC_Item* toItem() const = 0; + + /** + * @brief Cast to AC_Separator if this is a separator + * @return Pointer to AC_Separator or nullptr + */ + virtual const AC_Separator* toSeparator() const = 0; + + /** + * @brief Cast to AC_Toolbar if this is a toolbar + * @return Pointer to AC_Toolbar or nullptr + */ + virtual const AC_Toolbar* toToolbar() const = 0; + + // Additional virtual methods exist but are mostly pure virtual stubs +}; + +/** + * @brief Abstract interface for toolbar items (buttons, etc.) + * + * AC_Item extends AC_Object with item-specific functionality like + * checked state and action association. + */ +class AC_Item : public AC_Object { +public: + virtual ~AC_Item() = 0; + + /** + * @brief Check if this item is checked (for toggle buttons) + * @return true if checked + */ + virtual bool isChecked() const = 0; + + /** + * @brief Set the checked state + * @param checked New checked state + */ + virtual void setChecked(bool checked) = 0; + + /** + * @brief Get the associated QAction + * @return QAction pointer or nullptr + */ + virtual QAction* action() const = 0; +}; + +/** + * @brief Abstract interface for toolbar separators + */ +class AC_Separator : public AC_Object { +public: + virtual ~AC_Separator() = 0; +}; + +/** + * @brief Abstract interface for containers that hold AC_Objects + * + * AC_Container provides methods for managing child objects within + * a toolbar or similar container. + * + * vtable at 0x180054ef8 (AC_ToolbarImpl's AC_Container vtable) + */ +class AC_Container { +public: + virtual ~AC_Container() = 0; + + /** + * @brief Get the number of objects in this container + * @return Object count + */ + virtual int objectCount() const = 0; + + /** + * @brief Get object at specified index + * @param index Zero-based index + * @return AC_Object at index or nullptr + */ + virtual AC_Object* objectAtIndex(int index) const = 0; + + /** + * @brief Find object by identity + * @param identity Identity string to find + * @return Found object or nullptr + */ + virtual AC_Object* findObject(const char* identity) const = 0; + + /** + * @brief Find item by identity + * @param identity Identity string to find + * @return Found item or nullptr + */ + virtual AC_Item* findItem(const char* identity) const = 0; + + /** + * @brief Get index of an object + * @param object Object to find + * @return Zero-based index or -1 if not found + */ + virtual int indexOf(AC_Object* object) const = 0; + + /** + * @brief Get index of object by identity + * @param identity Identity string to find + * @return Zero-based index or -1 if not found + */ + virtual int indexOf(const char* identity) const = 0; + + /** + * @brief Check if item is checked + * @param identity Item identity + * @return true if item exists and is checked + */ + virtual bool isChecked(const char* identity) const = 0; + + /** + * @brief Set checked state of item + * @param identity Item identity + * @param checked New checked state + */ + virtual void setChecked(const char* identity, bool checked) = 0; +}; + +/** + * @brief Context-sensitive help interface + * + * AC_Help provides methods for context-sensitive help in toolbars. + * + * vtable at 0x1800550f8 (AC_ToolbarImpl's AC_Help vtable) + */ +class AC_Help { +public: + virtual ~AC_Help(); + + /** + * @brief Help type enumeration + */ + enum cshHelpType { + Type0 = 0, + Type1 = 1, + Type2 = 2, + Type3 = 3, + Type4 = 4, + ToolbarHelp = 5 // Used by AC_ToolbarImpl::cshHelpId + }; + + /** + * @brief Get context-sensitive help ID + * @return Help ID string + */ + virtual QString cshHelpId() = 0; + + /** + * @brief Get help prefix for a type + * @param type Help type + * @return Prefix string + */ + static QString cshHelpPref(cshHelpType type); + + /** + * @brief Get help shortcut string + * @return Shortcut string + */ + static QString cshHelpShortcut(); +}; + +/** + * @brief Abstract base class for toolbars + * + * AC_Toolbar is the abstract interface for toolbar functionality. + * The concrete implementation is AC_ToolbarImpl. + * + * Key features: + * - Item management (insert, remove, find) + * - Configuration save/restore + * - Placeholder system for customization + * - Integration with AC_Manager + * + * vtable at 0x180054eb0 (32 entries for main vtable) + */ +class AC_Toolbar : public AC_Object, public AC_Container, public AC_Help { +public: + virtual ~AC_Toolbar() = 0; + + // ========================================================================= + // Identity and Basic Properties + // ========================================================================= + + /** + * @brief Get the toolbar identity + * @return Reference to identity QString (at offset -72 from AC_Toolbar*) + */ + virtual const QString& identity() const override = 0; + + /** + * @brief Get the toolbar text/title + * @return Toolbar title + */ + virtual QString text() const = 0; + + /** + * @brief Set the toolbar text/title + * @param text New title + */ + virtual void setText(const QString& text) = 0; + + /** + * @brief Check if toolbar is visible + * @return true if visible + */ + virtual bool isVisible() const override = 0; + + /** + * @brief Set toolbar visibility + * @param visible New visibility state + */ + virtual void setVisible(bool visible) override = 0; + + /** + * @brief Check if toolbar is enabled + * @return true if enabled + */ + virtual bool isEnabled() const override = 0; + + /** + * @brief Set toolbar enabled state + * @param enabled New enabled state + */ + virtual void setEnabled(bool enabled) override = 0; + + /** + * @brief Check if toolbar is customizable + * @return true if customization is allowed + */ + virtual bool isCustomizable() const = 0; + + // ========================================================================= + // Manager and Owner + // ========================================================================= + + /** + * @brief Get the associated AC_Manager + * @return Manager pointer or nullptr + */ + virtual AC_Manager* manager() const = 0; + + /** + * @brief Get the owner object + * @return Owner QObject or nullptr + */ + virtual QObject* owner() const = 0; + + /** + * @brief Set the owner object + * @param owner New owner + */ + virtual void setOwner(QObject* owner) = 0; + + // ========================================================================= + // Item Generator + // ========================================================================= + + /** + * @brief Get the toolbar item generator + * @return Item generator or nullptr + */ + virtual AC_ToolbarItemGenerator* itemGenerator() const = 0; + + /** + * @brief Set the toolbar item generator + * @param generator New generator + */ + virtual void setItemGenerator(AC_ToolbarItemGenerator* generator) = 0; + + // ========================================================================= + // Content Management + // ========================================================================= + + /** + * @brief Insert an object from XML element + * @param beforeObject Insert before this object (nullptr = end) + * @param element XML element defining the item + * @return Inserted AC_Object or nullptr + */ + virtual AC_Object* insert(AC_Object* beforeObject, const QDomElement& element) = 0; + + /** + * @brief Insert a separator before an object + * @param beforeObject Insert before this object + * @return Created separator or nullptr + */ + virtual AC_Separator* insertSeparator(AC_Object* beforeObject) = 0; + + /** + * @brief Insert at a named placeholder + * @param placeholder Placeholder name + * @param element XML element defining the item + * @return Inserted AC_Object or nullptr + */ + virtual AC_Object* insertAtPlaceholder(const char* placeholder, + const QDomElement& element) = 0; + + /** + * @brief Insert at placeholder with full parameters + * @param placeholder Placeholder name + * @param responderIdentity Responder identity + * @param actionName Action name + * @param objectName Object name (may be nullptr) + * @param keywords Keywords list (may be nullptr) + * @param visible Initial visibility + * @return Inserted AC_Object or nullptr + */ + virtual AC_Object* insertAtPlaceholder(const char* placeholder, + const QString& responderIdentity, + const QString& actionName, + const char* objectName, + const QList* keywords, + bool visible) = 0; + + /** + * @brief Insert placeholder contents + * @param beforeObject Insert before this object + * @param responderIdentity Responder identity + * @param actionName Action name + * @param objectName Object name + * @param keywords Keywords list + * @param visible Visibility + * @param flag Additional flag + * @return Inserted AC_Item or nullptr + */ + virtual AC_Item* insertPlaceHolderContents(AC_Object* beforeObject, + const QString& responderIdentity, + const QString& actionName, + const char* objectName, + const QList* keywords, + bool visible, + bool flag) = 0; + + /** + * @brief Remove an object by identity + * @param identity Object identity to remove + * @return true if removed successfully + */ + virtual bool removeObject(const char* identity) = 0; + + /** + * @brief Remove a QAction from the toolbar + * @param action Action to remove + */ + virtual void removeAction(QAction* action) = 0; + + /** + * @brief Remove a child QObject + * @param child Child to remove + */ + virtual void removeChild(QObject* child) = 0; + + /** + * @brief Clear all objects from toolbar + */ + virtual void clear() = 0; + + /** + * @brief Clear a specific placeholder + * @param placeholder Placeholder name to clear + */ + virtual void clearPlaceholder(const char* placeholder) = 0; + + /** + * @brief Clear all placeholders + */ + virtual void clearPlaceholders() = 0; + + /** + * @brief Hide all objects + */ + virtual void hideAllObjects() = 0; + + /** + * @brief Remove the toolbar from its parent + */ + virtual void remove() = 0; + + // ========================================================================= + // Configuration + // ========================================================================= + + /** + * @brief Get current configuration + * @return List of item identities in current order + */ + virtual QList config() const = 0; + + /** + * @brief Set configuration from list + * @param config List of item identities + */ + virtual void setConfig(const QList& config) = 0; + + /** + * @brief Get default configuration + * @return List of item identities in default order + */ + virtual QList defaultConfig() const = 0; + + /** + * @brief Set default configuration + * @param config List of item identities for default + */ + virtual void setDefaultConfig(const QList& config) = 0; + + /** + * @brief Check if current config matches default + * @return true if config is default + */ + virtual bool isDefaultConfig() const = 0; + + /** + * @brief Check if a button is in default config + * @param identity Button identity + * @return true if button is default + */ + virtual bool isDefaultButton(const QString& identity) const = 0; + + /** + * @brief Change toolbar content from XML + * @param element New XML definition + * @param addedIds Output list of added IDs + * @param removedIds Output list of removed IDs + * @return true if changed successfully + */ + virtual bool changeContent(const QDomElement& element, + QList* addedIds, + QList* removedIds) = 0; + + /** + * @brief Change toolbar content from name + * @param name Toolbar definition name + * @param addedIds Output list of added IDs + * @param removedIds Output list of removed IDs + * @return true if changed successfully + */ + virtual bool changeContent(const QString& name, + QList* addedIds, + QList* removedIds) = 0; + + // ========================================================================= + // Validation and Updates + // ========================================================================= + + /** + * @brief Validate all content (enable/disable states) + */ + virtual void validateContent() = 0; + + /** + * @brief Validate content if toolbar is visible + */ + virtual void validateContentIfVisible() = 0; + + /** + * @brief Validate tooltip text for all items + */ + virtual void validateTooltipText() = 0; + + /** + * @brief Validate tooltip text if toolbar is visible + */ + virtual void validateTooltipTextIfVisible() = 0; + + /** + * @brief Update separator visibility based on adjacent items + */ + virtual void updateSeparators() = 0; + + /** + * @brief Update customized button states + * @param identity Button identity + * @param oldName Old name + * @param newName New name + */ + virtual void updateCustomizedButtons(const QString& identity, + const QString& oldName, + const QString& newName) = 0; + + // ========================================================================= + // Customization + // ========================================================================= + + /** + * @brief Open customization dialog + * @param parent Parent widget for dialog + */ + virtual void customize(QWidget* parent) = 0; + + /** + * @brief Connect update signals + * @param receiver Receiver object + * @param slot Slot to connect + */ + virtual void connectUpdate(QObject* receiver, const char* slot) = 0; + + // ========================================================================= + // Widget Conversion + // ========================================================================= + + /** + * @brief Get as QWidget + * @return QWidget pointer (this - 128 for AC_ToolbarImpl) + */ + virtual QWidget* toQWidget() = 0; + + /** + * @brief Get as QToolBar + * @return QToolBar pointer + */ + virtual QToolBar* toQToolBar() = 0; + + // ========================================================================= + // Visible Objects + // ========================================================================= + + /** + * @brief Get count of visible objects + * @return Number of visible objects + */ + virtual int visibleObjects() = 0; + + // ========================================================================= + // Translation + // ========================================================================= + + /** + * @brief Translate a string using toolbar's context + * @param text Text to translate + * @return Translated string + */ + virtual QString translate(const QString& text) = 0; +}; + +/** + * @brief Concrete implementation of AC_Container + * + * AC_ContainerImpl provides the base container functionality used by + * AC_ToolbarImpl and other container classes. + * + * sizeof(AC_ContainerImpl) = 0x58 (88 bytes) on x64 + * + * Memory layout: + * - +0x00: vptr (AC_ContainerImpl vtable) + * - +0x08: AC_ManagerImpl* m_manager + * - +0x10: QString m_identity (24 bytes) + * - +0x28: bool m_enabled + * - +0x29: bool m_isToolbar (flag) + * - +0x30: std::vector m_objects + * - +0x48: Internal tree/map for placeholders + */ +class AC_ContainerImpl { +public: + /** + * @brief Construct container with manager + * @param manager Owning manager + * @param isToolbar true if this is a toolbar container + */ + AC_ContainerImpl(AC_ManagerImpl* manager, bool isToolbar); + AC_ContainerImpl(const AC_ContainerImpl& other); + virtual ~AC_ContainerImpl(); + + AC_ContainerImpl& operator=(const AC_ContainerImpl& other); + + // AC_Container interface implementation + int objectCount() const; + AC_Object* objectAtIndex(int index) const; + AC_Object* findObject(const char* identity) const; + AC_Item* findItem(const char* identity) const; + int indexOf(AC_Object* object) const; + int indexOf(const char* identity) const; + bool isChecked(const char* identity) const; + void setChecked(const char* identity, bool checked); + + /** + * @brief Get all objects + * @return Reference to objects vector + */ + const std::vector& objects() const; + + /** + * @brief Update objects from external vector + * @param newObjects New objects to set + */ + void updateObjects(const std::vector& newObjects); + + /** + * @brief Handle child object destruction + * @param object Destroyed object + */ + virtual void childDestroyed(AC_Object* object); + + /** + * @brief Handle child QObject destruction + * @param object Destroyed QObject + */ + virtual void childDestroyed(QObject* object); + + /** + * @brief Handle child insertion + * @param object Inserted object + * @param index Insertion index + */ + virtual void childInsert(AC_Object* object, int index); +}; + +/** + * @brief Concrete implementation of AC_Toolbar + * + * AC_ToolbarImpl inherits from QToolBar and implements AC_Toolbar, AC_Container, + * and AC_Help interfaces. It provides full toolbar functionality including: + * - Dynamic item management + * - Customization support + * - Configuration persistence + * - Context-sensitive help + * + * sizeof(AC_ToolbarImpl) = 0x118 (280 bytes) on x64 + * + * Memory layout: + * - +0x00: QToolBar (vptr for QObject at +0x00, QPaintDevice at +0x10) + * - +0x28: AC_ContainerImpl m_container (88 bytes, ends at +0x80) + * - +0x80: AC_Toolbar vptr (main toolbar interface) + * - +0x88: AC_Container vptr + * - +0x90: AC_Help vptr + * - +0x98: QString m_responderIdentity (24 bytes) + * - +0xB0: std::vector m_defaultConfig (24 bytes) + * - +0xC8: bool m_isCustomizable + * - +0xD0: void* m_customizeButton + * - +0xD8: void* m_unknown1 + * - +0xE0: QObject* m_owner + * - +0xE8: QWeakPointer m_mainWindow (16 bytes) + * - +0xF8: float m_scaleFactor (default 1.0) + * - +0x100: QString m_translationContext (24 bytes) + * + * Vtable addresses: + * - QObject vtable: 0x180054c90 + * - QPaintDevice vtable: 0x180054e70 + * - AC_Toolbar vtable: 0x180054eb0 + * - AC_Container vtable: 0x180054ef8 + * - AC_Help vtable: 0x1800550f8 + * + * Signals: + * - customized(QString) - emitted when toolbar is customized + */ +class AC_ToolbarImpl : public QToolBar { + Q_OBJECT + +public: + /** + * @brief Construct AC_ToolbarImpl + * @param owner Owner QObject + * @param title Toolbar title + * @param mainWindow Parent main window + * @param objectName Object name (C-string) + * @param manager Owning AC_ManagerImpl + * @param element XML element defining toolbar content + * @param defaultConfig Default configuration (may be nullptr) + */ + AC_ToolbarImpl(QObject* owner, const QString& title, QMainWindow* mainWindow, + const char* objectName, AC_ManagerImpl* manager, + const QDomElement& element, const QList* defaultConfig); + virtual ~AC_ToolbarImpl() override; + + // ========================================================================= + // AC_Object interface + // ========================================================================= + const QString& identity() const; + bool isVisible() const; + void setVisible(bool visible); + bool isEnabled() const; + void setEnabled(bool enabled); + const AC_Item* toItem() const { return nullptr; } + const AC_Separator* toSeparator() const { return nullptr; } + const AC_Toolbar* toToolbar() const; + + // ========================================================================= + // AC_Container interface + // ========================================================================= + int objectCount() const; + AC_Object* objectAtIndex(int index) const; + AC_Object* findObject(const char* identity) const; + AC_Item* findItem(const char* identity) const; + int indexOf(AC_Object* object) const; + int indexOf(const char* identity) const; + bool isChecked(const char* identity) const; + void setChecked(const char* identity, bool checked); + + // ========================================================================= + // AC_Help interface + // ========================================================================= + QString cshHelpId(); + + // ========================================================================= + // AC_Toolbar interface + // ========================================================================= + QString text() const; + void setText(const QString& text); + bool isCustomizable() const; + AC_Manager* manager() const; + QObject* owner() const; + void setOwner(QObject* owner); + AC_ToolbarItemGenerator* itemGenerator() const; + void setItemGenerator(AC_ToolbarItemGenerator* generator); + + AC_Object* insert(AC_Object* beforeObject, const QDomElement& element); + AC_Separator* insertSeparator(AC_Object* beforeObject); + AC_Object* insertAtPlaceholder(const char* placeholder, const QDomElement& element); + AC_Object* insertAtPlaceholder(const char* placeholder, + const QString& responderIdentity, + const QString& actionName, + const char* objectName, + const QList* keywords, + bool visible); + AC_Item* insertPlaceHolderContents(AC_Object* beforeObject, + const QString& responderIdentity, + const QString& actionName, + const char* objectName, + const QList* keywords, + bool visible, + bool flag); + + bool removeObject(const char* identity); + void removeAction(QAction* action); + void removeChild(QObject* child); + void clear(); + void clearPlaceholder(const char* placeholder); + void clearPlaceholders(); + void hideAllObjects(); + void remove(); + + QList config() const; + void setConfig(const QList& config); + QList defaultConfig() const; + void setDefaultConfig(const QList& config); + bool isDefaultConfig() const; + bool isDefaultButton(const QString& identity) const; + bool changeContent(const QDomElement& element, + QList* addedIds, + QList* removedIds); + bool changeContent(const QString& name, + QList* addedIds, + QList* removedIds); + + void validateContent(); + void validateContentIfVisible(); + void validateTooltipText(); + void validateTooltipTextIfVisible(); + void updateSeparators(); + void updateCustomizedButtons(const QString& identity, + const QString& oldName, + const QString& newName); + + void customize(QWidget* parent); + void connectUpdate(QObject* receiver, const char* slot); + + QWidget* toQWidget(); + QToolBar* toQToolBar(); + int visibleObjects(); + QString translate(const QString& text); + + // ========================================================================= + // Static helpers + // ========================================================================= + + /** + * @brief Translation helper + */ + +signals: + /** + * @brief Emitted when toolbar is customized + * @param identity Toolbar identity + */ + void customized(QString identity); + +protected: + /** + * @brief Handle show events + */ + virtual void showEvent(QShowEvent* event) override; + + /** + * @brief Create toolbar content from XML + * @param element XML element defining content + */ + void create(const QDomElement& element); + + /** + * @brief Create toolbar content with default config + * @param element XML element + * @param defaultConfig Default configuration + */ + void create(const QDomElement& element, const QList& defaultConfig); + + /** + * @brief Create the customize button + */ + void createCustomizeButton(); + +private slots: + /** + * @brief Handle owner destruction + */ + void ownerDestroyed(); +}; + +/** + * @brief Interface for generating custom toolbar items + * + * Implement this interface to provide custom item creation logic + * for toolbars managed by AC_Manager. + */ +class AC_ToolbarItemGenerator { +public: + virtual ~AC_ToolbarItemGenerator() = default; + + /** + * @brief Create an item for the given identity + * @param identity Item identity + * @param parent Parent toolbar + * @return Created item or nullptr + */ + virtual AC_Item* createItem(const QString& identity, AC_ToolbarImpl* parent) = 0; +}; + +// ============================================================================ +// Offset Constants (for reference/debugging) +// ============================================================================ +namespace AC_ToolbarImpl_Offsets { + // Offsets from QToolBar base + constexpr size_t ContainerImpl = 0x28; // 40 - AC_ContainerImpl embedded + constexpr size_t ToolbarVtable = 0x80; // 128 - AC_Toolbar vptr + constexpr size_t ContainerVtable = 0x88; // 136 - AC_Container vptr + constexpr size_t HelpVtable = 0x90; // 144 - AC_Help vptr + constexpr size_t ResponderIdentity = 0x98; // 152 - QString + constexpr size_t DefaultConfigVector = 0xB0; // 176 - std::vector + constexpr size_t IsCustomizable = 0xC8; // 200 - bool + constexpr size_t CustomizeButton = 0xD0; // 208 - void* + constexpr size_t Owner = 0xE0; // 224 - QObject* + constexpr size_t MainWindowWeakPtr = 0xE8; // 232 - QWeakPointer + constexpr size_t ScaleFactor = 0xF8; // 248 - float (default 1.0) + constexpr size_t TranslationContext = 0x100; // 256 - QString +} + +namespace AC_ContainerImpl_Offsets { + constexpr size_t Manager = 0x08; // 8 - AC_ManagerImpl* + constexpr size_t Identity = 0x10; // 16 - QString + constexpr size_t Enabled = 0x28; // 40 - bool + constexpr size_t IsToolbar = 0x29; // 41 - bool + constexpr size_t Objects = 0x30; // 48 - std::vector + constexpr size_t Placeholders = 0x48; // 72 - Internal tree/map +} + diff --git a/framework/include/toon_boom/toon_boom_layout.hpp b/framework/include/toon_boom/toon_boom_layout.hpp index 20504ec..1724d88 100644 --- a/framework/include/toon_boom/toon_boom_layout.hpp +++ b/framework/include/toon_boom/toon_boom_layout.hpp @@ -14,6 +14,7 @@ #ifndef TOON_BOOM_LAYOUT_HPP #define TOON_BOOM_LAYOUT_HPP +#include "./toolbar.hpp" #include #include #include @@ -46,9 +47,7 @@ class TULayoutDisplayTools; class TULayout; class AC_Manager; class AC_Menu; -class AC_Toolbar; class AC_ActionInfo; -class AC_ToolbarItemGenerator; class AC_Responder; class AC_ResponderTemplate; class TUWidgetLayoutView; @@ -59,64 +58,43 @@ class UI_Splitter; class WID_VBoxLayout; class WID_HBoxLayout; -/** - * @brief Result code for action command handling - */ -enum class AC_Result { - NotHandled = 0, - Handled = 1, - Error = 2 -}; - // ============================================================================= -// AC_Responder, AC_ResponderTemplate, AC_ResponderTemplateWidget +// AC_Responder - Defined in ac_manager.hpp // ============================================================================= // -// These classes are implemented in Toon Boom DLLs (ToonBoomActionManager.dll -// or similar). Since we don't have access to those libraries for linking, -// we provide forward declarations only. +// The AC_Responder interface and AC_ResponderBase convenience class are +// defined in ac_manager.hpp. Include that header to create custom responders. // -// For reference, the full interface is documented in RE/ToonBoomLayout_Classes.md +// To create a custom responder: +// 1. Inherit from AC_ResponderBase (provides default implementations) +// 2. Override perform() to handle actions via Qt slots +// 3. Register with AC_Manager::registerResponder() +// +// Example: +// class MyResponder : public QObject, public AC_ResponderBase { +// Q_OBJECT +// public: +// MyResponder(AC_Manager* mgr) : AC_ResponderBase("myResponder", mgr) { +// mgr->registerResponder(this, nullptr); +// } +// public slots: +// void onActionDoSomething() { /* handle action */ } +// }; +// +// Toon Boom's internal classes (for reference only - cannot be extended): +// - AC_ResponderTemplate: Toon Boom's internal base class +// - AC_ResponderTemplateWidget: Template combining QWidget with responder // // Key vtable addresses (in ToonBoomLayout.dll): // - AC_Responder vtable: 0x18004cd28 // - AC_ResponderTemplate vtable: 0x18004cdc8 // - AC_ResponderTemplateWidget vtable: 0x18004ce68 -// -// AC_Responder is a pure abstract interface with the following virtual methods: -// - perform(AC_ActionInfo*) -> AC_Result -// - performDownToChildren(AC_ActionInfo*) -> AC_Result -// - parentResponder() -> AC_Responder* -// - proxyResponder() -> AC_Responder* -// - acceptsFirstResponder() -> bool -// - acceptsSelectionResponder() -> bool -// - becomeFirstResponder() -> bool -// - becomeSelectionResponder() -> bool -// - resignFirstResponder() -> bool -// - handleShortcuts() const -> bool -// - shouldReceiveMessages() const -> bool -// - responderIdentity() const -> const QString& -// - responderDescription() const -> const QString& -// - setResponderDescription(const QString&) -> void -// - actionManager() const -> AC_Manager* -// -// AC_ResponderTemplate (sizeof 0x38): -// - Inherits AC_Responder -// - +0x08: QString m_identity -// - +0x20: QString m_description -// - +0x30: AC_Manager* m_manager -// -// AC_ResponderTemplateWidget (sizeof ~0x68 for T=QWidget): -// - Inherits T (QWidget, QFrame, etc.) and AC_ResponderTemplate -// - Combines a Qt widget with action responder capabilities // ============================================================================= -// Forward declarations only - implemented in Toon Boom DLLs -class AC_Responder; +// Toon Boom internal classes - forward declarations only +// These are implemented in Toon Boom DLLs and cannot be extended by users class AC_ResponderTemplate; -// Template class - forward declaration for common instantiations -// The actual template is implemented in Toon Boom DLLs template class AC_ResponderTemplateWidget; @@ -261,7 +239,31 @@ public: virtual void setMenu(AC_Manager *manager, const char *menuName, MenuType type); // slot 8 virtual void setMenu(AC_Menu *menu, MenuType type); // slot 9 virtual AC_Menu *menu(MenuType type); // slot 10 + + /** + * @brief Returns the QDomElement defining this view's toolbar + * + * Override this method to provide a view-specific toolbar. The default + * implementation returns an empty QDomElement (no toolbar). + * + * To access the AC_Manager for toolbar lookup, use: + * @code + * QDomElement MyView::toolbar() { + * AC_Manager* manager = TULayoutView_getActionManager(this); + * if (manager) { + * // manager->getToolbarElement() at vtable[52] + * // Returns QDomElement for a named toolbar + * } + * return QDomElement(); + * } + * @endcode + * + * @return QDomElement defining toolbar, or empty element for no toolbar + * @see TULayoutView_getActionManager() + * @see docs/TULayoutView_Toolbar_Integration.md + */ virtual QDomElement toolbar(); // slot 11 + virtual void setToolbarInfo(const LAY_ToolbarInfo &info); // slot 12 virtual void connectView() {} // slot 13 (empty impl) virtual void disconnectView() {} // slot 14 (empty impl) @@ -324,42 +326,94 @@ private: // TUWidgetLayoutView // ============================================================================= // -// TUWidgetLayoutView is implemented in ToonBoomLayout.dll. It inherits from -// AC_ResponderTemplateWidget and embeds a TULayoutView at offset +0x68. +// TUWidgetLayoutView is a concrete layout view class implemented in +// ToonBoomLayout.dll. It combines a QWidget (for UI display) with both +// AC_Responder capabilities (for action handling) and TULayoutView +// functionality (for the layout system). // -// Since the base classes are implemented in Toon Boom DLLs, we cannot define -// a compilable C++ class here. Use this as a reference for the memory layout -// when working with TUWidgetLayoutView pointers obtained from the application. +// INHERITANCE HIERARCHY: +// QWidget +// └── AC_ResponderTemplateWidget (multiple inheritance) +// ├── QWidget base +// └── AC_ResponderTemplate (mixin at +0x28) +// └── TUWidgetLayoutView +// └── TULayoutView (embedded at +0x68) // -// Memory layout (x64 MSVC): -// - +0x00: vptr (QObject) - from AC_ResponderTemplateWidget -// - +0x10: vptr (QPaintDevice) -// - +0x18-0x27: QWidget members -// - +0x28: vptr (AC_ResponderTemplateWidget) -// - +0x30: AC_Manager* m_actionManager -// - +0x38: QString m_responderIdentity -// - +0x50: QString m_responderDescription -// - +0x68: vptr (TULayoutView) - TULayoutView base starts here -// - +0x70: QString m_internalName (from TULayoutView) -// - +0x88: LAY_ToolbarInfo m_toolbarInfo (from TULayoutView) -// - +0xF0: AC_Menu* m_menuByType[2] (from TULayoutView) -// - +0x100: bool m_initializedFromCopy (from TULayoutView) -// - +0x108: QString m_caption (from TULayoutView) +// VTABLE STRUCTURE (4 vtables due to multiple inheritance): +// +0x00: vptr[0] - QObject vtable (includes QWidget virtuals) +// +0x10: vptr[1] - QPaintDevice vtable +// +0x28: vptr[2] - AC_ResponderTemplateWidget / AC_Responder vtable +// +0x68: vptr[3] - TULayoutView vtable // -// sizeof(TUWidgetLayoutView) ≈ 0x120 (288 bytes) on x64 +// MEMORY LAYOUT (x64 MSVC, sizeof = 0x120 / 288 bytes): +// +0x00: vptr (QObject) +// +0x08: QObjectData* d_ptr (QObject) +// +0x10: vptr (QPaintDevice) +// +0x18: [QWidget internal data ~16 bytes] +// +0x28: vptr (AC_ResponderTemplateWidget) +// +0x30: AC_Manager* m_actionManager +// +0x38: QString m_responderIdentity (24 bytes) +// +0x50: QString m_responderDescription (24 bytes) +// +0x68: vptr (TULayoutView) ─┐ +// +0x70: QString m_internalName │ TULayoutView +// +0x88: LAY_ToolbarInfo m_toolbarInfo │ embedded +// +0xF0: AC_Menu* m_menuByType[2] │ (184 bytes) +// +0x100: bool m_initializedFromCopy │ +// +0x108: QString m_caption ─┘ // -// Key methods (in ToonBoomLayout.dll): -// - Constructor at 0x1800300A0 -// - Destructor at 0x180030480 -// - getWidget() at 0x180030E90 - returns (this - 104) from TULayoutView* +// KEY VIRTUAL METHOD OVERRIDES IN TUWIDGETLAYOUTVIEW: +// From TULayoutView: +// - widget() - pure virtual, not implemented (returns _purecall) +// - getWidget() const/non-const - returns (this - 104), i.e., the QWidget* +// - triggerMenuChanged() - emits menuChanged() signal on QWidget +// - isTULayoutView() - empty implementation (RTTI marker) +// From QWidget: +// - mousePressEvent() - accepts event and sets focus (Qt::MouseFocusReason) +// - metaObject(), qt_metacast(), qt_metacall() - Qt meta-object support // -// To get TULayoutView* from TUWidgetLayoutView*: -// TULayoutView* layoutView = reinterpret_cast( -// reinterpret_cast(widgetLayoutView) + 104); +// SIGNALS (Qt): +// - menuChanged() - emitted by triggerMenuChanged() // -// To get TUWidgetLayoutView* from TULayoutView*: -// TUWidgetLayoutView* widget = reinterpret_cast( -// reinterpret_cast(layoutView) - 104); +// CONSTRUCTOR PARAMETERS: +// TUWidgetLayoutView(AC_Manager* manager, const QString& objectName, +// QWidget* parent, const char* className, +// Qt::WindowFlags flags) +// +// CONSTRUCTION SEQUENCE: +// 1. AC_ResponderTemplateWidget ctor (parent, flags, objectName) +// 2. TULayoutView default ctor (at this+104) +// 3. Set all 4 vtables to TUWidgetLayoutView vtables +// 4. QWidget::setMinimumWidth(150) +// 5. If parent and manager: call initActionManager(manager) +// Else: store manager at +0x30 +// +// DESTRUCTION SEQUENCE: +// 1. Reset vtables +// 2. Destroy TULayoutView::m_caption at +0x108 +// 3. Destroy TULayoutView::m_toolbarInfo at +0x88 +// 4. Destroy TULayoutView::m_internalName at +0x70 +// 5. Call AC_ResponderTemplateWidget dtor +// +// EXPORTED METHODS (ToonBoomLayout.dll): +// - ??0TUWidgetLayoutView@@QEAA@... - Constructor +// - ??1TUWidgetLayoutView@@UEAA@XZ - Destructor +// - ?getWidget@TUWidgetLayoutView@@UEAA/UEBAPEAVQWidget@@XZ - Get QWidget* +// - ?mousePressEvent@TUWidgetLayoutView@@MEAAXPEAVQMouseEvent@@@Z +// - ?triggerMenuChanged@TUWidgetLayoutView@@MEAAXXZ +// - ?menuChanged@TUWidgetLayoutView@@QEAAXXZ - Qt signal +// - ?metaObject/qt_metacast/qt_metacall - Qt meta-object methods +// - ?tr@TUWidgetLayoutView@@SA?AVQString@@PEBD0H@Z - Translation +// +// USAGE NOTES: +// Since TUWidgetLayoutView has external base classes, you cannot directly +// subclass it in user code. Instead: +// 1. Obtain TUWidgetLayoutView* from the layout system +// 2. Use helper functions to convert between pointer types +// 3. Access TULayoutView virtuals through TULayoutView_getLayoutView() +// 4. Access QWidget through TUWidgetLayoutView_getWidget() +// +// @see TULayoutView_getActionManager() for accessing AC_Manager* +// @see docs/TUWidgetLayoutView_Analysis.md for detailed analysis // ============================================================================= // Forward declaration - implemented in ToonBoomLayout.dll @@ -393,6 +447,39 @@ inline QWidget *TUWidgetLayoutView_getWidget(TUWidgetLayoutView *widget) { return reinterpret_cast(widget); } +/** + * @brief Get AC_Manager* from a TULayoutView* embedded in TUWidgetLayoutView + * + * This function provides access to the AC_Manager instance for views that + * inherit from TUWidgetLayoutView. The AC_Manager is stored in the + * AC_ResponderTemplateWidget base class at offset +48, which is + * offset -56 from the embedded TULayoutView*. + * + * @note This only works for TULayoutView instances that are embedded in + * TUWidgetLayoutView. Direct TULayoutView subclasses do NOT have + * an AC_Manager member. + * + * @param view Pointer to TULayoutView (must be embedded in TUWidgetLayoutView) + * @return AC_Manager* or nullptr if invalid + * + * @code + * // Example usage in a toolbar() override: + * QDomElement MyView::toolbar() { + * AC_Manager* manager = TULayoutView_getActionManager(this); + * if (manager) { + * // Use manager->getToolbarElement(...) to get toolbar definition + * } + * return QDomElement(); + * } + * @endcode + */ +inline AC_Manager *TULayoutView_getActionManager(TULayoutView *view) { + // AC_Manager is at offset +48 in TUWidgetLayoutView + // TULayoutView is embedded at offset +104 in TUWidgetLayoutView + // So from TULayoutView*, AC_Manager** is at offset -56 (= 48 - 104) + return *reinterpret_cast(reinterpret_cast(view) - 56); +} + /** * @brief Container widget that holds 1-2 TULayoutView instances *