feat(framework/examples): add some examples demonstrating how to use the framework

This commit is contained in:
☙◦ The Tablet ❀ GamerGirlandCo ◦❧ 2026-01-21 16:16:54 -05:00
parent d06367c451
commit fcb686ac0c
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
17 changed files with 694 additions and 1 deletions

20
.clangd
View File

@ -1,6 +1,24 @@
If:
PathMatch:
- .*/example/.*
CompileFlags:
BuiltinHeaders: QueryDriver
CompilationDatabase: .
CompilationDatabase: ./example/build/ninja/compile_commands.json
Add:
- '/wd4244'
- '/wd4267'
- '/wd4838'
- '/wd4430'
Remove:
- 'external:I*'
- 'external:W*'
---
If:
PathExclude:
- .*/example/.*
CompileFlags:
BuiltinHeaders: QueryDriver
CompilationDatabase: ./build/ninja/compile_commands.json
Remove:
- 'external:I*'
- 'external:W*'

39
example/CMakeLists.txt Normal file
View File

@ -0,0 +1,39 @@
cmake_minimum_required(VERSION 3.20)
project(toon-boom-extension-framework-examples
VERSION 0.1.0
DESCRIPTION "Toon Boom extension framework examples"
LANGUAGES CXX C
)
include(FetchContent)
if(NOT DEFINED IN_SUPERPROJECT)
FetchContent_Declare(
toon-boom-extension-framework
GIT_REPOSITORY https://github.com/GamerGirlandCo/toon-boom-extension-framework.git
GIT_TAG master
FIND_PACKAGE_ARGS NAMES toon-boom-extension-framework
)
else()
FetchContent_Declare(
toon-boom-extension-framework
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..
FIND_PACKAGE_ARGS NAMES toon-boom-extension-framework
)
endif()
FetchContent_MakeAvailable(toon-boom-extension-framework)
find_package(toon-boom-extension-framework CONFIG REQUIRED)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "/Zc:__cplusplus")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui Core5Compat Xml QUIET)
add_subdirectory(simple)
add_subdirectory(_all)

39
example/CMakePresets.json Normal file
View File

@ -0,0 +1,39 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 4,
"minor": 2,
"patch": 0
},
"configurePresets": [
{
"name": "ninja",
"displayName": "Ninja",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/ninja",
"toolchainFile": "C:/vcpkg/scripts/buildsystems/vcpkg.cmake",
"environment": {
"VCPKG_VISUAL_STUDIO_PATH": "C:/Program Files/Microsoft Visual Studio/18/Community",
"VCPKG_ROOT": "C:/vcpkg",
"CMAKE_GENERATOR_PLATFORM": "x64"
},
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_CXX_COMPILER": "cl.exe",
"CMAKE_MAKE_PROGRAM": "C:/Program Files/Microsoft Visual Studio/18/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe"
}
}
],
"buildPresets": [
{
"name": "ninja-debug",
"configurePreset": "ninja",
"configuration": "RelWithDebInfo"
},
{
"name": "ninja-release",
"configurePreset": "ninja",
"configuration": "Release"
}
]
}

View File

@ -0,0 +1,24 @@
file(GLOB_RECURSE EXAMPLE_LIB_SRC CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/*.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/*.cxx"
"${CMAKE_CURRENT_SOURCE_DIR}/*.c"
)
file(GLOB_RECURSE EXAMPLE_LIB_HEADERS CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/*.hpp"
)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
add_library(all-examples SHARED ${EXAMPLE_LIB_SRC} ${EXAMPLE_LIB_HEADERS})
target_compile_options(all-examples PUBLIC "/std:c++20" "/Zc:gotoScope-")
target_include_directories(all-examples PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
set_target_properties(all-examples PROPERTIES
AUTOMOC ON
AUTOUIC ON
AUTORCC ON
)
target_link_libraries(all-examples PUBLIC libtoonboom_static)
target_link_libraries(all-examples PRIVATE simple-example)

View File

@ -0,0 +1,51 @@
#pragma once
#define LIB_ALL
#include "QtScript/qscriptengine.h"
#include <QtCore/QtCore>
#include <QtScript/QtScript>
typedef QScriptValue(FunctionSignature)(QScriptContext *, QScriptEngine *);
/* // Usage
void setupScriptingModern(QScriptEngine *engine, BaseExample *example) {
auto lambda = example->run();
// Automatically deduces type and creates wrapper
QScriptValue scriptFunc = CallbackWrapper<decltype(lambda)>::create(
engine, std::move(lambda)
);
engine->globalObject().setProperty(example->jsName(), scriptFunc);
} */
class BaseExample {
public:
BaseExample() {}
~BaseExample() {}
virtual QString jsName() = 0;
virtual std::function<QScriptValue(QScriptContext *, QScriptEngine *)>
run() = 0;
};
template <typename Lambda> struct CallbackWrapper {
// The actual function pointer that can be passed to C APIs
static QScriptValue invoke(QScriptContext *ctx, QScriptEngine *eng) {
void *ptr = ctx->callee().data().toVariant().value<void *>();
auto *lambda = static_cast<Lambda *>(ptr);
return (*lambda)(ctx, eng);
}
// Helper to create a script function from any lambda
static QScriptValue create(QScriptEngine *engine, Lambda &&lambda) {
// Store lambda in heap-allocated wrapper
auto *stored = new Lambda(std::forward<Lambda>(lambda));
QScriptValue func = engine->newFunction(CallbackWrapper<Lambda>::invoke);
func.setData(engine->newVariant(QVariant::fromValue<void *>(stored)));
// Attach finalizer for cleanup
engine->newQObject(func, nullptr, QScriptEngine::ScriptOwnership);
return func;
}
};

View File

@ -0,0 +1,47 @@
#pragma once
#include <basic_view.hpp>
#include <examples_container.hpp>
#include "./base.hpp"
class SimpleBaseExample : public BaseExample {
public:
SimpleBaseExample() : BaseExample() {
m_container = new SimpleExamplesContainer();
}
~SimpleBaseExample() {}
protected:
SimpleExamplesContainer *m_container = nullptr;
};
class SimpleExample : public SimpleBaseExample {
public:
SimpleExample() : SimpleBaseExample() {}
~SimpleExample() {}
QString jsName() override {
return "showSimpleExample";
}
std::function<QScriptValue(QScriptContext *, QScriptEngine *)> run() override {
return [this](QScriptContext *context, QScriptEngine *engine) -> QScriptValue {
m_container->showBasicGreetingView();
return engine->undefinedValue();
};
}
};
class ToolbarExample : public SimpleBaseExample {
public:
ToolbarExample() : SimpleBaseExample() {}
~ToolbarExample() {}
std::function<QScriptValue(QScriptContext *, QScriptEngine *)> run() override {
return [this](QScriptContext *context, QScriptEngine *engine) -> QScriptValue {
m_container->showCounterView();
return engine->undefinedValue();
};
}
QString jsName() override {
return "showToolbarExample";
}
};

View File

@ -0,0 +1,34 @@
#pragma once
#include <QtScript/qscriptcontext.h>
#include <QtCore/QMap>
#include <QtCore/QtCore>
#include <QtScript/qscriptengine.h>
#include <vector>
#include "./defs/base.hpp"
#include "./defs/simple.hpp"
class ToonBoomExamples {
public:
ToonBoomExamples() {
addExample(new SimpleExample());
addExample(new ToolbarExample());
}
void addExample(BaseExample *example) { examples.push_back(example); }
QScriptValue getExamples(QScriptEngine *engine) {
QScriptValue obj = engine->newObject();
for (auto &example : examples) {
auto lambda = example->run();
QScriptValue scriptFunc =
CallbackWrapper<decltype(lambda)>::create(engine, std::move(lambda));
obj.setProperty(example->jsName(), scriptFunc);
}
return obj;
}
~ToonBoomExamples() {}
private:
std::vector<BaseExample *> examples;
};

38
example/_all/lib_all.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "include/lib_all.hpp"
#include <hooks/toon_boom_hooks.hpp>
#include <iostream>
extern bool is_first_load;
void AddExamples(QScriptEngine *engine) {
std::cout << "AddExamples" << std::endl;
auto examples = new ToonBoomExamples();
engine->globalObject().setProperty("extensionExamples",
examples->getExamples(engine));
}
extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
bool was_first_load = is_first_load;
if (was_first_load) {
// Sleep(20000);
Add_ScriptEngine_hook(&AddExamples);
}
if (hookInit() != TRUE) {
std::cerr << "Failed to initialize hooks" << std::endl;
MessageBoxA(NULL, "Failed to initialize hooks", "Error",
MB_ICONERROR | MB_OK);
return FALSE;
}
if (was_first_load) {
MessageBoxA(NULL, "Hooks initialized!!!", "Congratulations!!!",
MB_ICONINFORMATION | MB_OK);
}
break;
}
return TRUE;
}

View File

@ -0,0 +1,23 @@
file(GLOB_RECURSE SIMPLE_SOURCES CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cxx"
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
)
file(GLOB_RECURSE SIMPLE_HEADERS CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/src/include/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/include/*.hpp"
)
list(FILTER SIMPLE_SOURCES EXCLUDE REGEX "/(out|build|cmake-build-|CMakeFiles)/")
list(FILTER SIMPLE_HEADERS EXCLUDE REGEX "/(out|build|cmake-build-|CMakeFiles)/")
add_library(simple-example STATIC ${SIMPLE_SOURCES} ${SIMPLE_HEADERS})
set_target_properties(simple-example PROPERTIES
AUTOMOC ON
AUTOUIC ON
AUTORCC ON
)
target_include_directories(simple-example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/include)
target_link_libraries(simple-example PRIVATE libtoonboom_static)

View File

@ -0,0 +1,68 @@
#include <toon_boom/PLUG_Services.hpp>
#include "./include/examples_container.hpp"
#include "./include/toolbar_view.hpp"
#include "./include/basic_view.hpp"
#include "toon_boom/ext/util.hpp"
SimpleExamplesContainer::SimpleExamplesContainer() {}
SimpleExamplesContainer::~SimpleExamplesContainer() {}
void SimpleExamplesContainer::showBasicGreetingView() {
auto lm = PLUG_Services::getLayoutManager();
if (!lm) {
return;
}
const char* id = "BasicGreetingView";
const QString name = "Basic Greeting View";
auto viewFactory = []() -> TULayoutView* { return new BasicGreetingView(); };
if (!addViewIfNotExists(id, name, viewFactory, false, QSize(400, 400), true)) {
return;
}
lm->raiseArea(name, nullptr, true, QPoint(100, 100));
}
void SimpleExamplesContainer::showCounterView() {
auto lm = PLUG_Services::getLayoutManager();
auto am = PLUG_Services::getActionManager();
if (!lm) {
std::cerr << "Failed to get layout manager!" << std::endl;
return;
}
if (!am) {
std::cerr << "Failed to get action manager!" << std::endl;
return;
}
const QString name = "Counter View";
auto viewFactory = []() -> TULayoutView* { return new CounterView(); };
if (!addViewIfNotExists("Counter View", name, viewFactory, false, QSize(700, 400), true)) {
return;
}
auto area = lm->raiseArea(name, nullptr, true, QPoint(200, 200));
debug::out << "Area: " << debug::addrToHex(area) << std::endl;
auto asCounterView = dynamic_cast<CounterView*>(m_views[name]);
asCounterView->getWidget()->setFocus(Qt::OtherFocusReason);
lm->showViewToolBars();
}
bool SimpleExamplesContainer::addViewIfNotExists(const char* id, const QString& displayName, std::function<TULayoutView*()> viewFactory, bool isDocked, QSize minSize, bool useMinSz) {
auto lm = PLUG_Services::getLayoutManager();
std::string asStr;
for (auto &c : displayName) {
asStr += c.toLatin1();
}
if (!m_views.contains(displayName)) {
m_views[displayName] = viewFactory();
bool res = lm->addArea(id, displayName, m_views[displayName], true, true, isDocked, minSize, useMinSz, false, true, true);
if (!res) {
debug::out << "Failed to add view " << asStr << " to layout!" << std::endl;
return false;
}
debug::out << "Successfully added view " << asStr << " to layout!" << std::endl;
}
return true;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "./widgets.hpp"
#include <toon_boom/ext/layout.hpp>
#include <QtCore/QPointer>
typedef AC_Toolbar* (__fastcall *toolbar_fn)(void*, const char*);
class BasicGreetingView : public TUWidgetLayoutViewBase<GreetingsWidget> {
public:
BasicGreetingView();
~BasicGreetingView() override;
GreetingsWidget *createWidget() override;
QString displayName() const override;
};

View File

@ -0,0 +1,16 @@
#pragma once
#include <functional>
#include <map>
#include <QtCore/QtCore>
#include <toon_boom/toon_boom_layout.hpp>
class SimpleExamplesContainer {
public:
SimpleExamplesContainer();
~SimpleExamplesContainer();
void showBasicGreetingView();
void showCounterView();
private:
bool addViewIfNotExists(const char* id, const QString& displayName, std::function<TULayoutView*()> viewFactory, bool isDocked = true, QSize minSize = QSize(500, 400), bool useMinSz = true);
std::map<QString, TULayoutView*> m_views;
};

View File

@ -0,0 +1,23 @@
#pragma once
#include "./widgets.hpp"
#include <toon_boom/toon_boom_layout.hpp> // Includes ac_manager.hpp via toolbar.hpp
#include <toon_boom/ext/layout.hpp>
#include <QtWidgets/QWidget>
#include <QtCore/QPointer>
class CounterView : public TUWidgetLayoutViewBase<CounterWidget> {
public:
CounterView();
~CounterView() override;
CounterWidget *createWidget() override;
QDomElement toolbar() override;
QString displayName() const override;
void onParentDisconnect() override;
void afterWidgetCreated() override;
private:
QDomDocument m_toolbarDoc; // Must store document, not just element (QDomElement refs doc's data)
void initToolbar();
bool has_initialized_toolbar = false;
};

View File

@ -0,0 +1,57 @@
#pragma once
#include <QtCore/qtmetamacros.h>
#include <QtWidgets/qframe.h>
#include <QtWidgets/qgroupbox.h>
#include <QtWidgets/QtWidgets>
#include <toon_boom/ac_manager.hpp>
class WidgetWrapper : public QFrame {
public:
WidgetWrapper(QWidget *parent = nullptr) : QFrame(parent) {
setSizePolicy(QSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding));
m_wrapperLayout = new QVBoxLayout(this);
m_wrapperFrame = new QGroupBox();
m_wrapperLayout->addWidget(m_wrapperFrame, 1);
m_wrapperLayout->setContentsMargins(10, 10, 10, 10);
};
~WidgetWrapper() override {};
protected:
QGroupBox *m_wrapperFrame;
QBoxLayout *m_wrapperLayout;
};
class GreetingsWidget : public WidgetWrapper {
public:
GreetingsWidget(QWidget *parent = nullptr);
~GreetingsWidget() override;
private:
QVBoxLayout *m_mainLayout;
};
class CounterWidget : public WidgetWrapper, public AC_ResponderBase {
Q_OBJECT
public:
CounterWidget(QWidget *parent = nullptr);
~CounterWidget() override;
static const QString &IDENTITY;
public slots:
void onActionIncrementCounter();
void onActionDecrementCounter();
void onActionResetCounter();
void onActionIncrementCounterValidate(AC_ActionInfo *info);
void onActionDecrementCounterValidate(AC_ActionInfo *info);
void onActionResetCounterValidate(AC_ActionInfo *info);
int counter() const;
private:
QVBoxLayout *m_mainLayout;
QHBoxLayout *m_counterLayout;
void updateCounterLabel();
QGroupBox *m_counterFrame;
int m_counter = 0;
QLabel *m_counterLabel;
};

View File

@ -0,0 +1,18 @@
#include "./include/basic_view.hpp"
#include <QtWidgets/QLabel>
BasicGreetingView::BasicGreetingView()
: TUWidgetLayoutViewBase<GreetingsWidget>() {
}
GreetingsWidget *BasicGreetingView::createWidget() {
auto w = new GreetingsWidget(nullptr);
return w;
}
QString BasicGreetingView::displayName() const {
return QString("Basic Greeting View 👋");
}
BasicGreetingView::~BasicGreetingView() {
}

View File

@ -0,0 +1,93 @@
#include "./include/toolbar_view.hpp"
#include "./include/widgets.hpp"
#include <QtXml/QtXml>
#include <iostream>
#include <toon_boom/PLUG_Services.hpp>
#include <toon_boom/ext/util.hpp>
#include <toon_boom/toon_boom_layout.hpp>
#include <toon_boom/ext/util.hpp>
using namespace util;
CounterView::CounterView()
: TUWidgetLayoutViewBase<CounterWidget>() {}
CounterWidget *CounterView::createWidget() {
auto w = new CounterWidget(nullptr);
return w;
}
void CounterView::afterWidgetCreated() { initToolbar(); }
void CounterView::onParentDisconnect() {
debug::out << "Parent disconnected" << std::endl;
has_initialized_toolbar = false;
m_toolbarDoc = QDomDocument(); // Clear the document
}
CounterView::~CounterView() {}
QString CounterView::displayName() const {
return "Example Toolbar View";
}
void CounterView::initToolbar() {
if (has_initialized_toolbar) {
return;
}
QString errorMsg;
int errorLine = 0;
int errorCol = 0;
std::string rawToolbarXml(R"XML(<?xml version="1.0" encoding="UTF-8"?>
<toolbars>
<toolbar id="TestToolbar" customizable="true" text="Test Toolbar" visible="true">
<item icon="timeline/add.svg" id="INCREMENT_COUNTER" slot="onActionIncrementCounter()" responder="counter" text="Increment Counter" />
<item icon="timeline/remove.svg" id="DECREMENT_COUNTER" slot="onActionDecrementCounter()" responder="counter" text="Decrement Counter" />
<item icon="view/resetview.svg" id="RESET_COUNTER" slot="onActionResetCounter()" responder="counter" text="Reset Counter" />
</toolbar>
</toolbars>
)XML");
QString rawToolbarXmlQStr(rawToolbarXml.c_str());
debug::out << "Toolbar xml: " << rawToolbarXml << std::endl;
bool success = m_toolbarDoc.setContent(rawToolbarXmlQStr,
&errorMsg, &errorLine, &errorCol);
if (errorLine != 0 || errorCol != 0 || !success) {
debug::out << "Error loading toolbar XML: "
<< " at line " << errorLine << ", column " << errorCol
<< std::endl;
std::string errStr;
for (auto &c : errorMsg) {
errStr += c.toLatin1();
}
debug::out << "Error message: " << errStr << std::endl;
return;
}
debug::out << "Toolbar document node count: "
<< m_toolbarDoc.documentElement().childNodes().size() << std::endl;
has_initialized_toolbar = registerToolbar(m_toolbarDoc.documentElement(), "TestToolbar");
}
QDomElement CounterView::toolbar() {
auto am = PLUG_Services::getActionManager();
auto mgrEl = am->toolbarElement("TestToolbar");
debug::out << "mgr el" << std::endl;
/* if (mgrEl.isElement() && !mgrEl.isNull()) {
auto tagName = mgrEl.tagName();
debug::out << "\t<" << tagName.toStdString() << ">" << std::endl;
} */
debug::out << "\tis null: " << mgrEl.isNull() << std::endl
<< "\tis element:" << mgrEl.isElement() << std::endl;
auto tbe = m_toolbarDoc.documentElement().firstChildElement();
{
auto id = tbe.attribute("id");
auto asStr = id.toStdString();
debug::out << "Getting toolbar: " << asStr
<< std::endl;
}
debug::out << "item count: " << tbe.childNodes().size() << std::endl;
return tbe;
}

