Improving Menu Bars (#347)

* menu and menubar changes so far

* attempting to add a simpler way to create menubars

* menu and menubar changes so far

* attempting to add a simpler way to create menubars

* attempting to add a simpler way to create menubars

* rebased from master

* rebased from master

* Move qaction creation to qwidget macro

* removed addMenuWithName

* exec, and popup working

Co-authored-by: Atul R <atulanand94@gmail.com>
This commit is contained in:
gluaxspeed 2020-01-22 16:06:12 -05:00 committed by Atul R
parent 6bfc1a735c
commit 34d32a1e74
9 changed files with 191 additions and 33 deletions

View File

@ -20,5 +20,7 @@ class DLL_EXPORT QMenuWrap : public Napi::ObjectWrap<QMenuWrap> {
static Napi::FunctionReference constructor;
// wrapped methods
Napi::Value setTitle(const Napi::CallbackInfo& info);
Napi::Value addAction(const Napi::CallbackInfo& info);
Napi::Value addSeparator(const Napi::CallbackInfo& info);
Napi::Value exec(const Napi::CallbackInfo& info);
Napi::Value popup(const Napi::CallbackInfo& info);
};

View File

@ -20,5 +20,6 @@ class DLL_EXPORT QMenuBarWrap : public Napi::ObjectWrap<QMenuBarWrap> {
static Napi::FunctionReference constructor;
// wrapped methods
Napi::Value addMenu(const Napi::CallbackInfo& info);
Napi::Value addSeparator(const Napi::CallbackInfo& info);
Napi::Value setNativeMenuBar(const Napi::CallbackInfo& info);
};

View File

@ -5,6 +5,7 @@
#include "QtCore/QObject/qobject_macro.h"
#include "QtCore/QSize/qsize_wrap.h"
#include "QtGui/QIcon/qicon_wrap.h"
#include "QtWidgets/QAction/qaction_wrap.h"
#include "QtWidgets/QLayout/qlayout_wrap.h"
#include "core/YogaWidget/yogawidget_macro.h"
/*
@ -311,6 +312,15 @@
Napi::HandleScope scope(env); \
this->instance->showNormal(); \
return env.Null(); \
} \
Napi::Value addAction(const Napi::CallbackInfo& info) { \
Napi::Env env = info.Env(); \
Napi::HandleScope scope(env); \
Napi::Object actionObject = info[0].As<Napi::Object>(); \
QActionWrap* actionWrap = \
Napi::ObjectWrap<QActionWrap>::Unwrap(actionObject); \
this->instance->addAction(actionWrap->getInternalInstance()); \
return env.Null(); \
}
#endif // QWIDGET_WRAPPED_METHODS_DECLARATION
@ -360,7 +370,8 @@
InstanceMethod("showFullScreen", &WidgetWrapName::showFullScreen), \
InstanceMethod("showMaximized", &WidgetWrapName::showMaximized), \
InstanceMethod("showMinimized", &WidgetWrapName::showMinimized), \
InstanceMethod("showNormal", &WidgetWrapName::showNormal),
InstanceMethod("showNormal", &WidgetWrapName::showNormal), \
InstanceMethod("addAction", &WidgetWrapName::addAction),
#endif // QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE

View File

@ -5,6 +5,7 @@
#include <QWidget>
#include "QtCore/QPoint/qpoint_wrap.h"
#include "QtWidgets/QAction/qaction_wrap.h"
Napi::FunctionReference QMenuWrap::constructor;
@ -15,7 +16,9 @@ Napi::Object QMenuWrap::init(Napi::Env env, Napi::Object exports) {
Napi::Function func =
DefineClass(env, CLASSNAME,
{InstanceMethod("setTitle", &QMenuWrap::setTitle),
InstanceMethod("addAction", &QMenuWrap::addAction),
InstanceMethod("addSeparator", &QMenuWrap::addSeparator),
InstanceMethod("exec", &QMenuWrap::exec),
InstanceMethod("popup", &QMenuWrap::popup),
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QMenuWrap)});
constructor = Napi::Persistent(func);
exports.Set(CLASSNAME, func);
@ -57,13 +60,55 @@ Napi::Value QMenuWrap::setTitle(const Napi::CallbackInfo& info) {
return env.Null();
}
Napi::Value QMenuWrap::addAction(const Napi::CallbackInfo& info) {
Napi::Value QMenuWrap::addSeparator(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Napi::Object actionObject = info[0].As<Napi::Object>();
QActionWrap* actionWrap = Napi::ObjectWrap<QActionWrap>::Unwrap(actionObject);
this->instance->addAction(actionWrap->getInternalInstance());
// TODO: see if we need to return from here an pointer to qaction or not.
auto value =
Napi::External<QAction>::New(env, this->instance->addSeparator());
return Napi::Value::From(env, value);
}
Napi::Value QMenuWrap::exec(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
if (info.Length() == 2) {
Napi::Object pointObject = info[0].As<Napi::Object>();
QPointWrap* pointWrap = Napi::ObjectWrap<QPointWrap>::Unwrap(pointObject);
QPoint* qpoint = pointWrap->getInternalInstance();
Napi::Object actionObject = info[1].As<Napi::Object>();
QActionWrap* actionWrap =
Napi::ObjectWrap<QActionWrap>::Unwrap(actionObject);
this->instance->exec(*qpoint, actionWrap->getInternalInstance());
} else if (info.Length() == 0) {
this->instance->exec();
} else {
Napi::TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
}
return env.Null();
}
Napi::Value QMenuWrap::popup(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Napi::Object pointObject = info[0].As<Napi::Object>();
QPointWrap* pointWrap = Napi::ObjectWrap<QPointWrap>::Unwrap(pointObject);
QPoint* qpoint = pointWrap->getInternalInstance();
Napi::Object actionObject = info[1].As<Napi::Object>();
QAction* action = nullptr;
if (!actionObject.IsUndefined() && !actionObject.IsNull()) {
QActionWrap* actionWrap =
Napi::ObjectWrap<QActionWrap>::Unwrap(actionObject);
action = actionWrap->getInternalInstance();
}
this->instance->popup(*qpoint, action);
return env.Null();
}

View File

@ -5,6 +5,7 @@
#include <QWidget>
#include "QtWidgets/QAction/qaction_wrap.h"
#include "QtWidgets/QMenu/qmenu_wrap.h"
Napi::FunctionReference QMenuBarWrap::constructor;
@ -15,6 +16,7 @@ Napi::Object QMenuBarWrap::init(Napi::Env env, Napi::Object exports) {
Napi::Function func = DefineClass(
env, CLASSNAME,
{InstanceMethod("addMenu", &QMenuBarWrap::addMenu),
InstanceMethod("addSeparator", &QMenuBarWrap::addSeparator),
InstanceMethod("setNativeMenuBar", &QMenuBarWrap::setNativeMenuBar),
QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QMenuBarWrap)});
constructor = Napi::Persistent(func);
@ -57,11 +59,21 @@ Napi::Value QMenuBarWrap::addMenu(const Napi::CallbackInfo& info) {
Napi::Object menuObject = info[0].As<Napi::Object>();
QMenuWrap* menuWrap = Napi::ObjectWrap<QMenuWrap>::Unwrap(menuObject);
this->instance->addMenu(menuWrap->getInternalInstance());
return env.Null();
}
Napi::Value QMenuBarWrap::addSeparator(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
auto value =
Napi::External<QAction>::New(env, this->instance->addSeparator());
return Napi::Value::From(env, value);
}
Napi::Value QMenuBarWrap::setNativeMenuBar(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);

View File

@ -1,8 +1,16 @@
import { QWidget, QMainWindow, FlexLayout, QTreeWidget, QTreeWidgetItem } from './index';
import { ItemFlag, CheckState } from './lib/QtEnums';
import { QSpinBox } from './lib/QtWidgets/QSpinBox';
import { QLineEdit } from './lib/QtWidgets/QLineEdit';
import { QStatusBar } from './lib/QtWidgets/QStatusBar';
import {
QWidget,
QMainWindow,
FlexLayout,
QTreeWidget,
QMenuBar,
QApplication,
QMenu,
QCursor,
QPushButton,
} from './index';
import { QPoint } from './lib/QtCore/QPoint';
import { QAction } from './lib/QtWidgets/QAction';
const win = new QMainWindow();
const center = new QWidget();
@ -10,21 +18,64 @@ const layout = new FlexLayout();
center.setLayout(layout);
win.setCentralWidget(center);
const statusBar = new QStatusBar();
const spinBox = new QSpinBox();
statusBar.addPermanentWidget(spinBox);
statusBar.addEventListener('messageChanged', message => console.log(`Status bar message changed to: ${message}`));
const tree = new QTreeWidget();
tree.hide();
tree.setColumnCount(2);
tree.setHeaderLabels(['Properties', 'Value']);
center.layout?.addWidget(tree);
const menubar = new QMenuBar();
win.setMenuBar(menubar);
const fm = menubar.addMenu('&File');
const qaction = fm.addAction('&Quit');
fm.addSeparator();
const showTree = fm.addAction('&ShowTree');
const hideTree = fm.addAction('&HideTree');
const menu = new QMenu();
const sh = menu.addAction('SayHello');
// Button row
const buttonRow = new QWidget();
const buttonRowLayout = new FlexLayout();
buttonRow.setLayout(buttonRowLayout);
buttonRow.setObjectName('buttonRow');
// Buttons
const button = new QPushButton();
button.setText('click me');
button.setObjectName('clickme');
buttonRowLayout.addWidget(button);
layout.addWidget(buttonRow);
qaction.addEventListener('triggered', () => {
const app = QApplication.instance();
app.exit(0);
});
showTree.addEventListener('triggered', () => {
tree.show();
});
hideTree.addEventListener('triggered', () => {
tree.hide();
});
button.addEventListener('clicked', () => {
const { x, y } = new QCursor().pos();
menu.exec(new QPoint(x, y), new QAction());
});
sh.addEventListener('triggered', () => {
console.log('Hello!');
});
menubar.addSeparator();
menubar.addMenu('Hello');
win.setStatusBar(statusBar);
win.show();
statusBar.showMessage('Hello World', 3000);
setTimeout(_ => {
statusBar.removeWidget(spinBox);
statusBar.showMessage('Removed spinBox');
}, 3000);
(global as any).win = win;
setInterval(() => null, 1000);

View File

@ -2,6 +2,7 @@ import { NativeElement } from '../core/Component';
import { NodeWidget, QWidgetSignals } from './QWidget';
import addon from '../utils/addon';
import { QAction } from './QAction';
import { QPoint } from '../QtCore/QPoint';
/**
@ -19,7 +20,6 @@ const menu = new QMenu();
*/
export class QMenu extends NodeWidget<QMenuSignals> {
native: NativeElement;
actions: Set<QAction>;
constructor();
constructor(parent: NodeWidget<any>);
constructor(parent?: NodeWidget<any>) {
@ -32,15 +32,23 @@ export class QMenu extends NodeWidget<QMenuSignals> {
super(native);
this.native = native;
this.setNodeParent(parent);
this.actions = new Set();
}
setTitle(title: string): void {
this.native.setTitle(title);
}
addAction(action: QAction): QAction {
this.native.addAction(action.native);
this.actions.add(action);
return action;
addSeparator(): QAction {
return this.native.addSeparator();
}
exec(point?: QPoint, action?: QAction): void {
if (point && action) {
this.native.exec(point.native, action.native);
return;
}
this.native.exec();
}
popup(point: QPoint, action?: QAction): void {
this.native.popup(point.native, action?.native);
}
}

View File

@ -3,6 +3,7 @@ import { NativeElement } from '../core/Component';
import { NodeWidget, QWidgetSignals } from './QWidget';
import addon from '../utils/addon';
import { checkIfNativeElement } from '../utils/helpers';
import { QAction } from './QAction';
/**
@ -24,6 +25,7 @@ global.win = win;
*/
export class QMenuBar extends NodeWidget<QMenuBarSignals> {
native: NativeElement;
_menus: Set<QMenu>;
constructor();
constructor(parent: NodeWidget<any>);
constructor(native: NativeElement);
@ -40,11 +42,23 @@ export class QMenuBar extends NodeWidget<QMenuBarSignals> {
}
super(native);
this.native = native;
this._menus = new Set<QMenu>();
this.setNodeParent(parent);
}
addMenu(menu: QMenu): void {
addMenu(menu: QMenu | string): QMenu {
if (typeof menu === 'string') {
const qmenu = new QMenu();
qmenu.setTitle(menu);
this.native.addMenu(qmenu.native);
this._menus.add(qmenu);
return qmenu;
}
this.native.addMenu(menu.native);
this._menus.add(menu);
return menu;
}
addSeparator(): QAction {
return this.native.addSeparator();
}
setNativeMenuBar(nativeMenuBar: boolean): void {
this.native.setNativeMenuBar(nativeMenuBar);

View File

@ -13,6 +13,7 @@ import { QSize } from '../QtCore/QSize';
import { QRect } from '../QtCore/QRect';
import { QObjectSignals } from '../QtCore/QObject';
import { QFont } from '../QtGui/QFont';
import { QAction } from './QAction';
/**
@ -49,6 +50,7 @@ Implement all native QWidget methods here so that all widgets get access to thos
*/
export abstract class NodeWidget<Signals extends QWidgetSignals> extends YogaWidget<Signals> {
layout?: NodeLayout<Signals>;
actions = new Set<QAction>();
_rawInlineStyle = '';
type = 'widget';
show(): void {
@ -212,6 +214,18 @@ export abstract class NodeWidget<Signals extends QWidgetSignals> extends YogaWid
font(): QFont {
return QFont.fromQVariant(this.property('font'));
}
addAction(action: QAction | string): QAction {
if (typeof action === 'string') {
const qaction = new QAction();
qaction.setText(action);
this.native.addAction(qaction.native);
this.actions.add(qaction);
return qaction;
}
this.native.addAction(action.native);
this.actions.add(action);
return action;
}
}
export interface QWidgetSignals extends QObjectSignals {