Added event listener to all widgets

This commit is contained in:
Atul R 2019-06-15 23:43:11 +02:00
parent 229ecddeb1
commit 3d08908f9a
34 changed files with 253 additions and 143 deletions

View File

@ -14,6 +14,7 @@
"../src/cpp/core/FlexLayout/flexitem.cpp",
"../src/cpp/core/YogaWidget/nodestyle.cpp",
"../src/cpp/core/Events/eventsmap.cpp",
"../src/cpp/core/Events/eventwidget.cpp",
"../src/cpp/core/YogaWidget/yogawidget.cpp",
# wrapped cpps
"../src/cpp/QtGui/QApplication/qapplication_wrap.cpp",

13
demo.ts
View File

@ -25,16 +25,16 @@ const testGridLayout = () => {
label.setStyleSheet("background-color:blue; color:white;");
const button1 = new QPushButton();
button1.setSignalListener(QPushButtonSignal.clicked, isChecked => {
button1.addEventListener(QPushButtonSignal.clicked, isChecked => {
console.log("clicked", isChecked);
});
button1.setSignalListener(QPushButtonSignal.pressed, (...args) => {
button1.addEventListener(QPushButtonSignal.pressed, (...args) => {
console.log("pressed", ...args);
});
button1.setSignalListener(QPushButtonSignal.released, (...args) => {
button1.addEventListener(QPushButtonSignal.released, (...args) => {
console.log("released", ...args);
});
button1.setSignalListener(QPushButtonSignal.toggled, isToggled => {
button1.addEventListener(QPushButtonSignal.toggled, isToggled => {
console.log("toggled", isToggled);
});
@ -127,9 +127,8 @@ const testFlexLayout = () => {
const button = new QPushButton(view2);
button.setObjectName("button");
button.setText("Hululu");
button.native.subscribeToEvent("MouseButtonPress");
button.setSignalListener("MouseButtonPress", () => {
console.log("MouseButtonPress");
button.addEventListener("pressed", () => {
console.log("pressed");
});
flayout2.addWidget(button, button.getFlexNode());

View File

@ -20,7 +20,7 @@ const getButton = (
const button = new QPushButton();
button.setText(label);
button.setObjectName(`btn${value}`);
button.setSignalListener(QPushButtonSignal.clicked, () => {
button.addEventListener(QPushButtonSignal.clicked, () => {
onBtnClick(value, type);
});
return {

View File

@ -2,8 +2,9 @@
#include <QWidget>
#include <QWidget>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
class NWidget: public QWidget, public YogaWidget
class NWidget: public QWidget, public YogaWidget, public EventWidget
{
public:

View File

@ -2,6 +2,7 @@
#include "src/cpp/QtWidgets/QLayout/qlayout_wrap.h"
#include "src/cpp/core/YogaWidget/yogawidget_macro.h"
#include "src/cpp/core/Events/eventwidget_macro.h"
/*
This macro adds common QWidgets exported methods
@ -12,6 +13,7 @@
#define QWIDGET_WRAPPED_METHODS_DECLARATION \
\
YOGAWIDGET_WRAPPED_METHODS_DECLARATION \
EVENTWIDGET_WRAPPED_METHODS_DECLARATION \
\
Napi::Value show(const Napi::CallbackInfo& info) { \
Napi::Env env = info.Env(); \
@ -75,6 +77,7 @@ Napi::Value setObjectName(const Napi::CallbackInfo& info){ \
#define QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(WidgetWrapName) \
\
YOGAWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(WidgetWrapName) \
EVENTWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(WidgetWrapName) \
InstanceMethod("show", &WidgetWrapName::show), \
InstanceMethod("resize",&WidgetWrapName::resize), \
InstanceMethod("close",&WidgetWrapName::close), \

View File

@ -3,8 +3,9 @@
#include <QWidget>
#include <QCheckBox>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
class NCheckBox: public QCheckBox, public YogaWidget
class NCheckBox: public QCheckBox, public YogaWidget, public EventWidget
{
public:

View File

@ -3,8 +3,9 @@
#include <QWidget>
#include <QLabel>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
class NLabel: public QLabel, public YogaWidget
class NLabel: public QLabel, public YogaWidget, public EventWidget
{
public:

View File

@ -3,8 +3,9 @@
#include <QWidget>
#include <QLineEdit>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
class NLineEdit: public QLineEdit, public YogaWidget
class NLineEdit: public QLineEdit, public YogaWidget, public EventWidget
{
public:

View File

@ -3,10 +3,11 @@
#include <QWidget>
#include <QMainWindow>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
#include "deps/spdlog/spdlog.h"
#include <QEvent>
class NMainWindow: public QMainWindow, public YogaWidget
class NMainWindow: public QMainWindow, public YogaWidget, public EventWidget
{
private:

View File

@ -3,8 +3,9 @@
#include <QWidget>
#include <QProgressBar>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
class NProgressBar: public QProgressBar, public YogaWidget
class NProgressBar: public QProgressBar, public YogaWidget, public EventWidget
{
public:

View File

@ -1,44 +1,44 @@
#pragma once
#include <QWidget>
#include <QPushButton>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
#include "napi.h"
#include <napi-thread-safe-callback.hpp>
#include <QEvent>
#include "src/cpp/core/Events/eventsmap.h"
#include <QDebug>
class NPushButton: public QPushButton, public YogaWidget
class NPushButton: public QPushButton, public YogaWidget, public EventWidget
{
public:
std::unique_ptr<ThreadSafeCallback> emitOnNode;
SET_YOGA_WIDGET_Q_PROPERTIES
using QPushButton::QPushButton; //inherit all constructors of QPushButton
Q_OBJECT
public:
std::unordered_map<QEvent::Type, std::string> subscribedEvents;
void subscribeToEvent(std::string evtString){
try {
int evtType = EventsMap::events.at(evtString);
this->subscribedEvents.insert({static_cast<QEvent::Type>(evtType), evtString});
} catch (...) {
qDebug()<< "Coudn't subscribe to event "<< evtString.c_str();
}
}
bool event(QEvent* event){
try {
QEvent::Type e = event->type();
std::string eventTypeString = subscribedEvents.at(e);
this->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, eventTypeString) };
});
} catch (...) {}
EventWidget::event(event);
return QWidget::event(event);
}
~NPushButton(){
this->emitOnNode.release(); //cleanup instance->emitOnNode
}
void connectWidgetSignalsToEventEmitter(){
// Qt Connects: Implement all signal connects here
QObject::connect(this, &QPushButton::clicked, [=](bool checked) {
this->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "clicked"), Napi::Value::From(env, checked) };
});
});
QObject::connect(this, &QPushButton::released, [=]() {
this->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "released") };
});
});
QObject::connect(this, &QPushButton::pressed, [=]() {
this->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "pressed") };
});
});
QObject::connect(this, &QPushButton::toggled, [=](bool checked) {
this->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "toggled"), Napi::Value::From(env, checked) };
});
});
}
};

View File

@ -9,8 +9,6 @@ Napi::Object QPushButtonWrap::init(Napi::Env env, Napi::Object exports) {
char CLASSNAME[] = "QPushButton";
Napi::Function func = DefineClass(env, CLASSNAME, {
InstanceMethod("setText", &QPushButtonWrap::setText),
InstanceMethod("setupSignalListeners",&QPushButtonWrap::setupSignalListeners),
InstanceMethod("subscribeToEvent",&QPushButtonWrap::subscribeToEvent),
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QPushButtonWrap)
});
constructor = Napi::Persistent(func);
@ -43,39 +41,6 @@ QPushButtonWrap::~QPushButtonWrap() {
delete this->instance;
}
Napi::Value QPushButtonWrap::setupSignalListeners(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
this->instance->emitOnNode = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
// Qt Connects: Implement all signal connects here
QObject::connect(this->instance, &QPushButton::clicked, [=](bool checked) {
this->instance->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "clicked"), Napi::Value::From(env, checked) };
});
});
QObject::connect(this->instance, &QPushButton::released, [=]() {
this->instance->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "released") };
});
});
QObject::connect(this->instance, &QPushButton::pressed, [=]() {
this->instance->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "pressed") };
});
});
QObject::connect(this->instance, &QPushButton::toggled, [=](bool checked) {
this->instance->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, "toggled"), Napi::Value::From(env, checked) };
});
});
return env.Null();
}
Napi::Value QPushButtonWrap::subscribeToEvent(const Napi::CallbackInfo& info){
Napi::Env env = info.Env();
Napi::String eventString = info[0].As<Napi::String>();
this->instance->subscribeToEvent(eventString.Utf8Value());
return env.Null();
}
Napi::Value QPushButtonWrap::setText(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

View File

@ -3,8 +3,9 @@
#include <QWidget>
#include <QRadioButton>
#include "src/cpp/core/YogaWidget/yogawidget.h"
#include "src/cpp/core/Events/eventwidget.h"
class NRadioButton: public QRadioButton, public YogaWidget
class NRadioButton: public QRadioButton, public YogaWidget, public EventWidget
{
public:

View File

@ -294,6 +294,8 @@ void *NCheckBox::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QCheckBox::qt_metacast(_clname);
}

View File

@ -294,6 +294,8 @@ void *NLabel::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QLabel::qt_metacast(_clname);
}

View File

@ -294,6 +294,8 @@ void *NLineEdit::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QLineEdit::qt_metacast(_clname);
}

View File

@ -294,6 +294,8 @@ void *NMainWindow::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QMainWindow::qt_metacast(_clname);
}

View File

@ -294,6 +294,8 @@ void *NProgressBar::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QProgressBar::qt_metacast(_clname);
}

View File

@ -294,6 +294,8 @@ void *NPushButton::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QPushButton::qt_metacast(_clname);
}

View File

@ -294,6 +294,8 @@ void *NRadioButton::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QRadioButton::qt_metacast(_clname);
}

View File

@ -294,6 +294,8 @@ void *NWidget::qt_metacast(const char *_clname)
return static_cast<void*>(this);
if (!strcmp(_clname, "YogaWidget"))
return static_cast< YogaWidget*>(this);
if (!strcmp(_clname, "EventWidget"))
return static_cast< EventWidget*>(this);
return QWidget::qt_metacast(_clname);
}

View File

@ -0,0 +1,36 @@
#include "eventwidget.h"
#include "deps/spdlog/spdlog.h"
void EventWidget::subscribeToEvent(std::string evtString){
try {
int evtType = EventsMap::events.at(evtString);
this->subscribedEvents.insert({static_cast<QEvent::Type>(evtType), evtString});
} catch (...) {
spdlog::info("EventWidget: Couldn't subscribe to qt event {}. If this is a signal you can safely ignore this warning", evtString.c_str());
}
}
void EventWidget::event(QEvent* event){
if(this->emitOnNode){
try {
QEvent::Type evtType = event->type();
std::string eventTypeString = subscribedEvents.at(evtType);
this->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
args = { Napi::String::New(env, eventTypeString) };
});
} catch (...) {
// Do nothing
}
}
}
void EventWidget::connectWidgetSignalsToEventEmitter(){
// Do nothing
// This method should be overriden in sub classes to connect all signals to event emiiter of node. See Push button
}
EventWidget::~EventWidget(){
if(this->emitOnNode){
this->emitOnNode.release();
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <QEvent>
#include <napi-thread-safe-callback.hpp>
#include "src/cpp/core/Events/eventsmap.h"
class EventWidget {
public:
std::unique_ptr<ThreadSafeCallback> emitOnNode = nullptr;
std::unordered_map<QEvent::Type, std::string> subscribedEvents;
void subscribeToEvent(std::string evtString);
void event(QEvent* event);
void connectWidgetSignalsToEventEmitter();
~EventWidget();
};

View File

@ -0,0 +1,38 @@
#pragma once
#include "eventwidget.h"
/*
This macro adds common YogaWidget's exported methods
The exported methods are taken into this macro to avoid writing them in each and every widget we export.
*/
#ifndef EVENTWIDGET_WRAPPED_METHODS_DECLARATION
#define EVENTWIDGET_WRAPPED_METHODS_DECLARATION \
\
Napi::Value initNodeEventEmitter(const Napi::CallbackInfo& info) { \
Napi::Env env = info.Env(); \
this->instance->emitOnNode = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>()); \
this->instance->connectWidgetSignalsToEventEmitter(); \
return env.Null(); \
} \
\
Napi::Value subscribeToQtEvent(const Napi::CallbackInfo& info){ \
Napi::Env env = info.Env(); \
Napi::String eventString = info[0].As<Napi::String>(); \
this->instance->subscribeToEvent(eventString.Utf8Value()); \
return env.Null(); \
} \
#endif //EVENTWIDGET_WRAPPED_METHODS_DECLARATION
#ifndef EVENTWIDGET_WRAPPED_METHODS_EXPORT_DEFINE
#define EVENTWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(WidgetWrapName) \
\
InstanceMethod("initNodeEventEmitter",&WidgetWrapName::initNodeEventEmitter), \
InstanceMethod("subscribeToQtEvent",&WidgetWrapName::subscribeToQtEvent), \
#endif // EVENTWIDGET_WRAPPED_METHODS_EXPORT_DEFINE

View File

@ -1,10 +1,10 @@
import addon from "../../core/addon";
import { YogaWidget } from "../../core/YogaWidget";
import { NodeLayout } from "../../QtWidgets/QLayout";
import { EventWidget } from "../../core/EventWidget";
// All Widgets should extend from NodeWidget
// Implement all native QWidget methods here so that all widgets get access to those aswell
export abstract class NodeWidget extends YogaWidget {
export abstract class NodeWidget extends EventWidget {
type = "widget";
layout?: NodeLayout;
show = () => {
@ -34,12 +34,14 @@ export abstract class NodeWidget extends YogaWidget {
export class QWidget extends NodeWidget {
native: any;
constructor(parent?: QWidget) {
super();
let native;
if (parent) {
this.native = new addon.QWidget(parent.native);
this.parent = parent;
native = new addon.QWidget(parent.native);
} else {
this.native = new addon.QWidget();
native = new addon.QWidget();
}
super(native);
this.parent = parent;
this.native = native;
}
}

View File

@ -3,15 +3,20 @@ import { NodeWidget } from "../../QtGui/QWidget";
export class QCheckBox extends NodeWidget {
native: any;
constructor(parent?: NodeWidget) {
super();
let native;
if (parent) {
this.native = new addon.QCheckBox(parent.native);
this.parent = parent;
native = new addon.QCheckBox(parent.native);
} else {
this.native = new addon.QCheckBox();
native = new addon.QCheckBox();
}
super(native);
this.native = native;
this.parent = parent;
// bind member functions
this.setText.bind(this);
}
setText = (text: string) => {
setText(text: string) {
this.native.setText(text);
};
}
}

View File

@ -4,21 +4,27 @@ import { NodeWidget } from "../../QtGui/QWidget";
export class QLabel extends NodeWidget {
native: any;
constructor(parent?: NodeWidget) {
super();
let native;
if (parent) {
this.native = new addon.QLabel(parent.native);
this.parent = parent;
native = new addon.QLabel(parent.native);
} else {
this.native = new addon.QLabel();
native = new addon.QLabel();
}
super(native);
this.native = native;
this.parent = parent;
// bind member functions
this.setWordWrap.bind(this);
this.setText.bind(this);
this.text.bind(this);
}
setWordWrap = (on: boolean) => {
setWordWrap(on: boolean) {
this.native.setWordWrap(on);
};
setText = (text: string | number) => {
}
setText(text: string | number) {
this.native.setText(`${text}`);
};
text = () => {
}
text() {
return this.native.text();
};
}
}

View File

@ -4,12 +4,15 @@ import { NodeWidget } from "../../QtGui/QWidget";
export class QLineEdit extends NodeWidget {
native: any;
constructor(parent?: NodeWidget) {
super();
let native;
if (parent) {
this.native = new addon.QLineEdit(parent.native);
this.parent = parent;
native = new addon.QLineEdit(parent.native);
} else {
this.native = new addon.QLineEdit();
native = new addon.QLineEdit();
}
super(native);
this.native = native;
this.parent = parent;
// bind member functions
}
}

View File

@ -6,23 +6,29 @@ export class QMainWindow extends NodeWidget {
protected centralWidget?: NodeWidget;
protected centralWidgetFlexNode?: FlexNode;
constructor(parent?: NodeWidget) {
super();
let native;
if (parent) {
this.native = new addon.QMainWindow(parent.native);
this.parent = parent;
native = new addon.QMainWindow(parent.native);
} else {
this.native = new addon.QMainWindow();
native = new addon.QMainWindow();
}
super(native);
this.native = native;
this.parent = parent;
// bind member functions
this.setCentralWidget.bind(this);
this.setFixedSize.bind(this);
}
setCentralWidget = (widget: NodeWidget) => {
setCentralWidget(widget: NodeWidget) {
this.centralWidgetFlexNode = widget.getFlexNode();
this.centralWidget = widget;
this.native.setCentralWidget(
this.centralWidget.native,
this.centralWidgetFlexNode.native
);
};
setFixedSize = (width: number, height: number) => {
}
setFixedSize(width: number, height: number) {
this.native.setFixedSize(width, height);
};
}
}

View File

@ -4,12 +4,15 @@ import { NodeWidget } from "../../QtGui/QWidget";
export class QProgressBar extends NodeWidget {
native: any;
constructor(parent?: NodeWidget) {
super();
let native;
if (parent) {
this.native = new addon.QProgressBar(parent.native);
this.parent = parent;
native = new addon.QProgressBar(parent.native);
} else {
this.native = new addon.QProgressBar();
native = new addon.QProgressBar();
}
super(native);
this.native = native;
this.parent = parent;
// bind member functions
}
}

View File

@ -1,6 +1,5 @@
import addon from "../../core/addon";
import { NodeWidget } from "../../QtGui/QWidget";
import { SignalNodeWidget } from "../../core/SignalNodeWidget";
export enum QPushButtonSignal {
clicked = "clicked",
@ -9,7 +8,7 @@ export enum QPushButtonSignal {
toggled = "toggled"
}
export class QPushButton extends SignalNodeWidget {
export class QPushButton extends NodeWidget {
native: any;
constructor(parent?: NodeWidget) {
let native;
@ -21,6 +20,7 @@ export class QPushButton extends SignalNodeWidget {
super(native);
this.parent = parent;
this.native = native;
// bind member functions
this.setText.bind(this);
}

View File

@ -4,12 +4,15 @@ import { NodeWidget } from "../../QtGui/QWidget";
export class QRadioButton extends NodeWidget {
native: any;
constructor(parent?: NodeWidget) {
super();
let native;
if (parent) {
this.native = new addon.QRadioButton(parent.native);
this.parent = parent;
native = new addon.QRadioButton(parent.native);
} else {
this.native = new addon.QRadioButton();
native = new addon.QRadioButton();
}
super(native);
this.native = native;
this.parent = parent;
// bind member functions
}
}

View File

@ -0,0 +1,20 @@
import { EventEmitter } from "events";
import { YogaWidget } from "../YogaWidget";
export abstract class EventWidget extends YogaWidget {
private emitter: EventEmitter;
constructor(native: any) {
super();
if (native.initNodeEventEmitter) {
this.emitter = new EventEmitter();
native.initNodeEventEmitter(this.emitter.emit.bind(this.emitter));
} else {
throw new Error("initNodeEventEmitter not implemented on native side");
}
}
addEventListener = (eventType: string, callback: (payload?: any) => void) => {
this.native.subscribeToQtEvent(eventType);
this.emitter.on(eventType, callback);
};
}

View File

@ -1,22 +0,0 @@
import { NodeWidget } from "../../QtGui/QWidget";
import { EventEmitter } from "events";
export abstract class SignalNodeWidget extends NodeWidget {
private emitter: EventEmitter;
constructor(native: any) {
super();
if (native.setupSignalListeners) {
this.emitter = new EventEmitter();
native.setupSignalListeners(this.emitter.emit.bind(this.emitter));
} else {
throw new Error("Signal Listeners not implemented on native side");
}
}
setSignalListener = (
signalType: string,
callback: (payload?: any) => void
) => {
this.emitter.on(signalType, callback);
};
}