View File

@ -0,0 +1,90 @@
#include "./include/widgets.hpp"
#include "QtCore/qobject.h"
#include <toon_boom/ac_manager.hpp>
#include <toon_boom/PLUG_Services.hpp>
GreetingsWidget::GreetingsWidget(QWidget *parent) : WidgetWrapper(parent) {
m_mainLayout = new QVBoxLayout(m_wrapperFrame);
m_mainLayout->setContentsMargins(5, 5, 5, 5);
QLabel *label = new QLabel("greetings, universe ~ 🌸");
label->setAlignment(Qt::AlignCenter);
label->setFont(QFont("Courier New", 48, QFont::Bold));
label->setStyleSheet("color: #00d9db;");
label->setWordWrap(true);
QLabel *subtitle = new QLabel("this isn't your usual harmony view....");
subtitle->setAlignment(Qt::AlignCenter);
subtitle->setFont(QFont("Courier New", 18, -1, true));
subtitle->setWordWrap(true);
m_mainLayout->addWidget(label);
m_mainLayout->addStretch();
m_mainLayout->addWidget(subtitle);
}
GreetingsWidget::~GreetingsWidget() {}
const QString &CounterWidget::IDENTITY = QString::fromStdString("counter");
CounterWidget::CounterWidget(QWidget *parent)
: WidgetWrapper(parent),
AC_ResponderBase(IDENTITY, this,
PLUG_Services::getActionManager()) {
auto asResponderBase = dynamic_cast<AC_ResponderBase *>(this);
auto asResponder = dynamic_cast<AC_Responder *>(asResponderBase);
actionManager()->registerResponder(asResponder, this);
m_mainLayout = new QVBoxLayout(m_wrapperFrame);
QLabel *title = new QLabel("Test widget 2: Counter");
title->setAlignment(Qt::AlignCenter);
title->setFont(QFont("Courier New", 48, QFont::Bold));
title->setStyleSheet("color: #00d9db;");
title->setWordWrap(true);
m_counterFrame = new QGroupBox(this);
m_counterLayout = new QHBoxLayout(m_counterFrame);
m_counterLayout->addStretch(1);
auto counterValueLabel = new QLabel("counter value:");
auto counterFont = QFont("Courier New", 24);
counterValueLabel->setFont(counterFont);
m_counterLayout->addWidget(counterValueLabel, 1);
m_counterLabel = new QLabel("0");
m_counterLabel->setFont(counterFont);
m_counterLayout->addStretch(1);
m_counterLayout->addWidget(m_counterLabel, 1);
m_mainLayout->addWidget(title, 0, Qt::AlignCenter);
m_mainLayout->addStretch(1);
m_mainLayout->addWidget(m_counterFrame, 0, Qt::AlignCenter);
}
void CounterWidget::onActionIncrementCounter() {
m_counter++;
updateCounterLabel();
}
void CounterWidget::onActionDecrementCounter() {
m_counter--;
updateCounterLabel();
}
void CounterWidget::onActionResetCounter() {
m_counter = 0;
updateCounterLabel();
}
void CounterWidget::updateCounterLabel() {
m_counterLabel->setText(QString::number(m_counter));
}
void CounterWidget::onActionIncrementCounterValidate(AC_ActionInfo *info) {
info->setEnabled(true);
}
void CounterWidget::onActionDecrementCounterValidate(AC_ActionInfo *info) {
info->setEnabled(true);
}
void CounterWidget::onActionResetCounterValidate(AC_ActionInfo *info) {
info->setEnabled(m_counter != 0);
}
int CounterWidget::counter() const { return m_counter; }
CounterWidget::~CounterWidget() { actionManager()->unregisterResponder(this); }