Merge pull request #886 from nodegui/qscreen_qwindow
Add `QScreen` and `QWindow`, remove the deprecated `QDesktopWidget`
This commit is contained in:
commit
8d4a7f2d00
@ -11,6 +11,9 @@ set(CORE_WIDGETS_ADDON "nodegui_core")
|
||||
|
||||
project(${CORE_WIDGETS_ADDON})
|
||||
|
||||
|
||||
# Note: CMake+moc also use this list when finding files which `moc` applied.
|
||||
|
||||
add_library(${CORE_WIDGETS_ADDON} SHARED
|
||||
"${CMAKE_JS_SRC}"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/main.cpp"
|
||||
@ -24,6 +27,8 @@ add_library(${CORE_WIDGETS_ADDON} SHARED
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/core/Events/eventsmap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/core/Events/eventwidget.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/core/YogaWidget/yogawidget.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/core/WrapperCache/wrappercache.cpp"
|
||||
# core deps
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/deps/yoga/log.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/deps/yoga/Utils.cpp"
|
||||
@ -65,7 +70,9 @@ add_library(${CORE_WIDGETS_ADDON} SHARED
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QKeySequence/qkeysequence_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QMovie/qmovie_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QPalette/qpalette_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QStyle/qstyle_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QAbstractItemModel/qabstractitemmodel_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QDate/qdate_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QDateTime/qdatetime_wrap.cpp"
|
||||
@ -147,7 +154,6 @@ add_library(${CORE_WIDGETS_ADDON} SHARED
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QStandardItemModel/qstandarditemmodel_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QStandardItem/qstandarditem_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QSvgWidget/qsvgwidget_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QDesktopWidget/qdesktopwidget_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QStyleFactory/qstylefactory_wrap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QSplitter/qsplitter_wrap.cpp"
|
||||
# Custom widgets (include them for automoc since they contain Q_OBJECT)
|
||||
@ -214,9 +220,13 @@ add_library(${CORE_WIDGETS_ADDON} SHARED
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QTextBrowser/ntextbrowser.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QTextEdit/ntextedit.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QSvgWidget/nsvgwidget.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QDesktopWidget/nqdesktopwidget.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QHeaderView/nheaderview.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QSplitter/nsplitter.hpp"
|
||||
|
||||
# Test
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/test/CacheTestQObject.h"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/test/CacheTestQObject.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/cpp/lib/test/cachetestqobject_wrap.cpp"
|
||||
)
|
||||
|
||||
AddCommonConfig(${CORE_WIDGETS_ADDON})
|
||||
|
||||
@ -17,6 +17,7 @@ DLL_EXPORT void* configureQWidget(QWidget* widget, YGNodeRef node,
|
||||
bool isLeafNode = false);
|
||||
DLL_EXPORT void* configureQObject(QObject* object);
|
||||
DLL_EXPORT void* configureComponent(void* component);
|
||||
DLL_EXPORT uint64_t hashPointerTo53bit(const void* input);
|
||||
|
||||
template <typename T>
|
||||
void safeDelete(QPointer<T>& component) {
|
||||
|
||||
@ -12,11 +12,17 @@
|
||||
and every widget we export.
|
||||
*/
|
||||
|
||||
#ifndef QOBJECT_WRAPPED_METHODS_DECLARATION
|
||||
#define QOBJECT_WRAPPED_METHODS_DECLARATION \
|
||||
#ifndef QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE
|
||||
#define QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(source) \
|
||||
\
|
||||
EVENTWIDGET_WRAPPED_METHODS_DECLARATION \
|
||||
EVENTWIDGET_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(source) \
|
||||
\
|
||||
Napi::Value __id__(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
Napi::HandleScope scope(env); \
|
||||
return Napi::Value::From( \
|
||||
env, extrautils::hashPointerTo53bit(this->instance.data())); \
|
||||
} \
|
||||
Napi::Value inherits(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
Napi::HandleScope scope(env); \
|
||||
@ -73,6 +79,11 @@
|
||||
return env.Null(); \
|
||||
}
|
||||
|
||||
#endif // QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE
|
||||
|
||||
#ifndef QOBJECT_WRAPPED_METHODS_DECLARATION
|
||||
#define QOBJECT_WRAPPED_METHODS_DECLARATION \
|
||||
QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(this->instance.data())
|
||||
#endif // QOBJECT_WRAPPED_METHODS_DECLARATION
|
||||
|
||||
#ifndef QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE
|
||||
@ -80,7 +91,8 @@
|
||||
\
|
||||
EVENTWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(ComponentWrapName) \
|
||||
\
|
||||
InstanceMethod("inherits", &ComponentWrapName::inherits), \
|
||||
InstanceMethod("__id__", &ComponentWrapName::__id__), \
|
||||
InstanceMethod("inherits", &ComponentWrapName::inherits), \
|
||||
InstanceMethod("setProperty", &ComponentWrapName::setProperty), \
|
||||
InstanceMethod("property", &ComponentWrapName::property), \
|
||||
InstanceMethod("setObjectName", &ComponentWrapName::setObjectName), \
|
||||
@ -90,9 +102,9 @@
|
||||
|
||||
#endif // QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE
|
||||
|
||||
#ifndef QOBJECT_SIGNALS
|
||||
#define QOBJECT_SIGNALS \
|
||||
QObject::connect(this, &QObject::objectNameChanged, \
|
||||
#ifndef QOBJECT_SIGNALS_ON_TARGET
|
||||
#define QOBJECT_SIGNALS_ON_TARGET(target) \
|
||||
QObject::connect(target, &QObject::objectNameChanged, \
|
||||
[=](const QString& objectName) { \
|
||||
Napi::Env env = this->emitOnNode.Env(); \
|
||||
Napi::HandleScope scope(env); \
|
||||
@ -100,5 +112,8 @@
|
||||
{Napi::String::New(env, "objectNameChanged"), \
|
||||
Napi::Value::From(env, objectName.toStdString())}); \
|
||||
});
|
||||
#endif // QOBJECT_SIGNALS_ON_TARGET
|
||||
|
||||
#ifndef QOBJECT_SIGNALS
|
||||
#define QOBJECT_SIGNALS QOBJECT_SIGNALS_ON_TARGET(this)
|
||||
#endif // QOBJECT_SIGNALS
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
|
||||
#include "Extras/Export/export.h"
|
||||
#include "QtCore/QObject/qobject_macro.h"
|
||||
#include "QtGui/QScreen/qscreen_wrap.h"
|
||||
#include "core/WrapperCache/wrappercache.h"
|
||||
#include "napi.h"
|
||||
|
||||
class DLL_EXPORT NApplication : public QApplication, public EventWidget {
|
||||
@ -22,5 +24,33 @@ class DLL_EXPORT NApplication : public QApplication, public EventWidget {
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({Napi::String::New(env, "focusWindowChanged")});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this, &QGuiApplication::primaryScreenChanged, [=](QScreen* screen) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance =
|
||||
WrapperCache::instance.get<QScreen, QScreenWrap>(env, screen);
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "primaryScreenChanged"), instance});
|
||||
});
|
||||
|
||||
QObject::connect(this, &QGuiApplication::screenAdded, [=](QScreen* screen) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance =
|
||||
WrapperCache::instance.get<QScreen, QScreenWrap>(env, screen);
|
||||
this->emitOnNode.Call({Napi::String::New(env, "screenAdded"), instance});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this, &QGuiApplication::screenRemoved, [=](QScreen* screen) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance =
|
||||
WrapperCache::instance.get<QScreen, QScreenWrap>(env, screen);
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "screenRemoved"), instance});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -30,11 +30,14 @@ class DLL_EXPORT QApplicationWrap : public Napi::ObjectWrap<QApplicationWrap> {
|
||||
Napi::Value quitOnLastWindowClosed(const Napi::CallbackInfo& info);
|
||||
Napi::Value palette(const Napi::CallbackInfo& info);
|
||||
Napi::Value setStyleSheet(const Napi::CallbackInfo& info);
|
||||
Napi::Value devicePixelRatio(const Napi::CallbackInfo& info);
|
||||
};
|
||||
|
||||
namespace StaticQApplicationWrapMethods {
|
||||
DLL_EXPORT Napi::Value instance(const Napi::CallbackInfo& info);
|
||||
DLL_EXPORT Napi::Value clipboard(const Napi::CallbackInfo& info);
|
||||
DLL_EXPORT Napi::Value instance(const Napi::CallbackInfo& info);
|
||||
DLL_EXPORT Napi::Value primaryScreen(const Napi::CallbackInfo& info);
|
||||
DLL_EXPORT Napi::Value screens(const Napi::CallbackInfo& info);
|
||||
DLL_EXPORT Napi::Value setStyle(const Napi::CallbackInfo& info);
|
||||
DLL_EXPORT Napi::Value style(const Napi::CallbackInfo& info);
|
||||
} // namespace StaticQApplicationWrapMethods
|
||||
|
||||
31
src/cpp/include/nodegui/QtGui/QScreen/qscreen_wrap.h
Normal file
31
src/cpp/include/nodegui/QtGui/QScreen/qscreen_wrap.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <napi.h>
|
||||
|
||||
#include <QPointer>
|
||||
#include <QScreen>
|
||||
|
||||
#include "Extras/Export/export.h"
|
||||
#include "QtCore/QObject/qobject_macro.h"
|
||||
|
||||
class DLL_EXPORT QScreenWrap : public Napi::ObjectWrap<QScreenWrap>,
|
||||
public EventWidget {
|
||||
QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(this)
|
||||
// Note: We don't use EVENTWIDGET_IMPLEMENTATIONS() here because this class
|
||||
// doesn't handle any QEvents.
|
||||
|
||||
private:
|
||||
QPointer<QScreen> instance;
|
||||
|
||||
public:
|
||||
// class constructor
|
||||
static Napi::FunctionReference constructor;
|
||||
|
||||
static Napi::Object init(Napi::Env env, Napi::Object exports);
|
||||
QScreenWrap(const Napi::CallbackInfo& info);
|
||||
QScreen* getInternalInstance();
|
||||
|
||||
virtual void connectSignalsToEventEmitter();
|
||||
|
||||
// Wrapped methods
|
||||
};
|
||||
32
src/cpp/include/nodegui/QtGui/QWindow/qwindow_wrap.h
Normal file
32
src/cpp/include/nodegui/QtGui/QWindow/qwindow_wrap.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <napi.h>
|
||||
|
||||
#include <QPointer>
|
||||
#include <QWindow>
|
||||
|
||||
#include "Extras/Export/export.h"
|
||||
#include "QtCore/QObject/qobject_macro.h"
|
||||
|
||||
class DLL_EXPORT QWindowWrap : public Napi::ObjectWrap<QWindowWrap>,
|
||||
public EventWidget {
|
||||
QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(this)
|
||||
// Note: We don't use EVENTWIDGET_IMPLEMENTATIONS() here because this class
|
||||
// doesn't handle any QEvents.
|
||||
|
||||
private:
|
||||
QPointer<QWindow> instance;
|
||||
|
||||
public:
|
||||
// class constructor
|
||||
static Napi::FunctionReference constructor;
|
||||
|
||||
static Napi::Object init(Napi::Env env, Napi::Object exports);
|
||||
QWindowWrap(const Napi::CallbackInfo& info);
|
||||
QWindow* getInternalInstance();
|
||||
|
||||
virtual void connectSignalsToEventEmitter();
|
||||
|
||||
// wrapped methods
|
||||
Napi::Value screen(const Napi::CallbackInfo& info);
|
||||
};
|
||||
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "core/NodeWidget/nodewidget.h"
|
||||
|
||||
class NQDesktopWidget : public QDesktopWidget, public NodeWidget {
|
||||
public:
|
||||
Q_OBJECT
|
||||
NODEWIDGET_IMPLEMENTATIONS(QDesktopWidget)
|
||||
public:
|
||||
using QDesktopWidget::QDesktopWidget; // inherit all constructors of
|
||||
// QStatusBar
|
||||
};
|
||||
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
#include <QPointer>
|
||||
|
||||
#include "QtWidgets/QWidget/qwidget_macro.h"
|
||||
#include "napi.h"
|
||||
#include "nqdesktopwidget.hpp"
|
||||
|
||||
class QDesktopWidgetWrap : public Napi::ObjectWrap<QDesktopWidgetWrap> {
|
||||
private:
|
||||
QPointer<NQDesktopWidget> instance;
|
||||
|
||||
public:
|
||||
static Napi::Object init(Napi::Env env, Napi::Object exports);
|
||||
QDesktopWidgetWrap(const Napi::CallbackInfo &info);
|
||||
~QDesktopWidgetWrap();
|
||||
NQDesktopWidget *getInternalInstance();
|
||||
static Napi::FunctionReference constructor;
|
||||
// wrapped methods
|
||||
Napi::Value availableGeometry(const Napi::CallbackInfo &info);
|
||||
Napi::Value screenGeometry(const Napi::CallbackInfo &info);
|
||||
Napi::Value screenNumber(const Napi::CallbackInfo &info);
|
||||
|
||||
QWIDGET_WRAPPED_METHODS_DECLARATION
|
||||
};
|
||||
@ -10,8 +10,10 @@
|
||||
#include "QtGui/QCursor/qcursor_wrap.h"
|
||||
#include "QtGui/QIcon/qicon_wrap.h"
|
||||
#include "QtGui/QStyle/qstyle_wrap.h"
|
||||
#include "QtGui/QWindow/qwindow_wrap.h"
|
||||
#include "QtWidgets/QAction/qaction_wrap.h"
|
||||
#include "QtWidgets/QLayout/qlayout_wrap.h"
|
||||
#include "core/WrapperCache/wrappercache.h"
|
||||
#include "core/YogaWidget/yogawidget_macro.h"
|
||||
/*
|
||||
|
||||
@ -537,6 +539,16 @@
|
||||
bool modified = info[0].As<Napi::Boolean>().Value(); \
|
||||
this->instance->setWindowModified(modified); \
|
||||
return env.Null(); \
|
||||
} \
|
||||
Napi::Value windowHandle(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
Napi::HandleScope scope(env); \
|
||||
QWindow* window = this->instance->windowHandle(); \
|
||||
if (window) { \
|
||||
return WrapperCache::instance.get<QWindow, QWindowWrap>(env, window); \
|
||||
} else { \
|
||||
return env.Null(); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif // QWIDGET_WRAPPED_METHODS_DECLARATION
|
||||
@ -613,7 +625,8 @@
|
||||
InstanceMethod("setDisabled", &WidgetWrapName::setDisabled), \
|
||||
InstanceMethod("setHidden", &WidgetWrapName::setHidden), \
|
||||
InstanceMethod("setVisible", &WidgetWrapName::setVisible), \
|
||||
InstanceMethod("setWindowModified", &WidgetWrapName::setWindowModified),
|
||||
InstanceMethod("setWindowModified", &WidgetWrapName::setWindowModified), \
|
||||
InstanceMethod("windowHandle", &WidgetWrapName::windowHandle),
|
||||
|
||||
#endif // QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE
|
||||
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
#ifndef COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE
|
||||
#define COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE(ComponentWrapName) \
|
||||
\
|
||||
InstanceValue("type", Napi::String::New(env, "native")),
|
||||
InstanceValue("type", Napi::String::New(env, "native")), \
|
||||
InstanceValue("wrapperType", \
|
||||
Napi::String::New(env, #ComponentWrapName)),
|
||||
#endif
|
||||
|
||||
#ifndef COMPONENT_WRAPPED_METHODS_DECLARATION
|
||||
|
||||
@ -33,54 +33,55 @@ struct InitHelper {
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef EVENTWIDGET_WRAPPED_METHODS_DECLARATION
|
||||
#define EVENTWIDGET_WRAPPED_METHODS_DECLARATION \
|
||||
COMPONENT_WRAPPED_METHODS_DECLARATION \
|
||||
Napi::Value initNodeEventEmitter(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
EventWidget* eventWidget = \
|
||||
dynamic_cast<EventWidget*>(this->instance.data()); \
|
||||
if (eventWidget) { \
|
||||
eventWidget->emitOnNode = \
|
||||
Napi::Persistent(info[0].As<Napi::Function>()); \
|
||||
} \
|
||||
InitHelper<std::remove_pointer<decltype(this->instance.data())>::type>:: \
|
||||
connectSignalsToEventEmitter(this->instance.data()); \
|
||||
return env.Null(); \
|
||||
} \
|
||||
Napi::Value getNodeEventEmitter(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
EventWidget* eventWidget = \
|
||||
dynamic_cast<EventWidget*>(this->instance.data()); \
|
||||
if (eventWidget && eventWidget->emitOnNode) { \
|
||||
return eventWidget->emitOnNode.Value(); \
|
||||
} else { \
|
||||
return env.Null(); \
|
||||
} \
|
||||
} \
|
||||
Napi::Value subscribeToQtEvent(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
Napi::String eventString = info[0].As<Napi::String>(); \
|
||||
EventWidget* eventWidget = \
|
||||
dynamic_cast<EventWidget*>(this->instance.data()); \
|
||||
bool success = false; \
|
||||
if (eventWidget) { \
|
||||
eventWidget->subscribeToQtEvent(eventString.Utf8Value()); \
|
||||
success = true; \
|
||||
} \
|
||||
return Napi::Boolean::New(env, success); \
|
||||
} \
|
||||
Napi::Value unSubscribeToQtEvent(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
Napi::String eventString = info[0].As<Napi::String>(); \
|
||||
EventWidget* eventWidget = \
|
||||
dynamic_cast<EventWidget*>(this->instance.data()); \
|
||||
if (eventWidget) { \
|
||||
eventWidget->unSubscribeToQtEvent(eventString.Utf8Value()); \
|
||||
} \
|
||||
return env.Null(); \
|
||||
#ifndef EVENTWIDGET_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE
|
||||
#define EVENTWIDGET_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(source) \
|
||||
COMPONENT_WRAPPED_METHODS_DECLARATION \
|
||||
Napi::Value initNodeEventEmitter(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
EventWidget* eventWidget = dynamic_cast<EventWidget*>(source); \
|
||||
if (eventWidget) { \
|
||||
eventWidget->emitOnNode = \
|
||||
Napi::Persistent(info[0].As<Napi::Function>()); \
|
||||
} \
|
||||
InitHelper<std::remove_pointer<decltype(source)>::type>:: \
|
||||
connectSignalsToEventEmitter(source); \
|
||||
return env.Null(); \
|
||||
} \
|
||||
Napi::Value getNodeEventEmitter(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
EventWidget* eventWidget = dynamic_cast<EventWidget*>(source); \
|
||||
if (eventWidget && eventWidget->emitOnNode) { \
|
||||
return eventWidget->emitOnNode.Value(); \
|
||||
} else { \
|
||||
return env.Null(); \
|
||||
} \
|
||||
} \
|
||||
Napi::Value subscribeToQtEvent(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
Napi::String eventString = info[0].As<Napi::String>(); \
|
||||
EventWidget* eventWidget = dynamic_cast<EventWidget*>(source); \
|
||||
bool success = false; \
|
||||
if (eventWidget) { \
|
||||
eventWidget->subscribeToQtEvent(eventString.Utf8Value()); \
|
||||
success = true; \
|
||||
} \
|
||||
return Napi::Boolean::New(env, success); \
|
||||
} \
|
||||
Napi::Value unSubscribeToQtEvent(const Napi::CallbackInfo& info) { \
|
||||
Napi::Env env = info.Env(); \
|
||||
Napi::String eventString = info[0].As<Napi::String>(); \
|
||||
EventWidget* eventWidget = dynamic_cast<EventWidget*>(source); \
|
||||
if (eventWidget) { \
|
||||
eventWidget->unSubscribeToQtEvent(eventString.Utf8Value()); \
|
||||
} \
|
||||
return env.Null(); \
|
||||
}
|
||||
#endif // EVENTWIDGET_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE
|
||||
|
||||
#ifndef EVENTWIDGET_WRAPPED_METHODS_DECLARATION
|
||||
#define EVENTWIDGET_WRAPPED_METHODS_DECLARATION \
|
||||
EVENTWIDGET_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE( \
|
||||
this->instance.data())
|
||||
#endif // EVENTWIDGET_WRAPPED_METHODS_DECLARATION
|
||||
|
||||
#ifndef EVENTWIDGET_WRAPPED_METHODS_EXPORT_DEFINE
|
||||
|
||||
103
src/cpp/include/nodegui/core/WrapperCache/wrappercache.h
Normal file
103
src/cpp/include/nodegui/core/WrapperCache/wrappercache.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <napi.h>
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "Extras/Export/export.h"
|
||||
#include "QtGui/QScreen/qscreen_wrap.h"
|
||||
|
||||
struct CachedObject {
|
||||
napi_ref ref;
|
||||
napi_env env;
|
||||
};
|
||||
|
||||
/**
|
||||
* C++ side cache for wrapper objects.
|
||||
*
|
||||
* This can cache wrappers for QObjects and uses the Qt "destroyed" signal to
|
||||
* track lifetime and remove objects from the cache. It has a JS side component
|
||||
* `WrapperCache.ts` which can cache the JS side wrapper object.
|
||||
*/
|
||||
class DLL_EXPORT WrapperCache : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QMap<const QObject*, CachedObject> cache;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Singleton instance. Use this to access the cache.
|
||||
*/
|
||||
static WrapperCache instance;
|
||||
|
||||
/**
|
||||
* Get a wrapper for a given Qt object.
|
||||
*
|
||||
* @param T - (template argument) The Qt class of the object being cached,
|
||||
* e.g. `QScreen`.
|
||||
* @param W - (template argument) The wrapper type which matches the object
|
||||
* `QScreenWrap`.
|
||||
* @param env = Napi environment
|
||||
* @param object - Pointer to the QObject for which a wrapper is required.
|
||||
* @return The JS wrapper object.
|
||||
*/
|
||||
template <class T, class W>
|
||||
Napi::Object get(Napi::Env env, T* object) {
|
||||
if (this->cache.contains(object)) {
|
||||
napi_value result = nullptr;
|
||||
napi_get_reference_value(env, this->cache[object].ref, &result);
|
||||
return Napi::Object(env, result);
|
||||
}
|
||||
|
||||
Napi::Object wrapper =
|
||||
W::constructor.New({Napi::External<T>::New(env, object)});
|
||||
|
||||
napi_ref ref = nullptr;
|
||||
napi_create_reference(env, wrapper, 1, &ref);
|
||||
this->cache[object].env = napi_env(env);
|
||||
this->cache[object].ref = ref;
|
||||
|
||||
QObject::connect(object, &QObject::destroyed, this,
|
||||
&WrapperCache::handleDestroyed);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
static Napi::Object init(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set("WrapperCache_injectCallback",
|
||||
Napi::Function::New<injectDestroyCallback>(env));
|
||||
return exports;
|
||||
}
|
||||
|
||||
static Napi::Value injectDestroyCallback(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
destroyedCallback = Napi::Persistent(info[0].As<Napi::Function>());
|
||||
return env.Null();
|
||||
}
|
||||
|
||||
static Napi::FunctionReference destroyedCallback;
|
||||
|
||||
public Q_SLOTS:
|
||||
void handleDestroyed(const QObject* object) {
|
||||
if (!this->cache.contains(object)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Callback to JS with the address/ID of the destroyed object. So that it
|
||||
// can clear it out of the cache.
|
||||
if (destroyedCallback) {
|
||||
Napi::Env env = destroyedCallback.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
destroyedCallback.Call(
|
||||
env.Global(),
|
||||
{Napi::Value::From(env, extrautils::hashPointerTo53bit(object))});
|
||||
}
|
||||
|
||||
uint32_t result = 0;
|
||||
napi_reference_unref(this->cache[object].env, this->cache[object].ref,
|
||||
&result);
|
||||
this->cache.remove(object);
|
||||
}
|
||||
};
|
||||
20
src/cpp/include/nodegui/test/CacheTestQObject.h
Normal file
20
src/cpp/include/nodegui/test/CacheTestQObject.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "Extras/Export/export.h"
|
||||
|
||||
class CacheTestQObject;
|
||||
|
||||
class DLL_EXPORT CacheTestQObject : public QObject {
|
||||
Q_OBJECT
|
||||
private:
|
||||
CacheTestQObject* _foo;
|
||||
CacheTestQObject* _bar;
|
||||
|
||||
public:
|
||||
CacheTestQObject();
|
||||
CacheTestQObject* foo();
|
||||
void clearFoo();
|
||||
CacheTestQObject* bar();
|
||||
};
|
||||
34
src/cpp/include/nodegui/test/cachetestqobject_wrap.h
Normal file
34
src/cpp/include/nodegui/test/cachetestqobject_wrap.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <napi.h>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
#include "Extras/Export/export.h"
|
||||
#include "QtCore/QObject/qobject_macro.h"
|
||||
#include "test/CacheTestQObject.h"
|
||||
|
||||
class DLL_EXPORT CacheTestQObjectWrap
|
||||
: public Napi::ObjectWrap<CacheTestQObjectWrap>,
|
||||
public EventWidget {
|
||||
QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(this)
|
||||
|
||||
private:
|
||||
QPointer<CacheTestQObject> instance;
|
||||
|
||||
public:
|
||||
// class constructor
|
||||
static Napi::FunctionReference constructor;
|
||||
|
||||
static Napi::Object init(Napi::Env env, Napi::Object exports);
|
||||
|
||||
CacheTestQObjectWrap(const Napi::CallbackInfo& info);
|
||||
CacheTestQObject* getInternalInstance();
|
||||
|
||||
virtual void connectSignalsToEventEmitter();
|
||||
|
||||
// wrapped methods
|
||||
Napi::Value foo(const Napi::CallbackInfo& info);
|
||||
Napi::Value clearFoo(const Napi::CallbackInfo& info);
|
||||
Napi::Value bar(const Napi::CallbackInfo& info);
|
||||
};
|
||||
@ -110,6 +110,20 @@ void* extrautils::configureQWidget(QWidget* widget, YGNodeRef node,
|
||||
return configureQObject(widget);
|
||||
}
|
||||
|
||||
uint64_t extrautils::hashPointerTo53bit(const void* input) {
|
||||
// Hash the address of the object down to something which will
|
||||
// fit into the JS 53bit safe integer space.
|
||||
uint64_t address = reinterpret_cast<uint64_t>(input);
|
||||
uint64_t top8Bits = address & 0xff00000000000000u;
|
||||
uint64_t foldedBits = (top8Bits >> 11) ^ address;
|
||||
|
||||
// Clear the top 8bits which we folded, now shift out the last 3 bits
|
||||
// Pointers are aligned on 64bit architectures to at least 8bytes
|
||||
// boundaries.
|
||||
uint64_t result = (foldedBits & ~0xff00000000000000u) >> 3;
|
||||
return result;
|
||||
}
|
||||
|
||||
Napi::FunctionReference NUtilsWrap::constructor;
|
||||
|
||||
Napi::Object NUtilsWrap::init(Napi::Env env, Napi::Object exports) {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "QtGui/QPalette/qpalette_wrap.h"
|
||||
#include "QtGui/QStyle/qstyle_wrap.h"
|
||||
#include "core/Integration/qode-api.h"
|
||||
#include "core/WrapperCache/wrappercache.h"
|
||||
|
||||
Napi::FunctionReference QApplicationWrap::constructor;
|
||||
|
||||
@ -23,10 +24,14 @@ Napi::Object QApplicationWrap::init(Napi::Env env, Napi::Object exports) {
|
||||
&QApplicationWrap::quitOnLastWindowClosed),
|
||||
InstanceMethod("palette", &QApplicationWrap::palette),
|
||||
InstanceMethod("setStyleSheet", &QApplicationWrap::setStyleSheet),
|
||||
InstanceMethod("devicePixelRatio", &QApplicationWrap::devicePixelRatio),
|
||||
StaticMethod("instance", &StaticQApplicationWrapMethods::instance),
|
||||
StaticMethod("clipboard", &StaticQApplicationWrapMethods::clipboard),
|
||||
StaticMethod("setStyle", &StaticQApplicationWrapMethods::setStyle),
|
||||
StaticMethod("style", &StaticQApplicationWrapMethods::style),
|
||||
StaticMethod("primaryScreen",
|
||||
&StaticQApplicationWrapMethods::primaryScreen),
|
||||
StaticMethod("screens", &StaticQApplicationWrapMethods::screens),
|
||||
QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QApplicationWrap)});
|
||||
constructor = Napi::Persistent(func);
|
||||
exports.Set(CLASSNAME, func);
|
||||
@ -164,3 +169,39 @@ Napi::Value QApplicationWrap::quitOnLastWindowClosed(
|
||||
bool quit = this->instance->quitOnLastWindowClosed();
|
||||
return Napi::Value::From(env, quit);
|
||||
}
|
||||
|
||||
Napi::Value StaticQApplicationWrapMethods::primaryScreen(
|
||||
const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto screen = QApplication::primaryScreen();
|
||||
if (screen) {
|
||||
return WrapperCache::instance.get<QScreen, QScreenWrap>(env, screen);
|
||||
} else {
|
||||
return env.Null();
|
||||
}
|
||||
}
|
||||
|
||||
Napi::Value StaticQApplicationWrapMethods::screens(
|
||||
const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
auto screens = QApplication::screens();
|
||||
Napi::Array jsArray = Napi::Array::New(env, screens.size());
|
||||
for (int i = 0; i < screens.size(); i++) {
|
||||
QScreen* screen = screens[i];
|
||||
auto instance =
|
||||
WrapperCache::instance.get<QScreen, QScreenWrap>(env, screen);
|
||||
jsArray[i] = instance;
|
||||
}
|
||||
return jsArray;
|
||||
}
|
||||
|
||||
Napi::Value QApplicationWrap::devicePixelRatio(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
qreal result = this->instance->devicePixelRatio();
|
||||
return Napi::Value::From(env, result);
|
||||
}
|
||||
|
||||
131
src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp
Normal file
131
src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include "QtGui/QScreen/qscreen_wrap.h"
|
||||
|
||||
#include "Extras/Utils/nutils.h"
|
||||
#include "QtCore/QRect/qrect_wrap.h"
|
||||
#include "QtCore/QSizeF/qsizef_wrap.h"
|
||||
|
||||
Napi::FunctionReference QScreenWrap::constructor;
|
||||
|
||||
Napi::Object QScreenWrap::init(Napi::Env env, Napi::Object exports) {
|
||||
Napi::HandleScope scope(env);
|
||||
char CLASSNAME[] = "QScreen";
|
||||
Napi::Function func =
|
||||
DefineClass(env, CLASSNAME,
|
||||
{// InstanceMethod("clear", &QScreenWrap::clear),
|
||||
QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QScreenWrap)});
|
||||
constructor = Napi::Persistent(func);
|
||||
exports.Set(CLASSNAME, func);
|
||||
return exports;
|
||||
}
|
||||
|
||||
QScreenWrap::QScreenWrap(const Napi::CallbackInfo& info)
|
||||
: Napi::ObjectWrap<QScreenWrap>(info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
if (info[0].IsExternal()) {
|
||||
this->instance = info[0].As<Napi::External<QScreen>>().Data();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Incorrect initialization of QScreenWrap")
|
||||
.ThrowAsJavaScriptException();
|
||||
}
|
||||
this->rawData = extrautils::configureComponent(this->getInternalInstance());
|
||||
}
|
||||
|
||||
QScreen* QScreenWrap::getInternalInstance() { return this->instance; }
|
||||
|
||||
void QScreenWrap::connectSignalsToEventEmitter() {
|
||||
QOBJECT_SIGNALS_ON_TARGET(this->instance.data());
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QScreen::availableGeometryChanged,
|
||||
[=](const QRect& geometry) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance = QRectWrap::constructor.New({Napi::External<QRect>::New(
|
||||
env, new QRect(geometry.x(), geometry.y(), geometry.width(),
|
||||
geometry.height()))});
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "availableGeometryChanged"), instance});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QScreen::geometryChanged,
|
||||
[=](const QRect& geometry) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance = QRectWrap::constructor.New({Napi::External<QRect>::New(
|
||||
env, new QRect(geometry.x(), geometry.y(), geometry.width(),
|
||||
geometry.height()))});
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "geometryChanged"), instance});
|
||||
});
|
||||
|
||||
QObject::connect(this->instance.data(), &QScreen::logicalDotsPerInchChanged,
|
||||
[=](qreal dpi) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "logicalDotsPerInchChanged"),
|
||||
Napi::Value::From(env, dpi)});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QScreen::orientationChanged,
|
||||
[=](Qt::ScreenOrientation orientation) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "orientationChanged"),
|
||||
Napi::Value::From(env, static_cast<int>(orientation))});
|
||||
});
|
||||
|
||||
QObject::connect(this->instance.data(), &QScreen::physicalDotsPerInchChanged,
|
||||
[=](qreal dpi) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "physicalDotsPerInchChanged"),
|
||||
Napi::Value::From(env, dpi)});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QScreen::physicalSizeChanged,
|
||||
[=](const QSizeF& size) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance = QSizeFWrap::constructor.New(
|
||||
{Napi::External<QSizeF>::New(env, new QSizeF(size))});
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "physicalSizeChanged"), instance});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QScreen::primaryOrientationChanged,
|
||||
[=](Qt::ScreenOrientation orientation) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "primaryOrientationChanged"),
|
||||
Napi::Value::From(env, static_cast<int>(orientation))});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QScreen::refreshRateChanged,
|
||||
[=](qreal refreshRate) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->emitOnNode.Call({Napi::String::New(env, "refreshRateChanged"),
|
||||
Napi::Value::From(env, refreshRate)});
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QScreen::virtualGeometryChanged,
|
||||
[=](const QRect& rect) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance = QRectWrap::constructor.New({Napi::External<QRect>::New(
|
||||
env, new QRect(rect.x(), rect.y(), rect.width(), rect.height()))});
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "virtualGeometryChanged"), instance});
|
||||
});
|
||||
}
|
||||
60
src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp
Normal file
60
src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "QtGui/QWindow/qwindow_wrap.h"
|
||||
|
||||
#include "Extras/Utils/nutils.h"
|
||||
#include "QtGui/QScreen/qscreen_wrap.h"
|
||||
#include "core/WrapperCache/wrappercache.h"
|
||||
|
||||
Napi::FunctionReference QWindowWrap::constructor;
|
||||
|
||||
Napi::Object QWindowWrap::init(Napi::Env env, Napi::Object exports) {
|
||||
Napi::HandleScope scope(env);
|
||||
char CLASSNAME[] = "QWindow";
|
||||
Napi::Function func =
|
||||
DefineClass(env, CLASSNAME,
|
||||
{InstanceMethod("screen", &QWindowWrap::screen),
|
||||
QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QWindowWrap)});
|
||||
constructor = Napi::Persistent(func);
|
||||
exports.Set(CLASSNAME, func);
|
||||
return exports;
|
||||
}
|
||||
|
||||
QWindow* QWindowWrap::getInternalInstance() { return this->instance; }
|
||||
|
||||
QWindowWrap::QWindowWrap(const Napi::CallbackInfo& info)
|
||||
: Napi::ObjectWrap<QWindowWrap>(info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
if (info.Length() == 1 && info[0].IsExternal()) {
|
||||
this->instance = info[0].As<Napi::External<QWindow>>().Data();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Wrong number of arguments to QWindow.")
|
||||
.ThrowAsJavaScriptException();
|
||||
}
|
||||
this->rawData = extrautils::configureQObject(this->getInternalInstance());
|
||||
}
|
||||
|
||||
void QWindowWrap::connectSignalsToEventEmitter() {
|
||||
QOBJECT_SIGNALS_ON_TARGET(this->instance.data());
|
||||
|
||||
QObject::connect(
|
||||
this->instance.data(), &QWindow::screenChanged, [=](QScreen* screen) {
|
||||
Napi::Env env = this->emitOnNode.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
auto instance =
|
||||
WrapperCache::instance.get<QScreen, QScreenWrap>(env, screen);
|
||||
this->emitOnNode.Call(
|
||||
{Napi::String::New(env, "screenChanged"), instance});
|
||||
});
|
||||
}
|
||||
|
||||
Napi::Value QWindowWrap::screen(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
QScreen* screen = this->instance->screen();
|
||||
if (screen) {
|
||||
return WrapperCache::instance.get<QScreen, QScreenWrap>(env, screen);
|
||||
} else {
|
||||
return env.Null();
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
#include "QtWidgets/QDesktopWidget/qdesktopwidget_wrap.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "Extras/Utils/nutils.h"
|
||||
#include "QtCore/QRect/qrect_wrap.h"
|
||||
#include "QtWidgets/QWidget/qwidget_wrap.h"
|
||||
|
||||
Napi::FunctionReference QDesktopWidgetWrap::constructor;
|
||||
|
||||
Napi::Object QDesktopWidgetWrap::init(Napi::Env env, Napi::Object exports) {
|
||||
Napi::HandleScope scope(env);
|
||||
char CLASSNAME[] = "QDesktopWidget";
|
||||
Napi::Function func = DefineClass(
|
||||
env, CLASSNAME,
|
||||
{InstanceMethod("screenGeometry", &QDesktopWidgetWrap::screenGeometry),
|
||||
InstanceMethod("availableGeometry",
|
||||
&QDesktopWidgetWrap::availableGeometry),
|
||||
InstanceMethod("screenNumber", &QDesktopWidgetWrap::screenNumber),
|
||||
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QDesktopWidgetWrap)});
|
||||
constructor = Napi::Persistent(func);
|
||||
exports.Set(CLASSNAME, func);
|
||||
return exports;
|
||||
}
|
||||
|
||||
NQDesktopWidget *QDesktopWidgetWrap::getInternalInstance() {
|
||||
return this->instance;
|
||||
}
|
||||
|
||||
QDesktopWidgetWrap::QDesktopWidgetWrap(const Napi::CallbackInfo &info)
|
||||
: Napi::ObjectWrap<QDesktopWidgetWrap>(info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
if (info.Length() == 0) {
|
||||
this->instance = new NQDesktopWidget();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Wrong number of arguments")
|
||||
.ThrowAsJavaScriptException();
|
||||
}
|
||||
this->rawData = extrautils::configureQWidget(
|
||||
this->getInternalInstance(), this->getInternalInstance()->getFlexNode(),
|
||||
true);
|
||||
}
|
||||
|
||||
QDesktopWidgetWrap::~QDesktopWidgetWrap() {
|
||||
extrautils::safeDelete(this->instance);
|
||||
}
|
||||
|
||||
Napi::Value QDesktopWidgetWrap::screenGeometry(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
Napi::Number screen = info[0].As<Napi::Number>();
|
||||
QRect rect = this->instance->screenGeometry(screen);
|
||||
auto instance = QRectWrap::constructor.New(
|
||||
{Napi::External<QRect>::New(env, new QRect(rect))});
|
||||
return instance;
|
||||
}
|
||||
|
||||
Napi::Value QDesktopWidgetWrap::availableGeometry(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
Napi::Number screen = info[0].As<Napi::Number>();
|
||||
QRect rect = this->instance->availableGeometry(screen);
|
||||
auto instance = QRectWrap::constructor.New(
|
||||
{Napi::External<QRect>::New(env, new QRect(rect))});
|
||||
return instance;
|
||||
}
|
||||
|
||||
Napi::Value QDesktopWidgetWrap::screenNumber(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
int value = this->instance->screenNumber();
|
||||
return Napi::Value::From(env, value);
|
||||
}
|
||||
7
src/cpp/lib/core/WrapperCache/wrappercache.cpp
Normal file
7
src/cpp/lib/core/WrapperCache/wrappercache.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "core/WrapperCache/wrappercache.h"
|
||||
|
||||
#include "Extras/Utils/nutils.h"
|
||||
|
||||
DLL_EXPORT WrapperCache WrapperCache::instance;
|
||||
|
||||
Napi::FunctionReference WrapperCache::destroyedCallback;
|
||||
28
src/cpp/lib/test/CacheTestQObject.cpp
Normal file
28
src/cpp/lib/test/CacheTestQObject.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "test/CacheTestQObject.h"
|
||||
|
||||
CacheTestQObject::CacheTestQObject() : _foo(0), _bar(0) {}
|
||||
|
||||
CacheTestQObject* CacheTestQObject::foo() {
|
||||
if (_foo) {
|
||||
return _foo;
|
||||
}
|
||||
_foo = new CacheTestQObject();
|
||||
_foo->setParent(this);
|
||||
return _foo;
|
||||
}
|
||||
|
||||
void CacheTestQObject::clearFoo() {
|
||||
if (_foo) {
|
||||
delete _foo;
|
||||
_foo = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CacheTestQObject* CacheTestQObject::bar() {
|
||||
if (_bar) {
|
||||
return _bar;
|
||||
}
|
||||
_bar = new CacheTestQObject();
|
||||
_bar->setParent(this);
|
||||
return _bar;
|
||||
}
|
||||
71
src/cpp/lib/test/cachetestqobject_wrap.cpp
Normal file
71
src/cpp/lib/test/cachetestqobject_wrap.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "test/cachetestqobject_wrap.h"
|
||||
|
||||
#include "Extras/Utils/nutils.h"
|
||||
#include "core/WrapperCache/wrappercache.h"
|
||||
|
||||
Napi::FunctionReference CacheTestQObjectWrap::constructor;
|
||||
|
||||
Napi::Object CacheTestQObjectWrap::init(Napi::Env env, Napi::Object exports) {
|
||||
Napi::HandleScope scope(env);
|
||||
char CLASSNAME[] = "CacheTestQObject";
|
||||
Napi::Function func = DefineClass(
|
||||
env, CLASSNAME,
|
||||
{InstanceMethod("foo", &CacheTestQObjectWrap::foo),
|
||||
InstanceMethod("clearFoo", &CacheTestQObjectWrap::clearFoo),
|
||||
InstanceMethod("bar", &CacheTestQObjectWrap::bar),
|
||||
QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(CacheTestQObjectWrap)});
|
||||
constructor = Napi::Persistent(func);
|
||||
exports.Set(CLASSNAME, func);
|
||||
return exports;
|
||||
}
|
||||
|
||||
CacheTestQObject* CacheTestQObjectWrap::getInternalInstance() {
|
||||
return this->instance;
|
||||
}
|
||||
|
||||
CacheTestQObjectWrap::CacheTestQObjectWrap(const Napi::CallbackInfo& info)
|
||||
: Napi::ObjectWrap<CacheTestQObjectWrap>(info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
if (info.Length() == 1 && info[0].IsExternal()) {
|
||||
this->instance = info[0].As<Napi::External<CacheTestQObject>>().Data();
|
||||
} else {
|
||||
if (info.Length() == 0) {
|
||||
this->instance = new CacheTestQObject();
|
||||
} else {
|
||||
Napi::TypeError::New(env,
|
||||
"Wrong number of arguments to CacheTestQObject.")
|
||||
.ThrowAsJavaScriptException();
|
||||
}
|
||||
}
|
||||
this->rawData = extrautils::configureQObject(this->getInternalInstance());
|
||||
}
|
||||
|
||||
void CacheTestQObjectWrap::connectSignalsToEventEmitter() {
|
||||
QOBJECT_SIGNALS_ON_TARGET(this->instance.data());
|
||||
}
|
||||
|
||||
Napi::Value CacheTestQObjectWrap::foo(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
CacheTestQObject* foo = this->instance->foo();
|
||||
return WrapperCache::instance.get<CacheTestQObject, CacheTestQObjectWrap>(
|
||||
env, foo);
|
||||
}
|
||||
|
||||
Napi::Value CacheTestQObjectWrap::clearFoo(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
this->instance->clearFoo();
|
||||
return env.Null();
|
||||
}
|
||||
|
||||
Napi::Value CacheTestQObjectWrap::bar(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
CacheTestQObject* bar = this->instance->bar();
|
||||
return WrapperCache::instance.get<CacheTestQObject, CacheTestQObjectWrap>(
|
||||
env, bar);
|
||||
}
|
||||
@ -45,7 +45,9 @@
|
||||
#include "QtGui/QPen/qpen_wrap.h"
|
||||
#include "QtGui/QPicture/qpicture_wrap.h"
|
||||
#include "QtGui/QPixmap/qpixmap_wrap.h"
|
||||
#include "QtGui/QScreen/qscreen_wrap.h"
|
||||
#include "QtGui/QStyle/qstyle_wrap.h"
|
||||
#include "QtGui/QWindow/qwindow_wrap.h"
|
||||
#include "QtWidgets/QAction/qaction_wrap.h"
|
||||
#include "QtWidgets/QBoxLayout/qboxlayout_wrap.h"
|
||||
#include "QtWidgets/QButtonGroup/qbuttongroup_wrap.h"
|
||||
@ -55,7 +57,6 @@
|
||||
#include "QtWidgets/QComboBox/qcombobox_wrap.h"
|
||||
#include "QtWidgets/QDateEdit/qdateedit_wrap.h"
|
||||
#include "QtWidgets/QDateTimeEdit/qdatetimeedit_wrap.h"
|
||||
#include "QtWidgets/QDesktopWidget/qdesktopwidget_wrap.h"
|
||||
#include "QtWidgets/QDial/qdial_wrap.h"
|
||||
#include "QtWidgets/QDialog/qdialog_wrap.h"
|
||||
#include "QtWidgets/QDoubleSpinBox/qdoublespinbox_wrap.h"
|
||||
@ -114,6 +115,9 @@
|
||||
#include "QtWidgets/QWidget/qwidget_wrap.h"
|
||||
#include "core/FlexLayout/flexlayout_wrap.h"
|
||||
#include "core/Integration/integration.h"
|
||||
#include "core/WrapperCache/wrappercache.h"
|
||||
#include "test/cachetestqobject_wrap.h"
|
||||
|
||||
// These cant be instantiated in JS Side
|
||||
void InitPrivateHelpers(Napi::Env env) {
|
||||
qodeIntegration::integrate();
|
||||
@ -123,6 +127,7 @@ void InitPrivateHelpers(Napi::Env env) {
|
||||
Napi::Object Main(Napi::Env env, Napi::Object exports) {
|
||||
InitPrivateHelpers(env);
|
||||
NUtilsWrap::init(env, exports);
|
||||
WrapperCache::init(env, exports);
|
||||
QApplicationWrap::init(env, exports);
|
||||
QDateWrap::init(env, exports);
|
||||
QDateTimeWrap::init(env, exports);
|
||||
@ -227,13 +232,18 @@ Napi::Object Main(Napi::Env env, Napi::Object exports) {
|
||||
QStandardItemWrap::init(env, exports);
|
||||
QSvgWidgetWrap::init(env, exports);
|
||||
QSplitterWrap::init(env, exports);
|
||||
QDesktopWidgetWrap::init(env, exports);
|
||||
QPaintEventWrap::init(env, exports);
|
||||
QPaletteWrap::init(env, exports);
|
||||
QAbstractItemModelWrap::init(env, exports);
|
||||
QHeaderViewWrap::init(env, exports);
|
||||
QItemSelectionModelWrap::init(env, exports);
|
||||
QStyleFactoryWrap::init(env, exports);
|
||||
QScreenWrap::init(env, exports);
|
||||
QWindowWrap::init(env, exports);
|
||||
|
||||
// Test
|
||||
CacheTestQObjectWrap::init(env, exports);
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
|
||||
14
src/index.ts
14
src/index.ts
@ -32,6 +32,8 @@ export { QDropEvent } from './lib/QtGui/QEvent/QDropEvent';
|
||||
export { QDragMoveEvent } from './lib/QtGui/QEvent/QDragMoveEvent';
|
||||
export { QDragLeaveEvent } from './lib/QtGui/QEvent/QDragLeaveEvent';
|
||||
export { QPaintEvent } from './lib/QtGui/QEvent/QPaintEvent';
|
||||
export { QScreen } from './lib/QtGui/QScreen';
|
||||
export { QWindow } from './lib/QtGui/QWindow';
|
||||
export { WidgetEventTypes } from './lib/core/EventWidget';
|
||||
// Abstract:
|
||||
export { NodeWidget, QWidget, QWidgetSignals } from './lib/QtWidgets/QWidget';
|
||||
@ -61,7 +63,6 @@ export { QCheckBox, QCheckBoxSignals } from './lib/QtWidgets/QCheckBox';
|
||||
export { QColorDialog, QColorDialogSignals } from './lib/QtWidgets/QColorDialog';
|
||||
export { QDateEdit } from './lib/QtWidgets/QDateEdit';
|
||||
export { QDateTimeEdit, NodeDateTimeEdit, QDateTimeEditSignals } from './lib/QtWidgets/QDateTimeEdit';
|
||||
export { QDesktopWidget } from './lib/QtWidgets/QDesktopWidget';
|
||||
export { QLabel, QLabelSignals } from './lib/QtWidgets/QLabel';
|
||||
export { QLCDNumber, QLCDNumberSignals, Mode, SegmentStyle } from './lib/QtWidgets/QLCDNumber';
|
||||
export { QDial, QDialSignals } from './lib/QtWidgets/QDial';
|
||||
@ -168,5 +169,14 @@ export { FlexLayout, FlexLayoutSignals } from './lib/core/FlexLayout';
|
||||
// Others:
|
||||
export { StyleSheet } from './lib/core/Style/StyleSheet';
|
||||
export { NativeElement, Component } from './lib/core/Component';
|
||||
export { checkIfNativeElement, checkIfNapiExternal } from './lib/utils/helpers';
|
||||
export {
|
||||
checkIfNativeElement,
|
||||
checkIfNapiExternal,
|
||||
JsWrapFunction,
|
||||
registerNativeWrapFunction as registerNativeWrapper,
|
||||
wrapNative,
|
||||
} from './lib/utils/helpers';
|
||||
export { Margins } from './lib/utils/Margins';
|
||||
|
||||
// Test:
|
||||
export { CacheTestQObject } from './lib/core/__test__/CacheTestQObject';
|
||||
|
||||
@ -4,10 +4,11 @@ import { checkIfNativeElement } from '../utils/helpers';
|
||||
import { QClipboard } from './QClipboard';
|
||||
import { QStyle } from './QStyle';
|
||||
import { QObjectSignals, NodeObject } from '../QtCore/QObject';
|
||||
import { QDesktopWidget } from '../QtWidgets/QDesktopWidget';
|
||||
import { QPalette } from './QPalette';
|
||||
import { StyleSheet } from '../core/Style/StyleSheet';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import { QScreen } from './QScreen';
|
||||
import { wrapperCache } from '../core/WrapperCache';
|
||||
|
||||
/**
|
||||
|
||||
@ -42,37 +43,51 @@ export class QApplication extends NodeObject<QApplicationSignals> {
|
||||
|
||||
this.setStyleSheet = memoizeOne(this.setStyleSheet);
|
||||
}
|
||||
static clipboard(): QClipboard {
|
||||
return new QClipboard(addon.QApplication.clipboard());
|
||||
devicePixelRatio(): number {
|
||||
return this.native.devicePixelRatio();
|
||||
}
|
||||
exec(): number {
|
||||
return this.native.exec();
|
||||
}
|
||||
exit(exitCode: number): number {
|
||||
return this.native.exit(exitCode);
|
||||
}
|
||||
palette(): QPalette {
|
||||
return new QPalette(this.native.palette());
|
||||
}
|
||||
processEvents(): void {
|
||||
this.native.processEvents();
|
||||
}
|
||||
exec(): number {
|
||||
return this.native.exec();
|
||||
quit(): number {
|
||||
return this.native.quit();
|
||||
}
|
||||
quitOnLastWindowClosed(): boolean {
|
||||
return this.native.quitOnLastWindowClosed();
|
||||
}
|
||||
setQuitOnLastWindowClosed(quit: boolean): void {
|
||||
this.native.setQuitOnLastWindowClosed(quit);
|
||||
}
|
||||
setStyleSheet(styleSheet: string): void {
|
||||
const preparedSheet = StyleSheet.create(styleSheet);
|
||||
this.native.setStyleSheet(preparedSheet);
|
||||
}
|
||||
static clipboard(): QClipboard {
|
||||
return new QClipboard(addon.QApplication.clipboard());
|
||||
}
|
||||
static instance(): QApplication {
|
||||
const nativeQApp = addon.QApplication.instance();
|
||||
return new QApplication(nativeQApp);
|
||||
}
|
||||
quit(): number {
|
||||
return this.native.quit();
|
||||
static primaryScreen(): QScreen | null {
|
||||
const screenNative = addon.QApplication.primaryScreen();
|
||||
if (screenNative == null) {
|
||||
return null;
|
||||
}
|
||||
return wrapperCache.get<QScreen>(QScreen, screenNative);
|
||||
}
|
||||
exit(exitCode: number): number {
|
||||
return this.native.exit(exitCode);
|
||||
}
|
||||
setQuitOnLastWindowClosed(quit: boolean): void {
|
||||
this.native.setQuitOnLastWindowClosed(quit);
|
||||
}
|
||||
quitOnLastWindowClosed(): boolean {
|
||||
return this.native.quitOnLastWindowClosed();
|
||||
}
|
||||
palette(): QPalette {
|
||||
return new QPalette(this.native.palette());
|
||||
}
|
||||
setStyleSheet(styleSheet: string): void {
|
||||
const preparedSheet = StyleSheet.create(styleSheet);
|
||||
this.native.setStyleSheet(preparedSheet);
|
||||
static screens(): QScreen[] {
|
||||
const screenNativeList = addon.QApplication.screens();
|
||||
return screenNativeList.map((screenNative: any) => wrapperCache.get<QScreen>(QScreen, screenNative));
|
||||
}
|
||||
static setStyle(style: QStyle): void {
|
||||
addon.QApplication.setStyle(style.native);
|
||||
@ -80,11 +95,11 @@ export class QApplication extends NodeObject<QApplicationSignals> {
|
||||
static style(): QStyle {
|
||||
return new QStyle(addon.QApplication.style());
|
||||
}
|
||||
static desktop(): QDesktopWidget {
|
||||
return new QDesktopWidget();
|
||||
}
|
||||
}
|
||||
|
||||
export interface QApplicationSignals extends QObjectSignals {
|
||||
focusWindowChanged: () => void;
|
||||
primaryScreenChanged: (screen: QScreen) => void;
|
||||
screenAdded: (screen: QScreen) => void;
|
||||
screenRemoved: (screen: QScreen) => void;
|
||||
}
|
||||
|
||||
111
src/lib/QtGui/QScreen.ts
Normal file
111
src/lib/QtGui/QScreen.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { NativeElement } from '../core/Component';
|
||||
import { checkIfNativeElement, registerNativeWrapFunction } from '../utils/helpers';
|
||||
import { NodeObject, QObjectSignals } from '../QtCore/QObject';
|
||||
import { QRect } from '../QtCore/QRect';
|
||||
import { QSizeF } from '../QtCore/QSizeF';
|
||||
import { QSize } from '../QtCore/QSize';
|
||||
import { wrapperCache } from '../core/WrapperCache';
|
||||
|
||||
export class QScreen extends NodeObject<QScreenSignals> {
|
||||
native: NativeElement;
|
||||
constructor(native: NativeElement) {
|
||||
super(native);
|
||||
if (checkIfNativeElement(native)) {
|
||||
this.native = native;
|
||||
} else {
|
||||
throw new Error('QScreen cannot be initialised this way.');
|
||||
}
|
||||
}
|
||||
|
||||
availableGeometry(): QRect {
|
||||
return QRect.fromQVariant(this.property('availableGeometry'));
|
||||
}
|
||||
availableSize(): QSize {
|
||||
return QSize.fromQVariant(this.property('availableSize'));
|
||||
}
|
||||
availableVirtualGeometry(): QRect {
|
||||
return QRect.fromQVariant(this.property('availableVirtualGeometry'));
|
||||
}
|
||||
availableVirtualSize(): QSize {
|
||||
return QSize.fromQVariant(this.property('availableVirtualSize'));
|
||||
}
|
||||
depth(): number {
|
||||
return this.property('depth').toInt();
|
||||
}
|
||||
devicePixelRatio(): number {
|
||||
return this.property('devicePixelRatio').toDouble();
|
||||
}
|
||||
geometry(): QRect {
|
||||
return QRect.fromQVariant(this.property('geometry'));
|
||||
}
|
||||
logicalDotsPerInch(): number {
|
||||
return this.property('logicalDotsPerInch').toDouble();
|
||||
}
|
||||
logicalDotsPerInchX(): number {
|
||||
return this.property('logicalDotsPerInchX').toDouble();
|
||||
}
|
||||
logicalDotsPerInchY(): number {
|
||||
return this.property('logicalDotsPerInchY').toDouble();
|
||||
}
|
||||
manufacturer(): string {
|
||||
return this.property('manufacturer').toString();
|
||||
}
|
||||
model(): string {
|
||||
return this.property('model').toString();
|
||||
}
|
||||
name(): string {
|
||||
return this.property('name').toString();
|
||||
}
|
||||
nativeOrientation(): ScreenOrientation {
|
||||
return <any>this.property('nativeOrientation').toInt();
|
||||
}
|
||||
orientation(): ScreenOrientation {
|
||||
return <any>this.property('orientation').toInt();
|
||||
}
|
||||
physicalDotsPerInch(): number {
|
||||
return this.property('physicalDotsPerInch').toDouble();
|
||||
}
|
||||
physicalDotsPerInchX(): number {
|
||||
return this.property('physicalDotsPerInchX').toDouble();
|
||||
}
|
||||
physicalDotsPerInchY(): number {
|
||||
return this.property('physicalDotsPerInchY').toDouble();
|
||||
}
|
||||
physicalSize(): QSizeF {
|
||||
return QSizeF.fromQVariant(this.property('physicalSize'));
|
||||
}
|
||||
primaryOrientation(): ScreenOrientation {
|
||||
return <any>this.property('primaryOrientation').toInt();
|
||||
}
|
||||
refreshRate(): number {
|
||||
return this.property('refreshRate').toDouble();
|
||||
}
|
||||
serialNumber(): string {
|
||||
return this.property('serialNumber').toString();
|
||||
}
|
||||
size(): QSize {
|
||||
return QSize.fromQVariant(this.property('size'));
|
||||
}
|
||||
virtualGeometry(): QRect {
|
||||
return QRect.fromQVariant(this.property('virtualGeometry'));
|
||||
}
|
||||
virtualSize(): QSize {
|
||||
return QSize.fromQVariant(this.property('virtualSize'));
|
||||
}
|
||||
}
|
||||
|
||||
export interface QScreenSignals extends QObjectSignals {
|
||||
availableGeometryChanged: (geometry: QRect) => void;
|
||||
geometryChanged: (geometry: QRect) => void;
|
||||
logicalDotsPerInchChanged: (dpi: number) => void;
|
||||
orientationChanged: (orientation: ScreenOrientation) => void;
|
||||
physicalDotsPerInchChanged: (dpi: number) => void;
|
||||
physicalSizeChanged: (size: QSizeF) => void;
|
||||
primaryOrientationChanged: (orientation: ScreenOrientation) => void;
|
||||
refreshRateChanged: (refreshRate: number) => void;
|
||||
virtualGeometryChanged: (rect: QRect) => void;
|
||||
}
|
||||
|
||||
registerNativeWrapFunction('QScreenWrap', (native: any) => {
|
||||
return wrapperCache.get<QScreen>(QScreen, native);
|
||||
});
|
||||
30
src/lib/QtGui/QWindow.ts
Normal file
30
src/lib/QtGui/QWindow.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { NativeElement } from '../core/Component';
|
||||
import { checkIfNativeElement, registerNativeWrapFunction } from '../utils/helpers';
|
||||
import { NodeObject, QObjectSignals } from '../QtCore/QObject';
|
||||
import { QScreen } from './QScreen';
|
||||
import { wrapperCache } from '../core/WrapperCache';
|
||||
|
||||
export class QWindow extends NodeObject<QWindowSignals> {
|
||||
native: NativeElement;
|
||||
constructor(native: NativeElement) {
|
||||
super(native);
|
||||
|
||||
if (checkIfNativeElement(native)) {
|
||||
this.native = native;
|
||||
} else {
|
||||
throw new Error('QWindow cannot be initialised this way.');
|
||||
}
|
||||
}
|
||||
|
||||
screen(): QScreen {
|
||||
return wrapperCache.get<QScreen>(QScreen, this.native.screen());
|
||||
}
|
||||
}
|
||||
|
||||
export interface QWindowSignals extends QObjectSignals {
|
||||
screenChanged: (screen: QScreen) => void;
|
||||
}
|
||||
|
||||
registerNativeWrapFunction('QWindowWrap', (native: any) => {
|
||||
return wrapperCache.get<QWindow>(QWindow, native);
|
||||
});
|
||||
@ -1,50 +0,0 @@
|
||||
import { QRect } from '../QtCore/QRect';
|
||||
import { NodeWidget, QWidgetSignals } from './QWidget';
|
||||
import { NativeElement } from '../core/Component';
|
||||
import addon from '../utils/addon';
|
||||
|
||||
/**
|
||||
|
||||
> QDesktopWidget is a class that provides access to screen information on multi-head systems..
|
||||
|
||||
* **This class is a JS wrapper around Qt's [QDesktopWidget Class](https://doc.qt.io/qt-5/qdesktopwidget.html)**
|
||||
|
||||
The QDesktopWidget class provides information about the user's desktop, such as its total size, number of screens, the geometry of each screen, and whether they are configured as separate desktops or a single virtual desktop.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const { QDesktopWidget } = require("@nodegui/nodegui");
|
||||
|
||||
const desktop = new QDesktopWidget();
|
||||
const availableGeometry = desktop.availableGeometry();
|
||||
const screenGeometry = desktop.screenGeometry();
|
||||
console.log(availableGeometry.width() + 'x' + availableGeometry.height());
|
||||
console.log(screenGeometry.width() + 'x' + screenGeometry.height());
|
||||
console.log(desktop.screenNumber());
|
||||
```
|
||||
*/
|
||||
export type QDesktopWidgetSignals = QWidgetSignals;
|
||||
export class QDesktopWidget extends NodeWidget<QDesktopWidgetSignals> {
|
||||
native: NativeElement;
|
||||
constructor(parent?: NodeWidget<any>) {
|
||||
let native;
|
||||
if (parent) {
|
||||
native = new addon.QDesktopWidget(parent.native);
|
||||
} else {
|
||||
native = new addon.QDesktopWidget();
|
||||
}
|
||||
super(native);
|
||||
this.native = native;
|
||||
this.nodeParent = parent;
|
||||
}
|
||||
availableGeometry(screen = -1): QRect {
|
||||
return new QRect(this.native.availableGeometry(screen));
|
||||
}
|
||||
screenGeometry(screen = -1): QRect {
|
||||
return new QRect(this.native.screenGeometry(screen));
|
||||
}
|
||||
screenNumber(): number {
|
||||
return this.native.screenNumber();
|
||||
}
|
||||
}
|
||||
@ -17,8 +17,10 @@ import { QFont } from '../QtGui/QFont';
|
||||
import { QAction } from './QAction';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import { QGraphicsEffect } from './QGraphicsEffect';
|
||||
import { wrapperCache } from '../core/WrapperCache';
|
||||
import { QSizePolicyPolicy } from './QSizePolicy';
|
||||
import { QStyle } from '../QtGui/QStyle';
|
||||
import { QWindow } from '../QtGui/QWindow';
|
||||
|
||||
/**
|
||||
|
||||
@ -247,6 +249,7 @@ export abstract class NodeWidget<Signals extends QWidgetSignals> extends YogaWid
|
||||
resize(width: number, height: number): void {
|
||||
this.native.resize(width, height);
|
||||
}
|
||||
// TODO: QScreen *QWidget::screen() const
|
||||
setAcceptDrops(on: boolean): void {
|
||||
this.native.setAcceptDrops(on);
|
||||
}
|
||||
@ -422,7 +425,13 @@ export abstract class NodeWidget<Signals extends QWidgetSignals> extends YogaWid
|
||||
// TODO: QWidget * window() const
|
||||
// TODO: QString windowFilePath() const
|
||||
// TODO: Qt::WindowFlags windowFlags() const
|
||||
// TODO: QWindow * windowHandle() const
|
||||
windowHandle(): QWindow | null {
|
||||
const handle = this.native.windowHandle();
|
||||
if (handle != null) {
|
||||
return wrapperCache.get<QWindow>(QWindow, handle);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// TODO: QIcon windowIcon() const
|
||||
// TODO: Qt::WindowModality windowModality() const
|
||||
windowOpacity(): number {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { NativeElement, Component, NativeRawPointer } from './Component';
|
||||
import { wrapWithActivateUvLoop } from '../utils/helpers';
|
||||
import { wrapNative, wrapWithActivateUvLoop } from '../utils/helpers';
|
||||
|
||||
function addDefaultErrorHandler(native: NativeElement, emitter: EventEmitter): void {
|
||||
native.subscribeToQtEvent('error');
|
||||
@ -54,10 +54,11 @@ export abstract class EventWidget<Signals extends unknown> extends Component {
|
||||
// Preserve the value of `_isQObjectEventProcessed` as we dispatch this event
|
||||
// to JS land, and restore it afterwards. This lets us support recursive event
|
||||
// dispatches on the same object.
|
||||
const wrappedArgs = args.map(wrapNative);
|
||||
const previousEventProcessed = this._isEventProcessed;
|
||||
this._isEventProcessed = false;
|
||||
try {
|
||||
this.emitter.emit(event, ...args);
|
||||
this.emitter.emit(event, ...wrappedArgs);
|
||||
} catch (e) {
|
||||
console.log(`An exception was thrown while dispatching an event of type '${event.toString()}':`);
|
||||
console.log(e);
|
||||
|
||||
41
src/lib/core/WrapperCache.ts
Normal file
41
src/lib/core/WrapperCache.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import addon from '../utils/addon';
|
||||
import { NativeElement } from './Component';
|
||||
|
||||
/**
|
||||
* JS side cache for wrapper objects.
|
||||
*
|
||||
* This is mainly used for caching wrappers of Qt objects which are not
|
||||
* directly created by our Nodejs application. The purpose of the cache
|
||||
* is to keep "alive" wrapper objects and their underlying C++ wrappers
|
||||
* which may be connected to Qt signals from the real Qt object.
|
||||
* This makes it easier for application to grab one of these objects,
|
||||
* set up event handlers, and then let the object go and *not* have the
|
||||
* wrapper automatically and unexpectedly garbage collected.
|
||||
*/
|
||||
export class WrapperCache {
|
||||
private _cache = new Map<number, any>();
|
||||
|
||||
constructor() {
|
||||
addon.WrapperCache_injectCallback(this._objectDestroyedCallback.bind(this));
|
||||
}
|
||||
|
||||
private _objectDestroyedCallback(objectId: number): void {
|
||||
if (!this._cache.has(objectId)) {
|
||||
return;
|
||||
}
|
||||
const wrapper = this._cache.get(objectId);
|
||||
wrapper.native = null;
|
||||
this._cache.delete(objectId);
|
||||
}
|
||||
|
||||
get<T>(wrapperConstructor: { new (native: any): T }, native: NativeElement): T {
|
||||
const id = native.__id__();
|
||||
if (this._cache.has(id)) {
|
||||
return this._cache.get(id) as T;
|
||||
}
|
||||
const wrapper = new wrapperConstructor(native);
|
||||
this._cache.set(id, wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
export const wrapperCache = new WrapperCache();
|
||||
30
src/lib/core/__test__/CacheTestQObject.ts
Normal file
30
src/lib/core/__test__/CacheTestQObject.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import addon from '../../utils/addon';
|
||||
import { NativeElement } from '../Component';
|
||||
import { NodeObject, QObjectSignals } from '../../QtCore/QObject';
|
||||
import { wrapperCache } from '../../core/WrapperCache';
|
||||
|
||||
export class CacheTestQObject extends NodeObject<QObjectSignals> {
|
||||
native: NativeElement;
|
||||
constructor(arg?: NativeElement) {
|
||||
let native;
|
||||
if (native == null) {
|
||||
native = new addon.CacheTestQObject();
|
||||
} else {
|
||||
native = arg;
|
||||
}
|
||||
super(native);
|
||||
this.native = native;
|
||||
}
|
||||
|
||||
foo(): CacheTestQObject {
|
||||
return wrapperCache.get<CacheTestQObject>(CacheTestQObject, this.native.foo());
|
||||
}
|
||||
|
||||
clearFoo(): void {
|
||||
this.native.clearFoo();
|
||||
}
|
||||
|
||||
bar(): CacheTestQObject {
|
||||
return wrapperCache.get<CacheTestQObject>(CacheTestQObject, this.native.bar());
|
||||
}
|
||||
}
|
||||
47
src/lib/core/__test__/WrapperCache.test.ts
Normal file
47
src/lib/core/__test__/WrapperCache.test.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { QApplication } from '../../QtGui/QApplication';
|
||||
import { CacheTestQObject } from './CacheTestQObject';
|
||||
|
||||
describe('WrapperCache using CacheTestQObject', () => {
|
||||
const qApp = QApplication.instance();
|
||||
qApp.setQuitOnLastWindowClosed(true);
|
||||
|
||||
it('Cached foo', () => {
|
||||
const a = new CacheTestQObject();
|
||||
expect(a).not.toBeNull();
|
||||
|
||||
const foo = a.foo();
|
||||
expect(foo).not.toBeNull();
|
||||
|
||||
const foo2 = a.foo();
|
||||
expect(foo).toBe(foo2);
|
||||
expect(foo.native.__id__()).toBe(foo2.native.__id__());
|
||||
});
|
||||
|
||||
it('clearFoo() and wrapper expiration', () => {
|
||||
const a = new CacheTestQObject();
|
||||
const foo = a.foo();
|
||||
a.clearFoo();
|
||||
expect(foo.native).toBeNull();
|
||||
});
|
||||
|
||||
it('clearFoo() and new wrapper', () => {
|
||||
const a = new CacheTestQObject();
|
||||
const foo = a.foo();
|
||||
const fooId = foo.native.__id__();
|
||||
a.clearFoo();
|
||||
expect(foo.native).toBeNull();
|
||||
|
||||
const foo2 = a.foo();
|
||||
expect(foo2).not.toBe(foo);
|
||||
expect(foo2.native.__id__()).not.toBe(fooId);
|
||||
});
|
||||
|
||||
it('Cached foo and bar', () => {
|
||||
const a = new CacheTestQObject();
|
||||
const foo = a.foo();
|
||||
const bar = a.bar();
|
||||
expect(foo).not.toEqual(bar);
|
||||
expect(foo.native.__id__()).not.toEqual(bar.native.__id__());
|
||||
});
|
||||
qApp.quit();
|
||||
});
|
||||
@ -25,3 +25,37 @@ export function wrapWithActivateUvLoop<T extends Function>(func: T): T {
|
||||
};
|
||||
return fn as any;
|
||||
}
|
||||
|
||||
export type JsWrapFunction = (element: any) => any;
|
||||
const nativeWrapperRegistry = new Map<string, JsWrapFunction>();
|
||||
|
||||
/**
|
||||
* Register a function to wrap a specific Node API wrapper objects with a JS object.
|
||||
*
|
||||
* @param wrapperTypeName the C++ wrapper type name the wrap function applies to.
|
||||
* @param jsWrapFunction function to wrap a native wrapper to a JS wrapper object.
|
||||
*/
|
||||
export function registerNativeWrapFunction(wrapperTypeName: string, jsWrapFunction: JsWrapFunction): void {
|
||||
nativeWrapperRegistry.set(wrapperTypeName, jsWrapFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to wrap a native Node object with its JS wrapper.
|
||||
*
|
||||
* @param native the native object to wrap
|
||||
* @return the JS object wrapping the native object or the native object if
|
||||
* it couldn't be wrapped or doesn't need to be wrapped.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export function wrapNative(native: any): any {
|
||||
if (!checkIfNativeElement(native)) {
|
||||
return native;
|
||||
}
|
||||
|
||||
const func: JsWrapFunction | undefined = nativeWrapperRegistry.get(native.wrapperType);
|
||||
if (func == null) {
|
||||
return native;
|
||||
}
|
||||
|
||||
return func(native);
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ Steps:
|
||||
|
||||
Inherit from both QPushButton and NodeWidget. Make sure you have added NODEWIDGET_IMPLEMENTATIONS macro. This adds a crucial method for events support. It will override `event(QEvent *)` method of QPushbutton so that nodejs can listen to the events of this widget. This makes sure we convert all the QEvent's of this widget to an event for the nodejs event emitter.
|
||||
|
||||
Also make sure to connect all the signals of the widgets to the event emitter instance from NodeJS. This way we kindof convert the signal to a simple nodejs event.
|
||||
Also make sure to connect all the signals of the widgets to the event emitter instance from NodeJS. This way we kind of convert the signal to a simple nodejs event.
|
||||
|
||||
```cpp
|
||||
#pragma once
|
||||
@ -144,5 +144,5 @@ We need to run Qt's MOC (Meta Object Compiler) on the file whenever we use Q_OBJ
|
||||
# How does it work ?
|
||||
|
||||
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.
|
||||
2. We send this event emitter'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 `connectSignalsToEventEmitter`. 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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user