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
+2 -1
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:
+3
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), \
+2 -1
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:
+2 -1
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:
+2 -1
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:
+2 -1
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:
@@ -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:
+27 -27
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) };
});
});
}
};
@@ -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();
@@ -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:
+2
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);
}
+2
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);
}
+2
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);
}
+2
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);
}
+2
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);
}
+2
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);
}
+2
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);
}
+2
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);
}
+36
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();
}
}
+19
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();
};
+38
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
+8 -6
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;
}
}
+11 -6
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);
};
}
}
+16 -10
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();
};
}
}
+7 -4
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
}
}
+14 -8
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);
};
}
}
+7 -4
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
}
}
+2 -2
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);
}
+7 -4
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
}
}
+20
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);
};
}
-22
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);
};
}