docs: add docs pertaining to the ac_responder system and view toolbars

This commit is contained in:
☙◦ The Tablet ❀ GamerGirlandCo ◦❧ 2026-01-12 21:39:55 -05:00
parent b491e115ad
commit 044a9b60dd
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
4 changed files with 1452 additions and 0 deletions

529
docs/AC_Responder_System.md Normal file
View File

@ -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
<toolbar id="DrawingToolToolbar" text="Tools">
<!-- Simple item with responder and slot -->
<item
checkable="true"
icon="drawingtool/select.png"
id="SelectTool"
responder="sceneUI"
slot="onActionChooseSelectToolInNormalMode()"
text="Select" />
<!-- Item with owner responder (view that owns the toolbar) -->
<item
icon="library/refresh.png"
id="LIBRARY_REFRESH"
responder="owner"
slot="onActionFolderRefresh()"
text="Refresh" />
<!-- Item with script execution -->
<item
icon="script/createkeyframeson.png"
id="CREATE_KEYFRAMES_ON"
itemParameter="TB_CreateKeyFramesOn in TB_CreateKeyFramesOn.js"
responder="scriptResponder"
slot="onActionExecuteScript(QString)"
text="Create Keyframes On" />
</toolbar>
```
### 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 <toon_boom/ac_manager.hpp>
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 <toon_boom/ac_manager.hpp>
#include <QWidget>
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 `<slotName>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
<toolbar id="MyToolbar" text="My Tools">
<item
id="MyAction"
icon="my/icon.png"
responder="myCustomResponder"
slot="onActionMyAction()"
text="My Action" />
</toolbar>
```
### 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<QString> 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<AC_Responder*>(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** (`<slotName>Validate(AC_ActionInfo*)`) for state updates
5. **Reference your responder** by identity in the toolbar XML `responder` attribute

View File

@ -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
<toolbar id="DrawingViewToolbar" trContext="Toolbars">
<item id="DrawingTool.Select" />
<separator />
<item id="DrawingTool.Brush" />
<!-- ... more items ... -->
</toolbar>
```
### 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<QString> m_buttonConfig; // +0x38 - Current button order
QList<QString> 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
<toolbar id="MyCustomViewToolbar" trContext="MyToolbars">
<item id="MyResponder.Action1" />
<item id="MyResponder.Action2" />
<separator />
<placeholder id="CustomItems" />
</toolbar>
```
### 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<void(*)(AC_Manager*, QDomElement*, const QString&)>(
(*reinterpret_cast<void***>(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<void(*)(AC_Manager*, const QDomElement&, const QString&, bool)>(
(*reinterpret_cast<void***>(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

View File

@ -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<QWidget>** - 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<QWidget>
└── 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<QWidget>) |
| +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<QWidget> 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<QWidget>` 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<QWidget>::~AC_ResponderTemplateWidget`
### getWidget()
```cpp
QWidget* getWidget() {
return reinterpret_cast<QWidget*>(
reinterpret_cast<char*>(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<QWidget>::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

View File

@ -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<T> (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<QString>
- `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<QString> 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.