Adds custom keyevent handler. And remove dependency on napi-thread-safe-callback
This commit is contained in:
parent
ba409c8c14
commit
e15d6b14ac
@ -29,6 +29,7 @@
|
||||
"../src/cpp/QtWidgets/QProgressBar/qprogressbar_wrap.cpp",
|
||||
"../src/cpp/QtWidgets/QRadioButton/qradiobutton_wrap.cpp",
|
||||
"../src/cpp/QtWidgets/QLineEdit/qlineedit_wrap.cpp",
|
||||
"../src/cpp/core/Events/types/KeyEvent/keyevent_wrap.cpp",
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"includes": [],
|
||||
"target_defaults": {
|
||||
"include_dirs": ['../deps/', "<!@(node -p \"require('napi-thread-safe-callback').include\")"],
|
||||
"include_dirs": ['../deps/'],
|
||||
"cflags": ['-DSPDLOG_COMPILED_LIB'],
|
||||
"sources": [
|
||||
"../deps/yoga/Yoga.cpp",
|
||||
|
||||
9
demo.ts
9
demo.ts
@ -11,6 +11,7 @@ import { QProgressBar } from "./src/lib/QtWidgets/QProgressBar";
|
||||
import { QRadioButton } from "./src/lib/QtWidgets/QRadioButton";
|
||||
import { QLineEdit } from "./src/lib/QtWidgets/QLineEdit";
|
||||
import { FlexLayout } from "./src/lib/core/FlexLayout";
|
||||
import { KeyEvent } from "./src/lib/QtGui/QKeyEvent";
|
||||
|
||||
// Test all widgets in this one. This works as of now!
|
||||
const testGridLayout = () => {
|
||||
@ -70,8 +71,10 @@ const testFlexLayout = () => {
|
||||
// -> view2 -> button
|
||||
|
||||
const win = new QMainWindow();
|
||||
win.addEventListener("MouseMove", (...args) => {
|
||||
console.log(...args);
|
||||
win.addEventListener("KeyPress", nativeEvent => {
|
||||
const evt = new KeyEvent(nativeEvent);
|
||||
console.log(evt.text());
|
||||
console.log("KeyPress", evt);
|
||||
});
|
||||
win.setObjectName("win");
|
||||
win.resize(300, 300);
|
||||
@ -142,5 +145,5 @@ const testFlexLayout = () => {
|
||||
return win;
|
||||
};
|
||||
|
||||
// (global as any).win1 = testGridLayout(); //to keep gc from collecting
|
||||
(global as any).win1 = testGridLayout(); //to keep gc from collecting
|
||||
(global as any).win2 = testFlexLayout(); //to keep gc from collecting
|
||||
|
||||
@ -112,24 +112,24 @@ public:
|
||||
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) };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ 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") };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ 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") };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ 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) };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ Napi::String::New(env, "toggled"), Napi::Value::From(env, checked) });
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -148,8 +148,4 @@ We need to run Qt's MOC (Meta Object Compiler) on the file whenever we use Q_OBJ
|
||||
1. On JS side for each widget instance we create an instance of NodeJS's Event Emitter. This is done by the class `EventWidget` from which `NodeWidget` inherits
|
||||
2. We send this event emiiter's `emit` function to the C++ side by calling `initNodeEventEmitter` method and store a pointer to the event emitter's emit function using `emitOnNode`. initNodeEventEmitter function is added by a macro from EventWidget (c++). You can find the initNodeEventEmitter method with the event widget macros.
|
||||
3. We setup Qt's connect method for all the signals that we want to listen to and call the emitOnNode (which is actually emit from Event emitter) whenever a signal arrives. This is done manually on every widget by overriding the method `connectWidgetSignalsToEventEmitter`. Check `npushbutton.h` for details. This takes care of all the signals of the widgets. Now to export all qt events of the widget, we had overriden the widgets `event(Event*)` method to listen to events received by the widget and send it to the event emitter. This is done inside the EVENTWIDGET_IMPLEMENTATIONS macro
|
||||
|
||||
|
||||
> Note that we **can't** just store Napi::Function emit directly and use it. This is because we would need access to `Napi::Env` while making a call and there is no way to do it asynchronously.
|
||||
> Since NAPI (node-addon-api) doesnt support asynchronous callbacks properly yet. (Although work in underway) we use this third party library (https://github.com/mika-fischer/napi-thread-safe-callback) to do so. This library provides us a way to access the Napi::Env variable whenever we need it.
|
||||
```
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"napi-thread-safe-callback": "^0.0.6",
|
||||
"node-addon-api": "^1.6.3"
|
||||
},
|
||||
"gypfile": true
|
||||
|
||||
@ -13,24 +13,24 @@ public:
|
||||
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) };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ 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") };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ 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") };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ 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) };
|
||||
});
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({ Napi::String::New(env, "toggled"), Napi::Value::From(env, checked) });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
class QPushButtonWrap : public Napi::ObjectWrap<QPushButtonWrap> {
|
||||
private:
|
||||
NPushButton* instance;
|
||||
// std::unique_ptr<ThreadSafeCallback> emitOnNode;
|
||||
public:
|
||||
static Napi::Object init(Napi::Env env, Napi::Object exports);
|
||||
QPushButtonWrap(const Napi::CallbackInfo& info);
|
||||
|
||||
@ -17,10 +17,14 @@ void EventWidget::event(QEvent* event){
|
||||
try {
|
||||
QEvent::Type evtType = event->type();
|
||||
std::string eventTypeString = subscribedEvents.at(evtType);
|
||||
this->emitOnNode->call([=](Napi::Env env, std::vector<napi_value>& args) {
|
||||
Napi::Value nativeEvent = Napi::External<QEvent>::New(env, event);
|
||||
args = { Napi::String::New(env, eventTypeString), nativeEvent };
|
||||
});
|
||||
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
Napi::Value nativeEvent = Napi::External<QEvent>::New(env, event);
|
||||
std::vector<napi_value> args = { Napi::String::New(env, eventTypeString), nativeEvent };
|
||||
|
||||
this->emitOnNode.Call(args);
|
||||
} catch (...) {
|
||||
// Do nothing
|
||||
}
|
||||
@ -34,6 +38,6 @@ void EventWidget::connectWidgetSignalsToEventEmitter(){
|
||||
|
||||
EventWidget::~EventWidget(){
|
||||
if(this->emitOnNode){
|
||||
this->emitOnNode.release();
|
||||
this->emitOnNode.Reset();
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <QEvent>
|
||||
#include <napi-thread-safe-callback.hpp>
|
||||
#include "src/cpp/core/Events/eventsmap.h"
|
||||
#include <napi.h>
|
||||
|
||||
class EventWidget {
|
||||
public:
|
||||
std::unique_ptr<ThreadSafeCallback> emitOnNode = nullptr;
|
||||
Napi::FunctionReference emitOnNode;
|
||||
std::unordered_map<QEvent::Type, std::string> subscribedEvents;
|
||||
|
||||
void subscribeToQtEvent(std::string evtString);
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
\
|
||||
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->emitOnNode = Napi::Persistent(info[0].As<Napi::Function>()); \
|
||||
this->instance->connectWidgetSignalsToEventEmitter(); \
|
||||
return env.Null(); \
|
||||
} \
|
||||
|
||||
44
src/cpp/core/Events/types/KeyEvent/keyevent_wrap.cpp
Normal file
44
src/cpp/core/Events/types/KeyEvent/keyevent_wrap.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "keyevent_wrap.h"
|
||||
#include "src/cpp/Extras/Utils/nutils.h"
|
||||
#include <QString>
|
||||
#include "deps/spdlog/spdlog.h"
|
||||
|
||||
|
||||
Napi::FunctionReference QKeyEventWrap::constructor;
|
||||
|
||||
Napi::Object QKeyEventWrap::init(Napi::Env env, Napi::Object exports) {
|
||||
Napi::HandleScope scope(env);
|
||||
char CLASSNAME[] = "QKeyEvent";
|
||||
Napi::Function func = DefineClass(env, CLASSNAME, {
|
||||
InstanceMethod("text", &QKeyEventWrap::text),
|
||||
});
|
||||
constructor = Napi::Persistent(func);
|
||||
exports.Set(CLASSNAME, func);
|
||||
return exports;
|
||||
}
|
||||
|
||||
QKeyEvent* QKeyEventWrap::getInternalInstance() {
|
||||
return this->instance;
|
||||
}
|
||||
|
||||
QKeyEventWrap::QKeyEventWrap(const Napi::CallbackInfo& info): Napi::ObjectWrap<QKeyEventWrap>(info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
if(info.Length() == 1) {
|
||||
Napi::External<QKeyEvent> eventObject = info[0].As<Napi::External<QKeyEvent>>();
|
||||
this->instance = eventObject.Data();
|
||||
} else {
|
||||
extrautils::throwTypeError(env, "Wrong number of arguments");
|
||||
}
|
||||
}
|
||||
|
||||
QKeyEventWrap::~QKeyEventWrap() {
|
||||
// Do not destroy instance here. It will be done by Qt Event loop.
|
||||
}
|
||||
|
||||
Napi::Value QKeyEventWrap::text(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
int keyText = this->instance->key();
|
||||
Napi::String keyValue = Napi::String::New(env, std::to_string(keyText));
|
||||
return keyValue;
|
||||
}
|
||||
20
src/cpp/core/Events/types/KeyEvent/keyevent_wrap.h
Normal file
20
src/cpp/core/Events/types/KeyEvent/keyevent_wrap.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <napi.h>
|
||||
#include <QKeyEvent>
|
||||
|
||||
class QKeyEventWrap : public Napi::ObjectWrap<QKeyEventWrap>{
|
||||
private:
|
||||
QKeyEvent* instance;
|
||||
|
||||
public:
|
||||
static Napi::Object init(Napi::Env env, Napi::Object exports);
|
||||
QKeyEventWrap(const Napi::CallbackInfo& info);
|
||||
~QKeyEventWrap();
|
||||
QKeyEvent* getInternalInstance();
|
||||
//class constructor
|
||||
static Napi::FunctionReference constructor;
|
||||
//wrapped methods
|
||||
Napi::Value text(const Napi::CallbackInfo& info);
|
||||
// Napi::Value setFlexNode(const Napi::CallbackInfo& info);
|
||||
};
|
||||
@ -10,6 +10,7 @@
|
||||
#include "src/cpp/QtWidgets/QRadioButton/qradiobutton_wrap.h"
|
||||
#include "src/cpp/QtWidgets/QLineEdit/qlineedit_wrap.h"
|
||||
#include "src/cpp/core/FlexLayout/flexlayout_wrap.h"
|
||||
#include "src/cpp/core/Events/types/KeyEvent/keyevent_wrap.h"
|
||||
#include <napi.h>
|
||||
|
||||
// These cant be instantiated in JS Side
|
||||
@ -29,6 +30,7 @@ Napi::Object Main(Napi::Env env, Napi::Object exports) {
|
||||
QProgressBarWrap::init(env, exports);
|
||||
QRadioButtonWrap::init(env, exports);
|
||||
QLineEditWrap::init(env, exports);
|
||||
QKeyEventWrap::init(env, exports);
|
||||
return QLabelWrap::init(env, exports);
|
||||
}
|
||||
|
||||
|
||||
13
src/lib/QtGui/QKeyEvent/index.ts
Normal file
13
src/lib/QtGui/QKeyEvent/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import addon from "../../core/addon";
|
||||
import { NativeElement } from "../../core/Component";
|
||||
import { NativeEvent } from "../../core/EventWidget";
|
||||
|
||||
export class KeyEvent {
|
||||
native: NativeElement;
|
||||
constructor(event: NativeEvent) {
|
||||
this.native = new addon.QKeyEvent(event);
|
||||
}
|
||||
text = (): string => {
|
||||
return this.native.text();
|
||||
};
|
||||
}
|
||||
@ -2,7 +2,7 @@ import { EventEmitter } from "events";
|
||||
import { YogaWidget } from "../YogaWidget";
|
||||
import { NativeElement } from "../Component";
|
||||
|
||||
type NativeEvent = {};
|
||||
export type NativeEvent = {};
|
||||
export abstract class EventWidget extends YogaWidget {
|
||||
private emitter: EventEmitter;
|
||||
constructor(native: NativeElement) {
|
||||
|
||||
@ -413,11 +413,6 @@ mkdirp@^0.5.0:
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
napi-thread-safe-callback@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/napi-thread-safe-callback/-/napi-thread-safe-callback-0.0.6.tgz#ef86a149b5312e480f74e89a614e6d9e3b17b456"
|
||||
integrity sha512-X7uHCOCdY4u0yamDxDrv3jF2NtYc8A1nvPzBQgvpoSX+WB3jAe2cVNsY448V1ucq7Whf9Wdy02HEUoLW5rJKWg==
|
||||
|
||||
node-addon-api@^1.6.3:
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.3.tgz#3998d4593e2dca2ea82114670a4eb003386a9fe1"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user