diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c5809f74..1e0f8f25a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,9 +44,11 @@ add_library(${CORE_WIDGETS_ADDON} SHARED "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QIcon/qicon_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QCursor/qcursor_wrap.cpp" "${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/QtCore/QObject/qobject_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QVariant/qvariant_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QSize/qsize_wrap.cpp" + "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QRect/qrect_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QUrl/qurl_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QWidget/qwidget_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QGridLayout/qgridlayout_wrap.cpp" @@ -71,6 +73,7 @@ add_library(${CORE_WIDGETS_ADDON} SHARED "${PROJECT_SOURCE_DIR}/src/cpp/lib/core/FlexLayout/flexlayout_wrap.cpp" # Custom widgets (include them for automoc since they contain Q_OBJECT) "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtCore/QObject/nobject.hpp" + "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtGui/QMovie/nmovie.hpp" "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QWidget/nwidget.hpp" "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QLabel/nlabel.hpp" "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QCheckBox/ncheckbox.hpp" diff --git a/src/cpp/include/nodegui/QtCore/QRect/qrect_wrap.h b/src/cpp/include/nodegui/QtCore/QRect/qrect_wrap.h new file mode 100644 index 000000000..faa6951fd --- /dev/null +++ b/src/cpp/include/nodegui/QtCore/QRect/qrect_wrap.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include + +#include "core/Component/component_macro.h" + +class QRectWrap : public Napi::ObjectWrap { + private: + std::unique_ptr instance; + + public: + static Napi::FunctionReference constructor; + static Napi::Object init(Napi::Env env, Napi::Object exports); + QRectWrap(const Napi::CallbackInfo& info); + ~QRectWrap(); + QRect* getInternalInstance(); + // Wrapped methods + Napi::Value setHeight(const Napi::CallbackInfo& info); + Napi::Value setWidth(const Napi::CallbackInfo& info); + Napi::Value setLeft(const Napi::CallbackInfo& info); + Napi::Value setTop(const Napi::CallbackInfo& info); + Napi::Value height(const Napi::CallbackInfo& info); + Napi::Value width(const Napi::CallbackInfo& info); + Napi::Value left(const Napi::CallbackInfo& info); + Napi::Value top(const Napi::CallbackInfo& info); + + COMPONENT_WRAPPED_METHODS_DECLARATION +}; + +namespace StaticQRectWrapMethods { +Napi::Value fromQVariant(const Napi::CallbackInfo& info); +} // namespace StaticQRectWrapMethods \ No newline at end of file diff --git a/src/cpp/include/nodegui/QtGui/QMovie/nmovie.hpp b/src/cpp/include/nodegui/QtGui/QMovie/nmovie.hpp new file mode 100644 index 000000000..ac83b4fd5 --- /dev/null +++ b/src/cpp/include/nodegui/QtGui/QMovie/nmovie.hpp @@ -0,0 +1,64 @@ +#pragma once +#include + +#include "QtCore/QRect/qrect_wrap.h" +#include "QtCore/QSize/qsize_wrap.h" +#include "core/Events/eventwidget.h" +#include "core/Events/eventwidget_macro.h" + +class NMovie : public QMovie, public EventWidget { + Q_OBJECT + EVENTWIDGET_IMPLEMENTATIONS(QMovie) + public: + using QMovie::QMovie; + + void connectWidgetSignalsToEventEmitter() { + // Qt Connects: Implement all signal connects here + QObject::connect(this, &QMovie::error, + [=](QImageReader::ImageReaderError error) { + Napi::Env env = this->emitOnNode.Env(); + Napi::HandleScope scope(env); + this->emitOnNode.Call( + {Napi::String::New(env, "error"), + Napi::Number::New(env, static_cast(error))}); + }); + QObject::connect(this, &QMovie::finished, [=]() { + Napi::Env env = this->emitOnNode.Env(); + Napi::HandleScope scope(env); + this->emitOnNode.Call({Napi::String::New(env, "finished")}); + }); + QObject::connect(this, &QMovie::frameChanged, [=](int frameNumber) { + Napi::Env env = this->emitOnNode.Env(); + Napi::HandleScope scope(env); + this->emitOnNode.Call({Napi::String::New(env, "frameChanged"), + Napi::Number::New(env, frameNumber)}); + }); + QObject::connect(this, &QMovie::started, [=]() { + Napi::Env env = this->emitOnNode.Env(); + Napi::HandleScope scope(env); + this->emitOnNode.Call({Napi::String::New(env, "started")}); + }); + QObject::connect(this, &QMovie::resized, [=](const QSize &size) { + Napi::Env env = this->emitOnNode.Env(); + Napi::HandleScope scope(env); + auto instance = QSizeWrap::constructor.New({Napi::External::New( + env, new QSize(size.width(), size.height()))}); + this->emitOnNode.Call({Napi::String::New(env, "resized"), instance}); + }); + QObject::connect(this, &QMovie::stateChanged, + [=](QMovie::MovieState state) { + Napi::Env env = this->emitOnNode.Env(); + Napi::HandleScope scope(env); + this->emitOnNode.Call( + {Napi::String::New(env, "stateChanged"), + Napi::Number::New(env, static_cast(state))}); + }); + QObject::connect(this, &QMovie::updated, [=](const QRect &rect) { + Napi::Env env = this->emitOnNode.Env(); + Napi::HandleScope scope(env); + auto instance = QRectWrap::constructor.New( + {Napi::External::New(env, new QRect(rect))}); + this->emitOnNode.Call({Napi::String::New(env, "updated"), instance}); + }); + } +}; diff --git a/src/cpp/include/nodegui/QtGui/QMovie/qmovie_wrap.h b/src/cpp/include/nodegui/QtGui/QMovie/qmovie_wrap.h new file mode 100644 index 000000000..df52cf949 --- /dev/null +++ b/src/cpp/include/nodegui/QtGui/QMovie/qmovie_wrap.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include + +#include "QtCore/QObject/qobject_macro.h" +#include "nmovie.hpp" + +class QMovieWrap : public Napi::ObjectWrap { + private: + QPointer instance; + + public: + static Napi::Object init(Napi::Env env, Napi::Object exports); + QMovieWrap(const Napi::CallbackInfo& info); + ~QMovieWrap(); + NMovie* getInternalInstance(); + // class constructor + static Napi::FunctionReference constructor; + // wrapped methods + Napi::Value setFileName(const Napi::CallbackInfo& info); + Napi::Value fileName(const Napi::CallbackInfo& info); + Napi::Value setFormat(const Napi::CallbackInfo& info); + Napi::Value format(const Napi::CallbackInfo& info); + Napi::Value setScaledSize(const Napi::CallbackInfo& info); + Napi::Value start(const Napi::CallbackInfo& info); + Napi::Value stop(const Napi::CallbackInfo& info); + Napi::Value setPaused(const Napi::CallbackInfo& info); + Napi::Value jumpToNextFrame(const Napi::CallbackInfo& info); + Napi::Value jumpToFrame(const Napi::CallbackInfo& info); + Napi::Value state(const Napi::CallbackInfo& info); + Napi::Value currentFrameNumber(const Napi::CallbackInfo& info); + Napi::Value currentPixmap(const Napi::CallbackInfo& info); + Napi::Value loadFromData(const Napi::CallbackInfo& info); + QOBJECT_WRAPPED_METHODS_DECLARATION +}; diff --git a/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h b/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h index eaeefcb08..ea38c9381 100644 --- a/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h +++ b/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h @@ -19,6 +19,7 @@ class QPixmapWrap : public Napi::ObjectWrap { QPixmap* getInternalInstance(); // Wrapped methods Napi::Value load(const Napi::CallbackInfo& info); + Napi::Value loadFromData(const Napi::CallbackInfo& info); Napi::Value save(const Napi::CallbackInfo& info); Napi::Value scaled(const Napi::CallbackInfo& info); Napi::Value height(const Napi::CallbackInfo& info); diff --git a/src/cpp/include/nodegui/QtWidgets/QLabel/qlabel_wrap.h b/src/cpp/include/nodegui/QtWidgets/QLabel/qlabel_wrap.h index bc2fba867..b9dd16382 100644 --- a/src/cpp/include/nodegui/QtWidgets/QLabel/qlabel_wrap.h +++ b/src/cpp/include/nodegui/QtWidgets/QLabel/qlabel_wrap.h @@ -25,5 +25,6 @@ class QLabelWrap : public Napi::ObjectWrap { Napi::Value setText(const Napi::CallbackInfo& info); Napi::Value text(const Napi::CallbackInfo& info); Napi::Value setPixmap(const Napi::CallbackInfo& info); + Napi::Value setMovie(const Napi::CallbackInfo& info); Napi::Value setOpenExternalLinks(const Napi::CallbackInfo& info); }; diff --git a/src/cpp/lib/QtCore/QRect/qrect_wrap.cpp b/src/cpp/lib/QtCore/QRect/qrect_wrap.cpp new file mode 100644 index 000000000..9d334529e --- /dev/null +++ b/src/cpp/lib/QtCore/QRect/qrect_wrap.cpp @@ -0,0 +1,117 @@ +#include "QtCore/QRect/qrect_wrap.h" + +#include "Extras/Utils/nutils.h" +#include "QtCore/QVariant/qvariant_wrap.h" + +Napi::FunctionReference QRectWrap::constructor; + +Napi::Object QRectWrap::init(Napi::Env env, Napi::Object exports) { + Napi::HandleScope scope(env); + char CLASSNAME[] = "QRect"; + Napi::Function func = DefineClass( + env, CLASSNAME, + {InstanceMethod("setHeight", &QRectWrap::setHeight), + InstanceMethod("setWidth", &QRectWrap::setWidth), + InstanceMethod("setLeft", &QRectWrap::setLeft), + InstanceMethod("setTop", &QRectWrap::setTop), + InstanceMethod("height", &QRectWrap::height), + InstanceMethod("width", &QRectWrap::width), + InstanceMethod("left", &QRectWrap::left), + InstanceMethod("top", &QRectWrap::top), + StaticMethod("fromQVariant", &StaticQRectWrapMethods::fromQVariant), + COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE}); + constructor = Napi::Persistent(func); + exports.Set(CLASSNAME, func); + return exports; +} + +QRectWrap::QRectWrap(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + if (info.Length() == 4) { + int x = info[0].As().Int32Value(); + int y = info[1].As().Int32Value(); + int width = info[2].As().Int32Value(); + int height = info[3].As().Int32Value(); + this->instance = std::make_unique(x, y, width, height); + } else if (info.Length() == 1) { + this->instance = + std::unique_ptr(info[0].As>().Data()); + } else if (info.Length() == 0) { + this->instance = std::make_unique(); + } else { + Napi::TypeError::New(env, "Wrong number of arguments") + .ThrowAsJavaScriptException(); + } + this->rawData = extrautils::configureComponent(this->getInternalInstance()); +} + +QRectWrap::~QRectWrap() { this->instance.reset(); } + +QRect* QRectWrap::getInternalInstance() { return this->instance.get(); } + +Napi::Value QRectWrap::setHeight(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + int height = info[0].As().Int32Value(); + this->instance->setHeight(height); + return env.Null(); +} +Napi::Value QRectWrap::setWidth(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + int width = info[0].As().Int32Value(); + this->instance->setWidth(width); + return env.Null(); +} + +Napi::Value QRectWrap::setLeft(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + int value = info[0].As().Int32Value(); + this->instance->setLeft(value); + return env.Null(); +} +Napi::Value QRectWrap::setTop(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + int value = info[0].As().Int32Value(); + this->instance->setTop(value); + return env.Null(); +} +Napi::Value QRectWrap::height(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + return Napi::Value::From(env, this->instance->height()); +} +Napi::Value QRectWrap::width(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + return Napi::Value::From(env, this->instance->width()); +} +Napi::Value QRectWrap::left(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + return Napi::Value::From(env, this->instance->left()); +} +Napi::Value QRectWrap::top(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + return Napi::Value::From(env, this->instance->top()); +} + +Napi::Value StaticQRectWrapMethods::fromQVariant( + const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + Napi::Object variantObject = info[0].As(); + QVariantWrap* variantWrap = + Napi::ObjectWrap::Unwrap(variantObject); + QVariant* variant = variantWrap->getInternalInstance(); + QRect rect = variant->value(); + auto instance = QRectWrap::constructor.New( + {Napi::External::New(env, new QRect(rect))}); + return instance; +} diff --git a/src/cpp/lib/QtGui/QMovie/qmovie_wrap.cpp b/src/cpp/lib/QtGui/QMovie/qmovie_wrap.cpp new file mode 100644 index 000000000..0cb3b2110 --- /dev/null +++ b/src/cpp/lib/QtGui/QMovie/qmovie_wrap.cpp @@ -0,0 +1,174 @@ +#include "QtGui/QMovie/qmovie_wrap.h" + +#include +#include +#include + +#include "Extras/Utils/nutils.h" +#include "QtGui/QPixmap/qpixmap_wrap.h" + +Napi::FunctionReference QMovieWrap::constructor; + +Napi::Object QMovieWrap::init(Napi::Env env, Napi::Object exports) { + Napi::HandleScope scope(env); + char CLASSNAME[] = "QMovie"; + Napi::Function func = DefineClass( + env, CLASSNAME, + {InstanceMethod("setFileName", &QMovieWrap::setFileName), + InstanceMethod("fileName", &QMovieWrap::fileName), + InstanceMethod("setFormat", &QMovieWrap::setFormat), + InstanceMethod("format", &QMovieWrap::format), + InstanceMethod("setScaledSize", &QMovieWrap::setScaledSize), + InstanceMethod("start", &QMovieWrap::start), + InstanceMethod("stop", &QMovieWrap::stop), + InstanceMethod("setPaused", &QMovieWrap::setPaused), + InstanceMethod("jumpToNextFrame", &QMovieWrap::jumpToNextFrame), + InstanceMethod("jumpToFrame", &QMovieWrap::jumpToFrame), + InstanceMethod("state", &QMovieWrap::state), + InstanceMethod("currentFrameNumber", &QMovieWrap::currentFrameNumber), + InstanceMethod("currentPixmap", &QMovieWrap::currentPixmap), + InstanceMethod("loadFromData", &QMovieWrap::loadFromData), + QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QMovieWrap)}); + constructor = Napi::Persistent(func); + exports.Set(CLASSNAME, func); + return exports; +} + +NMovie* QMovieWrap::getInternalInstance() { return this->instance; } + +QMovieWrap::~QMovieWrap() { extrautils::safeDelete(this->instance); } + +QMovieWrap::QMovieWrap(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + if (info.Length() == 1) { + if (info[0].IsExternal()) { + this->instance = new NMovie(info[0].As>().Data()); + } else { + Napi::Object parentObject = info[0].As(); + QMovieWrap* parentWidgetWrap = + Napi::ObjectWrap::Unwrap(parentObject); + this->instance = new NMovie(parentWidgetWrap->getInternalInstance()); + } + } else if (info.Length() == 0) { + this->instance = new NMovie(); + } else { + Napi::TypeError::New(env, "Wrong number of arguments") + .ThrowAsJavaScriptException(); + } + this->rawData = extrautils::configureQObject(this->getInternalInstance()); +} + +Napi::Value QMovieWrap::setFileName(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + Napi::String fileName = info[0].As(); + this->instance->setFileName(QString::fromStdString(fileName.Utf8Value())); + return env.Null(); +} + +Napi::Value QMovieWrap::fileName(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + QString fileName = this->instance->fileName(); + return Napi::Value::From(env, fileName.toStdString()); +} + +Napi::Value QMovieWrap::setFormat(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + Napi::String formatName = info[0].As(); + std::string format = formatName.Utf8Value(); + QByteArray byteArray(format.c_str(), format.length()); + this->instance->setFormat(byteArray); + return env.Null(); +} + +Napi::Value QMovieWrap::format(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + QByteArray format = this->instance->format(); + return Napi::Value::From(env, format.toStdString()); +} + +Napi::Value QMovieWrap::setScaledSize(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + Napi::Object sizeObject = info[0].As(); + QSizeWrap* sizeWrap = Napi::ObjectWrap::Unwrap(sizeObject); + this->instance->setScaledSize(*sizeWrap->getInternalInstance()); + return env.Null(); +} + +Napi::Value QMovieWrap::start(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + this->instance->start(); + return env.Null(); +} + +Napi::Value QMovieWrap::stop(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + this->instance->stop(); + return env.Null(); +} + +Napi::Value QMovieWrap::setPaused(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + Napi::Boolean paused = info[0].As(); + this->instance->setPaused(paused.Value()); + return env.Null(); +} + +Napi::Value QMovieWrap::jumpToNextFrame(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + bool jumped = this->instance->jumpToNextFrame(); + return Napi::Value::From(env, jumped); +} + +Napi::Value QMovieWrap::jumpToFrame(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + Napi::Number frameNo = info[0].As(); + bool jumped = this->instance->jumpToFrame(frameNo.Int32Value()); + return Napi::Value::From(env, jumped); +} + +Napi::Value QMovieWrap::state(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + QMovie::MovieState state = this->instance->state(); + return Napi::Value::From(env, static_cast(state)); +} + +Napi::Value QMovieWrap::currentFrameNumber(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + int currentFrameNumber = this->instance->currentFrameNumber(); + return Napi::Value::From(env, currentFrameNumber); +} + +Napi::Value QMovieWrap::currentPixmap(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + QPixmap pixmap = this->instance->currentPixmap(); + auto instance = QPixmapWrap::constructor.New( + {Napi::External::New(env, new QPixmap(pixmap))}); + return instance; +} + +Napi::Value QMovieWrap::loadFromData(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + Napi::Buffer buffer = info[0].As>(); + QByteArray byteArray = QByteArray(buffer.Data(), buffer.Length()); + QBuffer* bufferDevice = new QBuffer(); + bufferDevice->setData(byteArray); + this->instance->setDevice(bufferDevice); + return env.Null(); +} \ No newline at end of file diff --git a/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp b/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp index 39ba0d928..6c73147ab 100644 --- a/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp +++ b/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp @@ -11,6 +11,7 @@ Napi::Object QPixmapWrap::init(Napi::Env env, Napi::Object exports) { Napi::Function func = DefineClass( env, CLASSNAME, {InstanceMethod("load", &QPixmapWrap::load), + InstanceMethod("loadFromData", &QPixmapWrap::loadFromData), InstanceMethod("save", &QPixmapWrap::save), InstanceMethod("scaled", &QPixmapWrap::scaled), InstanceMethod("height", &QPixmapWrap::height), @@ -63,6 +64,29 @@ Napi::Value QPixmapWrap::load(const Napi::CallbackInfo& info) { return Napi::Boolean::New(env, loadSuccess); } +Napi::Value QPixmapWrap::loadFromData(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + bool loadSuccess = false; + + if (info.Length() > 0 && info.Length() < 3) { + Napi::Buffer buffer = info[0].As>(); + + if (info.Length() > 1) { + Napi::String format = info[1].As(); + loadSuccess = this->instance->loadFromData(buffer.Data(), buffer.Length(), + format.Utf8Value().c_str()); + } else { + loadSuccess = + this->instance->loadFromData(buffer.Data(), buffer.Length()); + } + } else { + Napi::TypeError::New(env, "Wrong number of arguments") + .ThrowAsJavaScriptException(); + } + return Napi::Boolean::New(env, loadSuccess); +} + Napi::Value QPixmapWrap::save(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); Napi::HandleScope scope(env); diff --git a/src/cpp/lib/QtWidgets/QLabel/qlabel_wrap.cpp b/src/cpp/lib/QtWidgets/QLabel/qlabel_wrap.cpp index 8dbb0ca3e..de4ad5b5a 100644 --- a/src/cpp/lib/QtWidgets/QLabel/qlabel_wrap.cpp +++ b/src/cpp/lib/QtWidgets/QLabel/qlabel_wrap.cpp @@ -3,6 +3,7 @@ #include #include "Extras/Utils/nutils.h" +#include "QtGui/QMovie/qmovie_wrap.h" #include "QtGui/QPixmap/qpixmap_wrap.h" #include "QtWidgets/QWidget/qwidget_wrap.h" Napi::FunctionReference QLabelWrap::constructor; @@ -17,6 +18,7 @@ Napi::Object QLabelWrap::init(Napi::Env env, Napi::Object exports) { InstanceMethod("setText", &QLabelWrap::setText), InstanceMethod("text", &QLabelWrap::text), InstanceMethod("setPixmap", &QLabelWrap::setPixmap), + InstanceMethod("setMovie", &QLabelWrap::setMovie), InstanceMethod("setOpenExternalLinks", &QLabelWrap::setOpenExternalLinks), QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QLabelWrap)}); @@ -97,6 +99,16 @@ Napi::Value QLabelWrap::setPixmap(const Napi::CallbackInfo& info) { return env.Null(); } +Napi::Value QLabelWrap::setMovie(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + Napi::Object movieObject = info[0].As(); + QMovieWrap* movieWrap = Napi::ObjectWrap::Unwrap(movieObject); + this->instance->setMovie(movieWrap->getInternalInstance()); + return env.Null(); +} + Napi::Value QLabelWrap::setOpenExternalLinks(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); Napi::HandleScope scope(env); diff --git a/src/cpp/main.cpp b/src/cpp/main.cpp index 335a158e6..63a5fa574 100644 --- a/src/cpp/main.cpp +++ b/src/cpp/main.cpp @@ -1,6 +1,7 @@ #include #include "QtCore/QObject/qobject_wrap.h" +#include "QtCore/QRect/qrect_wrap.h" #include "QtCore/QSize/qsize_wrap.h" #include "QtCore/QUrl/qurl_wrap.h" #include "QtCore/QVariant/qvariant_wrap.h" @@ -11,6 +12,7 @@ #include "QtGui/QEvent/QMouseEvent/qmouseevent_wrap.h" #include "QtGui/QIcon/qicon_wrap.h" #include "QtGui/QKeySequence/qkeysequence_wrap.h" +#include "QtGui/QMovie/qmovie_wrap.h" #include "QtGui/QPixmap/qpixmap_wrap.h" #include "QtWidgets/QAction/qaction_wrap.h" #include "QtWidgets/QCheckBox/qcheckbox_wrap.h" @@ -45,12 +47,14 @@ Napi::Object Main(Napi::Env env, Napi::Object exports) { QObjectWrap::init(env, exports); QVariantWrap::init(env, exports); QSizeWrap::init(env, exports); + QRectWrap::init(env, exports); QUrlWrap::init(env, exports); QClipboardWrap::init(env, exports); QWidgetWrap::init(env, exports); QPixmapWrap::init(env, exports); QKeySequenceWrap::init(env, exports); QIconWrap::init(env, exports); + QMovieWrap::init(env, exports); QCursorWrap::init(env, exports); QGridLayoutWrap::init(env, exports); FlexLayoutWrap::init(env, exports); diff --git a/src/index.ts b/src/index.ts index ea6c8b88a..091d3aa91 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,8 +5,9 @@ export * from './lib/QtEnums'; // Gui: export { QApplication } from './lib/QtGui/QApplication'; export { QKeySequence } from './lib/QtGui/QKeySequence'; -export { QPixmap, ReadWriteImageFormats, ImageFormats } from './lib/QtGui/QPixmap'; +export { QPixmap, ImageFormats } from './lib/QtGui/QPixmap'; export { QIcon, QIconMode, QIconState } from './lib/QtGui/QIcon'; +export { QMovie, CacheMode, MovieState, QMovieEvents } from './lib/QtGui/QMovie'; export { QCursor } from './lib/QtGui/QCursor'; export { QTextOptionWrapMode } from './lib/QtGui/QTextOption'; export { QClipboard, QClipboardMode } from './lib/QtGui/QClipboard'; @@ -43,6 +44,7 @@ export { QShortcut, QShortcutEvents } from './lib/QtWidgets/QShortcut'; export { QObject, NodeObject } from './lib/QtCore/QObject'; export { QVariant } from './lib/QtCore/QVariant'; export { QSize } from './lib/QtCore/QSize'; +export { QRect } from './lib/QtCore/QRect'; export { QUrl, ParsingMode } from './lib/QtCore/QUrl'; // Layouts: export { QGridLayout } from './lib/QtWidgets/QGridLayout'; diff --git a/src/lib/QtCore/QRect.ts b/src/lib/QtCore/QRect.ts new file mode 100644 index 000000000..60208f97b --- /dev/null +++ b/src/lib/QtCore/QRect.ts @@ -0,0 +1,47 @@ +import { NativeElement, Component } from '../core/Component'; +import addon from '../utils/addon'; +import { checkIfNativeElement } from '../utils/helpers'; +import { QVariant } from './QVariant'; + +export class QRect extends Component { + native: NativeElement; + //eslint-disable-next-line @typescript-eslint/no-inferrable-types + constructor(arg?: NativeElement | number, y: number = 0, width: number = 0, height: number = 0) { + super(); + const count = arguments.length; + if (count > 1) { + this.native = new addon.QRect(arg, y, width, height); + } else if (count == 1 && checkIfNativeElement(arg)) { + this.native = arg as NativeElement; + } else { + this.native = new addon.QRect(); + } + } + setWidth(width: number): void { + return this.native.setWidth(width); + } + width(): number { + return this.native.width(); + } + setHeight(height: number): void { + return this.native.setHeight(height); + } + height(): number { + return this.native.height(); + } + left(): number { + return this.native.left(); + } + setLeft(height: number): void { + return this.native.setLeft(height); + } + top(): number { + return this.native.top(); + } + setTop(height: number): void { + return this.native.setTop(height); + } + static fromQVariant(variant: QVariant): QRect { + return new QRect(addon.QRect.fromQVariant(variant.native)); + } +} diff --git a/src/lib/QtCore/__tests__/QRect.test.ts b/src/lib/QtCore/__tests__/QRect.test.ts new file mode 100644 index 000000000..23fc101f0 --- /dev/null +++ b/src/lib/QtCore/__tests__/QRect.test.ts @@ -0,0 +1,39 @@ +import { QRect } from '../QRect'; +import { QVariant } from '../QVariant'; + +describe('QRect', () => { + it('initialize empty', () => { + const rect = new QRect(); + expect(rect).toBeTruthy(); + }); + it('initialize with x, y, width, height', () => { + const rect = new QRect(10, 11, 20, 30); + expect(rect).toBeTruthy(); + }); + it('width', () => { + const rect = new QRect(); + rect.setWidth(300); + expect(rect.width()).toBe(300); + }); + it('height', () => { + const rect = new QRect(); + rect.setHeight(200); + expect(rect.height()).toBe(200); + }); + it('left', () => { + const rect = new QRect(); + rect.setHeight(200); + expect(rect.height()).toBe(200); + }); + it('top', () => { + const rect = new QRect(); + rect.setHeight(200); + expect(rect.height()).toBe(200); + }); + it('initialize from QVariant', () => { + const rect = new QRect(10, 10, 300, 200); + const variant = new QVariant(rect); + expect(variant).toBeTruthy(); + expect(QRect.fromQVariant(variant).left()).toBe(rect.left()); + }); +}); diff --git a/src/lib/QtGui/QMovie.ts b/src/lib/QtGui/QMovie.ts new file mode 100644 index 000000000..c6338d18a --- /dev/null +++ b/src/lib/QtGui/QMovie.ts @@ -0,0 +1,96 @@ +import addon from '../utils/addon'; +import { NativeElement } from '../core/Component'; +import { checkIfNativeElement } from '../utils/helpers'; +import { QObject } from '../QtCore/QObject'; +import { QSize } from '../QtCore/QSize'; +import { BaseWidgetEvents } from '../core/EventWidget'; +import { QPixmap } from './QPixmap'; + +export const QMovieEvents = Object.freeze({ + ...BaseWidgetEvents, + error: 'error', + finished: 'finished', + frameChanged: 'frameChanged', + resized: 'resized', + started: 'started', + stateChanged: 'stateChanged', + updated: 'updated', +}); + +type supportedFormats = 'gif' | 'webp'; +export class QMovie extends QObject { + native: NativeElement; + constructor(arg?: QObject | NativeElement) { + super(); + if (arg) { + if (checkIfNativeElement(arg)) { + this.native = arg as NativeElement; + } else { + this.native = new addon.QMovie(arg); + } + } else { + this.native = new addon.QMovie(); + } + } + setFileName(fileName: string): void { + this.native.setFileName(fileName); + this.jumpToFrame(0); + } + loadFromData(buffer: Buffer): void { + this.native.loadFromData(buffer); + } + fileName(): string { + return this.native.fileName(); + } + setFormat(formatName: supportedFormats): void { + this.native.setFormat(formatName); + } + format(): string { + return this.native.format(); + } + + setScaledSize(size: QSize): void { + this.native.setScaledSize(size.native); + } + setSpeed(percentSpeed: number): void { + this.setProperty('speed', percentSpeed); + } + start(): void { + this.native.start(); + } + stop(): void { + this.native.stop(); + } + setPaused(paused: boolean): void { + this.native.setPaused(paused); + } + jumpToNextFrame(): boolean { + return this.native.jumpToNextFrame(); + } + jumpToFrame(frame: number): boolean { + return this.native.jumpToFrame(frame); + } + setCacheMode(cacheMode: CacheMode): void { + this.setProperty('cacheMode', cacheMode); + } + state(): MovieState { + return this.native.state(); + } + currentFrameNumber(): number { + return this.native.currentFrameNumber(); + } + currentPixmap(): QPixmap { + return new QPixmap(this.native.currentPixmap()); + } +} + +export enum CacheMode { + CacheNone, + CacheAll, +} + +export enum MovieState { + NotRunning, + Paused, + Running, +} diff --git a/src/lib/QtGui/QPixmap.ts b/src/lib/QtGui/QPixmap.ts index d843fb3b0..b06f50221 100644 --- a/src/lib/QtGui/QPixmap.ts +++ b/src/lib/QtGui/QPixmap.ts @@ -4,8 +4,7 @@ import { AspectRatioMode } from '../QtEnums'; import { checkIfNativeElement } from '../utils/helpers'; import { QVariant } from '../QtCore/QVariant'; -export type ImageFormats = 'BMP' | 'GIF' | 'JPG' | 'JPEG' | 'PNG' | 'PBM' | 'PGM' | 'PPM' | 'XBM' | 'XPM'; -export type ReadWriteImageFormats = 'BMP' | 'JPG' | 'JPEG' | 'PNG' | 'PBM' | 'XBM' | 'XPM'; +export type ImageFormats = 'BMP' | 'GIF' | 'JPG' | 'JPEG' | 'PNG' | 'PBM' | 'PGM' | 'PPM' | 'XBM' | 'XPM' | 'SVG'; type arg = string | NativeElement; export class QPixmap extends Component { @@ -24,7 +23,10 @@ export class QPixmap extends Component { load(imageUrl: string): boolean { return this.native.load(imageUrl); } - save(fileName: string, format?: ReadWriteImageFormats): boolean { + loadFromData(buffer: Buffer, format?: ImageFormats): boolean { + return format ? this.native.loadFromData(buffer, format) : this.native.loadFromData(buffer); + } + save(fileName: string, format?: ImageFormats): boolean { return format ? this.native.save(fileName, format) : this.native.save(fileName); } scaled(width: number, height: number, aspectRatioMode?: AspectRatioMode): QPixmap { diff --git a/src/lib/QtGui/__tests__/QMovie.test.ts b/src/lib/QtGui/__tests__/QMovie.test.ts new file mode 100644 index 000000000..8d89b5887 --- /dev/null +++ b/src/lib/QtGui/__tests__/QMovie.test.ts @@ -0,0 +1,89 @@ +import { QMovie, MovieState } from '../QMovie'; +import path from 'path'; +import { QPixmap } from '../QPixmap'; +import { QSize } from '../../QtCore/QSize'; +import fs from 'fs'; + +const testImagePath = path.resolve(__dirname, 'assets', 'fine.gif'); +describe('QMovie', () => { + it('initialize empty', () => { + const movie = new QMovie(); + expect(movie).toBeTruthy(); + }); + it('setFileName', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + expect(movie.fileName()).toBe(testImagePath); + }); + it('setFormat', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + // movie.setFormat('GIF'); + expect(movie.format()).toBe('gif'); + }); + it('start', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + movie.start(); + expect(movie.state()).toBe(MovieState.Running); + }); + it('setPaused', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + movie.start(); + movie.setPaused(true); + expect(movie.state()).toBe(MovieState.Paused); + movie.setPaused(false); + expect(movie.state()).toBe(MovieState.Running); + }); + it('stop', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + movie.start(); + movie.stop(); + expect(movie.state()).toBe(MovieState.NotRunning); + }); + it('jumpToFrame and jumpToNextFrame', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + movie.start(); + movie.stop(); + movie.jumpToFrame(2); + expect(movie.currentFrameNumber()).toBe(2); + movie.jumpToNextFrame(); + expect(movie.currentFrameNumber()).toBe(3); + }); + it('currentPixmap', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + movie.start(); + movie.stop(); + movie.jumpToFrame(2); + const pixmap = movie.currentPixmap(); + expect(pixmap).toBeInstanceOf(QPixmap); + expect(pixmap.height()).toBe(270); + }); + + it('setScaledSize', () => { + const movie = new QMovie(); + movie.setFileName(testImagePath); + movie.start(); + movie.stop(); + movie.jumpToFrame(2); + movie.setScaledSize(new QSize(200, 200)); + movie.jumpToNextFrame(); + const pixmap = movie.currentPixmap(); + expect(pixmap.height()).toBe(200); + }); + it('custom: loadFromData', () => { + const movie = new QMovie(); + const arrayBuffer = fs.readFileSync(testImagePath, null).buffer; + movie.loadFromData(Buffer.from(arrayBuffer)); + movie.start(); + movie.stop(); + movie.jumpToFrame(2); + const pixmap = movie.currentPixmap(); + expect(pixmap).toBeInstanceOf(QPixmap); + expect(pixmap.height()).toBe(270); + }); +}); diff --git a/src/lib/QtGui/__tests__/QPixmap.test.ts b/src/lib/QtGui/__tests__/QPixmap.test.ts index 68596bd9d..75a643e7f 100644 --- a/src/lib/QtGui/__tests__/QPixmap.test.ts +++ b/src/lib/QtGui/__tests__/QPixmap.test.ts @@ -47,6 +47,14 @@ describe('QPixmap', () => { expect(isLoaded).toBe(true); expect(pixmap.height()).toBe(1083); }); + it('load from data', () => { + const pixmap = new QPixmap(); + expect(pixmap.height()).toBe(0); + const arrayBuffer = fs.readFileSync(testImagePath, null).buffer; + const isLoaded = pixmap.loadFromData(Buffer.from(arrayBuffer)); + expect(isLoaded).toBe(true); + expect(pixmap.height()).toBe(1083); + }); it('save to a file', async () => { const outputFilePath = path.resolve(__dirname, 'assets', 'nodegui_save.png'); await new Promise(resolve => fs.unlink(outputFilePath, resolve)); diff --git a/src/lib/QtGui/__tests__/assets/fine.gif b/src/lib/QtGui/__tests__/assets/fine.gif new file mode 100644 index 000000000..f89db7ee0 Binary files /dev/null and b/src/lib/QtGui/__tests__/assets/fine.gif differ diff --git a/src/lib/QtWidgets/QLabel.ts b/src/lib/QtWidgets/QLabel.ts index d70202fbf..113b4fe94 100644 --- a/src/lib/QtWidgets/QLabel.ts +++ b/src/lib/QtWidgets/QLabel.ts @@ -3,6 +3,7 @@ import { NodeWidget } from './QWidget'; import { BaseWidgetEvents } from '../core/EventWidget'; import { NativeElement } from '../core/Component'; import { QPixmap } from '../QtGui/QPixmap'; +import { QMovie } from '../QtGui/QMovie'; export const QLabelEvents = Object.freeze({ ...BaseWidgetEvents, @@ -10,6 +11,7 @@ export const QLabelEvents = Object.freeze({ export class QLabel extends NodeWidget { native: NativeElement; private _pixmap?: QPixmap; + private _movie?: QMovie; constructor(parent?: NodeWidget) { let native; if (parent) { @@ -40,6 +42,13 @@ export class QLabel extends NodeWidget { pixmap(): QPixmap | undefined { return this._pixmap; } + setMovie(movie: QMovie): void { + this.native.setMovie(movie.native); + this._movie = movie; + } + movie(): QMovie | undefined { + return this._movie; + } setOpenExternalLinks(open: boolean): void { this.native.setOpenExternalLinks(open); } diff --git a/src/lib/QtWidgets/__tests__/QLabel.test.ts b/src/lib/QtWidgets/__tests__/QLabel.test.ts index d71bce0eb..812e558c9 100644 --- a/src/lib/QtWidgets/__tests__/QLabel.test.ts +++ b/src/lib/QtWidgets/__tests__/QLabel.test.ts @@ -1,5 +1,6 @@ import { QLabel } from '../QLabel'; import { QPixmap } from '../../QtGui/QPixmap'; +import { QMovie } from '../../QtGui/QMovie'; describe('QLabel', () => { const label = new QLabel(); @@ -28,4 +29,10 @@ describe('QLabel', () => { label.setPixmap(pixMap); expect(label.pixmap()).toEqual(pixMap); }); + it('setMovie', () => { + const label = new QLabel(); + const movie = new QMovie(); + label.setMovie(movie); + expect(label.movie()).toEqual(movie); + }); });