Adds Abstract button - QPushbutton, checkbox and radiobutton methods and tests (#206)

* Adds QAbstract button and related methods to QPushbutton, checkbox and radiobutton
Also adds QIcon to QVariant

* Adds iconSize to abstract button
This commit is contained in:
Atul R 2019-11-19 01:27:26 +01:00 committed by GitHub
parent 11ff1be321
commit 97c67219e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 257 additions and 99 deletions

View File

@ -21,6 +21,11 @@ class QIconWrap : public Napi::ObjectWrap<QIconWrap> {
Napi::Value pixmap(const Napi::CallbackInfo& info);
Napi::Value isMask(const Napi::CallbackInfo& info);
Napi::Value setIsMask(const Napi::CallbackInfo& info);
Napi::Value cacheKey(const Napi::CallbackInfo& info);
COMPONENT_WRAPPED_METHODS_DECLARATION
};
namespace StaticQIconWrapMethods {
Napi::Value fromQVariant(const Napi::CallbackInfo& info);
} // namespace StaticQIconWrapMethods

View File

@ -0,0 +1,45 @@
#pragma once
#include "QtGui/QIcon/qicon_wrap.h"
#include "QtWidgets/QWidget/qwidget_macro.h"
#include "QtWidgets/QWidget/qwidget_wrap.h"
/*
This macro adds common QAbstractScrollArea exported methods
The exported methods are taken into this macro to avoid writing them in each
and every widget we export.
*/
#ifndef QABSTRACTBUTTON_WRAPPED_METHODS_DECLARATION
#define QABSTRACTBUTTON_WRAPPED_METHODS_DECLARATION \
QWIDGET_WRAPPED_METHODS_DECLARATION \
Napi::Value setText(const Napi::CallbackInfo& info) { \
Napi::Env env = info.Env(); \
Napi::HandleScope scope(env); \
\
Napi::String napiText = info[0].As<Napi::String>(); \
std::string text = napiText.Utf8Value(); \
this->instance->setText(text.c_str()); \
return env.Null(); \
} \
\
Napi::Value setIcon(const Napi::CallbackInfo& info) { \
Napi::Env env = info.Env(); \
Napi::HandleScope scope(env); \
\
Napi::Object iconObject = info[0].As<Napi::Object>(); \
QIconWrap* iconWrap = Napi::ObjectWrap<QIconWrap>::Unwrap(iconObject); \
this->instance->setIcon(*iconWrap->getInternalInstance()); \
return env.Null(); \
}
#endif // QABSTRACTBUTTON_WRAPPED_METHODS_DECLARATION
#ifndef QABSTRACTBUTTON_WRAPPED_METHODS_EXPORT_DEFINE
#define QABSTRACTBUTTON_WRAPPED_METHODS_EXPORT_DEFINE(WidgetWrapName) \
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(WidgetWrapName) \
InstanceMethod("setText", &WidgetWrapName::setText), \
InstanceMethod("setIcon", &WidgetWrapName::setIcon),
#endif // QABSTRACTBUTTON_WRAPPED_METHODS_EXPORT_DEFINE

View File

@ -5,6 +5,7 @@
#include <QPointer>
#include "QtWidgets/QAbstractButton/qabstractbutton_macro.h"
#include "QtWidgets/QWidget/qwidget_macro.h"
#include "ncheckbox.hpp"
@ -20,9 +21,8 @@ class QCheckBoxWrap : public Napi::ObjectWrap<QCheckBoxWrap> {
// class constructor
static Napi::FunctionReference constructor;
// wrapped methods
Napi::Value setText(const Napi::CallbackInfo& info);
Napi::Value isChecked(const Napi::CallbackInfo& info);
Napi::Value setChecked(const Napi::CallbackInfo& info);
QWIDGET_WRAPPED_METHODS_DECLARATION
QABSTRACTBUTTON_WRAPPED_METHODS_DECLARATION
};

View File

@ -6,9 +6,9 @@
#include <QPointer>
#include "Extras/Utils/nutils.h"
#include "QtWidgets/QAbstractButton/qabstractbutton_macro.h"
#include "QtWidgets/QWidget/qwidget_macro.h"
#include "npushbutton.hpp"
class QPushButtonWrap : public Napi::ObjectWrap<QPushButtonWrap> {
private:
QPointer<NPushButton> instance;
@ -21,9 +21,7 @@ class QPushButtonWrap : public Napi::ObjectWrap<QPushButtonWrap> {
// class constructor
static Napi::FunctionReference constructor;
// wrapped methods
Napi::Value setText(const Napi::CallbackInfo &info);
Napi::Value setFlat(const Napi::CallbackInfo &info);
Napi::Value setIcon(const Napi::CallbackInfo &info);
QWIDGET_WRAPPED_METHODS_DECLARATION
QABSTRACTBUTTON_WRAPPED_METHODS_DECLARATION
};

View File

@ -5,6 +5,7 @@
#include <QPointer>
#include "QtWidgets/QAbstractButton/qabstractbutton_macro.h"
#include "QtWidgets/QWidget/qwidget_macro.h"
#include "nradiobutton.hpp"
@ -20,7 +21,6 @@ class QRadioButtonWrap : public Napi::ObjectWrap<QRadioButtonWrap> {
// class constructor
static Napi::FunctionReference constructor;
// wrapped methods
Napi::Value setText(const Napi::CallbackInfo& info);
QWIDGET_WRAPPED_METHODS_DECLARATION
QABSTRACTBUTTON_WRAPPED_METHODS_DECLARATION
};

View File

@ -1,20 +1,22 @@
#include "QtGui/QIcon/qicon_wrap.h"
#include "Extras/Utils/nutils.h"
#include "QtCore/QVariant/qvariant_wrap.h"
#include "QtGui/QPixmap/qpixmap_wrap.h"
#include "deps/spdlog/spdlog.h"
Napi::FunctionReference QIconWrap::constructor;
Napi::Object QIconWrap::init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
char CLASSNAME[] = "QIcon";
Napi::Function func =
DefineClass(env, CLASSNAME,
{InstanceMethod("pixmap", &QIconWrap::pixmap),
InstanceMethod("isMask", &QIconWrap::isMask),
InstanceMethod("setIsMask", &QIconWrap::setIsMask),
COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE});
Napi::Function func = DefineClass(
env, CLASSNAME,
{InstanceMethod("pixmap", &QIconWrap::pixmap),
InstanceMethod("isMask", &QIconWrap::isMask),
InstanceMethod("setIsMask", &QIconWrap::setIsMask),
InstanceMethod("cacheKey", &QIconWrap::cacheKey),
StaticMethod("fromQVariant", &StaticQIconWrapMethods::fromQVariant),
COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE});
constructor = Napi::Persistent(func);
exports.Set(CLASSNAME, func);
return exports;
@ -25,9 +27,14 @@ QIconWrap::QIconWrap(const Napi::CallbackInfo& info)
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
if (info.Length() == 1) {
Napi::String url = info[0].As<Napi::String>();
QString imageUrl = QString::fromUtf8(url.Utf8Value().c_str());
this->instance = std::make_unique<QIcon>(imageUrl);
if (info[0].IsExternal()) {
this->instance =
std::unique_ptr<QIcon>(info[0].As<Napi::External<QIcon>>().Data());
} else {
Napi::String url = info[0].As<Napi::String>();
QString imageUrl = QString::fromUtf8(url.Utf8Value().c_str());
this->instance = std::make_unique<QIcon>(imageUrl);
}
} else if (info.Length() == 0) {
this->instance = std::make_unique<QIcon>();
} else {
@ -90,3 +97,23 @@ Napi::Value QIconWrap::setIsMask(const Napi::CallbackInfo& info) {
return env.Null();
}
Napi::Value QIconWrap::cacheKey(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
return Napi::Value::From(env, this->instance->cacheKey());
}
Napi::Value StaticQIconWrapMethods::fromQVariant(
const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Napi::Object variantObject = info[0].As<Napi::Object>();
QVariantWrap* variantWrap =
Napi::ObjectWrap<QVariantWrap>::Unwrap(variantObject);
QVariant* variant = variantWrap->getInternalInstance();
QIcon icon = variant->value<QIcon>();
auto instance = QIconWrap::constructor.New(
{Napi::External<QIcon>::New(env, new QIcon(icon))});
return instance;
}

View File

@ -10,12 +10,11 @@ Napi::FunctionReference QCheckBoxWrap::constructor;
Napi::Object QCheckBoxWrap::init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
char CLASSNAME[] = "QCheckBox";
Napi::Function func =
DefineClass(env, CLASSNAME,
{InstanceMethod("setText", &QCheckBoxWrap::setText),
InstanceMethod("setChecked", &QCheckBoxWrap::setChecked),
InstanceMethod("isChecked", &QCheckBoxWrap::isChecked),
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QCheckBoxWrap)});
Napi::Function func = DefineClass(
env, CLASSNAME,
{InstanceMethod("setChecked", &QCheckBoxWrap::setChecked),
InstanceMethod("isChecked", &QCheckBoxWrap::isChecked),
QABSTRACTBUTTON_WRAPPED_METHODS_EXPORT_DEFINE(QCheckBoxWrap)});
constructor = Napi::Persistent(func);
exports.Set(CLASSNAME, func);
return exports;
@ -46,17 +45,6 @@ QCheckBoxWrap::QCheckBoxWrap(const Napi::CallbackInfo& info)
QCheckBoxWrap::~QCheckBoxWrap() { extrautils::safeDelete(this->instance); }
Napi::Value QCheckBoxWrap::setText(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Napi::String text = info[0].As<Napi::String>();
std::string label = text.Utf8Value();
this->instance->setText(label.c_str());
return env.Null();
}
Napi::Value QCheckBoxWrap::isChecked(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);

View File

@ -1,7 +1,6 @@
#include "QtWidgets/QPushButton/qpushbutton_wrap.h"
#include "Extras/Utils/nutils.h"
#include "QtGui/QIcon/qicon_wrap.h"
#include "QtWidgets/QWidget/qwidget_wrap.h"
Napi::FunctionReference QPushButtonWrap::constructor;
@ -9,12 +8,10 @@ Napi::FunctionReference QPushButtonWrap::constructor;
Napi::Object QPushButtonWrap::init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
char CLASSNAME[] = "QPushButton";
Napi::Function func =
DefineClass(env, CLASSNAME,
{InstanceMethod("setText", &QPushButtonWrap::setText),
InstanceMethod("setFlat", &QPushButtonWrap::setFlat),
InstanceMethod("setIcon", &QPushButtonWrap::setIcon),
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QPushButtonWrap)});
Napi::Function func = DefineClass(
env, CLASSNAME,
{InstanceMethod("setFlat", &QPushButtonWrap::setFlat),
QABSTRACTBUTTON_WRAPPED_METHODS_EXPORT_DEFINE(QPushButtonWrap)});
constructor = Napi::Persistent(func);
exports.Set(CLASSNAME, func);
return exports;
@ -45,16 +42,6 @@ QPushButtonWrap::QPushButtonWrap(const Napi::CallbackInfo& info)
QPushButtonWrap::~QPushButtonWrap() { extrautils::safeDelete(this->instance); }
Napi::Value QPushButtonWrap::setText(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Napi::String napiText = info[0].As<Napi::String>();
std::string text = napiText.Utf8Value();
this->instance->setText(text.c_str());
return env.Null();
}
Napi::Value QPushButtonWrap::setFlat(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
@ -63,13 +50,3 @@ Napi::Value QPushButtonWrap::setFlat(const Napi::CallbackInfo& info) {
this->instance->setFlat(isFlat.Value());
return env.Null();
}
Napi::Value QPushButtonWrap::setIcon(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Napi::Object iconObject = info[0].As<Napi::Object>();
QIconWrap* iconWrap = Napi::ObjectWrap<QIconWrap>::Unwrap(iconObject);
this->instance->setIcon(*iconWrap->getInternalInstance());
return env.Null();
}

View File

@ -11,10 +11,9 @@ Napi::FunctionReference QRadioButtonWrap::constructor;
Napi::Object QRadioButtonWrap::init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
char CLASSNAME[] = "QRadioButton";
Napi::Function func =
DefineClass(env, CLASSNAME,
{InstanceMethod("setText", &QRadioButtonWrap::setText),
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QRadioButtonWrap)});
Napi::Function func = DefineClass(
env, CLASSNAME,
{QABSTRACTBUTTON_WRAPPED_METHODS_EXPORT_DEFINE(QRadioButtonWrap)});
constructor = Napi::Persistent(func);
exports.Set(CLASSNAME, func);
return exports;
@ -46,13 +45,3 @@ QRadioButtonWrap::QRadioButtonWrap(const Napi::CallbackInfo& info)
QRadioButtonWrap::~QRadioButtonWrap() {
extrautils::safeDelete(this->instance);
}
Napi::Value QRadioButtonWrap::setText(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Napi::String napiText = info[0].As<Napi::String>();
std::string text = napiText.Utf8Value();
this->instance->setText(text.c_str());
return env.Null();
}

View File

@ -1,6 +1,8 @@
import addon from '../utils/addon';
import { Component, NativeElement } from '../core/Component';
import { QPixmap } from './QPixmap';
import { QVariant } from '../QtCore/QVariant';
import { checkIfNativeElement } from '../utils/helpers';
export enum QIconMode {
Normal,
@ -21,6 +23,8 @@ export class QIcon extends Component {
if (typeof arg === 'string') {
const imageUrl = arg;
this.native = new addon.QIcon(imageUrl);
} else if (checkIfNativeElement(arg)) {
this.native = arg as NativeElement;
} else {
this.native = new addon.QIcon();
}
@ -42,4 +46,10 @@ export class QIcon extends Component {
setIsMask(isMask: boolean): void {
this.native.setIsMask(isMask);
}
cacheKey(): number {
return this.native.cacheKey();
}
static fromQVariant(variant: QVariant): QIcon {
return addon.QIcon.fromQVariant(variant.native);
}
}

View File

@ -0,0 +1,26 @@
import { QIcon } from '../QIcon';
import path from 'path';
import { QVariant } from '../../QtCore/QVariant';
const testImagePath = path.resolve(__dirname, 'assets', 'nodegui.png');
describe('QIcon', () => {
it('initialize empty', () => {
const icon = new QIcon();
expect(icon).toBeTruthy();
});
it('initialize with string', () => {
const icon = new QIcon(testImagePath);
expect(icon).toBeTruthy();
});
it('returns the cache Key', () => {
const icon = new QIcon(testImagePath);
const cacheKey = icon.cacheKey();
expect(Number.isInteger(cacheKey)).toBe(true);
});
it('initialize from QVariant', () => {
const icon = new QIcon(testImagePath);
const variant = new QVariant(icon);
expect(variant).toBeTruthy();
expect(QIcon.fromQVariant(variant).cacheKey()).toBe(icon.cacheKey());
});
});

View File

@ -0,0 +1,19 @@
import { NodeWidget } from './QWidget';
import { QIcon } from '../QtGui/QIcon';
import { QSize } from '../QtCore/QSize';
export abstract class QAbstractButton extends NodeWidget {
setText(text: string): void {
this.native.setText(text);
}
setIcon(icon: QIcon): void {
this.native.setIcon(icon.native);
}
setIconSize(iconSize: QSize): void {
this.setProperty('iconSize', iconSize.native);
}
iconSize(): QSize {
const iconSize = this.property('iconSize');
return QSize.fromQVariant(iconSize);
}
}

View File

@ -2,12 +2,13 @@ import addon from '../utils/addon';
import { NodeWidget } from './QWidget';
import { BaseWidgetEvents } from '../core/EventWidget';
import { NativeElement } from '../core/Component';
import { QAbstractButton } from './QAbstractButton';
export const QCheckBoxEvents = Object.freeze({
...BaseWidgetEvents,
toggled: 'toggled',
});
export class QCheckBox extends NodeWidget {
export class QCheckBox extends QAbstractButton {
native: NativeElement;
constructor(parent?: NodeWidget) {
let native;
@ -20,16 +21,10 @@ export class QCheckBox extends NodeWidget {
this.native = native;
this.nodeParent = parent;
}
setText(text: string): void {
// react:✓ //TODO:getter
this.native.setText(text);
}
setChecked(check: boolean): void {
// react:✓
this.native.setChecked(check);
}
isChecked(): boolean {
// react:✓
return this.native.isChecked();
}
}

View File

@ -2,7 +2,7 @@ import addon from '../utils/addon';
import { NodeWidget } from './QWidget';
import { BaseWidgetEvents } from '../core/EventWidget';
import { NativeElement } from '../core/Component';
import { QIcon } from '../QtGui/QIcon';
import { QAbstractButton } from './QAbstractButton';
export const QPushButtonEvents = Object.freeze({
...BaseWidgetEvents,
@ -12,7 +12,7 @@ export const QPushButtonEvents = Object.freeze({
toggled: 'toggled',
});
export class QPushButton extends NodeWidget {
export class QPushButton extends QAbstractButton {
native: NativeElement;
constructor(parent?: NodeWidget) {
let native;
@ -25,16 +25,7 @@ export class QPushButton extends NodeWidget {
this.nodeParent = parent;
this.native = native;
}
setText(text: string | number): void {
// react:✓, //TODO:getter
this.native.setText(`${text}`);
}
setFlat(isFlat: boolean): void {
// react:✓, //TODO:getter
this.native.setFlat(isFlat);
}
setIcon(icon: QIcon): void {
// react:✓, //TODO:getter
this.native.setIcon(icon.native);
}
}

View File

@ -2,11 +2,12 @@ import addon from '../utils/addon';
import { NodeWidget } from './QWidget';
import { BaseWidgetEvents } from '../core/EventWidget';
import { NativeElement } from '../core/Component';
import { QAbstractButton } from './QAbstractButton';
export const QRadioButtonEvents = Object.freeze({
...BaseWidgetEvents,
});
export class QRadioButton extends NodeWidget {
export class QRadioButton extends QAbstractButton {
native: NativeElement;
constructor(parent?: NodeWidget) {
let native;
@ -19,8 +20,4 @@ export class QRadioButton extends NodeWidget {
this.native = native;
this.nodeParent = parent;
}
setText(text: string | number): void {
// react:✓ TODO://getter
this.native.setText(`${text}`);
}
}

View File

@ -0,0 +1,29 @@
import { QCheckBox } from '../QCheckBox';
import { QIcon } from '../../QtGui/QIcon';
import path from 'path';
describe('QCheckBox', () => {
it('instantiate a button instance', () => {
const button = new QCheckBox();
expect(button.inherits('QCheckBox')).toBe(true);
});
it('setText', () => {
const button = new QCheckBox();
button.setText('hello');
expect(button.property('text').toString()).toEqual('hello');
});
it('setIcon', () => {
const button = new QCheckBox();
const testImagePath = path.resolve(__dirname, 'assets', 'nodegui.png');
const icon = new QIcon(testImagePath);
button.setIcon(icon);
expect(QIcon.fromQVariant(button.property('icon')).cacheKey()).toEqual(icon.cacheKey());
});
it('setChecked', () => {
const button = new QCheckBox();
button.setChecked(true);
expect(button.isChecked()).toEqual(true);
button.setChecked(false);
expect(button.isChecked()).toEqual(false);
});
});

View File

@ -0,0 +1,38 @@
import { QPushButton } from '../QPushButton';
import { QIcon } from '../../QtGui/QIcon';
import path from 'path';
import { QSize } from '../../QtCore/QSize';
describe('QPushButton', () => {
it('instantiate a button instance', () => {
const button = new QPushButton();
expect(button.inherits('QPushButton')).toBe(true);
});
it('setText', () => {
const button = new QPushButton();
button.setText('hello');
expect(button.property('text').toString()).toEqual('hello');
});
it('setIcon', () => {
const button = new QPushButton();
const testImagePath = path.resolve(__dirname, 'assets', 'nodegui.png');
const icon = new QIcon(testImagePath);
button.setIcon(icon);
expect(QIcon.fromQVariant(button.property('icon')).cacheKey()).toEqual(icon.cacheKey());
});
it('setFlat', () => {
const button = new QPushButton();
button.setFlat(true);
expect(button.property('flat').toBool()).toEqual(true);
});
it('setIconSize', () => {
const button = new QPushButton();
const testImagePath = path.resolve(__dirname, 'assets', 'nodegui.png');
const icon = new QIcon(testImagePath);
button.setIcon(icon);
button.setIconSize(new QSize(111, 111));
const returnedSize = button.iconSize();
expect(returnedSize.width()).toBe(111);
expect(returnedSize.height()).toBe(111);
});
});

View File

@ -0,0 +1,22 @@
import { QRadioButton } from '../QRadioButton';
import { QIcon } from '../../QtGui/QIcon';
import path from 'path';
describe('QRadioButton', () => {
it('instantiate a button instance', () => {
const button = new QRadioButton();
expect(button.inherits('QRadioButton')).toBe(true);
});
it('setText', () => {
const button = new QRadioButton();
button.setText('hello');
expect(button.property('text').toString()).toEqual('hello');
});
it('setIcon', () => {
const button = new QRadioButton();
const testImagePath = path.resolve(__dirname, 'assets', 'nodegui.png');
const icon = new QIcon(testImagePath);
button.setIcon(icon);
expect(QIcon.fromQVariant(button.property('icon')).cacheKey()).toEqual(icon.cacheKey());
});
});

View File

@ -0,0 +1,2 @@
nodegui_save.png
nodegui_save.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB