From 044a9b60dd4161001f0f230a6663af760ea36cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=99=E2=97=A6=20The=20Tablet=20=E2=9D=80=20GamerGirla?= =?UTF-8?q?ndCo=20=E2=97=A6=E2=9D=A7?= Date: Mon, 12 Jan 2026 21:39:55 -0500 Subject: [PATCH] docs: add docs pertaining to the ac_responder system and view toolbars --- docs/AC_Responder_System.md | 529 +++++++++++++++++++++++ docs/TULayoutView_Toolbar_Integration.md | 356 +++++++++++++++ docs/TUWidgetLayoutView_Analysis.md | 263 +++++++++++ docs/ToonBoomActionManager_Classes.md | 304 +++++++++++++ 4 files changed, 1452 insertions(+) create mode 100644 docs/AC_Responder_System.md create mode 100644 docs/TULayoutView_Toolbar_Integration.md create mode 100644 docs/TUWidgetLayoutView_Analysis.md create mode 100644 docs/ToonBoomActionManager_Classes.md diff --git a/docs/AC_Responder_System.md b/docs/AC_Responder_System.md new file mode 100644 index 0000000..99e899e --- /dev/null +++ b/docs/AC_Responder_System.md @@ -0,0 +1,529 @@ +# AC_Responder System - Toolbar Button Click Handling + +This document explains how toolbar button clicks are routed to responders in Toon Boom Harmony Premium and Storyboard Pro, and how to create custom responders to handle actions. + +**IDA Databases:** +- `RE/ToonBoomActionManager.dll.i64` - AC_Manager and AC_Responder implementations +- `RE/ToonBoomLayout.dll.i64` - Layout responder implementations +- `RE/HarmonyPremium.exe.i64` - Application-specific responders + +## Overview + +Toon Boom uses a **Responder Chain** pattern (similar to macOS/Cocoa) for handling toolbar button clicks: + +1. **Toolbar XML** defines button items with a `responder` attribute and a `slot` attribute +2. When clicked, `AC_Manager` looks up the responder by name +3. The responder's slot is invoked via Qt's meta-object system +4. If the responder doesn't handle it, the action propagates up the chain + +## Toolbar XML Structure + +From `toolbars.xml`: + +```xml + + + + + + + + + + +``` + +### Key XML Attributes + +| Attribute | Description | +|-----------|-------------| +| `id` | Unique identifier for the toolbar item | +| `responder` | Name of the responder to handle clicks | +| `slot` | Qt slot signature to invoke | +| `icon` | Path to icon image | +| `text` | Display text / tooltip | +| `checkable` | If "true", button toggles on/off | +| `condition` | Expression for conditional visibility | +| `itemParameter` | Extra parameter passed to slot | +| `shortcut` | Keyboard shortcut name | + +### Common Responder Names + +| Responder | Description | +|-----------|-------------| +| `owner` | The QObject that "owns" the toolbar (usually the view) | +| `sceneUI` | Main scene UI responder (Harmony_SceneUI / SBoard_SceneUI) | +| `scene` | Scene data responder | +| `selection` | Selection responder (for cut/copy/paste) | +| `timelineView` | Timeline view responder | +| `xsheetView` | Xsheet view responder | +| `onionSkinResponder` | Onion skin feature responder | +| `scriptResponder` | Script execution responder | +| `artLayerResponder` | Art layer selection responder | + +## The Responder Chain + +When a toolbar button is clicked: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 1. User clicks toolbar button │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 2. AC_ToolbarItemImpl triggers AC_ActionInfo │ +│ - Creates AC_ActionInfo with slot name, parameters │ +│ - Gets responder name from XML attribute │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 3. AC_Manager::responder(name) looks up responder │ +│ - "owner" → toolbar's owner QObject cast to AC_Responder │ +│ - other names → registered responder by identity │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 4. AC_Responder::perform(AC_ActionInfo*) is called │ +│ - Sets responder in action info │ +│ - Invokes slot via QMetaObject::invokeMethod │ +│ - Returns AC_Result (Handled, NotHandled, Error) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 5. If NotHandled, propagate up chain │ +│ - Try parent responder via parentResponder() │ +│ - Eventually reaches applicationResponder │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## AC_Responder Interface + +The `AC_Responder` abstract interface defines how objects participate in the responder chain: + +```cpp +class AC_Responder { +public: + virtual ~AC_Responder() = 0; + + // Identity + virtual const QString& responderIdentity() const = 0; + virtual const QString& responderDescription() const = 0; + virtual void setResponderDescription(const QString& desc) = 0; + + // Chain navigation + virtual AC_Responder* parentResponder() = 0; + virtual AC_Responder* proxyResponder() = 0; + + // First responder status (keyboard focus) + virtual bool acceptsFirstResponder() = 0; + virtual bool becomeFirstResponder() = 0; + virtual bool resignFirstResponder() = 0; + + // Selection responder status + virtual bool acceptsSelectionResponder() = 0; + virtual bool becomeSelectionResponder() = 0; + virtual bool resignSelectionResponder() = 0; + + // Action handling + virtual AC_Result perform(AC_ActionInfo* info) = 0; + virtual AC_Result performDownToChildren(AC_ActionInfo* info) = 0; + virtual bool shouldReceiveMessages() const = 0; + virtual bool handleShortcuts() const = 0; + + // Event handling + virtual AC_Result handleEvent(QEvent* event) = 0; + + // Manager access + virtual AC_Manager* actionManager() const = 0; +}; +``` + +## AC_ResponderBase Helper Class + +The framework provides `AC_ResponderBase`, a concrete helper class that implements the `AC_Responder` interface with sensible defaults. This makes it easy to create custom responders without implementing every virtual method: + +```cpp +// From ac_manager.hpp +class AC_ResponderBase : public AC_Responder { +public: + AC_ResponderBase(const QString& identity, AC_Manager* manager = nullptr, + AC_Responder* parent = nullptr); + virtual ~AC_ResponderBase() = default; + + // Identity - stored internally + const QString& responderIdentity() const override; + const QString& responderDescription() const override; + void setResponderDescription(const QString& desc) override; + + // Chain - returns parent passed to constructor + AC_Responder* parentResponder() override; + AC_Responder* proxyResponder() override; // returns nullptr + + // First responder - all return false by default + bool acceptsFirstResponder() override; + bool becomeFirstResponder() override; + bool resignFirstResponder() override; + + // Selection responder - all return false by default + bool acceptsSelectionResponder() override; + bool becomeSelectionResponder() override; + bool resignSelectionResponder() override; + + // Action handling - return NotHandled by default + AC_Result perform(AC_ActionInfo* info) override; + AC_Result performDownToChildren(AC_ActionInfo* info) override; + + // Message handling - return true by default + bool shouldReceiveMessages() const override; + bool handleShortcuts() const override; + + // Event handling - returns NotHandled + AC_Result handleEvent(QEvent* event) override; + + // Manager access + AC_Manager* actionManager() const override; + void setActionManager(AC_Manager* manager); + +protected: + QString m_identity; + QString m_description; + AC_Manager* m_manager; + AC_Responder* m_parentResponder; +}; +``` + +## Creating a Custom Responder + +### Method 1: Using AC_ResponderBase with QObject + +The simplest approach is to create a class that inherits from both `QObject` (for Qt slots) and `AC_ResponderBase` (for responder functionality): + +```cpp +#include + +class MyResponder : public QObject, public AC_ResponderBase { + Q_OBJECT + +public: + MyResponder(const QString& identity, AC_Manager* manager, QObject* parent = nullptr) + : QObject(parent) + , AC_ResponderBase(identity, manager) + { + // Register with AC_Manager + manager->registerResponder(this, nullptr); + } + + ~MyResponder() { + if (AC_Manager* mgr = actionManager()) { + mgr->unregisterResponder(this); + } + } + +public slots: + // Slot that matches toolbar XML slot signature + void onActionMyCustomAction() { + qDebug() << "My custom action triggered!"; + } + + void onActionWithParameter(const QString& param) { + qDebug() << "Action with parameter:" << param; + } + + // Validate slot - called before action to update enabled/checked state + void onActionMyCustomActionValidate(AC_ActionInfo* info) { + // Enable based on some condition + info->setEnabled(canPerformAction()); + info->setChecked(isActionActive()); + } + +private: + bool canPerformAction() const { return true; } + bool isActionActive() const { return false; } +}; +``` + +### Method 2: Widget-Based Responder + +For a widget that also acts as a responder: + +```cpp +#include +#include + +class MyCustomWidget : public QWidget, public AC_ResponderBase { + Q_OBJECT + +public: + MyCustomWidget(const QString& identity, AC_Manager* manager, QWidget* parent = nullptr) + : QWidget(parent) + , AC_ResponderBase(identity, manager) + { + // Register with AC_Manager, passing 'this' as the associated widget + manager->registerResponder(this, this); + } + + ~MyCustomWidget() { + if (AC_Manager* mgr = actionManager()) { + mgr->unregisterResponder(this); + } + } + +public slots: + void onActionWidgetAction() { + qDebug() << "Widget action triggered!"; + } + + void onActionWidgetActionValidate(AC_ActionInfo* info) { + info->setEnabled(isEnabled()); + } +}; +``` + +### Method 3: Implementing AC_Responder Directly + +For full control over the responder interface: + +```cpp +class MyFullResponder : public QObject, public AC_Responder { + Q_OBJECT + +public: + MyFullResponder(const QString& identity, AC_Manager* manager) + : m_identity(identity), m_manager(manager) + { + manager->registerResponder(this, nullptr); + } + + // AC_Responder interface - implement all methods + 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 nullptr; } + + bool acceptsFirstResponder() override { return false; } + bool becomeFirstResponder() override { return false; } + bool resignFirstResponder() override { return false; } + + bool acceptsSelectionResponder() override { return false; } + bool becomeSelectionResponder() override { return false; } + bool resignSelectionResponder() override { return false; } + + AC_Result perform(AC_ActionInfo* info) override { + // Use Qt meta-object to invoke the slot by name + // AC_ActionInfo contains slot name and parameters + return AC_Result::NotHandled; + } + + AC_Result performDownToChildren(AC_ActionInfo* info) override { + return AC_Result::NotHandled; + } + + bool shouldReceiveMessages() const override { return true; } + bool handleShortcuts() const override { return true; } + + AC_Result handleEvent(QEvent*) override { return AC_Result::NotHandled; } + + AC_Manager* actionManager() const override { return m_manager; } + +public slots: + void onActionDoSomething() { + // Handle the action + } + +private: + QString m_identity; + QString m_description; + AC_Manager* m_manager; +}; +``` + +## AC_ActionInfo Structure + +When an action is triggered, an `AC_ActionInfo` object is created: + +```cpp +class AC_ActionInfo : public QObject { + // Key methods + const QString& slot() const; // Slot signature to invoke + const QString& text() const; // Action display text + QVariant itemParameter() const; // Extra parameter from XML + + // State methods + bool isEnabled() const; + void setEnabled(bool enabled); + bool isChecked() const; + void setChecked(bool checked); + + // Responder info + AC_Responder* responder() const; + void setResponder(AC_Responder* resp); +}; +``` + +## Validation Pattern + +Before displaying a menu or when the UI updates, Toon Boom calls validation methods: + +1. For each toolbar item, look for a slot named `Validate(AC_ActionInfo*)` +2. If found, invoke it to update enabled/checked state +3. Display the item according to the updated state + +Example from `TULayoutManager`: + +```cpp +// Address: 0x7ffa0be52e60 +void TULayoutManager::onActionFullscreenValidate(AC_ActionInfo* info) { + info->setVisible(true); // vtable[7] + info->setEnabled(true); // AC_ActionData::setEnabled +} +``` + +## Registration with AC_Manager + +Responders must be registered to be found by name: + +```cpp +AC_Manager* manager = PLUG_Services::getActionManager(); + +// Register a responder +bool success = manager->registerResponder(myResponder, myWidget); + +// Unregister when done +manager->unregisterResponder(myResponder); + +// Find a responder by identity +AC_Responder* resp = manager->responder("myResponderIdentity"); + +// Get responder for a widget +AC_Responder* widgetResp = manager->responderForWidget(someWidget); +``` + +## Example: Adding a Custom Toolbar Button + +### Step 1: Define in XML (or load programmatically) + +```xml + + + +``` + +### Step 2: Create and Register Responder + +```cpp +class MyToolResponder : public QObject, public AC_ResponderBase { + Q_OBJECT + +public: + MyToolResponder(AC_Manager* manager) + : QObject() + , AC_ResponderBase("myCustomResponder", manager) + { + manager->registerResponder(this, nullptr); + } + + ~MyToolResponder() { + if (AC_Manager* mgr = actionManager()) { + mgr->unregisterResponder(this); + } + } + +public slots: + void onActionMyAction() { + qDebug() << "My custom toolbar button clicked!"; + // Do your custom action here + } + + void onActionMyActionValidate(AC_ActionInfo* info) { + info->setEnabled(true); + } +}; +``` + +### Step 3: Initialize + +```cpp +void initializeMyToolbar() { + AC_Manager* manager = PLUG_Services::getActionManager(); + + // Create and register responder + MyToolResponder* responder = new MyToolResponder(manager); + + // Load toolbar XML + QDomDocument doc; + doc.setContent(myToolbarXmlString); + QList ids; + manager->loadToolbars(doc.documentElement(), ids); + + // Show the toolbar + TULayoutManager* layoutManager = getLayoutManager(); + layoutManager->showToolbar("MyToolbar", true); +} +``` + +## Owner Responder Pattern + +When `responder="owner"` is used, the toolbar's owner QObject is used: + +```cpp +// In AC_ToolbarImpl, owner is stored at offset +0xE0 +void AC_ToolbarImpl::setOwner(QObject* owner) { + m_owner = owner; + connect(owner, &QObject::destroyed, this, &AC_ToolbarImpl::ownerDestroyed); +} + +// When resolving "owner" responder: +if (responderName == "owner") { + QObject* owner = toolbar->owner(); + return qobject_cast(owner); +} +``` + +This pattern is commonly used for view-specific toolbars where the view itself handles the actions. + +## Key Addresses + +### ToonBoomActionManager.dll +| Symbol | Address | Description | +|--------|---------|-------------| +| AC_ManagerImpl::registerResponder | (via vtable) | Registers responder | +| AC_ManagerImpl::unregisterResponder | (via vtable) | Unregisters responder | +| AC_ManagerImpl::responder | (via vtable) | Finds responder by name | + +## Summary + +To respond to toolbar button clicks: + +1. **Create a class** that inherits from `QObject` and `AC_ResponderBase` (or implement `AC_Responder` directly) +2. **Register** with `AC_Manager::registerResponder(responder, widget)` +3. **Define slots** matching the toolbar XML `slot` attribute signatures +4. **Optionally define validate slots** (`Validate(AC_ActionInfo*)`) for state updates +5. **Reference your responder** by identity in the toolbar XML `responder` attribute diff --git a/docs/TULayoutView_Toolbar_Integration.md b/docs/TULayoutView_Toolbar_Integration.md new file mode 100644 index 0000000..d94f134 --- /dev/null +++ b/docs/TULayoutView_Toolbar_Integration.md @@ -0,0 +1,356 @@ +# TULayoutView Toolbar Integration in Toon Boom + +This document explains how toolbars are created, managed, and displayed within TULayoutView instances in Toon Boom Harmony Premium and Storyboard Pro. + +**IDA Databases:** +- `RE/HarmonyPremium.exe.i64` - Main application +- `RE/ToonBoomActionManager.dll.i64` - AC_Toolbar and AC_Manager implementations +- `RE/ToonBoomLayout.dll.i64` - TULayoutView and TULayoutFrame implementations + +## Overview + +Toon Boom uses a two-tier toolbar system: + +1. **Global Toolbars** - Application-wide toolbars (FileToolbar, EditToolbar, DrawingToolToolbar, etc.) +2. **View-Specific Toolbars** - Toolbars that appear when a specific view has focus (DrawingViewToolbar, TimelineViewToolbar, CameraViewToolbar, etc.) + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ TULayoutManager │ +│ - Manages all frames, areas, and global toolbars │ +│ - Holds reference to AC_Manager at offset +344 │ +│ - showToolbar() at vtable+416 creates/shows toolbars by name │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ TULayoutFrame │ +│ - Contains TULayoutMainWindow for toolbar docking │ +│ - showViewToolBar() displays view-specific toolbar │ +│ - Stores LAY_ToolbarInfo per view for configuration │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ TULayoutViewHolder │ +│ - Contains 1-2 TULayoutView instances │ +│ - Notifies frame when active view changes │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ TULayoutView │ +│ - Abstract base class for all views │ +│ - toolbar() virtual method returns QDomElement │ +│ - setToolbarInfo() receives LAY_ToolbarInfo │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Toolbar Definition and Creation Flow + +### 1. Toolbar XML Loading + +During application startup, toolbars are loaded from `toolbars.xml`: + +```cpp +// From HarmonyPremium.exe session initialization (0x140034EB0) +// Loads toolbars.xml via AC_Manager::addToolbarFromFile (vtable+376) + +UT_String toolbarsPath = RM_GetResourcePath("toolbars.xml"); +actionManager->addToolbarFromFile(toolbarsPath.ToQString(), &toolbarList); +``` + +The `toolbars.xml` file defines toolbar content using XML elements like: +```xml + + + + + + +``` + +### 2. Global Toolbar Initialization + +Global toolbars are shown during session initialization (`sub_14002F840`): + +```cpp +// Show global toolbars via TULayoutManager::showToolbar (vtable+416) +layoutManager->showToolbar("FileToolbar", true); +layoutManager->showToolbar("EditToolbar", true); +layoutManager->showToolbar("DrawingToolToolbar", true); +layoutManager->showToolbar("ArtLayerToolbar", true); + +// Conditional toolbars based on features +if (WHO_Features::hasOnionSkinToolbar()) { + layoutManager->showToolbar("OnionSkinToolbar", false, true, nullptr); +} +``` + +**Key Function Addresses (HarmonyPremium.exe):** +- Session toolbar init: `0x14002F840` +- TULayoutManager::showToolbar import: `0x1409c8ea0` + +### 3. View-Specific Toolbar Definition + +Each view class overrides `TULayoutView::toolbar()` to return its toolbar definition: + +```cpp +// Example: CameraView::toolbar() at 0x1403BC450 +QDomElement CameraView::toolbar() { + // Get AC_Manager from embedded context (offset -56 from TULayoutView*) + AC_Manager* manager = *(AC_Manager**)(this - 56); + if (manager) { + // Call AC_Manager::getToolbarElement (vtable+416 / offset 52*8) + QDomElement element; + manager->getToolbarElement(&element, "CameraViewToolbar"); + return element; + } + return QDomElement(); // Empty if no manager +} +``` + +**Known View Toolbar Implementations:** + +| View Class | Toolbar Name | Address | +|------------|--------------|---------| +| DrawingView | "DrawingViewToolbar" | `0x1403B9880` | +| CameraView | "CameraViewToolbar" | `0x1403BC450` | +| TimelineView | "TimelineViewToolbar" | `0x14011C5F0` | +| SGV_Graph3DView | (custom impl) | `0x1409e1866` | + +### 4. Toolbar Display Flow + +When a view gains focus, the toolbar is displayed through this flow: + +``` +1. User clicks on a view widget + │ + ▼ +2. Application event handler detects focus change + (sub_140059DE0 checks for TULayoutFrame inheritance) + │ + ▼ +3. TULayoutManager::setCurrentLayoutFrame(frame) + │ + ▼ +4. TULayoutFrame::showViewToolBar() + - Gets current view from view holder + - Calls view->toolbar() to get QDomElement + - Creates AC_ToolbarImpl from element + - Adds toolbar to TULayoutMainWindow + │ + ▼ +5. Toolbar becomes visible in frame's toolbar area +``` + +## AC_Toolbar Integration + +### AC_Manager Methods Used + +The AC_Manager provides these key toolbar methods: + +| Method | Vtable Offset | Description | +|--------|---------------|-------------| +| `getToolbarElement` | +416 (52*8) | Returns QDomElement for toolbar by name | +| `addToolbarFromFile` | +376 (47*8) | Loads toolbar definitions from XML file | +| `createToolbar` | +368 (46*8) | Creates AC_ToolbarImpl from element | + +### AC_ToolbarImpl Creation + +When `TULayoutFrame::showViewToolBar()` needs to display a toolbar: + +```cpp +// Pseudocode for toolbar creation +void TULayoutFrame::showViewToolBar() { + TULayoutView* view = getCurrentView(); + if (!view) return; + + // Get toolbar XML element from view + QDomElement toolbarElement = view->toolbar(); + if (toolbarElement.isNull()) return; + + // Create AC_ToolbarImpl via AC_Manager + AC_Toolbar* toolbar = m_actionManager->createToolbar( + this, // owner + toolbarElement.attribute("text"), + m_mainWindow, // parent QMainWindow + toolbarElement.attribute("id").toUtf8().constData(), + toolbarElement, + nullptr // default config + ); + + // Add to frame's main window + m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar->toQToolBar()); + + // Store for later removal + m_viewToolbar = toolbar; +} +``` + +### LAY_ToolbarInfo Configuration + +Each view can have stored toolbar configuration via `LAY_ToolbarInfo`: + +```cpp +// Structure of LAY_ToolbarInfo (104 bytes) +class LAY_ToolbarInfo { + int m_x; // +0x00 - X position + int m_y; // +0x04 - Y position + int m_index; // +0x08 - Toolbar index + int m_width; // +0x0C - Width + int m_height; // +0x10 - Height + bool m_newline; // +0x14 - Break to new line + bool m_visible; // +0x15 - Visibility + bool m_isDefault; // +0x16 - Using default config + QString m_name; // +0x18 - Toolbar name + Qt::Orientation m_orientation; // +0x30 - Horizontal/Vertical + Qt::ToolBarArea m_toolBarArea; // +0x34 - Docking area + QList m_buttonConfig; // +0x38 - Current button order + QList m_buttonDefaultConfig; // +0x50 - Default button order +}; +``` + +The view receives its toolbar info via `TULayoutView::setToolbarInfo()`: +- Import: `0x1409c8f4e` (thunk to ToonBoomLayout.dll) +- Called by TULayoutFrame when loading saved layout preferences + +## Implementing Custom View Toolbars + +### Step 1: Define Toolbar in XML + +Create a toolbar definition that will be loaded by AC_Manager: + +```xml + + + + + + +``` + +### Step 2: Override toolbar() in Your View + +```cpp +class MyCustomView : public TULayoutView { +public: + QDomElement toolbar() override { + // Get AC_Manager - depends on your view's structure + // For TUWidgetLayoutView subclasses, manager is at offset -56 + AC_Manager* manager = getActionManager(); + if (!manager) { + return QDomElement(); + } + + // Use AC_Manager to get toolbar element by name + QDomElement element; + // Call via vtable[52] - getToolbarElement + auto getToolbarElement = reinterpret_cast( + (*reinterpret_cast(manager))[52] + ); + + QString toolbarName("MyCustomViewToolbar"); + getToolbarElement(manager, &element, toolbarName); + + return element; + } +}; +``` + +### Step 3: Register Toolbar XML + +Ensure your toolbar XML is loaded during initialization: + +```cpp +// Option 1: Add to existing toolbars.xml (if modifying installation) + +// Option 2: Load programmatically +AC_Manager* manager = PLUG_Services::getActionManager(); +if (manager) { + // Use addToolbarFromElement (vtable+376) + QDomDocument doc; + doc.setContent(myToolbarXml); + QDomElement element = doc.documentElement(); + + // Call via vtable + auto addToolbarFromElement = reinterpret_cast( + (*reinterpret_cast(manager))[47] + ); + addToolbarFromElement(manager, element, "MyCustomViewToolbar", false); +} +``` + +## Key Memory Offsets + +### TULayoutView (from TULayoutView*) +- `+0x00`: vptr +- `+0x08`: QString m_internalName +- `+0x20`: LAY_ToolbarInfo m_toolbarInfo (104 bytes) +- `+0x88`: AC_Menu* m_menuByType[2] +- `+0xA0`: QString m_caption + +### TULayoutFrame (from TULayoutFrame*) +- `+0x28`: TULayoutManager* m_layoutManager +- `+0x48`: TULayoutMainWindow* m_mainWindow (toolbar host) +- `+0x90`: AC_Toolbar* m_toolbar +- `+0xC0`: AC_Toolbar* m_viewToolbar + +### AC_ToolbarImpl (from QToolBar base) +- `+0x28`: AC_ContainerImpl m_container (88 bytes) +- `+0x80`: AC_Toolbar vptr +- `+0x98`: QString m_responderIdentity +- `+0xC8`: bool m_isCustomizable +- `+0xE0`: QObject* m_owner + +## Database Reference + +### HarmonyPremium.exe +| Symbol | Address | Description | +|--------|---------|-------------| +| Session toolbar init | `0x14002F840` | Initializes all global toolbars | +| DrawingView::toolbar | `0x1403B9880` | Returns DrawingViewToolbar element | +| CameraView::toolbar | `0x1403BC450` | Returns CameraViewToolbar element | +| TimelineView::toolbar | `0x14011C5F0` | Returns TimelineViewToolbar element | +| TULayoutView::setToolbarInfo import | `0x1409c8f4e` | Sets toolbar configuration | +| TULayoutView::toolbar import | `0x1409c8fc0` | Returns toolbar QDomElement | +| TULayoutManager::showToolbar import | `0x1409c8ea0` | Shows/creates toolbar by name | +| TULayoutManager::addToolbar import | `0x1409c8e4c` | Adds toolbar to manager | + +### ToonBoomActionManager.dll +| Symbol | Address | Description | +|--------|---------|-------------| +| AC_ToolbarImpl::AC_ToolbarImpl | `0x180032df0` | Constructor | +| AC_ToolbarImpl::~AC_ToolbarImpl | `0x180033080` | Destructor | +| AC_ToolbarImpl::create | `0x180033910` | Creates toolbar from XML | +| AC_ToolbarImpl::insert | `0x1800345e0` | Inserts item at position | +| AC_ToolbarImpl vtable | `0x180054eb0` | Main vtable | + +## Toolbar Names Reference + +### Global Toolbars +- `FileToolbar` - File operations +- `EditToolbar` - Edit operations +- `DrawingToolToolbar` - Drawing tools +- `ArtLayerToolbar` - Art layer selection +- `SceneplanningToolToolbar` - Scene planning tools +- `OnionSkinToolbar` - Onion skin controls +- `FlipToolbar` - Flip/mirror tools +- `GameToolbar` - Game export tools +- `AlignmentGuidesToolbar` - Alignment guides +- `MarkDrawingToolBar` - Mark drawing tools + +### View-Specific Toolbars +- `DrawingViewToolbar` - Drawing view +- `CameraViewToolbar` - Camera view +- `TimelineViewToolbar` - Timeline view +- `XsheetViewToolbar` - Xsheet view +- `NetworkViewToolbar` - Network/Node view +- `FunctionViewToolbar` - Function curve view +- `PlaybackViewToolbar` - Playback view +- `ModelViewToolbar` - Model view +- `LibraryViewToolbar` - Library view +- `ModuleLibraryViewToolbar` - Module library view +- `FreeViewToolbar` - Free-form view diff --git a/docs/TUWidgetLayoutView_Analysis.md b/docs/TUWidgetLayoutView_Analysis.md new file mode 100644 index 0000000..1b6eecf --- /dev/null +++ b/docs/TUWidgetLayoutView_Analysis.md @@ -0,0 +1,263 @@ +# TUWidgetLayoutView Class Analysis + +This document contains the reverse engineering analysis of the `TUWidgetLayoutView` class from `ToonBoomLayout.dll` used in Toon Boom Harmony Premium and Storyboard Pro. + +## Overview + +`TUWidgetLayoutView` is a concrete implementation that combines: +- **QWidget** - for Qt UI rendering +- **AC_ResponderTemplateWidget** - for action/responder chain handling +- **TULayoutView** - for the Toon Boom layout system integration + +This class serves as the base for most view types in Toon Boom's panel/window system. + +## Class Hierarchy + +``` +QObject +└── QWidget + └── AC_ResponderTemplateWidget + └── TUWidgetLayoutView + └── [TULayoutView embedded at offset +104] +``` + +Note: `TULayoutView` is not a base class in the C++ inheritance sense but is **embedded** as a sub-object at offset +104. This is a form of composition that allows `TULayoutView` to have its own vtable and virtual methods. + +## Memory Layout (x64 MSVC) + +| Offset (hex) | Offset (dec) | Size | Member | +|--------------|--------------|------|--------| +| +0x00 | +0 | 8 | vptr (QObject) | +| +0x08 | +8 | 8 | QObjectData* d_ptr | +| +0x10 | +16 | 8 | vptr (QPaintDevice) | +| +0x18 | +24 | 16 | QWidget internal data | +| +0x28 | +40 | 8 | vptr (AC_ResponderTemplateWidget) | +| +0x30 | +48 | 8 | AC_Manager* m_actionManager | +| +0x38 | +56 | 24 | QString m_responderIdentity | +| +0x50 | +80 | 24 | QString m_responderDescription | +| **+0x68** | **+104** | 8 | **vptr (TULayoutView)** - TULayoutView starts here | +| +0x70 | +112 | 24 | QString m_internalName (TULayoutView) | +| +0x88 | +136 | 104 | LAY_ToolbarInfo m_toolbarInfo (TULayoutView) | +| +0xF0 | +240 | 16 | AC_Menu* m_menuByType[2] (TULayoutView) | +| +0x100 | +256 | 1+7 | bool m_initializedFromCopy + padding (TULayoutView) | +| +0x108 | +264 | 24 | QString m_caption (TULayoutView) | + +**Total size: 0x120 (288 bytes)** + +## VTable Structure + +TUWidgetLayoutView has **4 vtables** due to multiple inheritance: + +### vptr[0] at +0x00: QObject vtable +Contains all QObject and QWidget virtual methods including: +- `metaObject()`, `qt_metacast()`, `qt_metacall()` +- `event()`, `eventFilter()` +- `paintEvent()`, `mousePressEvent()`, etc. + +Address in ToonBoomLayout.dll: `??_7TUWidgetLayoutView@@6BQObject@@@` + +### vptr[1] at +0x10: QPaintDevice vtable +Contains QPaintDevice virtuals: +- `devType()` +- `paintEngine()` +- `metric()` + +Address in ToonBoomLayout.dll: `??_7TUWidgetLayoutView@@6BQPaintDevice@@@` + +### vptr[2] at +0x28: AC_ResponderTemplateWidget vtable +Contains AC_Responder interface methods: +- `perform(AC_ActionInfo*)` +- `performDownToChildren(AC_ActionInfo*)` +- `parentResponder()` +- `proxyResponder()` +- `acceptsFirstResponder()` +- `becomeFirstResponder()` +- `resignFirstResponder()` +- `handleShortcuts()` +- `shouldReceiveMessages()` +- `responderIdentity()` +- `responderDescription()` +- `actionManager()` +- `handleEvent(QEvent*)` + +Address in ToonBoomLayout.dll: `??_7TUWidgetLayoutView@@6B?$AC_ResponderTemplateWidget@VQWidget@@@@@` + +### vptr[3] at +0x68: TULayoutView vtable +Contains TULayoutView virtual methods (32 slots total): + +| Slot | Method | TUWidgetLayoutView Implementation | +|------|--------|-----------------------------------| +| 0 | ~TULayoutView() | Thunk to TUWidgetLayoutView dtor | +| 1 | widget() | _purecall (pure virtual) | +| 2 | initiate(QWidget*) | TULayoutView::initiate | +| 3 | getWidget() const | **Returns (this - 104)** | +| 4 | getWidget() | **Returns (this - 104)** | +| 5 | getParentHolderWidget() const | TULayoutView impl | +| 6 | getParentHolderWidget() | TULayoutView impl | +| 7 | hasMenu() | TULayoutView impl | +| 8 | setMenu(AC_Manager*, const char*, MenuType) | TULayoutView impl | +| 9 | setMenu(AC_Menu*, MenuType) | TULayoutView impl | +| 10 | menu(MenuType) | TULayoutView impl | +| 11 | toolbar() | TULayoutView impl | +| 12 | setToolbarInfo(LAY_ToolbarInfo&) | TULayoutView impl | +| 13 | connectView() | Empty | +| 14 | disconnectView() | Empty | +| 15 | initializedFromCopy() | TULayoutView impl | +| 16 | getCaption(bool) | TULayoutView impl | +| 17 | getDynamicTextForCaption() | TULayoutView impl | +| 18 | wantEditionStack() | Returns false | +| 19 | displayName() | TULayoutView impl | +| 20 | compositeChanged(QString&) | Empty | +| 21 | dropOverComposite(QDropEvent*, QString&) | Empty | +| 22 | wantComposites() | Returns false | +| 23 | initActionManager(AC_Manager*) | Empty | +| 24 | wantDisplaySelector() | Returns false | +| 25 | isUsingDefaultDisplay() | Returns false | +| 26 | storeViewPreferences(QDomElement&) | Returns false | +| 27 | loadViewPreferences(QDomElement&) | Empty | +| 28 | cshHelpId() | TULayoutView impl | +| 29 | **triggerMenuChanged()** | **Emits menuChanged() signal** | +| 30 | copy(TULayoutView&) | TULayoutView impl | +| 31 | **isTULayoutView()** | **Empty (RTTI marker)** | + +Address in ToonBoomLayout.dll: `??_7TUWidgetLayoutView@@6BTULayoutView@@@` + +## Key Methods + +### Constructor +```cpp +TUWidgetLayoutView( + AC_Manager* manager, // Action manager (stored at +0x30) + const QString& objectName, // Qt object name + QWidget* parent, // Parent widget + const char* className, // Class name string + Qt::WindowFlags flags // Window flags +) +``` + +**Construction sequence:** +1. Call `AC_ResponderTemplateWidget` ctor with (parent, flags, objectName) +2. Call `TULayoutView` default ctor at `this + 104` +3. Install all 4 TUWidgetLayoutView vtables +4. Set minimum width to 150 pixels +5. If parent != nullptr && manager != nullptr: + - Call `initActionManager(manager)` +6. Else: + - Store manager directly at offset +0x30 + +### Destructor +**Destruction sequence:** +1. Reset vtables to TUWidgetLayoutView vtables +2. Destroy `TULayoutView::m_caption` (QString at +0x108) +3. Destroy `TULayoutView::m_toolbarInfo` (LAY_ToolbarInfo at +0x88) +4. Destroy `TULayoutView::m_internalName` (QString at +0x70) +5. Jump to `AC_ResponderTemplateWidget::~AC_ResponderTemplateWidget` + +### getWidget() +```cpp +QWidget* getWidget() { + return reinterpret_cast( + reinterpret_cast(this) - 104); +} +``` +Called from TULayoutView* context (at +104), returns the containing QWidget* (at +0). + +### triggerMenuChanged() +```cpp +void triggerMenuChanged() { + // 'this' is TULayoutView* at +104 + // Emit signal on containing TUWidgetLayoutView (this - 104) + TUWidgetLayoutView* widget = (TUWidgetLayoutView*)((char*)this - 104); + widget->menuChanged(); +} +``` + +### mousePressEvent() +```cpp +void mousePressEvent(QMouseEvent* event) { + QWidget::mousePressEvent(event); + if (!event->isAccepted()) { + event->accept(); + setFocus(Qt::MouseFocusReason); // Focus reason = 7 + } +} +``` + +## Qt Meta-Object System + +TUWidgetLayoutView participates in the Qt meta-object system: + +- `staticMetaObject` - Static meta-object for the class +- `metaObject()` - Returns `&staticMetaObject` (or dynamic for QML) +- `qt_metacast(const char* className)`: + - "TUWidgetLayoutView" → returns `this` + - "TULayoutView" → returns `this + 104` + - Otherwise → delegates to AC_ResponderTemplateWidget::qt_metacast +- `tr()` - Static translation method + +### Signals +- `menuChanged()` - Emitted when view menu changes (slot 0 in staticMetaObject signals) + +## Exported Symbols + +From ToonBoomLayout.dll: + +| Symbol | Description | +|--------|-------------| +| `??0TUWidgetLayoutView@@QEAA@...@Z` | Constructor | +| `??1TUWidgetLayoutView@@UEAA@XZ` | Destructor | +| `?getWidget@TUWidgetLayoutView@@UEAAPEAVQWidget@@XZ` | Non-const getWidget | +| `?getWidget@TUWidgetLayoutView@@UEBAPEBVQWidget@@XZ` | Const getWidget | +| `?mousePressEvent@TUWidgetLayoutView@@MEAAXPEAVQMouseEvent@@@Z` | Mouse handler | +| `?triggerMenuChanged@TUWidgetLayoutView@@MEAAXXZ` | Trigger menu signal | +| `?menuChanged@TUWidgetLayoutView@@QEAAXXZ` | Signal implementation | +| `?metaObject@TUWidgetLayoutView@@UEBAPEBUQMetaObject@@XZ` | Meta-object | +| `?qt_metacast@TUWidgetLayoutView@@UEAAPEAXPEBD@Z` | Runtime cast | +| `?qt_metacall@TUWidgetLayoutView@@UEAAHW4Call@QMetaObject@@HPEAPEAX@Z` | Meta-call | +| `?qt_static_metacall@TUWidgetLayoutView@@...@Z` | Static meta-call | +| `?tr@TUWidgetLayoutView@@SA?AVQString@@PEBD0H@Z` | Translation | + +## Helper Functions + +The header provides inline helper functions for pointer conversion: + +```cpp +// Get TULayoutView* from TUWidgetLayoutView* +TULayoutView* TUWidgetLayoutView_getLayoutView(TUWidgetLayoutView* widget); + +// Get TUWidgetLayoutView* from TULayoutView* (must be embedded in TUWidgetLayoutView) +TUWidgetLayoutView* TULayoutView_getWidgetLayoutView(TULayoutView* view); + +// Get QWidget* from TUWidgetLayoutView* (same address, different type) +QWidget* TUWidgetLayoutView_getWidget(TUWidgetLayoutView* widget); + +// Get AC_Manager* from TULayoutView* embedded in TUWidgetLayoutView +AC_Manager* TULayoutView_getActionManager(TULayoutView* view); +``` + +## Subclasses + +Several classes in ToonBoomLayout.dll inherit from TUWidgetLayoutView: + +- `TUCanvasViewLayoutView` - Canvas/drawing view +- `TUFrameLayoutView` - Frame view +- `TUScrollViewLayoutView` - Scrollable view +- `TUTextEditLayoutView` - Text editing view +- `TUVBoxLayoutView` - Vertical box layout view + +These share the same `getWidget()` implementation (returning `this - 104`). + +## Analysis Methodology + +This analysis was performed using: +1. IDA Pro decompilation of constructor (`0x7ffa0be600a0`) and destructor (`0x7ffa0be60480`) +2. Disassembly verification of exact byte offsets +3. Cross-reference analysis of vtable addresses +4. Examination of related methods (getWidget, triggerMenuChanged, etc.) +5. Qt meta-object method analysis (qt_metacast, etc.) + +## References + +- `toon_boom_layout.hpp` - Header file with class declarations +- `TULayoutView_Toolbar_Integration.md` - Toolbar integration documentation +- `AC_Manager` - Action manager class documentation diff --git a/docs/ToonBoomActionManager_Classes.md b/docs/ToonBoomActionManager_Classes.md new file mode 100644 index 0000000..2c3cbbc --- /dev/null +++ b/docs/ToonBoomActionManager_Classes.md @@ -0,0 +1,304 @@ +# ToonBoomActionManager.dll Class Analysis + +This document describes the reverse-engineered class structures from `ToonBoomActionManager.dll`. + +**IDA Database:** `RE/ToonBoomActionManager.dll.i64` + +## Overview + +ToonBoomActionManager.dll provides the action/command management infrastructure for Toon Boom applications (Harmony Premium, Storyboard Pro). It implements: + +- **Responder Chain**: First responder and selection responder management +- **Menu System**: XML-based menu creation and management +- **Toolbar System**: Customizable toolbars with dynamic item insertion +- **Shortcut Management**: Keyboard shortcut handling +- **Action Triggering**: Command execution and validation + +## Class Hierarchy + +``` +AC_Manager (abstract interface) +└── AC_ManagerImpl (concrete, inherits QObject) + +AC_Object (abstract interface) +├── AC_Item (abstract interface) +├── AC_Separator (abstract interface) +└── AC_Toolbar (abstract, also inherits AC_Container, AC_Help) + └── AC_ToolbarImpl (concrete, inherits QToolBar) + +AC_Container (abstract interface) +└── AC_ContainerImpl (concrete) + +AC_Help (abstract interface) + +AC_Responder (abstract interface) +└── AC_ResponderTemplate (concrete) + └── AC_ResponderTemplateWidget (template) +``` + +--- + +## AC_Manager / AC_ManagerImpl + +### Purpose +Central manager for the action/command system. Handles responder registration, menu/toolbar creation, and action triggering. + +### Key Addresses +| Symbol | Address | +|--------|---------| +| AC_Manager vtable | `0x18004e508` | +| AC_ManagerImpl vtable (QObject) | `0x18004e750` | +| AC_ManagerImpl vtable (AC_Manager) | `0x18004e7c8` | +| AC_ManagerImpl::AC_ManagerImpl | `0x18000ef20` | +| AC_ManagerImpl::~AC_ManagerImpl | `0x18000f300` | + +### Memory Layout (AC_ManagerImpl) +Total size: **0x158 (344 bytes)** on x64 + +| Offset | Size | Type | Field | +|--------|------|------|-------| +| +0x00 | 0x10 | | QObject base | +| +0x10 | 0x08 | vptr | AC_Manager vtable | +| +0x18 | 0x08 | void* | m_keywords (shared ptr data) | +| +0x20 | 0x08 | void* | m_keywords (continued) | +| +0x28 | 0x08 | void* | m_keywords (continued) | +| +0x30 | 0x01 | bool | m_trimShortcuts (init value) | +| +0x38 | 0x18 | | Responder name→list tree | +| +0x50 | 0x18 | | Menu tree | +| +0x68 | 0x08 | ptr | m_shortcutManager | +| +0x78 | 0x18 | QString | m_hoverId | +| +0x90 | 0x18 | QString | m_genericImage | +| +0xA8 | 0x18 | QString | m_toolbarCustomizeImage | +| +0xC0 | 0x18 | | Toolbar tree | +| +0xD8 | 0x18 | vector | m_registeredResponders | +| +0xF0 | 0x18 | vector | m_responderStack | +| +0x108 | 0x08 | ptr | m_menuBar | +| +0x118 | 0x08 | ptr | m_applicationResponder | +| +0x120 | 0x08 | ptr | m_selectionResponder | +| +0x128 | 0x08 | ptr | m_itemGenerator | +| +0x130 | 0x01 | bool | m_option_trimShortcuts | + +### Key Methods + +#### Responder Management +- `firstResponder()` - Returns top of responder stack (offset +248) +- `applicationResponder()` - Returns m_applicationResponder (offset +296) +- `registerResponder(responder, widget)` - Adds responder to registry +- `setFirstResponder(responder)` - Sets active first responder +- `pushUp(responder)` / `pushOut(responder)` - Stack manipulation + +#### Menu/Toolbar Creation +- `createMenuBar(element, parent)` - Create menu from XML +- `createToolbar(element, ids, mainWindow, area, name, owner)` - Create toolbar +- `loadMenus(path)` / `loadToolbars(path, ids)` - Load from file + +#### Action Triggering +- `trigger(responderIdentity, actionName, forEach)` - Execute action +- `performValidation(responderIdentity, actionName, enabled, checked)` - Validate action state + +### Signals +```cpp +void firstResponderChanged(); +void selectionResponderChanged(); +void updateToolbarsSignal(); +void updateToolbarsText(); +``` + +--- + +## AC_Toolbar / AC_ToolbarImpl + +### Purpose +Customizable toolbar with support for: +- Dynamic item insertion from XML +- Placeholder-based customization +- Configuration save/restore +- Context-sensitive help + +### Key Addresses +| Symbol | Address | +|--------|---------| +| AC_ToolbarImpl vtable (QObject) | `0x180054c90` | +| AC_ToolbarImpl vtable (QPaintDevice) | `0x180054e70` | +| AC_ToolbarImpl vtable (AC_Toolbar) | `0x180054eb0` | +| AC_ToolbarImpl vtable (AC_Container) | `0x180054ef8` | +| AC_ToolbarImpl vtable (AC_Help) | `0x1800550f8` | +| AC_ToolbarImpl::AC_ToolbarImpl | `0x180032df0` | +| AC_ToolbarImpl::~AC_ToolbarImpl | `0x180033080` | + +### Memory Layout (AC_ToolbarImpl) +Total size: **0x118 (280 bytes)** on x64 + +| Offset | Size | Type | Field | +|--------|------|------|-------| +| +0x00 | 0x28 | | QToolBar base (includes QObject, QPaintDevice) | +| +0x28 | 0x58 | AC_ContainerImpl | m_container (embedded) | +| +0x80 | 0x08 | vptr | AC_Toolbar vtable | +| +0x88 | 0x08 | vptr | AC_Container vtable | +| +0x90 | 0x08 | vptr | AC_Help vtable | +| +0x98 | 0x18 | QString | m_responderIdentity | +| +0xB0 | 0x18 | vector | m_defaultConfig | +| +0xC8 | 0x01 | bool | m_isCustomizable | +| +0xD0 | 0x08 | ptr | m_customizeButton | +| +0xD8 | 0x08 | ptr | m_unknown | +| +0xE0 | 0x08 | QObject* | m_owner | +| +0xE8 | 0x10 | QWeakPointer | m_mainWindow | +| +0xF8 | 0x04 | float | m_scaleFactor (default 1.0) | +| +0x100 | 0x18 | QString | m_translationContext | + +### Interface Pointers +When you have an `AC_Toolbar*`: +- `QToolBar*` = `(char*)this - 128` +- `AC_ContainerImpl*` = `(char*)this - 88` +- Identity QString is at `(char*)this - 72` + +### Key Methods + +#### Item Management +- `insert(beforeObject, element)` - Insert item from XML +- `insertAtPlaceholder(placeholder, element)` - Insert at named placeholder +- `insertSeparator(beforeObject)` - Insert separator +- `removeObject(identity)` - Remove item by identity +- `clear()` - Remove all items + +#### Configuration +- `config()` - Get current item order as QList +- `setConfig(list)` - Restore from saved configuration +- `defaultConfig()` - Get default item order +- `isDefaultConfig()` - Check if current matches default + +#### Validation +- `validateContent()` - Update enabled/checked states +- `validateContentIfVisible()` - Only validate if toolbar is shown +- `updateSeparators()` - Hide separators adjacent to hidden items + +### Signals +```cpp +void customized(QString identity); +``` + +--- + +## AC_ContainerImpl + +### Purpose +Base container implementation for managing AC_Object children. + +### Memory Layout +Total size: **0x58 (88 bytes)** on x64 + +| Offset | Size | Type | Field | +|--------|------|------|-------| +| +0x00 | 0x08 | vptr | AC_ContainerImpl vtable | +| +0x08 | 0x08 | ptr | m_manager (AC_ManagerImpl*) | +| +0x10 | 0x18 | QString | m_identity | +| +0x28 | 0x01 | bool | m_enabled | +| +0x29 | 0x01 | bool | m_isToolbar | +| +0x30 | 0x18 | vector | m_objects | +| +0x48 | 0x10 | | Placeholder tree | + +--- + +## Enumerations + +### AC_Result +```cpp +enum class AC_Result : int { + NotHandled = 0, // Action not handled by any responder + Handled = 1, // Action handled successfully + Error = 2 // Error during handling +}; +``` + +### AC_ManagerOption +```cpp +enum class AC_ManagerOption : int { + TrimShortcuts = 0 // Whether to trim whitespace from shortcuts +}; +``` + +### AC_Help::cshHelpType +```cpp +enum cshHelpType { + Type0 = 0, + Type1 = 1, + Type2 = 2, + Type3 = 3, + Type4 = 4, + ToolbarHelp = 5 +}; +``` + +--- + +## XML Element Types + +AC_ToolbarImpl::insert() handles these XML element types: + +| Tag Name | Handler | Creates | +|----------|---------|---------| +| `item` | sub_1800363E0 | AC_ToolbarItemImpl | +| `menu` | sub_1800363E0 | AC_ToolbarItemImpl (menu button) | +| `multibutton` | sub_180037F30 | AC_ToolbarMultiButtonImpl | +| `combobox` | sub_1800395D0 | AC_ToolbarComboBox | +| `placeholder` | sub_18001B9F0 | Placeholder object | +| `separator` | sub_18003ABD0 | AC_ToolbarSeparatorImpl | + +--- + +## Usage Patterns + +### Getting AC_Manager Instance +```cpp +// Via PLUG_Services (from ToonBoomPlugInManager.dll) +AC_Manager* manager = PLUG_Services::getActionManager(); +``` + +### Creating a Toolbar +```cpp +QList ids; +AC_Toolbar* toolbar = manager->createToolbar( + xmlElement, // QDomElement with toolbar definition + &ids, // Output: list of created item IDs + mainWindow, // QMainWindow to attach to + Qt::TopToolBarArea,// Toolbar area + "myToolbar", // Object name + owner // Owner QObject for cleanup +); +``` + +### Triggering an Action +```cpp +AC_Result result = manager->trigger( + "NetworkView", // Responder identity + "onActionZoomIn", // Action/slot name + false // Don't iterate all responders +); +``` + +### Validating an Action +```cpp +bool enabled, checked; +manager->performValidation("NetworkView", "onActionZoomIn", &enabled, &checked); +``` + +--- + +## Related Files + +- `framework/include/toon_boom/ac_manager.hpp` - AC_Manager header +- `framework/include/toon_boom/toolbar.hpp` - AC_Toolbar header +- `framework/include/toon_boom/PLUG_Services.hpp` - Service access + +--- + +## Methodology + +This analysis was performed using: +1. IDA Pro decompilation of ToonBoomActionManager.dll +2. Vtable analysis to identify class hierarchies +3. Constructor/destructor analysis for memory layout +4. Cross-reference analysis for method identification +5. String analysis for signal/slot names + +All offsets verified against x64 Windows builds of Toon Boom Harmony Premium.