split project with app & doric module

This commit is contained in:
王劲鹏
2021-04-29 20:12:49 +08:00
committed by osborn
parent 25db4cc194
commit a5e00e4fa5
154 changed files with 795 additions and 293 deletions

View File

@@ -0,0 +1,126 @@
#include "DoricContext.h"
#include "DoricContextManager.h"
#include "DoricNativeDriver.h"
#include "shader/DoricRootNode.h"
#include "utils/DoricConstant.h"
#include "utils/DoricContextHolder.h"
DoricContext::DoricContext(QString contextId, QString source, QString extra) {
this->mRootNode = new DoricRootNode();
this->mRootNode->setContext(this);
this->mContextId = contextId;
this->source = source;
this->extra = extra;
}
DoricContext::~DoricContext() {
QVariantList args;
callEntity(DoricConstant::DORIC_ENTITY_DESTROY, args);
DoricContextManager::getInstance()->destroyContext(this);
}
DoricContext *DoricContext::create(QString script, QString source,
QString extra) {
DoricContext *context =
DoricContextManager::getInstance()->createContext(script, source, extra);
context->script = script;
context->init(extra);
QVariantList args;
context->callEntity(DoricConstant::DORIC_ENTITY_CREATE, args);
return context;
}
void DoricContext::init(QString initData) {
this->extra = initData;
if (!initData.isEmpty()) {
QVariantList args;
args.push_back(initData);
callEntity(DoricConstant::DORIC_ENTITY_INIT, args);
}
}
void DoricContext::build(int width, int height) {
QMap<QString, QVariant> map;
map.insert("width", QVariant(width));
map.insert("height", QVariant(height));
QVariant jsValue(map);
this->initParams = jsValue;
QVariantList args;
args.push_back(this->initParams);
callEntity(DoricConstant::DORIC_ENTITY_BUILD, args);
}
void DoricContext::callEntity(QString methodName, QVariantList args) {
return getDriver()->invokeContextEntityMethod(this->mContextId, methodName,
args);
}
DoricInterfaceDriver *DoricContext::getDriver() {
if (driver == NULL) {
driver = DoricNativeDriver::getInstance();
return driver;
}
return driver;
}
DoricRootNode *DoricContext::getRootNode() { return mRootNode; }
QObject *DoricContext::obtainPlugin(QString name) {
if (mPluginMap.keys().contains(name)) {
return mPluginMap.value(name);
} else {
QObject *plugin = getDriver()->getRegistry()->plugins.createObject(name);
dynamic_cast<DoricContextHolder *>(plugin)->setContext(this);
mPluginMap.insert(name, plugin);
return plugin;
}
}
void DoricContext::setQmlEngine(QQmlEngine *engine) { mQmlEngine = engine; }
QQmlEngine *DoricContext::getQmlEngine() { return mQmlEngine; }
DoricViewNode *DoricContext::targetViewNode(QString id) {
if (id == mRootNode->getId()) {
return mRootNode;
}
return nullptr;
}
QString DoricContext::getContextId() { return mContextId; }
QList<DoricViewNode *> DoricContext::allHeadNodes(QString type) {
return mHeadNodes[type].values();
}
void DoricContext::addHeadNode(QString type, DoricViewNode *viewNode) {
if (mHeadNodes.contains(type)) {
QMap<QString, DoricViewNode *> map = mHeadNodes[type];
map.insert(viewNode->getId(), viewNode);
mHeadNodes.insert(type, map);
} else {
QMap<QString, DoricViewNode *> map;
map.insert(viewNode->getId(), viewNode);
mHeadNodes.insert(type, map);
}
}
void DoricContext::removeHeadNode(QString type, DoricViewNode *viewNode) {
if (mHeadNodes.contains(type)) {
QMap<QString, DoricViewNode *> map = mHeadNodes[type];
map.remove(viewNode->getId());
mHeadNodes.insert(type, map);
}
}
void DoricContext::clearHeadNodes(QString type) {
if (mHeadNodes.contains(type)) {
QMap<QString, DoricViewNode *> map = mHeadNodes[type];
map.clear();
mHeadNodes.insert(type, map);
}
}

View File

@@ -0,0 +1,62 @@
#ifndef CONTEXT_H
#define CONTEXT_H
#include <QQmlEngine>
#include <QVariant>
#include "DoricInterfaceDriver.h"
class DoricViewNode;
class DoricRootNode;
class DoricContext {
private:
QString mContextId;
QMap<QString, QObject *> mPluginMap;
DoricRootNode *mRootNode;
QString source;
QString script;
QString extra;
QVariant initParams;
DoricInterfaceDriver *driver = NULL;
QQmlEngine *mQmlEngine;
QMap<QString, QMap<QString, DoricViewNode *>> mHeadNodes;
public:
DoricContext(QString contextId, QString source, QString extra);
~DoricContext();
static DoricContext *create(QString script, QString source, QString extra);
void init(QString initData);
void build(int width, int height);
void callEntity(QString methodName, QVariantList args);
DoricInterfaceDriver *getDriver();
DoricRootNode *getRootNode();
QObject *obtainPlugin(QString name);
void setQmlEngine(QQmlEngine *engine);
QQmlEngine *getQmlEngine();
DoricViewNode *targetViewNode(QString id);
QString getContextId();
QList<DoricViewNode *> allHeadNodes(QString type);
void addHeadNode(QString type, DoricViewNode *viewNode);
void removeHeadNode(QString type, DoricViewNode *viewNode);
void clearHeadNodes(QString type);
};
#endif // CONTEXT_H

View File

@@ -0,0 +1,21 @@
#include "DoricContextManager.h"
DoricContext *DoricContextManager::createContext(QString script, QString source,
QString extra) {
int contextId = counter->fetchAndAddOrdered(1);
DoricContext *context =
new DoricContext(QString::number(contextId), source, extra);
contextMap->insert(QString::number(contextId), context);
context->getDriver()->createContext(QString::number(contextId), script,
source);
return context;
}
DoricContext *DoricContextManager::getContext(QString contextId) {
return contextMap->value(contextId);
}
void DoricContextManager::destroyContext(DoricContext *context) {
context->getDriver()->destroyContext(context->getContextId());
contextMap->remove(context->getContextId());
}

View File

@@ -0,0 +1,32 @@
#ifndef CONTEXTMANAGER_H
#define CONTEXTMANAGER_H
#include <QDebug>
#include "DoricContext.h"
class DoricContextManager {
private:
static DoricContextManager *local_instance;
DoricContextManager() {}
~DoricContextManager() {}
QAtomicInt *counter = new QAtomicInt();
QMap<QString, DoricContext *> *contextMap =
new QMap<QString, DoricContext *>();
public:
static DoricContextManager *getInstance() {
static DoricContextManager instance;
return &instance;
}
DoricContext *createContext(QString script, QString source, QString extra);
DoricContext *getContext(QString contextId);
void destroyContext(DoricContext *context);
};
#endif // CONTEXTMANAGER_H

View File

@@ -0,0 +1,30 @@
#ifndef INTERFACEDRIVER_H
#define INTERFACEDRIVER_H
#include <QRunnable>
#include <QString>
#include <QVariant>
#include "DoricRegistry.h"
#include "async/DoricAsyncResult.h"
#include "utils/DoricThreadMode.h"
class DoricInterfaceDriver {
public:
virtual void invokeContextEntityMethod(QString contextId, QString method,
QVariantList args) = 0;
virtual void invokeDoricMethod(QString method, QVariantList args) = 0;
virtual DoricAsyncResult *asyncCall(std::function<void()> lambda,
DoricThreadMode mode) = 0;
virtual void createContext(QString contextId, QString script,
QString source) = 0;
virtual void destroyContext(QString contextId) = 0;
virtual DoricRegistry *getRegistry() = 0;
};
#endif // INTERFACEDRIVER_H

View File

@@ -0,0 +1,50 @@
#include <functional>
#include "DoricNativeDriver.h"
#include "async/DoricAsyncCall.h"
#include "utils/DoricConstant.h"
void DoricNativeDriver::invokeContextEntityMethod(QString contextId,
QString method,
QVariantList args) {
args.insert(0, QVariant(contextId));
args.insert(1, QVariant(method));
invokeDoricMethod(DoricConstant::DORIC_CONTEXT_INVOKE, args);
}
void DoricNativeDriver::invokeDoricMethod(QString method, QVariantList args) {
return DoricAsyncCall::ensureRunInThreadPool(
&jsEngine.mJSThreadPool,
[this, method, args] { this->jsEngine.invokeDoricMethod(method, args); });
}
DoricAsyncResult *DoricNativeDriver::asyncCall(std::function<void()> lambda,
DoricThreadMode mode) {
switch (mode) {
case UI:
DoricAsyncCall::ensureRunInMain(lambda);
break;
case JS:
DoricAsyncCall::ensureRunInThreadPool(&jsEngine.mJSThreadPool, lambda);
break;
}
return NULL;
}
void DoricNativeDriver::createContext(QString contextId, QString script,
QString source) {
DoricAsyncCall::ensureRunInThreadPool(
&jsEngine.mJSThreadPool, [this, contextId, script, source] {
this->jsEngine.prepareContext(contextId, script, source);
});
}
void DoricNativeDriver::destroyContext(QString contextId) {
DoricAsyncCall::ensureRunInThreadPool(
&jsEngine.mJSThreadPool,
[this, contextId] { this->jsEngine.destroyContext(contextId); });
}
DoricRegistry *DoricNativeDriver::getRegistry() {
return this->jsEngine.getRegistry();
}

View File

@@ -0,0 +1,39 @@
#ifndef NATIVEDRIVER_H
#define NATIVEDRIVER_H
#include <QDebug>
#include "DoricInterfaceDriver.h"
#include "engine/DoricJSEngine.h"
class DoricNativeDriver : public DoricInterfaceDriver {
private:
static DoricNativeDriver *local_instance;
DoricNativeDriver() {}
~DoricNativeDriver() {}
DoricJSEngine jsEngine;
public:
static DoricNativeDriver *getInstance() {
static DoricNativeDriver instance;
return &instance;
}
void invokeContextEntityMethod(QString contextId, QString method,
QVariantList args) override;
void invokeDoricMethod(QString method, QVariantList args) override;
DoricAsyncResult *asyncCall(std::function<void()> lambda,
DoricThreadMode mode) override;
void createContext(QString contextId, QString script,
QString source) override;
void destroyContext(QString contextId) override;
DoricRegistry *getRegistry() override;
};
#endif // NATIVEDRIVER_H

View File

@@ -0,0 +1,23 @@
#include "DoricPanel.h"
#include "shader/DoricRootNode.h"
DoricPanel::DoricPanel(QQmlEngine *qmlEngine, QQuickItem *quickItem) {
mQmlEngine = qmlEngine;
mQuickItem = quickItem;
}
DoricPanel::~DoricPanel() {
delete mContext;
}
void DoricPanel::config(QString script, QString alias, QString extra) {
DoricContext *context = DoricContext::create(script, alias, extra);
config(context);
}
void DoricPanel::config(DoricContext *context) {
this->mContext = context;
this->mContext->setQmlEngine(mQmlEngine);
this->mContext->getRootNode()->setRootView(mQuickItem);
this->mContext->build(mQuickItem->width(), mQuickItem->height());
}

View File

@@ -0,0 +1,27 @@
#ifndef PANEL_H
#define PANEL_H
#include <QQuickItem>
#include "DoricContext.h"
class DoricPanel {
private:
DoricContext *mContext;
int renderedWidth = -1;
int renderedHeight = -1;
QQmlEngine *mQmlEngine;
QQuickItem *mQuickItem;
public:
DoricPanel(QQmlEngine *qmlEngine, QQuickItem *quickItem);
~DoricPanel();
void config(QString script, QString alias, QString extra);
void config(DoricContext *context);
};
#endif // PANEL_H

View File

@@ -0,0 +1,37 @@
#include "DoricRegistry.h"
#include "plugin/DoricModalPlugin.h"
#include "plugin/DoricNetworkPlugin.h"
#include "plugin/DoricPopoverPlugin.h"
#include "plugin/DoricShaderPlugin.h"
#include "shader/DoricHLayoutNode.h"
#include "shader/DoricImageNode.h"
#include "shader/DoricRootNode.h"
#include "shader/DoricScrollerNode.h"
#include "shader/DoricStackNode.h"
#include "shader/DoricTextNode.h"
#include "shader/DoricVLayoutNode.h"
DoricRegistry::DoricRegistry() {
registerNativePlugin<DoricShaderPlugin>("shader");
registerNativePlugin<DoricModalPlugin>("modal");
registerNativePlugin<DoricPopoverPlugin>("popover");
registerNativePlugin<DoricNetworkPlugin>("network");
registerViewNode<DoricRootNode>("Root");
registerViewNode<DoricStackNode>("Stack");
registerViewNode<DoricVLayoutNode>("VLayout");
registerViewNode<DoricHLayoutNode>("HLayout");
registerViewNode<DoricTextNode>("Text");
registerViewNode<DoricScrollerNode>("Scroller");
registerViewNode<DoricImageNode>("Image");
}
bool DoricRegistry::acquirePluginInfo(QString name) {
return plugins.acquireClass(name);
}
bool DoricRegistry::acquireNodeInfo(QString name) {
return nodes.acquireClass(name);
}

View File

@@ -0,0 +1,28 @@
#ifndef REGISTRY_H
#define REGISTRY_H
#include <QString>
#include "utils/DoricObjectFactory.h"
class DoricRegistry {
public:
DoricObjectFactory plugins;
DoricObjectFactory nodes;
DoricRegistry();
template <typename T> void registerNativePlugin(QString name) {
plugins.registerClass<T>(name);
}
template <typename T> void registerViewNode(QString name) {
nodes.registerClass<T>(name);
}
bool acquirePluginInfo(QString name);
bool acquireNodeInfo(QString name);
};
#endif // REGISTRY_H

View File

@@ -0,0 +1,26 @@
#ifndef ASYNC_CALL_H
#define ASYNC_CALL_H
#include <QFuture>
#include <QThreadPool>
#include <QtConcurrent/QtConcurrent>
class DoricAsyncCall {
public:
static void ensureRunInThreadPool(QThreadPool *threadPool,
std::function<void()> lambda) {
QFuture<std::function<void()>::result_type> future =
QtConcurrent::run(threadPool, lambda);
}
template <typename Function>
static void ensureRunInMain(Function &&function,
QThread *thread = qApp->thread()) {
auto *obj = QAbstractEventDispatcher::instance(thread);
Q_ASSERT(obj);
QMetaObject::invokeMethod(obj, std::forward<Function>(function));
}
};
#endif // ASYNC_CALL_H

View File

@@ -0,0 +1,38 @@
#include "DoricAsyncResult.h"
DoricAsyncResult::DoricAsyncResult() {}
DoricAsyncResult::DoricAsyncResult(QJSValue result) { this->result = result; }
void DoricAsyncResult::setResult(QJSValue result) {
this->result = result;
if (this->callback != NULL) {
this->callback->onResult(result);
this->callback->onFinish();
}
}
void DoricAsyncResult::setError(QJSValue exception) {
this->result = exception;
if (this->callback != NULL) {
this->callback->onResult(result);
this->callback->onFinish();
}
}
bool DoricAsyncResult::hasResult() { return !result.equals(EMPTY); }
QJSValue DoricAsyncResult::getResult() { return this->result; }
void DoricAsyncResult::setCallback(DoricCallback *callback) {
this->callback = callback;
if (this->result.isError()) {
this->callback->onError(result);
this->callback->onFinish();
} else if (!result.equals(EMPTY)) {
this->callback->onResult(result);
this->callback->onFinish();
}
}
DoricSettableFuture *DoricAsyncResult::synchronous() { return NULL; }

View File

@@ -0,0 +1,34 @@
#ifndef ASYNCRESULT_H
#define ASYNCRESULT_H
#include <QJSValue>
#include "DoricCallback.h"
#include "DoricSettableFuture.h"
static QJSValue EMPTY(QJSValue::NullValue);
class DoricAsyncResult {
private:
QJSValue result = EMPTY;
DoricCallback *callback;
public:
DoricAsyncResult();
DoricAsyncResult(QJSValue result);
void setResult(QJSValue result);
void setError(QJSValue exception);
bool hasResult();
QJSValue getResult();
void setCallback(DoricCallback *callback);
DoricSettableFuture *synchronous();
};
#endif // ASYNCRESULT_H

View File

@@ -0,0 +1,15 @@
#ifndef CALLBACK_H
#define CALLBACK_H
#include <QJSValue>
class DoricCallback {
public:
virtual void onResult(QJSValue result) = 0;
virtual void onError(QJSValue error) = 0;
virtual void onFinish() = 0;
};
#endif // CALLBACK_H

View File

@@ -0,0 +1,17 @@
#include <QDebug>
#include "DoricSettableFuture.h"
void DoricSettableFuture::set(QJSValue result) {
if (mReadyLatch == NULL) {
qDebug() << "Result has already been set!";
return;
}
mResult = result;
delete mReadyLatch;
}
QJSValue DoricSettableFuture::get() {
mReadyLatch->lock();
return mResult;
}

View File

@@ -0,0 +1,19 @@
#ifndef SETTABLE_FUTURE_H
#define SETTABLE_FUTURE_H
#include <QJSValue>
#include "utils/DoricCountDownLatch.h"
class DoricSettableFuture {
private:
QJSValue mResult;
DoricCountDownLatch *mReadyLatch = new DoricCountDownLatch();
public:
void set(QJSValue result);
QJSValue get();
};
#endif // SETTABLE_FUTURE_H

View File

@@ -0,0 +1,193 @@
QT += quick
CONFIG += c++14
TEMPLATE = lib
CONFIG += staticlib
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
DEFINES += V8_COMPRESS_POINTERS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
DoricContext.cpp \
DoricContextManager.cpp \
DoricNativeDriver.cpp \
DoricPanel.cpp \
DoricRegistry.cpp \
async/DoricAsyncResult.cpp \
async/DoricSettableFuture.cpp \
engine/DoricBridgeExtension.cpp \
engine/DoricJSEngine.cpp \
engine/DoricNativeEmpty.cpp \
engine/DoricNativeJSE.cpp \
engine/DoricNativeLog.cpp \
engine/DoricNativeRequire.cpp \
engine/DoricTimerExtension.cpp \
engine/native/NativeExecutor.cpp \
engine/v8/JSValueHelper.cpp \
engine/v8/V8Executor.cpp \
plugin/DoricModalPlugin.cpp \
plugin/DoricNetworkPlugin.cpp \
plugin/DoricPopoverPlugin.cpp \
plugin/DoricShaderPlugin.cpp \
shader/DoricGroupNode.cpp \
shader/DoricHLayoutNode.cpp \
shader/DoricImageNode.cpp \
shader/DoricRootNode.cpp \
shader/DoricScrollerNode.cpp \
shader/DoricStackNode.cpp \
shader/DoricSuperNode.cpp \
shader/DoricTextNode.cpp \
shader/DoricVLayoutNode.cpp \
shader/DoricViewNode.cpp \
utils/DoricConstant.cpp \
utils/DoricContextHolder.cpp \
utils/DoricDialogBridge.cpp \
utils/DoricImageBridge.cpp \
utils/DoricLayouts.cpp \
utils/DoricMouseAreaBridge.cpp \
widget/flex/FlexLayout.cpp \
widget/flex/FlexLayoutConfig.cpp \
widget/flex/FlexLayoutService.cpp \
yoga/Utils.cpp \
yoga/YGConfig.cpp \
yoga/YGEnums.cpp \
yoga/YGLayout.cpp \
yoga/YGNode.cpp \
yoga/YGNodePrint.cpp \
yoga/YGStyle.cpp \
yoga/YGValue.cpp \
yoga/Yoga.cpp \
yoga/event/event.cpp \
yoga/internal/experiments.cpp \
yoga/log.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
DoricContext.h \
DoricContextManager.h \
DoricInterfaceDriver.h \
DoricNativeDriver.h \
DoricPanel.h \
DoricRegistry.h \
async/DoricAsyncCall.h \
async/DoricAsyncResult.h \
async/DoricCallback.h \
async/DoricSettableFuture.h \
engine/DoricBridgeExtension.h \
engine/DoricInterfaceJSE.h \
engine/DoricJSEngine.h \
engine/DoricNativeEmpty.h \
engine/DoricNativeJSE.h \
engine/DoricNativeLog.h \
engine/DoricNativeRequire.h \
engine/DoricPromise.h \
engine/DoricTimerExtension.h \
engine/native/NativeExecutor.h \
engine/v8/JSValueHelper.h \
engine/v8/V8Executor.h \
plugin/DoricModalPlugin.h \
plugin/DoricNativePlugin.h \
plugin/DoricNetworkPlugin.h \
plugin/DoricPopoverPlugin.h \
plugin/DoricShaderPlugin.h \
shader/DoricGroupNode.h \
shader/DoricHLayoutNode.h \
shader/DoricImageNode.h \
shader/DoricRootNode.h \
shader/DoricScrollerNode.h \
shader/DoricStackNode.h \
shader/DoricSuperNode.h \
shader/DoricTextNode.h \
shader/DoricVLayoutNode.h \
shader/DoricViewNode.h \
template/DoricSingleton.h \
utils/DoricConstant.h \
utils/DoricContextHolder.h \
utils/DoricCountDownLatch.h \
utils/DoricDialogBridge.h \
utils/DoricImageBridge.h \
utils/DoricLayouts.h \
utils/DoricMouseAreaBridge.h \
utils/DoricNetworkService.h \
utils/DoricObjectFactory.h \
utils/DoricThreadMode.h \
utils/DoricUtils.h \
widget/flex/FlexLayout.h \
widget/flex/FlexLayoutConfig.h \
widget/flex/FlexLayoutService.h \
yoga/BitUtils.h \
yoga/CompactValue.h \
yoga/Utils.h \
yoga/YGConfig.h \
yoga/YGEnums.h \
yoga/YGFloatOptional.h \
yoga/YGLayout.h \
yoga/YGMacros.h \
yoga/YGNode.h \
yoga/YGNodePrint.h \
yoga/YGStyle.h \
yoga/YGValue.h \
yoga/Yoga-internal.h \
yoga/Yoga.h \
yoga/event/event.h \
yoga/internal/experiments-inl.h \
yoga/internal/experiments.h \
yoga/log.h
win32:CONFIG(debug, debug|release): {
QMAKE_CFLAGS_DEBUG += -MT
QMAKE_CXXFLAGS_DEBUG += -MT
LIBS += -lwinmm
LIBS += -lAdvapi32
LIBS += -lDbghelp
INCLUDEPATH += $$PWD/../../v8/v8/win32/include
LIBS += -L$$PWD/../../v8/v8/win32/release/
LIBS += -lv8_monolith
}
else:win32:CONFIG(release, debug|release): {
QMAKE_CFLAGS_RELEASE += -MT
QMAKE_CXXFLAGS_RELEASE += -MT
LIBS += -lwinmm
LIBS += -lAdvapi32
LIBS += -lDbghelp
INCLUDEPATH += $$PWD/../../v8/v8/win32/include
LIBS += -L$$PWD/../../v8/v8/win32/release/
LIBS += -lv8_monolith
}
else:unix: {
QMAKE_CFLAGS_RELEASE += -MT
QMAKE_CXXFLAGS_RELEASE += -MT
INCLUDEPATH += $$PWD/../../v8/v8/darwin/include
LIBS += -L$$PWD/../../v8/v8/darwin/release/
LIBS += -lv8_monolith
}

View File

@@ -0,0 +1,317 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.14.2, 2021-04-29T17:00:52. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{a49b4abd-08cf-4556-b46e-b0f44132419f}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.Questionable</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">4</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.15.2 clang 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.15.2 clang 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5152.clang_64_kit</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_5_15_2_clang_64bit-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_5_15_2_clang_64bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="int" key="RunSystemFunction">0</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_5_15_2_clang_64bit-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_5_15_2_clang_64bit-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="int" key="QtQuickCompiler">0</value>
<value type="int" key="RunSystemFunction">0</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_5_15_2_clang_64bit-Profile</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_5_15_2_clang_64bit-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="int" key="QtQuickCompiler">0</value>
<value type="int" key="RunSystemFunction">0</value>
<value type="int" key="SeparateDebugInfo">0</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
<value type="QString">cpu-cycles</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
<value type="int" key="Analyzer.Perf.Frequency">250</value>
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
<value type="QString">-e</value>
<value type="QString">cpu-cycles</value>
<value type="QString">--call-graph</value>
<value type="QString">dwarf,4096</value>
<value type="QString">-F</value>
<value type="QString">250</value>
</valuelist>
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@@ -0,0 +1,34 @@
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMetaObject>
#include "../DoricContextManager.h"
#include "DoricBridgeExtension.h"
DoricBridgeExtension::DoricBridgeExtension(QObject *parent) : QObject(parent) {}
void DoricBridgeExtension::callNative(QString contextId, QString module,
QString methodName, QString callbackId,
QString argument) {
qDebug() << "contextId: " + contextId << "module: " + module
<< "methodName: " + methodName << "callbackId: " + callbackId
<< "jsValue: " + argument;
DoricContext *context =
DoricContextManager::getInstance()->getContext(contextId);
if (context == nullptr) {
qCritical() << "cannot find context: " + contextId;
return;
}
bool classRegistered =
context->getDriver()->getRegistry()->acquirePluginInfo(module);
if (classRegistered) {
QObject *plugin = context->obtainPlugin(module);
QMetaObject::invokeMethod(plugin, methodName.toUtf8(), Qt::DirectConnection,
QGenericReturnArgument(),
Q_ARG(QString, argument),
Q_ARG(QString, callbackId));
}
}

View File

@@ -0,0 +1,17 @@
#ifndef BRIDGEEXTENSION_H
#define BRIDGEEXTENSION_H
#include <QJSValue>
#include <QObject>
class DoricBridgeExtension : public QObject {
Q_OBJECT
public:
explicit DoricBridgeExtension(QObject *parent = nullptr);
Q_INVOKABLE void callNative(QString contextId, QString module,
QString methodName, QString callbackId,
QString argument);
};
#endif // BRIDGEEXTENSION_H

View File

@@ -0,0 +1,20 @@
#ifndef INTERFACE_JSE_H
#define INTERFACE_JSE_H
#include <QString>
#include <QVariant>
class DoricInterfaceJSE {
public:
virtual QString loadJS(QString script, QString source) = 0;
virtual void injectGlobalJSObject(QString name, QObject *object) = 0;
virtual void injectGlobalJSFunction(QString name, QObject *function,
QString property) = 0;
virtual void invokeObject(QString objectName, QString functionName,
QVariantList arguments) = 0;
};
#endif // INTERFACE_JSE_H

View File

@@ -0,0 +1,137 @@
#include <QGuiApplication>
#include <QJsonObject>
#include <QRect>
#include <QScreen>
#include <QSysInfo>
#include <QtConcurrent/QtConcurrent>
#include "../utils/DoricConstant.h"
#include "../utils/DoricUtils.h"
#include "DoricBridgeExtension.h"
#include "DoricJSEngine.h"
#include "DoricNativeEmpty.h"
#include "DoricNativeJSE.h"
#include "DoricNativeLog.h"
#include "DoricNativeRequire.h"
#include "DoricTimerExtension.h"
DoricJSEngine::DoricJSEngine(QObject *parent) : QObject(parent) {
mJSThreadPool.setMaxThreadCount(1);
mJSThreadPool.setExpiryTimeout(-1);
{
auto result = QtConcurrent::run(
&mJSThreadPool, [this] { mJSE = new DoricNativeJSE(JSEType::V8); });
}
{
auto result = QtConcurrent::run(&mJSThreadPool, [this] {
// inject env
QScreen *screen = QGuiApplication::primaryScreen();
QRect screenGeometry = screen->geometry();
int screenWidth = screenGeometry.width();
int screenHeight = screenGeometry.height();
QObject *envObject = new QObject();
envObject->setProperty("platform", "Qt");
envObject->setProperty("platformVersion", qVersion());
envObject->setProperty("appName", "appName");
envObject->setProperty("appVersion", "appVersion");
envObject->setProperty("screenWidth", screenWidth);
envObject->setProperty("screenHeight", screenHeight);
envObject->setProperty("screenScale", 1);
envObject->setProperty("statusBarHeight", 0);
envObject->setProperty("hasNotch", false);
envObject->setProperty("deviceBrand", QSysInfo::prettyProductName());
envObject->setProperty("deviceModel", QSysInfo::productType());
mJSE->injectGlobalJSObject(DoricConstant::INJECT_ENVIRONMENT, envObject);
// inject log
DoricNativeLog *nativeLog = new DoricNativeLog();
mJSE->injectGlobalJSFunction(DoricConstant::INJECT_LOG, nativeLog,
"function");
// inject empty
DoricNativeEmpty *nativeEmpty = new DoricNativeEmpty();
mJSE->injectGlobalJSFunction(DoricConstant::INJECT_EMPTY, nativeEmpty,
"function");
// inject require
DoricNativeRequire *nativeRequire = new DoricNativeRequire();
mJSE->injectGlobalJSFunction(DoricConstant::INJECT_REQUIRE, nativeRequire,
"function");
// inject timer set & clear
DoricTimerExtension *timerExtension =
new DoricTimerExtension([this](long timerId) {
auto result = QtConcurrent::run(&mJSThreadPool, [this, timerId] {
QVariantList arguments;
arguments.push_back(QVariant((int)timerId));
this->invokeDoricMethod(DoricConstant::DORIC_TIMER_CALLBACK,
arguments);
});
});
mJSE->injectGlobalJSFunction(DoricConstant::INJECT_TIMER_SET,
timerExtension, "setTimer");
mJSE->injectGlobalJSFunction(DoricConstant::INJECT_TIMER_CLEAR,
timerExtension, "clearTimer");
DoricBridgeExtension *bridgeExtension = new DoricBridgeExtension();
mJSE->injectGlobalJSFunction(DoricConstant::INJECT_BRIDGE,
bridgeExtension, "callNative");
});
}
{
auto result = QtConcurrent::run(&mJSThreadPool, [this] {
loadBuiltinJS(DoricConstant::DORIC_BUNDLE_SANDBOX);
QString libName = DoricConstant::DORIC_MODULE_LIB;
QString libJS =
DoricUtils::readAssetFile("/doric", DoricConstant::DORIC_BUNDLE_LIB);
QString script = packageModuleScript(libName, libJS);
mJSE->loadJS(script, "Module://" + libName);
});
}
}
void DoricJSEngine::prepareContext(QString contextId, QString script,
QString source) {
mJSE->loadJS(packageContextScript(contextId, script), "Context://" + source);
}
void DoricJSEngine::destroyContext(QString contextId) {
QString script =
QString(DoricConstant::TEMPLATE_CONTEXT_DESTROY).replace("%s", contextId);
mJSE->loadJS(script, "_Context://" + contextId);
}
void DoricJSEngine::invokeDoricMethod(QString method, QVariantList arguments) {
return mJSE->invokeObject(DoricConstant::GLOBAL_DORIC, method, arguments);
}
void DoricJSEngine::loadBuiltinJS(QString assetName) {
QString script = DoricUtils::readAssetFile("/doric", assetName);
QString result = mJSE->loadJS(script, "Assets://" + assetName);
qDebug() << result;
}
QString DoricJSEngine::packageContextScript(QString contextId,
QString content) {
return QString(DoricConstant::TEMPLATE_CONTEXT_CREATE)
.replace("%s1", content)
.replace("%s2", contextId)
.replace("%s3", contextId);
}
QString DoricJSEngine::packageModuleScript(QString moduleName,
QString content) {
return QString(DoricConstant::TEMPLATE_MODULE)
.replace("%s1", moduleName)
.replace("%s2", content);
}
DoricRegistry *DoricJSEngine::getRegistry() { return this->mRegistry; }
DoricJSEngine::~DoricJSEngine() {}

View File

@@ -0,0 +1,36 @@
#ifndef JSENGINE_H
#define JSENGINE_H
#include <QJSValue>
#include <QThreadPool>
#include "../DoricRegistry.h"
#include "DoricInterfaceJSE.h"
class DoricJSEngine : public QObject {
Q_OBJECT
private:
DoricInterfaceJSE *mJSE;
DoricRegistry *mRegistry = new DoricRegistry();
void loadBuiltinJS(QString assetName);
QString packageContextScript(QString contextId, QString content);
QString packageModuleScript(QString moduleName, QString content);
public:
QThreadPool mJSThreadPool;
explicit DoricJSEngine(QObject *parent = nullptr);
~DoricJSEngine();
void prepareContext(QString contextId, QString script, QString source);
void destroyContext(QString contextId);
void invokeDoricMethod(QString method, QVariantList arguments);
DoricRegistry *getRegistry();
};
#endif // JSENGINE_H

View File

@@ -0,0 +1,6 @@
#include "DoricNativeEmpty.h"
#include <QDebug>
Q_INVOKABLE void DoricNativeEmpty::function() {
qDebug() << "nativeEmpty";
}

View File

@@ -0,0 +1,15 @@
#ifndef NATIVEEMPTY_H
#define NATIVEEMPTY_H
#include <QObject>
class DoricNativeEmpty : public QObject {
Q_OBJECT
public:
DoricNativeEmpty(QObject *parent = nullptr) : QObject(parent) {}
Q_INVOKABLE void function();
};
#endif // NATIVEEMPTY_H

View File

@@ -0,0 +1,66 @@
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include "../utils/DoricUtils.h"
#include "DoricNativeJSE.h"
DoricNativeJSE::DoricNativeJSE(JSEType type) {
mType = type;
if (mType == JSEType::V8) {
v8Executor = new V8Executor();
} else if (mType == JSEType::Native) {
nativeExecutor = new NativeExecutor();
}
}
QString DoricNativeJSE::loadJS(QString script, QString source) {
if (mType == JSEType::V8) {
return v8Executor->loadJS(script, source);
} else if (mType == JSEType::Native) {
return nativeExecutor->loadJS(script, source);
}
}
void DoricNativeJSE::injectGlobalJSObject(QString name, QObject *object) {
if (mType == JSEType::V8) {
QJsonObject jsonObject;
QList<QByteArray> propertyNames = object->dynamicPropertyNames();
foreach (QByteArray propertyName, propertyNames) {
QString key = QString::fromStdString(propertyName.toStdString());
object->property(propertyName).toString();
if (key == "undefined" || key.isEmpty()) {
} else {
jsonObject[key] =
QJsonValue::fromVariant(object->property(propertyName));
}
}
QJsonDocument doc(jsonObject);
QString strJson(doc.toJson(QJsonDocument::Compact));
v8Executor->injectGlobalJSObject(name, strJson.toUtf8().constData());
} else if (mType == JSEType::Native) {
nativeExecutor->injectGlobalJSObject(name, object);
}
}
void DoricNativeJSE::injectGlobalJSFunction(QString name, QObject *function,
QString property) {
if (mType == JSEType::V8) {
v8Executor->injectGlobalJSFunction(name, function, property);
} else if (mType == JSEType::Native) {
nativeExecutor->injectGlobalJSFunction(name, function, property);
}
}
void DoricNativeJSE::invokeObject(QString objectName, QString functionName,
QVariantList arguments) {
if (mType == JSEType::V8) {
v8Executor->invokeObject(objectName, functionName, arguments);
} else if (mType == JSEType::Native) {
nativeExecutor->invokeObject(objectName, functionName, arguments);
}
}

View File

@@ -0,0 +1,31 @@
#ifndef NATIVE_JSE_H
#define NATIVE_JSE_H
#include "DoricInterfaceJSE.h"
#include "native/NativeExecutor.h"
#include "v8/V8Executor.h"
enum class JSEType { V8, Native };
class DoricNativeJSE : public DoricInterfaceJSE {
private:
JSEType mType;
V8Executor *v8Executor;
NativeExecutor *nativeExecutor;
public:
DoricNativeJSE(JSEType type);
QString loadJS(QString script, QString source) override;
void injectGlobalJSObject(QString name, QObject *object) override;
void injectGlobalJSFunction(QString name, QObject *function,
QString property) override;
void invokeObject(QString objectName, QString functionName,
QVariantList arguments) override;
};
#endif // NATIVE_JSE_H

View File

@@ -0,0 +1,13 @@
#include <QDebug>
#include "DoricNativeLog.h"
Q_INVOKABLE void DoricNativeLog::function(QString level, QString content) {
if (level == 'w') {
qWarning() << content;
} else if (level == 'd') {
qDebug() << content;
} else if (level == 'e') {
qCritical() << content;
}
}

View File

@@ -0,0 +1,15 @@
#ifndef NATIVE_LOG_H
#define NATIVE_LOG_H
#include <QObject>
class DoricNativeLog : public QObject {
Q_OBJECT
public:
DoricNativeLog(QObject *parent = nullptr) : QObject(parent) {}
Q_INVOKABLE void function(QString level, QString content);
};
#endif // NATIVE_LOG_H

View File

@@ -0,0 +1,7 @@
#include "DoricNativeRequire.h"
#include <QDebug>
Q_INVOKABLE void DoricNativeRequire::function(QString name) {
qDebug() << "nativeRequire: " << name.toUtf8();
}

View File

@@ -0,0 +1,15 @@
#ifndef NATIVE_REQUIRE_H
#define NATIVE_REQUIRE_H
#include <QObject>
class DoricNativeRequire : public QObject {
Q_OBJECT
public:
DoricNativeRequire(QObject *parent = nullptr) : QObject(parent) {}
Q_INVOKABLE void function(QString name);
};
#endif // NATIVE_REQUIRE_H

View File

@@ -0,0 +1,36 @@
#ifndef DORICPROMISE_H
#define DORICPROMISE_H
#include <QDebug>
#include "DoricContext.h"
#include "utils/DoricConstant.h"
class DoricPromise {
public:
static void resolve(DoricContext *context, QString callbackId,
QVariantList args) {
QVariantList params;
params.append(context->getContextId());
params.append(callbackId);
foreach (QVariant arg, args) { params.append(arg); }
context->getDriver()->invokeDoricMethod(DoricConstant::DORIC_BRIDGE_RESOLVE,
params);
}
static void reject(DoricContext *context, QString callbackId,
QVariantList args) {
QVariantList params;
params.append(context->getContextId());
params.append(callbackId);
foreach (QVariant arg, args) { params.append(arg); }
context->getDriver()->invokeDoricMethod(DoricConstant::DORIC_BRIDGE_REJECT,
params);
}
};
#endif // DORICPROMISE_H

View File

@@ -0,0 +1,36 @@
#include <QCoreApplication>
#include <QTimer>
#include "../utils/DoricConstant.h"
#include "DoricTimerExtension.h"
Q_INVOKABLE void DoricTimerExtension::setTimer(long timerId, int time,
bool repeat) {
connect(this, &DoricTimerExtension::startTimer, qApp, [=]() {
QTimer *timer = new QTimer();
timer->setSingleShot(!repeat);
connect(timer, &QTimer::timeout, [=]() {
if (deletedTimerIds->contains(timerId)) {
deletedTimerIds->remove(timerId);
timer->deleteLater();
} else {
this->method(timerId);
if (!repeat) {
deletedTimerIds->remove(timerId);
timer->deleteLater();
}
}
});
timer->start(time);
});
emit startTimer();
}
Q_INVOKABLE void DoricTimerExtension::clearTimer(long timerId) {
deletedTimerIds->insert(timerId);
}

View File

@@ -0,0 +1,28 @@
#ifndef NATIVETIMER_H
#define NATIVETIMER_H
#include <QObject>
#include <QSet>
class DoricTimerExtension : public QObject {
Q_OBJECT
private:
QSet<long> *deletedTimerIds = new QSet<long>();
std::function<void(long)> method;
public:
explicit DoricTimerExtension(std::function<void(long)> method,
QObject *parent = nullptr)
: QObject(parent) {
this->method = method;
}
Q_INVOKABLE void setTimer(long timerId, int time, bool repeat);
Q_INVOKABLE void clearTimer(long timerId);
signals:
void startTimer();
};
#endif // NATIVETIMER_H

View File

@@ -0,0 +1,82 @@
#include "NativeExecutor.h"
#include <QDebug>
NativeExecutor::NativeExecutor() {
mJSEngine = new QJSEngine();
mJSEngine->installExtensions(QJSEngine::AllExtensions);
}
NativeExecutor::~NativeExecutor() { delete mJSEngine; }
QString NativeExecutor::loadJS(QString script, QString source) {
return mJSEngine->evaluate(script, source).toString();
}
void NativeExecutor::injectGlobalJSObject(QString name, QObject *object) {
QJSValue jsObject = mJSEngine->newQObject(object);
QList<QByteArray> propertyNames = object->dynamicPropertyNames();
foreach (QByteArray propertyName, propertyNames) {
QString key = QString::fromStdString(propertyName.toStdString());
if (key == "undefined") {
} else {
jsObject.setProperty(
key, mJSEngine->toScriptValue(object->property(propertyName)));
}
}
mJSEngine->globalObject().setProperty(name, jsObject);
}
void NativeExecutor::injectGlobalJSFunction(QString name, QObject *function,
QString property) {
QJSValue functionObject = mJSEngine->newQObject(function);
mJSEngine->globalObject().setProperty(name,
functionObject.property(property));
}
QJSValue NativeExecutor::invokeObject(QString objectName, QString functionName,
QVariantList arguments) {
QJSValue object = mJSEngine->evaluate(objectName);
QJSValue function = object.property(functionName);
QJSValueList args;
foreach (QVariant variant, arguments) {
if (variant.type() == QVariant::String) {
args.push_back(QJSValue(variant.toString()));
} else if (variant.type() == QVariant::Map) {
QJSValue arg = mJSEngine->newObject();
QMap<QString, QVariant> map = variant.toMap();
foreach (QString key, map.keys()) {
QVariant value = map.value(key);
if (value.type() == QVariant::String) {
arg.setProperty(key, value.toString());
} else if (value.type() == QVariant::Int) {
arg.setProperty(key, value.toInt());
}
}
args.push_back(arg);
} else if (variant.type() == QVariant::StringList) {
QStringList array = variant.toStringList();
QJSValue arg = mJSEngine->newArray(array.size());
for (int i = 0; i != array.size(); i++) {
arg.setProperty(i, array.at(i));
}
args.push_back(arg);
}
}
QJSValue result = function.call(args);
if (result.isError()) {
qCritical() << "++++++++++++++++++++++++++++++++++++++++++++++++";
qCritical() << result.toString();
QStringList stacktraces = result.property("stack").toString().split("\n");
foreach (QString stacktrace, stacktraces) { qDebug() << stacktrace; }
qCritical() << "------------------------------------------------";
}
return result;
}

View File

@@ -0,0 +1,27 @@
#ifndef NATIVEEXECUTOR_H
#define NATIVEEXECUTOR_H
#include <QJSEngine>
class NativeExecutor {
private:
QJSEngine *mJSEngine;
public:
NativeExecutor();
~NativeExecutor();
QString loadJS(QString script, QString source);
void injectGlobalJSObject(QString name, QObject *object);
void injectGlobalJSFunction(QString name, QObject *function,
QString property);
QJSValue invokeObject(QString objectName, QString functionName,
QVariantList arguments);
};
#endif // NATIVEEXECUTOR_H

View File

@@ -0,0 +1,95 @@
#include "JSValueHelper.h"
#include <QJsonDocument>
#include <QJsonObject>
std::string JS2String(v8::Local<v8::Value> object) {
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
if (object->IsString() || object->IsRegExp() || object->IsFunction()) {
v8::String::Utf8Value utf8(isolate, object);
return std::string(*utf8);
}
if (object->IsObject()) {
v8::MaybeLocal<v8::String> str = v8::JSON::Stringify(
context, object->ToObject(context).ToLocalChecked());
if (str.IsEmpty()) {
return "<string conversion failed>";
}
v8::Local<v8::String> s = str.ToLocalChecked();
v8::String::Utf8Value str2(isolate, s);
return std::string(*str2 ? *str2 : "<string conversion failed>");
}
v8::String::Utf8Value str(
isolate, v8::JSON::Stringify(context, object).ToLocalChecked());
return std::string(*str ? *str : "<string conversion failed>");
}
double JS2Number(v8::Local<v8::Value> value) {
v8::HandleScope handleScope(v8::Isolate::GetCurrent());
v8::Local<v8::Context> context =
v8::Isolate::GetCurrent()->GetCurrentContext();
if (value->IsNumber()) {
return value->ToNumber(context).ToLocalChecked()->Value();
} else {
return 0;
}
}
bool JS2Bool(v8::Local<v8::Value> value) {
v8::HandleScope handleScope(v8::Isolate::GetCurrent());
if (value->IsBoolean()) {
return value->ToBoolean(v8::Isolate::GetCurrent())->Value();
} else {
return false;
}
}
v8::Local<v8::Value> String2JS(std::string string) {
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::EscapableHandleScope handleScope(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
v8::Local<v8::String> jsString = NewV8String(string.c_str());
v8::Local<v8::Value> ret =
v8::JSON::Parse(context, jsString).ToLocalChecked();
return handleScope.Escape(ret);
}
v8::Local<v8::Value> Variant2JS(QVariant variant) {
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::EscapableHandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
v8::Local<v8::Value> jsValue;
if (variant.type() == QVariant::String) {
jsValue = NewV8String(variant.toString().toUtf8().constData());
} else if (variant.type() == QVariant::Map) {
QMap<QString, QVariant> map = variant.toMap();
QJsonObject jsonObject;
foreach (QString key, map.keys()) {
QVariant value = map.value(key);
jsonObject.insert(key, QJsonValue::fromVariant(value));
}
QJsonDocument doc(jsonObject);
QString strJson(doc.toJson(QJsonDocument::Compact));
jsValue = String2JS(strJson.toUtf8().constData());
} else if (variant.type() == QVariant::StringList) {
QStringList list = variant.toStringList();
v8::Handle<v8::Array> array = v8::Array::New(isolate, list.size());
for (int i = 0; i != list.size(); i++) {
v8::Local<v8::Value> value = NewV8String(list.at(i).toUtf8().constData());
auto result = array->Set(context, i, value);
result.ToChecked();
}
jsValue = array;
} else if (variant.type() == QVariant::Int) {
jsValue = v8::Number::New(isolate, variant.toDouble());
}
return handle_scope.Escape(jsValue);
}

View File

@@ -0,0 +1,24 @@
#ifndef JSVALUEHELPER_H
#define JSVALUEHELPER_H
#include <QVariant>
#include <string>
#include "v8.h"
#define NewV8String(name) \
v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), name, \
v8::NewStringType::kNormal) \
.ToLocalChecked()
std::string JS2String(v8::Local<v8::Value> object);
double JS2Number(v8::Local<v8::Value> value);
bool JS2Bool(v8::Local<v8::Value> value);
v8::Local<v8::Value> String2JS(std::string string);
v8::Local<v8::Value> Variant2JS(QVariant variant);
#endif // JSVALUEHELPER_H

View File

@@ -0,0 +1,348 @@
#include <QDebug>
#include "JSValueHelper.h"
#include "V8Executor.h"
V8Executor::V8Executor() : platform(v8::platform::NewDefaultPlatform()) {
v8::V8::InitializeICUDefaultLocation("");
v8::V8::InitializeExternalStartupData("");
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
create_params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
m_isolate = v8::Isolate::New(create_params);
m_isolate_scope = new v8::Isolate::Scope(m_isolate);
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
context->Enter();
m_global_context = new v8::Global<v8::Context>(isolate, context);
}
V8Executor::~V8Executor() {
{
v8::HandleScope scope(m_isolate);
v8::Local<v8::Context> context = m_global_context->Get(m_isolate);
context->Exit();
}
m_global_context->Reset();
delete m_global_context;
delete m_isolate_scope;
m_isolate->Dispose();
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete create_params.array_buffer_allocator;
}
QString V8Executor::loadJS(QString script, QString source) {
v8::Isolate *isolate = m_isolate;
std::string exception;
v8::HandleScope scope(isolate);
v8::Local<v8::Value> ret = innerExec(script.toUtf8().constData(),
source.toUtf8().constData(), &exception);
std::string result = JS2String(ret);
return QString::fromUtf8(result.c_str());
}
void V8Executor::injectGlobalJSObject(QString name, std::string target) {
v8::Isolate *isolate = m_isolate;
v8::HandleScope handleScope(isolate);
v8::Local<v8::Value> local = String2JS(target);
injectObject(name.toUtf8().constData(), local);
}
void V8Executor::injectGlobalJSFunction(QString name, QObject *function,
QString property) {
if (map->keys().contains(name)) {
qCritical() << "already injected";
return;
} else {
QPair<QObject *, QString> pair(function, property);
map->insert(name, pair);
}
injectFunctions(nullptr, name.toUtf8().constData(), true);
}
void V8Executor::invokeObject(QString objectName, QString functionName,
QVariantList arguments) {
std::string exception;
v8::HandleScope handleScope(m_isolate);
int valueSize = arguments.size();
auto js_values = new v8::Local<v8::Value>[valueSize];
for (int i = 0; i < valueSize; i++) {
js_values[i] = Variant2JS(arguments.at(i));
}
v8::Local<v8::Value> value = invokeMethod(objectName.toUtf8().constData(),
functionName.toUtf8().constData(),
valueSize, js_values, &exception);
delete[] js_values;
}
// private segment
void V8Executor::injectObject(const char *string, v8::Local<v8::Value> local) {
v8::Isolate *isolate = m_isolate;
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
v8::Local<v8::Object> object = context->Global();
v8::Maybe<bool> result = object->Set(context, NewV8String(string), local);
result.ToChecked();
}
v8::Local<v8::Value> V8Executor::innerExec(const char *script,
const char *source,
std::string *exception_str) {
v8::Isolate *isolate = m_isolate;
v8::EscapableHandleScope handle_scope(isolate);
v8::Local<v8::Value> result = Undefined(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
v8::Context::Scope context_scope(context);
v8::ScriptOrigin origin(NewV8String(source));
if (script) {
v8::Local<v8::String> jsSource = NewV8String(script);
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
v8::MaybeLocal<v8::Script> maybeScript =
v8::Script::Compile(context, jsSource, &origin);
if (!maybeScript.IsEmpty()) {
v8::Local<v8::Script> js_script = maybeScript.ToLocalChecked();
v8::MaybeLocal<v8::Value> res = js_script->Run(context);
if (!res.IsEmpty()) {
result = res.ToLocalChecked();
}
}
v8::Local<v8::Value> exception = try_catch.Exception();
if (!exception.IsEmpty()) {
if (exception->IsObject()) {
v8::Local<v8::Object> exc = v8::Local<v8::Object>::Cast(exception);
v8::Local<v8::Value> stack =
exc->Get(context, NewV8String("stack")).FromMaybe(exception);
*exception_str = JS2String(stack);
} else {
*exception_str = JS2String(exception);
}
}
}
return handle_scope.Escape(result);
}
static void InjectedFunction(const v8::FunctionCallbackInfo<v8::Value> &args) {
v8::Isolate *isolate = args.GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
v8::Local<v8::Object> data = args.Data()->ToObject(context).ToLocalChecked();
std::string objectKey =
JS2String(data->Get(context, NewV8String("obj")).ToLocalChecked())
.c_str();
std::string functionKey =
JS2String(data->Get(context, NewV8String("func")).ToLocalChecked())
.c_str();
bool hashKey = data->Get(context, NewV8String("hashKey"))
.ToLocalChecked()
->BooleanValue(isolate);
// invoke
QPair<QObject *, QString> pair =
map->find(QString::fromUtf8(functionKey.c_str())).value();
QString functionKeyQString = QString::fromUtf8(functionKey.c_str());
if (args.Length() == 0) {
if (functionKeyQString == "nativeEmpty") {
QMetaObject::invokeMethod(pair.first, pair.second.toUtf8().constData(),
Qt::DirectConnection, QGenericReturnArgument());
}
} else if (args.Length() == 1) {
if (functionKeyQString == "nativeRequire") {
v8::Local<v8::Value> arg = args[0];
std::string argString = JS2String(arg);
QMetaObject::invokeMethod(
pair.first, pair.second.toUtf8().constData(), Qt::DirectConnection,
QGenericReturnArgument(),
Q_ARG(QString, QString::fromUtf8(argString.c_str())));
} else if (functionKeyQString == "nativeClearTimer") {
v8::Local<v8::Value> arg = args[0];
double number = JS2Number(arg);
QMetaObject::invokeMethod(pair.first, pair.second.toUtf8().constData(),
Qt::DirectConnection, QGenericReturnArgument(),
Q_ARG(long, number));
}
} else if (args.Length() == 2) {
v8::Local<v8::Value> arg0 = args[0];
std::string argString0 = JS2String(arg0);
v8::Local<v8::Value> arg1 = args[1];
std::string argString1 = JS2String(arg1);
QMetaObject::invokeMethod(
pair.first, pair.second.toUtf8().constData(), Qt::DirectConnection,
QGenericReturnArgument(),
Q_ARG(QString, QString::fromUtf8(argString0.c_str())),
Q_ARG(QString, QString::fromUtf8(argString1.c_str())));
} else if (args.Length() == 3) {
v8::Local<v8::Value> arg0 = args[0];
long argLong = JS2Number(arg0);
v8::Local<v8::Value> arg1 = args[1];
int argInt = JS2Number(arg1);
v8::Local<v8::Value> arg2 = args[2];
bool argBool = JS2Bool(arg2);
QMetaObject::invokeMethod(pair.first, pair.second.toUtf8().constData(),
Qt::DirectConnection, QGenericReturnArgument(),
Q_ARG(long, argLong), Q_ARG(int, argInt),
Q_ARG(bool, argBool));
} else if (args.Length() == 5) {
v8::Local<v8::Value> arg0 = args[0];
std::string argString0 = JS2String(arg0);
v8::Local<v8::Value> arg1 = args[1];
std::string argString1 = JS2String(arg1);
v8::Local<v8::Value> arg2 = args[2];
std::string argString2 = JS2String(arg2);
v8::Local<v8::Value> arg3 = args[3];
std::string argString3 = JS2String(arg3);
v8::Local<v8::Value> arg4 = args[4];
std::string argString4 = JS2String(arg4);
QMetaObject::invokeMethod(
pair.first, pair.second.toUtf8().constData(), Qt::DirectConnection,
QGenericReturnArgument(),
Q_ARG(QString, QString::fromUtf8(argString0.c_str())),
Q_ARG(QString, QString::fromUtf8(argString1.c_str())),
Q_ARG(QString, QString::fromUtf8(argString2.c_str())),
Q_ARG(QString, QString::fromUtf8(argString3.c_str())),
Q_ARG(QString, QString::fromUtf8(argString4.c_str())));
}
// begin check to perform micro task checkpoint
std::string objectNameString = "global";
std::string functionKeyString = "nativeEmpty";
int objectCompareResult = strncmp(objectKey.c_str(), objectNameString.c_str(),
strlen(objectKey.c_str()));
if (objectCompareResult == 0) {
int functionCompareResult =
strncmp(functionKey.c_str(), functionKeyString.c_str(),
strlen(functionKey.c_str()));
if (functionCompareResult == 0) {
isolate->PerformMicrotaskCheckpoint();
}
}
// end check
}
void V8Executor::injectFunctions(const char *objectName,
const char *functionName, bool hashKey) {
v8::Isolate *isolate = m_isolate;
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
v8::Local<v8::Object> object = context->Global();
if (objectName) {
object = object->Get(context, NewV8String(objectName))
.ToLocalChecked()
->ToObject(context)
.ToLocalChecked();
}
v8::Local<v8::String> name = NewV8String(functionName);
v8::Local<v8::Object> data = v8::Object::New(isolate);
if (objectName) {
v8::Maybe<bool> result =
data->Set(context, NewV8String("obj"), NewV8String(objectName));
result.ToChecked();
} else {
v8::Maybe<bool> result =
data->Set(context, NewV8String("obj"), NewV8String("global"));
result.ToChecked();
}
{
v8::Maybe<bool> result =
data->Set(context, NewV8String("func"), NewV8String(functionName));
result.ToChecked();
}
{
v8::Maybe<bool> result = data->Set(context, NewV8String("hashKey"),
v8::Boolean::New(isolate, hashKey));
result.ToChecked();
}
v8::Local<v8::Function> function =
v8::Function::New(context, InjectedFunction, data).ToLocalChecked();
v8::Maybe<bool> result = object->Set(context, name, function);
result.ToChecked();
}
v8::Local<v8::Value> V8Executor::invokeMethod(const char *objectName,
const char *functionName,
int argc,
v8::Local<v8::Value> argv[],
std::string *exception_str) {
v8::Isolate *isolate = m_isolate;
v8::EscapableHandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetEnteredOrMicrotaskContext();
v8::Local<v8::Object> object = context->Global();
v8::Local<v8::Value> result = Undefined(isolate);
if (objectName) {
object = object->Get(context, NewV8String(objectName))
.ToLocalChecked()
->ToObject(context)
.ToLocalChecked();
}
if (object.IsEmpty()) {
*exception_str = std::string("Cannot find Object:") +
std::string(objectName ? objectName : "global");
return handle_scope.Escape(result);
}
v8::Local<v8::Value> target_value =
object->Get(context, NewV8String(functionName)).ToLocalChecked();
if (!target_value->IsFunction()) {
*exception_str =
std::string("In ") + std::string(objectName ? objectName : "global") +
std::string("cannot find target function ") + std::string(functionName);
return handle_scope.Escape(result);
}
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
v8::Local<v8::Function> target_function =
v8::Local<v8::Function>::Cast(target_value);
result = target_function->Call(context, object, argc, argv).ToLocalChecked();
v8::Local<v8::Value> exception = try_catch.Exception();
if (!exception.IsEmpty()) {
if (exception->IsObject()) {
v8::Local<v8::Object> exc = v8::Local<v8::Object>::Cast(exception);
v8::Local<v8::Value> stack =
exc->Get(context, NewV8String("stack")).FromMaybe(exception);
*exception_str = JS2String(stack);
} else {
*exception_str = JS2String(exception);
}
}
return handle_scope.Escape(result);
}

View File

@@ -0,0 +1,52 @@
#ifndef V8EXECUTOR_H
#define V8EXECUTOR_H
#include "libplatform/libplatform.h"
#include "v8.h"
#include <QMap>
#include <QObject>
#include <QString>
static QMap<QString, QPair<QObject *, QString>> *map =
new QMap<QString, QPair<QObject *, QString>>();
class V8Executor {
private:
std::unique_ptr<v8::Platform> platform;
v8::Isolate::CreateParams create_params;
v8::Isolate *m_isolate;
v8::Isolate::Scope *m_isolate_scope;
v8::Global<v8::Context> *m_global_context;
void injectObject(const char *string, v8::Local<v8::Value> local);
v8::Local<v8::Value> innerExec(const char *script, const char *source,
std::string *exception_str);
void injectFunctions(const char *objectName, const char *functionName,
bool hashKey);
v8::Local<v8::Value> invokeMethod(const char *objectName,
const char *functionName, int argc,
v8::Local<v8::Value> argv[],
std::string *exception_str);
public:
V8Executor();
~V8Executor();
QString loadJS(QString script, QString source);
void injectGlobalJSObject(QString name, std::string target);
void injectGlobalJSFunction(QString name, QObject *function,
QString property);
void invokeObject(QString objectName, QString functionName,
QVariantList arguments);
};
#endif // V8EXECUTOR_H

View File

@@ -0,0 +1,260 @@
#include "DoricModalPlugin.h"
#include "engine/DoricPromise.h"
#include "shader/DoricRootNode.h"
#include "utils/DoricLayouts.h"
#include <QJsonDocument>
#include <QObject>
#include <QQmlComponent>
#include <QQuickWindow>
#include <QTimer>
void DoricModalPlugin::toast(QString jsValueString, QString callbackId) {
getContext()->getDriver()->asyncCall(
[this, jsValueString] {
QJsonDocument document =
QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
QString msg = jsValue["msg"].toString();
int gravity = jsValue["gravity"].toInt();
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/toast.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickWindow *window = qobject_cast<QQuickWindow *>(component.create());
QQuickWindow *parentWindow =
getContext()->getRootNode()->getRootView()->window();
window->contentItem()
->childItems()
.at(0)
->childItems()
.at(0)
->childItems()
.at(0)
->setProperty("text", msg);
std::function<void()> setX = [window, parentWindow]() {
window->setProperty("x",
(parentWindow->width() - window->width()) / 2.f +
parentWindow->x());
};
std::function<void()> setY = [window, parentWindow, gravity]() {
if ((gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom) {
window->setProperty("y", parentWindow->height() - window->height() -
20 + parentWindow->y());
} else if ((gravity & DoricGravity::DoricGravityTop) ==
DoricGravity::DoricGravityTop) {
window->setProperty("y", 20 + parentWindow->y());
} else {
window->setProperty(
"y", (parentWindow->height() - window->height()) / 2 +
parentWindow->y());
}
};
// init set x
setX();
// init set y
setY();
// update x
connect(window, &QQuickWindow::widthChanged, setX);
// update y
connect(window, &QQuickWindow::heightChanged, setY);
QTimer::singleShot(2000, qApp, [window]() { window->deleteLater(); });
},
DoricThreadMode::UI);
}
void DoricModalPlugin::alert(QString jsValueString, QString callbackId) {
getContext()->getDriver()->asyncCall(
[this, jsValueString, callbackId] {
QJsonDocument document =
QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
QJsonValue titleVal = jsValue["title"];
QJsonValue msgVal = jsValue["msg"];
QJsonValue okBtn = jsValue["okLabel"];
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/alert.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickWindow *window = qobject_cast<QQuickWindow *>(component.create());
window->setProperty("pointer", QString::number((qint64)window));
window->setProperty("plugin", QString::number((qint64)this));
window->setProperty("callbackId", callbackId);
window->setProperty("title", titleVal.toString());
window->setProperty("msg", msgVal.toString());
window->setProperty("okLabel", okBtn.toString());
QQuickWindow *parentWindow =
getContext()->getRootNode()->getRootView()->window();
std::function<void()> setX = [window, parentWindow]() {
window->setProperty("x",
(parentWindow->width() - window->width()) / 2.f +
parentWindow->x());
};
std::function<void()> setY = [window, parentWindow]() {
window->setProperty("y",
(parentWindow->height() - window->height()) / 2 +
parentWindow->y());
};
// init set x
setX();
// init set y
setY();
// update x
connect(window, &QQuickWindow::widthChanged, setX);
// update y
connect(window, &QQuickWindow::heightChanged, setY);
},
DoricThreadMode::UI);
}
void DoricModalPlugin::confirm(QString jsValueString, QString callbackId) {
getContext()->getDriver()->asyncCall(
[this, jsValueString, callbackId] {
QJsonDocument document =
QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
QJsonValue titleVal = jsValue["title"];
QJsonValue msgVal = jsValue["msg"];
QJsonValue okBtn = jsValue["okLabel"];
QJsonValue cancelBtn = jsValue["cancelLabel"];
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/confirm.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickWindow *window = qobject_cast<QQuickWindow *>(component.create());
window->setProperty("pointer", QString::number((qint64)window));
window->setProperty("plugin", QString::number((qint64)this));
window->setProperty("callbackId", callbackId);
window->setProperty("title", titleVal.toString());
window->setProperty("msg", msgVal.toString());
window->setProperty("okLabel", okBtn.toString());
window->setProperty("cancelLabel", cancelBtn.toString());
QQuickWindow *parentWindow =
getContext()->getRootNode()->getRootView()->window();
std::function<void()> setX = [window, parentWindow]() {
window->setProperty("x",
(parentWindow->width() - window->width()) / 2.f +
parentWindow->x());
};
std::function<void()> setY = [window, parentWindow]() {
window->setProperty("y",
(parentWindow->height() - window->height()) / 2 +
parentWindow->y());
};
// init set x
setX();
// init set y
setY();
// update x
connect(window, &QQuickWindow::widthChanged, setX);
// update y
connect(window, &QQuickWindow::heightChanged, setY);
},
DoricThreadMode::UI);
}
void DoricModalPlugin::prompt(QString jsValueString, QString callbackId) {
getContext()->getDriver()->asyncCall(
[this, jsValueString, callbackId] {
QJsonDocument document =
QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
QJsonValue titleVal = jsValue["title"];
QJsonValue msgVal = jsValue["msg"];
QJsonValue okBtn = jsValue["okLabel"];
QJsonValue cancelBtn = jsValue["cancelLabel"];
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/prompt.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickWindow *window = qobject_cast<QQuickWindow *>(component.create());
window->setProperty("pointer", QString::number((qint64)window));
window->setProperty("plugin", QString::number((qint64)this));
window->setProperty("callbackId", callbackId);
window->setProperty("title", titleVal.toString());
window->setProperty("msg", msgVal.toString());
window->setProperty("okLabel", okBtn.toString());
window->setProperty("cancelLabel", cancelBtn.toString());
QQuickWindow *parentWindow =
getContext()->getRootNode()->getRootView()->window();
std::function<void()> setX = [window, parentWindow]() {
window->setProperty("x",
(parentWindow->width() - window->width()) / 2.f +
parentWindow->x());
};
std::function<void()> setY = [window, parentWindow]() {
window->setProperty("y",
(parentWindow->height() - window->height()) / 2 +
parentWindow->y());
};
// init set x
setX();
// init set y
setY();
// update x
connect(window, &QQuickWindow::widthChanged, setX);
// update y
connect(window, &QQuickWindow::heightChanged, setY);
},
DoricThreadMode::UI);
}
void DoricModalPlugin::onAccepted(QString callbackId) {
QVariantList args;
DoricPromise::resolve(getContext(), callbackId, args);
}
void DoricModalPlugin::onAcceptedWithInput(QString callbackId, QString input) {
QVariantList args;
args.append(input);
DoricPromise::resolve(getContext(), callbackId, args);
}
void DoricModalPlugin::onRejected(QString callbackId) {
QVariantList args;
DoricPromise::reject(getContext(), callbackId, args);
}
void DoricModalPlugin::onRejectedWithInput(QString callbackId, QString input) {
QVariantList args;
args.append(input);
DoricPromise::reject(getContext(), callbackId, args);
}

View File

@@ -0,0 +1,28 @@
#ifndef DORICMODALPLUGIN_H
#define DORICMODALPLUGIN_H
#include "DoricNativePlugin.h"
class DoricModalPlugin : public DoricNativePlugin {
Q_OBJECT
public:
using DoricNativePlugin::DoricNativePlugin;
Q_INVOKABLE void toast(QString jsValueString, QString callbackId);
Q_INVOKABLE void alert(QString jsValueString, QString callbackId);
Q_INVOKABLE void confirm(QString jsValueString, QString callbackId);
Q_INVOKABLE void prompt(QString jsValueString, QString callbackId);
void onAccepted(QString callbackId);
void onAcceptedWithInput(QString callbackId, QString input);
void onRejected(QString callbackId);
void onRejectedWithInput(QString callbackId, QString input);
};
#endif // DORICMODALPLUGIN_H

View File

@@ -0,0 +1,11 @@
#ifndef DORICNATIVEPLUGIN_H
#define DORICNATIVEPLUGIN_H
#include "../utils/DoricContextHolder.h"
class DoricNativePlugin : public DoricContextHolder {
public:
using DoricContextHolder::DoricContextHolder;
};
#endif // DORICNATIVEPLUGIN_H

View File

@@ -0,0 +1,29 @@
#include "DoricNetworkPlugin.h"
#include "engine/DoricPromise.h"
#include "utils/DoricNetworkService.h"
#include <QCoreApplication>
#include <QJsonDocument>
#include <QJsonObject>
void DoricNetworkPlugin::request(QString jsValueString, QString callbackId) {
QJsonDocument document = QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
DoricNetworkService::getInstance()->request(
jsValue, qApp,
[this, callbackId](int code, QList<QByteArray> headers, QByteArray data) {
getContext()->getDriver()->asyncCall(
[this, callbackId, code, headers, data] {
QMap<QString, QVariant> map;
map.insert("status", code);
map.insert("headers", QVariant::fromValue(headers));
map.insert("data", QString(data));
QVariantList args;
args.append(map);
DoricPromise::resolve(getContext(), callbackId, args);
},
DoricThreadMode::JS);
});
}

View File

@@ -0,0 +1,13 @@
#ifndef DORICNETWORKPLUGIN_H
#define DORICNETWORKPLUGIN_H
#include "DoricNativePlugin.h"
class DoricNetworkPlugin : public DoricNativePlugin {
Q_OBJECT
public:
using DoricNativePlugin::DoricNativePlugin;
Q_INVOKABLE void request(QString jsValueString, QString callbackId);
};
#endif // DORICNETWORKPLUGIN_H

View File

@@ -0,0 +1,120 @@
#include "DoricPopoverPlugin.h"
#include "engine/DoricPromise.h"
#include "shader/DoricRootNode.h"
#include "shader/DoricViewNode.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QQuickWindow>
void DoricPopoverPlugin::show(QString jsValueString, QString callbackId) {
getContext()->getDriver()->asyncCall(
[this, jsValueString, callbackId] {
QJsonDocument document =
QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
QQuickItem *rootItem =
getContext()->getRootNode()->getRootView()->window()->contentItem();
if (this->fullScreenView == nullptr) {
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/stack.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
item->setWidth(rootItem->width());
item->setHeight(rootItem->height());
DoricLayouts *layout = new DoricLayouts();
layout->setWidth(item->width());
layout->setHeight(item->height());
layout->setView(item);
layout->setLayoutType(DoricLayoutType::DoricStack);
item->setProperty("doricLayout", QString::number((qint64)layout));
item->setParentItem(rootItem);
this->fullScreenView = item;
} else {
DoricLayouts *layout =
(DoricLayouts *)(this->fullScreenView->property("doricLayout")
.toULongLong());
layout->setWidth(rootItem->width());
layout->setHeight(rootItem->height());
}
this->fullScreenView->setVisible(true);
QString viewId = jsValue["id"].toString();
QString type = jsValue["type"].toString();
DoricViewNode *viewNode = getContext()->targetViewNode(viewId);
if (viewNode == nullptr) {
viewNode = DoricViewNode::create(getContext(), type);
viewNode->setId(viewId);
viewNode->init(nullptr);
viewNode->getNodeView()->setParentItem(this->fullScreenView);
}
viewNode->blend(jsValue["props"]);
DoricLayouts *layout =
(DoricLayouts *)(this->fullScreenView->property("doricLayout")
.toULongLong());
layout->apply();
getContext()->addHeadNode(TYPE, viewNode);
QVariantList args;
DoricPromise::resolve(getContext(), callbackId, args);
},
DoricThreadMode::UI);
}
void DoricPopoverPlugin::dismiss(QString jsValueString, QString callbackId) {
getContext()->getDriver()->asyncCall(
[this, jsValueString, callbackId] {
QJsonDocument document =
QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
if (jsValue.toObject().contains("id")) {
QString viewId = jsValue["id"].toString();
DoricViewNode *viewNode = getContext()->targetViewNode(viewId);
this->dismissViewNode(viewNode);
} else {
this->dismissPopover();
}
QVariantList args;
DoricPromise::resolve(getContext(), callbackId, args);
},
DoricThreadMode::UI);
}
void DoricPopoverPlugin::dismissViewNode(DoricViewNode *viewNode) {
if (viewNode != nullptr) {
getContext()->removeHeadNode(TYPE, viewNode);
viewNode->getNodeView()->setParent(nullptr);
viewNode->getNodeView()->setParentItem(nullptr);
viewNode->getNodeView()->deleteLater();
}
if (getContext()->allHeadNodes(TYPE).size() == 0) {
this->fullScreenView->setVisible(false);
}
}
void DoricPopoverPlugin::dismissPopover() {
foreach (DoricViewNode *node, getContext()->allHeadNodes(TYPE)) {
dismissViewNode(node);
}
}

View File

@@ -0,0 +1,27 @@
#ifndef DORICPOPOVERPLUGIN_H
#define DORICPOPOVERPLUGIN_H
#include "DoricNativePlugin.h"
#include <QQuickItem>
static QString TYPE = "popover";
class DoricPopoverPlugin : public DoricNativePlugin {
Q_OBJECT
public:
using DoricNativePlugin::DoricNativePlugin;
Q_INVOKABLE void show(QString jsValueString, QString callbackId);
Q_INVOKABLE void dismiss(QString jsValueString, QString callbackId);
private:
QQuickItem *fullScreenView = nullptr;
void dismissViewNode(DoricViewNode *node);
void dismissPopover();
};
#endif // DORICPOPOVERPLUGIN_H

View File

@@ -0,0 +1,36 @@
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include "../shader/DoricRootNode.h"
#include "DoricShaderPlugin.h"
void DoricShaderPlugin::render(QString jsValueString, QString callbackId) {
getContext()->getDriver()->asyncCall(
[this, jsValueString] {
try {
QJsonDocument document =
QJsonDocument::fromJson(jsValueString.toUtf8());
QJsonValue jsValue = document.object();
QString viewId = jsValue["id"].toString();
DoricRootNode *rootNode = getContext()->getRootNode();
if (rootNode->getId().isEmpty() &&
jsValue["type"].toString() == "Root") {
rootNode->setId(viewId);
rootNode->blend(jsValue["props"]);
rootNode->requestLayout();
} else {
DoricViewNode *viewNode = getContext()->targetViewNode(viewId);
if (viewNode != nullptr) {
viewNode->blend(jsValue["props"]);
viewNode->requestLayout();
}
}
} catch (...) {
qCritical() << "render exception";
}
},
DoricThreadMode::UI);
}

View File

@@ -0,0 +1,14 @@
#ifndef SHADERPLUGIN_H
#define SHADERPLUGIN_H
#include "DoricNativePlugin.h"
class DoricShaderPlugin : public DoricNativePlugin {
Q_OBJECT
public:
using DoricNativePlugin::DoricNativePlugin;
Q_INVOKABLE void render(QString jsValueString, QString callbackId);
};
#endif // SHADERPLUGIN_H

View File

@@ -0,0 +1,3 @@
<RCC>
</RCC>

View File

@@ -0,0 +1,312 @@
import QtQuick 2.12
import QtQuick.Layouts 1.15
import pub.doric.widget 1.0
Rectangle {
id: flex
property int minHeight: 0
property int minWidth: 0
property int flexShrink: 0
property int flexGrow: 0
property int marginTop: 0
property int marginLeft: 0
property int marginRight: 0
property int marginBottom: 0
property int paddingTop: 0
property int paddingLeft: 0
property int paddingRight: 0
property int paddingBottom: 0
property string alignContent: "auto"
property string alignItems: "auto"
property string alignSelf: "auto"
property string justifyContent: "flexStart"
property string display: "flex"
property string flexWrap: "noWrap"
property string flexDirection: "row"
FlexLayoutService {
id: flexLayoutService
}
function isFlex(child) {
if (typeof child.flexShrink === 'undefined') {
return false;
} else if (typeof child.flexGrow === 'undefined') {
return false;
} else if (typeof child.minHeight === 'undefined') {
return false;
} else if (typeof child.minWidth === 'undefined') {
return false;
} else if (typeof child.marginTop === 'undefined') {
return false;
} else if (typeof child.marginLeft === 'undefined') {
return false;
} else if (typeof child.marginRight === 'undefined') {
return false;
} else if (typeof child.marginBottom === 'undefined') {
return false;
} else if (typeof child.paddingTop === 'undefined') {
return false;
} else if (typeof child.paddingLeft === 'undefined') {
return false;
} else if (typeof child.paddingRight === 'undefined') {
return false;
} else if (typeof child.paddingBottom === 'undefined') {
return false;
} else if (typeof child.alignContent === 'undefined') {
return false;
} else if (typeof child.alignItems === 'undefined') {
return false;
} else if (typeof child.alignSelf === 'undefined') {
return false;
} else if (typeof child.justifyContent === 'undefined') {
return false;
} else if (typeof child.display === 'undefined') {
return false;
} else if (typeof child.flexWrap === 'undefined') {
return false;
} else if (typeof child.flexDirection === 'undefined') {
return false;
} else {
return true;
}
}
function setAlignContent(child, node) {
var align = child.alignContent;
if (align === "auto") {
node.setAlignContentAuto();
} else if (align === "flexStart") {
node.setAlignContentFlexStart();
} else if (align === "center") {
node.setAlignContentCenter();
} else if (align === "flexEnd") {
node.setAlignContentFlexEnd();
} else if (align === "stretch") {
node.setAlignContentStretch();
} else if (align === "baseline") {
node.setAlignContentBaseline();
} else if (align === "spaceBetween") {
node.setAlignContentSpaceBetween();
} else if (align === "spaceAround") {
node.setAlignContentSpaceAround();
} else {
throw "setAlignContent invalid param";
}
}
function setAlignItems(child, node) {
var align = child.alignItems;
if (align === "auto") {
node.setAlignItemsAuto();
} else if (align === "flexStart") {
node.setAlignItemsFlexStart();
} else if (align === "center") {
node.setAlignItemsCenter();
} else if (align === "flexEnd") {
node.setAlignItemsFlexEnd();
} else if (align === "stretch") {
node.setAlignItemsStretch();
} else if (align === "baseline") {
node.setAlignItemsBaseline();
} else if (align === "spaceBetween") {
node.setAlignItemsSpaceBetween();
} else if (align === "spaceAround") {
node.setAlignItemsSpaceAround();
} else {
throw "setAlignItems invalid param";
}
}
function setAlignSelf(child, node) {
var align = child.alignSelf;
if (align === "auto") {
node.setAlignSelfAuto();
} else if (align === "flexStart") {
node.setAlignSelfFlexStart();
} else if (align === "center") {
node.setAlignSelfCenter();
} else if (align === "flexEnd") {
node.setAlignSelfFlexEnd();
} else if (align === "stretch") {
node.setAlignSelfStretch();
} else if (align === "baseline") {
node.setAlignSelfBaseline();
} else if (align === "spaceBetween") {
node.setAlignSelfSpaceBetween();
} else if (align === "spaceAround") {
node.setAlignSelfSpaceAround();
} else {
throw "setAlignSelf invalid param";
}
}
function setDisplay(child, node) {
var display = child.display;
if (display === "flex") {
node.setDisplayFlex();
} else if (display === "none") {
node.setDisplayNone();
} else {
throw "setDisplay invalid param";
}
}
function setJustifyContent(child, node) {
var justify = child.justifyContent;
if (justify === "center") {
node.setJustifyCenter();
} else if (justify === "flexEnd") {
node.setJustifyFlexEnd();
} else if (justify === "flexStart") {
node.setJustifyFlexStart();
} else if (justify === "spaceAround") {
node.setJustifySpaceAround();
} else if (justify === "spaceEvenly") {
node.setJustifySpaceEvenly();
} else if (justify === "spaceBetween") {
node.setJustifySpaceBetween();
} else {
throw "setJustifyContent invalid param";
}
}
function setFlexWrap(child, node) {
var wrap = child.flexWrap;
if (wrap === "wrap") {
node.setWrap();
} else if (wrap === "noWrap") {
node.setNoWrap();
} else if (wrap === "wrapReverse") {
node.setWrapReverse();
} else {
throw "setFlexWrap invalid param";
}
}
function setFlexDirection(child, node) {
var direction = child.flexDirection;
if (direction === "row") {
node.setFlexDirectionRow();
} else if (direction === "column") {
node.setFlexDirectionColumn();
} else if (direction === "rowReverse") {
node.setFlexDirectionRowReverse();
} else if (direction === "columnReverse") {
node.setFlexDirectionColumnReverse();
} else {
throw "setFlexDirection invalid param";
}
}
function setOtherNodeProps(child, node) {
node.minHeight = child.minHeight;
node.minWidth = child.minWidth;
node.flexShrink = child.flexShrink;
node.flexGrow = child.flexGrow;
node.marginTop = child.marginTop;
node.marginLeft = child.marginLeft;
node.marginRight = child.marginRight;
node.marginBottom = child.marginBottom;
node.paddingTop = child.paddingTop;
node.paddingLeft = child.paddingLeft;
node.paddingRight = child.paddingRight;
node.paddingBottom = child.paddingBottom;
node.height = child.height;
node.width = child.width;
}
function setDefaultNodeProps(child, node) {
node.minHeight = 9999;
node.minWidth = 0;
node.flexShrink = 0;
node.flexGrow = 0;
node.marginTop = 0;
node.marginLeft = 0;
node.marginRight = 0;
node.marginBottom = 0;
node.paddingTop = 0;
node.paddingLeft = 0;
node.paddingRight = 0;
node.paddingBottom = 0;
node.height = child.height;
node.width = child.width;
node.setDisplayFlex();
node.setAlignSelfAuto();
node.setAlignItemsAuto();
node.setAlignContentAuto();
node.setJustifySpaceBetween();
node.setNoWrap();
node.setFlexDirectionRow();
}
function processNode(child, node) {
setOtherNodeProps(child, node, true);
setJustifyContent(child, node);
setFlexDirection(child, node);
setAlignContent(child, node);
setAlignItems(child, node);
setAlignSelf(child, node);
setFlexWrap(child, node);
setDisplay(child, node);
}
function updatePositions() {
if (flex.height !== 0 && flex.width !== 0) {
var rootNode = flexLayoutService.createNode();
processNode(flex, rootNode);
var nodes = []
var node = {}
var child = {}
var i = 0;
for (i = 0; i !== flex.children.length; i++) {
node = flexLayoutService.createNode();
child = flex.children[i];
if (isFlex(child)) {
processNode(child, node);
} else {
setDefaultNodeProps(child, node);
}
nodes.push(node);
}
rootNode.appendChildren(nodes);
rootNode.calculateLayoutLtr(flex.width, flex.height);
/* console.log(JSON.stringify({root: rootNode})); */
for (i = 0; i !== flex.children.length; i++) {
node = nodes[i];
flex.children[i].x = node.getLayoutLeft();
flex.children[i].y = node.getLayoutTop();
flex.children[i].width = node.getLayoutWidth();
flex.children[i].height = node.getLayoutHeight();
/* console.log(JSON.stringify(node)); */
}
flexLayoutService.collectGarbage(rootNode);
return true;
} else {
return false;
}
}
onChildrenChanged: updatePositions();
onWidthChanged: updatePositions();
onHeightChanged: updatePositions();
}

View File

@@ -0,0 +1,55 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: window
flags: flags | Qt.WindowStaysOnTopHint | Qt.Tool | Qt.FramelessWindowHint
visible: true
modality: Qt.ApplicationModal
property var pointer
property var plugin
property var callbackId
property var title
property var msg
property var okLabel
onTitleChanged: {
dialog.title = title
}
onMsgChanged: {
content.text = msg
}
onOkLabelChanged: {
dialog.standardButton(Dialog.Ok).text = qsTrId(okLabel)
}
Dialog {
id: dialog
standardButtons: Dialog.Ok
modal: true
contentItem: Text {
id: content
}
onAccepted: {
dialogBridge.onAccepted(pointer, plugin, callbackId)
}
onWidthChanged: {
window.width = implicitWidth
}
onHeightChanged: {
window.height = implicitHeight
}
}
Component.onCompleted: {
dialog.open()
}
}

View File

@@ -0,0 +1,64 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: window
flags: flags | Qt.WindowStaysOnTopHint | Qt.Tool | Qt.FramelessWindowHint
visible: true
modality: Qt.ApplicationModal
property var pointer
property var plugin
property var callbackId
property var title
property var msg
property var okLabel
property var cancelLabel
onTitleChanged: {
dialog.title = title
}
onMsgChanged: {
content.text = msg
}
onOkLabelChanged: {
dialog.standardButton(Dialog.Ok).text = qsTrId(okLabel)
}
onCancelLabelChanged: {
dialog.standardButton(Dialog.Cancel).text = qsTrId(cancelLabel)
}
Dialog {
id: dialog
standardButtons: Dialog.Ok | Dialog.Cancel
modal: true
contentItem: Text {
id: content
}
onAccepted: {
dialogBridge.onAccepted(pointer, plugin, callbackId)
}
onRejected: {
dialogBridge.onRejected(pointer, plugin, callbackId)
}
onWidthChanged: {
window.width = implicitWidth
}
onHeightChanged: {
window.height = implicitHeight
}
}
Component.onCompleted: {
dialog.open()
}
}

View File

@@ -0,0 +1,32 @@
// gravity.mjs
export function enumerate() {
const SPECIFIED = 1;
const START = 1 << 1;
const END = 1 << 2;
const SHIFT_X = 0;
const SHIFT_Y = 4;
const LEFT = (START | SPECIFIED) << SHIFT_X;
const RIGHT = (END | SPECIFIED) << SHIFT_X;
const TOP = (START | SPECIFIED) << SHIFT_Y;
const BOTTOM = (END | SPECIFIED) << SHIFT_Y;
const CENTER_X = SPECIFIED << SHIFT_X;
const CENTER_Y = SPECIFIED << SHIFT_Y;
const CENTER = CENTER_X | CENTER_Y;
var gravity = {
SPECIFIED,
START,
END,
SHIFT_X,
SHIFT_Y,
LEFT,
RIGHT,
TOP,
BOTTOM,
CENTER_X,
CENTER_Y,
CENTER
}
return gravity
}

View File

@@ -0,0 +1,74 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.12
import "util.mjs" as Util
Rectangle {
property var wrapper
clip: true
property var uuid: Util.uuidv4()
property var tag: "HLayout"
onWidthChanged: {
console.log(tag, uuid + " onWidthChanged: " + this.width)
}
onHeightChanged: {
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
color: 'transparent'
property var backgroundColor
onBackgroundColorChanged: {
color = backgroundColor
}
property var borderWidth: 0
onBorderWidthChanged: {
border.width = borderWidth
}
property var borderColor: ""
onBorderColorChanged: {
border.color = borderColor
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(tag, uuid + " wrapper: " + wrapper)
mouseAreaBridge.onClick(wrapper)
}
}
property var shadowColor
property var shadowRadius
property var shadowOffsetX
property var shadowOffsetY
property var shadowOpacity
onShadowOpacityChanged: {
if (shadowOpacity > 0) {
layer.enabled = true
} else {
layer.enabled = false
}
}
layer.enabled: false
layer.effect: DropShadow {
horizontalOffset: shadowOffsetX
verticalOffset: shadowOffsetY
radius: shadowRadius
samples: 16
color: shadowColor
transparentBorder: true
}
}

View File

@@ -0,0 +1,103 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import "util.mjs" as Util
import QtGraphicalEffects 1.12
AnimatedImage {
property var wrapper
property var uuid: Util.uuidv4()
property var tag: "Image"
Rectangle {
id: bg
color: "transparent"
}
onSourceChanged: {
console.log(tag, uuid + " onSourceChanged: " + this.source)
}
onStatusChanged: {
if (this.status === Image.Null) {
console.log(tag, uuid + " onStatusChanged: Image.Null")
imageBridge.onNull(wrapper);
} else if (this.status === Image.Ready) {
console.log(tag, uuid + " onStatusChanged: Image.Ready")
if (this.width !== 0 && this.height !== 0 && this.status === Image.Ready) {
imageBridge.onReady(wrapper);
}
} else if (this.status === Image.Loading) {
console.log(tag, uuid + " onStatusChanged: Image.Loading")
imageBridge.onLoading(wrapper);
} else if (this.status === Image.Error) {
console.log(tag, uuid + " onStatusChanged: Image.Error")
imageBridge.onError(wrapper);
}
}
onProgressChanged: {
console.log(tag, uuid + " onProgressChanged: " + this.progress)
}
onWidthChanged: {
console.log(tag, uuid + " onWidthChanged: " + this.width)
bg.width = this.width
if (this.width !== 0 && this.height !== 0 && this.status === Image.Ready) {
imageBridge.onReady(wrapper);
}
}
onHeightChanged: {
console.log(tag, uuid + " onHeightChanged: " + this.height)
bg.height = this.height
if (this.width !== 0 && this.height !== 0 && this.status === Image.Ready) {
imageBridge.onReady(wrapper);
}
}
property var backgroundColor
onBackgroundColorChanged: {
bg.color = backgroundColor
}
property var borderWidth: 0
onBorderWidthChanged: {
bg.border.width = borderWidth
}
property var borderColor: ""
onBorderColorChanged: {
bg.border.color = borderColor
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(tag, uuid + " wrapper: " + wrapper)
mouseAreaBridge.onClick(wrapper)
}
}
property var isBlur: false
onIsBlurChanged: {
console.log(tag, uuid + " onIsBlurChanged: " + this.isBlur)
if (isBlur) {
this.layer.enabled = true
} else {
this.layer.enabled = false
}
}
layer.enabled: false
layer.effect: FastBlur {
radius: 50
transparentBorder: true
}
}

View File

@@ -0,0 +1,10 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
Rectangle {
property var backgroundColor
onBackgroundColorChanged: {
color = backgroundColor
}
}

View File

@@ -0,0 +1,72 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
ApplicationWindow {
id: window
flags: flags | Qt.WindowStaysOnTopHint | Qt.Tool | Qt.FramelessWindowHint
visible: true
modality: Qt.ApplicationModal
property var pointer
property var plugin
property var callbackId
property var title
property var msg
property var okLabel
property var cancelLabel
onTitleChanged: {
dialog.title = title
}
onMsgChanged: {
content.text = msg
}
onOkLabelChanged: {
dialog.standardButton(Dialog.Ok).text = qsTrId(okLabel)
}
onCancelLabelChanged: {
dialog.standardButton(Dialog.Cancel).text = qsTrId(cancelLabel)
}
Dialog {
id: dialog
standardButtons: Dialog.Ok | Dialog.Cancel
modal: true
contentItem: ColumnLayout {
Text {
id: content
}
TextArea {
id: input
Layout.fillWidth: true
}
}
onAccepted: {
dialogBridge.onAcceptedWithInput(pointer, plugin, callbackId, input.text)
}
onRejected: {
dialogBridge.onRejectedWithInput(pointer, plugin, callbackId, input.text)
}
onWidthChanged: {
window.width = implicitWidth
}
onHeightChanged: {
window.height = implicitHeight
}
}
Component.onCompleted: {
dialog.open()
}
}

View File

@@ -0,0 +1,73 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.15
import "util.mjs" as Util
ScrollView {
property var wrapper
property var uuid: Util.uuidv4()
property var tag: "Scroller"
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
clip: true
background: Rectangle {
id: bg
color: 'transparent'
}
property var backgroundColor
onBackgroundColorChanged: {
bg.color = backgroundColor
}
property var borderWidth: 0
onBorderWidthChanged: {
bg.border.width = borderWidth
}
property var borderColor: ""
onBorderColorChanged: {
bg.border.color = borderColor
}
onWidthChanged: {
bg.implicitWidth = width
console.log(tag, uuid + " onWidthChanged: " + this.width)
}
onHeightChanged: {
bg.implicitHeight = height
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
onImplicitWidthChanged: {
console.log(tag, uuid + " onImplicitWidthChanged: " + this.implicitWidth)
}
onImplicitHeightChanged: {
console.log(tag, uuid + " onImplicitHeightChanged: " + this.implicitHeight)
}
onContentWidthChanged: {
console.log(tag, uuid + " onContentWidthChanged: " + this.contentWidth)
}
onContentHeightChanged: {
console.log(tag, uuid + " onContentHeightChanged: " + this.contentHeight)
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(tag, uuid + " wrapper: " + wrapper)
mouseAreaBridge.onClick(wrapper)
}
}
}

View File

@@ -0,0 +1,74 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.12
import "util.mjs" as Util
Rectangle {
property var wrapper
clip: true
property var uuid: Util.uuidv4()
property var tag: "Stack"
onWidthChanged: {
console.log(tag, uuid + " onWidthChanged: " + this.width)
}
onHeightChanged: {
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
color: 'transparent'
property var backgroundColor
onBackgroundColorChanged: {
color = backgroundColor
}
property var borderWidth: 0
onBorderWidthChanged: {
border.width = borderWidth
}
property var borderColor: ""
onBorderColorChanged: {
border.color = borderColor
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(tag, uuid + " wrapper: " + wrapper)
mouseAreaBridge.onClick(wrapper)
}
}
property var shadowColor
property var shadowRadius
property var shadowOffsetX
property var shadowOffsetY
property var shadowOpacity
onShadowOpacityChanged: {
if (shadowOpacity > 0) {
layer.enabled = true
} else {
layer.enabled = false
}
}
layer.enabled: false
layer.effect: DropShadow {
horizontalOffset: shadowOffsetX
verticalOffset: shadowOffsetY
radius: shadowRadius
samples: 16
color: shadowColor
transparentBorder: true
}
}

View File

@@ -0,0 +1,88 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import "util.mjs" as Util
import "gravity.mjs" as Gravity
TextArea {
property var wrapper
property var uuid: Util.uuidv4()
property var tag: "Text"
readOnly: true
leftPadding: 0
topPadding: 0
rightPadding: 0
bottomPadding: 0
property int textAlignment: 0
background: Rectangle {
id: bg
color: 'transparent'
}
property var backgroundColor
onBackgroundColorChanged: {
bg.color = backgroundColor
}
horizontalAlignment: TextInput.AlignHCenter
verticalAlignment: TextInput.AlignVCenter
onTextAlignmentChanged: {
let gravity = Gravity.enumerate()
let result = this.textAlignment | gravity.CENTER_Y
console.log(tag, uuid + " onTextAlignmentChanged: " + this.textAlignment)
switch(result) {
case gravity.CENTER:
this.horizontalAlignment = TextInput.AlignHCenter
this.verticalAlignment = TextInput.AlignVCenter
break
}
}
onWidthChanged: {
bg.implicitWidth = width
console.log(tag, uuid + " onWidthChanged: " + this.width)
let tempText = this.text
this.text = ""
this.text = tempText
}
onHeightChanged: {
bg.implicitHeight = height
console.log(tag, uuid + " onHeightChanged: " + this.height)
let tempText = this.text
this.text = ""
this.text = tempText
}
onTextChanged: {
console.log(tag, uuid + " onTextChanged: " + this.text)
}
property var borderWidth: 0
onBorderWidthChanged: {
bg.border.width = borderWidth
}
property var borderColor: ""
onBorderColorChanged: {
bg.border.color = borderColor
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(tag, uuid + " wrapper: " + wrapper)
mouseAreaBridge.onClick(wrapper)
}
}
}

View File

@@ -0,0 +1,33 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.15
ApplicationWindow {
id: window
flags: flags | Qt.WindowStaysOnTopHint | Qt.Tool | Qt.FramelessWindowHint | Qt.WindowTransparentForInput
color: "#bb000000"
visible: true
ColumnLayout {
Text {
text: "toast"
font.pixelSize: 20
color: 'white'
Layout.leftMargin: 5
Layout.rightMargin: 5
Layout.topMargin: 15
Layout.bottomMargin: 15
}
onWidthChanged: {
window.width = implicitWidth
}
onHeightChanged: {
window.height = implicitHeight
}
}
}

View File

@@ -0,0 +1,8 @@
// util.mjs
export function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}

View File

@@ -0,0 +1,7 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
Rectangle {
width: childrenRect.width
height: childrenRect.height
}

View File

@@ -0,0 +1,74 @@
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.12
import "util.mjs" as Util
Rectangle {
property var wrapper
clip: true
property var uuid: Util.uuidv4()
property var tag: "VLayout"
onWidthChanged: {
console.log(tag, uuid + " onWidthChanged: " + this.width)
}
onHeightChanged: {
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
color: 'transparent'
property var backgroundColor
onBackgroundColorChanged: {
color = backgroundColor
}
property var borderWidth: 0
onBorderWidthChanged: {
border.width = borderWidth
}
property var borderColor: ""
onBorderColorChanged: {
border.color = borderColor
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(tag, uuid + " wrapper: " + wrapper)
mouseAreaBridge.onClick(wrapper)
}
}
property var shadowColor
property var shadowRadius
property var shadowOffsetX
property var shadowOffsetY
property var shadowOpacity
onShadowOpacityChanged: {
if (shadowOpacity > 0) {
layer.enabled = true
} else {
layer.enabled = false
}
}
layer.enabled: false
layer.effect: DropShadow {
horizontalOffset: shadowOffsetX
verticalOffset: shadowOffsetY
radius: shadowRadius
samples: 16
color: shadowColor
transparentBorder: true
}
}

View File

@@ -0,0 +1,155 @@
#include "DoricGroupNode.h"
void DoricGroupNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
if (name == "children") {
mChildViewIds.clear();
if (prop.isArray()) {
QJsonArray array = prop.toArray();
const int length = array.size();
for (int i = 0; i < length; ++i) {
QJsonValue value = array.at(i);
if (value.isString()) {
mChildViewIds.append(value.toString());
}
}
}
} else {
DoricSuperNode::blend(view, name, prop);
}
}
void DoricGroupNode::blend(QJsonValue jsValue) {
DoricViewNode::blend(jsValue);
}
void DoricGroupNode::afterBlended(QJsonValue props) { configChildNode(); }
void DoricGroupNode::configChildNode() {
QQuickItem *parent = mView;
for (int idx = 0; idx < mChildViewIds.size(); idx++) {
QString id = mChildViewIds.at(idx);
QJsonValue model = getSubModel(id);
if (model.isUndefined()) {
DoricRegistry *registry = getContext()->getDriver()->getRegistry();
qCritical() << "model.isUndefined()";
continue;
}
QString type = model["type"].toString();
if (idx < mChildNodes.size()) {
DoricViewNode *oldNode = mChildNodes.at(idx);
if (id == oldNode->getId()) {
// The same, skip
} else {
if (mReusable) {
if (oldNode->getType() == type) {
// Same type,can be reused
oldNode->setId(id);
oldNode->blend(model["props"]);
} else {
// Replace this view
mChildNodes.removeAt(idx);
oldNode->getNodeView()->setParent(nullptr);
oldNode->getNodeView()->setParentItem(nullptr);
oldNode->getNodeView()->deleteLater();
DoricViewNode *newNode = DoricViewNode::create(getContext(), type);
if (newNode != nullptr) {
newNode->setId(id);
newNode->init(this);
if (idx >= mChildNodes.size()) {
mChildNodes.append(newNode);
newNode->getNodeView()->setParentItem(parent);
} else {
mChildNodes.insert(idx, newNode);
newNode->getNodeView()->setParentItem(parent);
newNode->getNodeView()->stackBefore(
parent->childItems().at(idx));
}
newNode->blend(model["props"]);
}
}
} else {
// Find in remain nodes
int position = -1;
for (int start = idx + 1; start < mChildNodes.size(); start++) {
DoricViewNode *node = mChildNodes.at(start);
if (id == node->getId()) {
// Found
position = start;
break;
}
}
if (position >= 0) {
// Found swap idx,position
mChildNodes.swapItemsAt(position, idx);
parent->childItems().swapItemsAt(position, idx);
} else {
// Not found,insert
DoricViewNode *newNode = DoricViewNode::create(getContext(), type);
if (newNode != nullptr) {
newNode->setId(id);
newNode->init(this);
if (idx >= mChildNodes.size()) {
mChildNodes.append(newNode);
newNode->getNodeView()->setParentItem(parent);
} else {
mChildNodes.insert(idx, newNode);
newNode->getNodeView()->setParentItem(parent);
newNode->getNodeView()->stackBefore(
parent->childItems().at(idx));
}
newNode->blend(model["props"]);
}
}
}
}
} else {
// Insert
DoricViewNode *newNode = DoricViewNode::create(getContext(), type);
if (newNode != nullptr) {
newNode->setId(id);
newNode->init(this);
if (idx >= mChildNodes.size()) {
mChildNodes.append(newNode);
newNode->getNodeView()->setParentItem(parent);
} else {
mChildNodes.insert(idx, newNode);
newNode->getNodeView()->setParentItem(parent);
newNode->getNodeView()->stackBefore(parent->childItems().at(idx));
}
newNode->blend(model["props"]);
}
}
}
int size = mChildNodes.size();
for (int idx = mChildViewIds.size(); idx < size; idx++) {
DoricViewNode *viewNode = mChildNodes.at(mChildViewIds.size());
mChildNodes.removeAt(mChildViewIds.size());
viewNode->getNodeView()->setParent(nullptr);
viewNode->getNodeView()->setParentItem(nullptr);
viewNode->getNodeView()->deleteLater();
}
}
void DoricGroupNode::blendSubNode(QJsonValue subProperties) {
QString subNodeId = subProperties["id"].toString();
for (DoricViewNode *node : mChildNodes) {
if (subNodeId == node->getId()) {
node->blend(subProperties["props"]);
break;
}
}
}
void DoricGroupNode::requestLayout() {
DoricSuperNode::requestLayout();
foreach (DoricViewNode *node, this->mChildNodes) { node->requestLayout(); }
}

View File

@@ -0,0 +1,28 @@
#ifndef DORICGROUPNODE_H
#define DORICGROUPNODE_H
#include "DoricSuperNode.h"
class DoricGroupNode : public DoricSuperNode {
public:
using DoricSuperNode::DoricSuperNode;
virtual void blend(QQuickItem *view, QString name, QJsonValue prop) override;
virtual void blend(QJsonValue jsValue) override;
protected:
QList<DoricViewNode *> mChildNodes;
QList<QString> mChildViewIds;
void configChildNode();
virtual void blendSubNode(QJsonValue subProperties) override;
virtual void afterBlended(QJsonValue props) override;
virtual void requestLayout() override;
};
#endif // DORICGROUPNODE_H

View File

@@ -0,0 +1,31 @@
#include "DoricHLayoutNode.h"
QQuickItem *DoricHLayoutNode::build() {
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/hlayout.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
getLayouts()->setLayoutType(DoricLayoutType::DoricHLayout);
item->setProperty("wrapper", QString::number((qint64)this));
return item;
}
void DoricHLayoutNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
QQuickItem *container = view;
if (name == "space") {
getLayouts()->setSpacing(prop.toDouble());
} else if (name == "gravity") {
getLayouts()->setGravity(prop.toInt());
} else {
DoricGroupNode::blend(view, name, prop);
}
}

View File

@@ -0,0 +1,16 @@
#ifndef DORICHLAYOUTNODE_H
#define DORICHLAYOUTNODE_H
#include "DoricGroupNode.h"
class DoricHLayoutNode : public DoricGroupNode {
public:
using DoricGroupNode::DoricGroupNode;
QQuickItem *build() override;
virtual void blend(QQuickItem *view, QString name, QJsonValue prop) override;
};
#endif // DORICHLAYOUTNODE_H

View File

@@ -0,0 +1,79 @@
#include "DoricImageNode.h"
#include "DoricSuperNode.h"
#include "../utils/DoricUtils.h"
#include <QQuickItem>
QQuickItem *DoricImageNode::build() {
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/image.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
item->setProperty("wrapper", QString::number((qint64)this));
return item;
}
void DoricImageNode::blend(QJsonValue jsValue) {
if (jsValue.toObject().contains("scaleType"))
this->contentMode = jsValue["scaleType"].toInt();
if (jsValue.toObject().contains("placeHolderColor"))
this->placeHolderColor = jsValue["placeHolderColor"].toInt();
if (jsValue.toObject().contains("errorColor"))
this->errorColor = jsValue["errorColor"].toInt();
if (jsValue.toObject().contains("loadCallback"))
this->loadCallbackId = jsValue["loadCallback"].toString();
DoricViewNode::blend(jsValue);
}
void DoricImageNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
QQuickItem *container = view;
if (name == "imageUrl") {
container->setProperty("fillMode", this->contentMode);
container->setProperty("source", prop.toString());
} else if (name == "imageBase64") {
container->setProperty("fillMode", this->contentMode);
container->setProperty("source", prop.toString());
} else if (name == "isBlur") {
if (prop.toBool()) {
container->setProperty("isBlur", prop.toBool());
}
} else {
DoricViewNode::blend(view, name, prop);
}
}
void DoricImageNode::onReady() {
if (!this->loadCallbackId.isEmpty()) {
QVariantList args;
QMap<QString, QVariant> map;
map.insert("width", mView->width());
map.insert("height", mView->height());
args.append(QVariant::fromValue(map));
this->callJSResponse(this->loadCallbackId, args);
}
DoricSuperNode *node = this->mSuperNode;
while (node->mSuperNode != nullptr) {
node = node->mSuperNode;
}
node->requestLayout();
}
void DoricImageNode::onError() {
if (!this->loadCallbackId.isEmpty()) {
QVariantList args;
this->callJSResponse(this->loadCallbackId, args);
}
}

View File

@@ -0,0 +1,30 @@
#ifndef DORICIMAGENODE_H
#define DORICIMAGENODE_H
#include "DoricViewNode.h"
class DoricImageNode : public DoricViewNode {
public:
using DoricViewNode::DoricViewNode;
QQuickItem *build() override;
virtual void blend(QJsonValue jsValue) override;
virtual void blend(QQuickItem *view, QString name, QJsonValue prop) override;
void onReady();
void onError();
private:
QString loadCallbackId = "";
int contentMode = 0;
int placeHolderColor = -1;
int errorColor = -1;
};
#endif // DORICIMAGENODE_H

View File

@@ -0,0 +1,15 @@
#include "DoricRootNode.h"
void DoricRootNode::setRootView(QQuickItem *rootView) {
this->mView = rootView;
this->createLayouts(rootView);
this->getLayouts()->setLayoutType(DoricLayoutType::DoricStack);
}
QQuickItem *DoricRootNode::getRootView() { return mView; }
void DoricRootNode::requestLayout() {
getLayouts()->apply();
DoricStackNode::requestLayout();
}

View File

@@ -0,0 +1,19 @@
#ifndef ROOTNODE_H
#define ROOTNODE_H
#include <QQuickItem>
#include "DoricStackNode.h"
class DoricRootNode : public DoricStackNode {
public:
using DoricStackNode::DoricStackNode;
void setRootView(QQuickItem *rootView);
QQuickItem *getRootView();
virtual void requestLayout() override;
};
#endif // ROOTNODE_H

View File

@@ -0,0 +1,119 @@
#include "DoricScrollerNode.h"
QQuickItem *DoricScrollerNode::build() {
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/scroller.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
item->setProperty("wrapper", QString::number((qint64)this));
return item;
}
void DoricScrollerNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
if (name == "content") {
if (!prop.isString()) {
return;
}
mChildViewId = prop.toString();
} else if (name == "onScroll") {
if (!prop.isString()) {
return;
}
onScrollFuncId = prop.toString();
} else if (name == "onScrollEnd") {
if (!prop.isString()) {
return;
}
onScrollEndFuncId = prop.toString();
} else {
DoricSuperNode::blend(view, name, prop);
}
}
void DoricScrollerNode::afterBlended(QJsonValue jsValue) {
QJsonValue contentModel = getSubModel(mChildViewId);
if (contentModel == QJsonValue::Undefined) {
return;
}
QString viewId = contentModel["id"].toString();
QString type = contentModel["type"].toString();
QJsonValue props = contentModel["props"];
QQuickItem *parent = mView;
if (mChildNode != nullptr) {
if (viewId == mChildNode->getId()) {
// skip
} else {
if (mReusable && mChildNode->getType() == type) {
mChildNode->setId(viewId);
mChildNode->blend(props);
} else {
// remove all views
for (int i = 0; i != parent->childItems().size(); i++) {
parent->childItems().at(i)->setParent(nullptr);
parent->childItems().at(i)->setParentItem(nullptr);
parent->childItems().at(i)->deleteLater();
}
mChildNode = DoricViewNode::create(getContext(), type);
mChildNode->setId(viewId);
mChildNode->init(this);
mChildNode->blend(props);
QQmlListProperty<QQuickItem> contentChildren =
qvariant_cast<QQmlListProperty<QQuickItem>>(
parent->property("contentChildren"));
contentChildren.append(&contentChildren, mChildNode->getNodeView());
}
}
} else {
mChildNode = DoricViewNode::create(getContext(), type);
mChildNode->setId(viewId);
mChildNode->init(this);
mChildNode->blend(props);
QQmlListProperty<QQuickItem> contentChildren =
qvariant_cast<QQmlListProperty<QQuickItem>>(
parent->property("contentChildren"));
contentChildren.append(&contentChildren, mChildNode->getNodeView());
}
}
void DoricScrollerNode::requestLayout() {
this->mChildNode->requestLayout();
DoricLayouts *layout = (DoricLayouts *)(mChildNode->getNodeView()
->property("doricLayout")
.toULongLong());
if (layout != nullptr) {
layout->apply(QSizeF(mView->width(), mView->height()));
mView->setProperty("contentWidth", layout->getMeasuredWidth());
mView->setProperty("contentHeight", layout->getMeasuredHeight());
}
}
void DoricScrollerNode::blendSubNode(QJsonValue subProperties) {
if (mChildNode != nullptr) {
mChildNode->blend(subProperties["props"]);
}
}
QSizeF DoricScrollerNode::sizeThatFits(QSizeF size) {
DoricLayouts *layout = (DoricLayouts *)mChildNode->getNodeView()
->property("doricLayout")
.toULongLong();
layout->apply(size);
return QSizeF(qMin(size.width(), layout->getMeasuredWidth()),
qMin(size.height(), layout->getMeasuredHeight()));
}

View File

@@ -0,0 +1,30 @@
#ifndef DORICSCROLLERNODE_H
#define DORICSCROLLERNODE_H
#include "DoricSuperNode.h"
class DoricScrollerNode : public DoricSuperNode {
private:
DoricViewNode *mChildNode = nullptr;
QString mChildViewId;
QString onScrollFuncId;
QString onScrollEndFuncId;
public:
using DoricSuperNode::DoricSuperNode;
QQuickItem *build() override;
virtual void blend(QQuickItem *view, QString name, QJsonValue prop) override;
virtual void blendSubNode(QJsonValue subProperties) override;
virtual void afterBlended(QJsonValue jsValue) override;
virtual void requestLayout() override;
QSizeF sizeThatFits(QSizeF size);
};
#endif // DORICSCROLLERNODE_H

View File

@@ -0,0 +1,30 @@
#include "DoricStackNode.h"
QQuickItem *DoricStackNode::build() {
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/stack.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
getLayouts()->setLayoutType(DoricLayoutType::DoricStack);
item->setProperty("wrapper", QString::number((qint64)this));
return item;
}
void DoricStackNode::blendLayoutConfig(QJsonValue jsValue) {
DoricViewNode::blendLayoutConfig(jsValue);
QJsonValue maxWidth = jsValue["maxWidth"];
if (maxWidth.isDouble()) {
}
QJsonValue maxHeight = jsValue["maxHeight"];
if (maxHeight.isDouble()) {
}
}

View File

@@ -0,0 +1,15 @@
#ifndef DORICSTACKNODE_H
#define DORICSTACKNODE_H
#include "DoricGroupNode.h"
class DoricStackNode : public DoricGroupNode {
public:
using DoricGroupNode::DoricGroupNode;
QQuickItem *build() override;
void blendLayoutConfig(QJsonValue jsValue) override;
};
#endif // DORICSTACKNODE_H

View File

@@ -0,0 +1,56 @@
#include <QJSValueIterator>
#include "DoricSuperNode.h"
void DoricSuperNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
if (name == "subviews") {
if (prop.isArray()) {
QJsonArray array = prop.toArray();
const int length = array.size();
for (int i = 0; i < length; ++i) {
QJsonValue subNode = array.at(i);
mixinSubNode(subNode);
blendSubNode(subNode);
}
}
} else {
DoricViewNode::blend(view, name, prop);
}
}
void DoricSuperNode::mixinSubNode(QJsonValue subNode) {
QString id = subNode["id"].toString();
QList<QString> keys = subNodes.keys();
if (!keys.contains(id)) {
subNodes.insert(id, subNode);
} else {
mixin(subNode, subNodes.value(id));
}
}
void DoricSuperNode::mixin(QJsonValue src, QJsonValue target) {
QJsonValue srcProps = src["props"];
QJsonValue targetProps = target["props"];
foreach (const QString &key, srcProps.toObject().keys()) {
QJsonValue value = srcProps[key];
if (key == "subviews" && value.isArray()) {
} else {
targetProps.toObject().insert(key, value);
}
}
}
QJsonValue DoricSuperNode::getSubModel(QString id) {
if (subNodes.keys().contains(id)) {
return subNodes.value(id);
} else {
return QJsonValue::Undefined;
}
}
void DoricSuperNode::blendSubLayoutConfig(DoricViewNode *viewNode,
QJsonValue jsValue) {
viewNode->blendLayoutConfig(jsValue);
}

View File

@@ -0,0 +1,32 @@
#ifndef DORICSUPERNODE_H
#define DORICSUPERNODE_H
#include <QJsonArray>
#include "DoricViewNode.h"
class DoricSuperNode : public DoricViewNode {
private:
QMap<QString, QJsonValue> subNodes;
protected:
virtual void blend(QQuickItem *view, QString name, QJsonValue prop) override;
virtual void blendSubNode(QJsonValue subProperties) = 0;
public:
using DoricViewNode::DoricViewNode;
bool mReusable = false;
QJsonValue getSubModel(QString id);
void blendSubLayoutConfig(DoricViewNode *viewNode, QJsonValue jsValue);
private:
void mixinSubNode(QJsonValue subNode);
void mixin(QJsonValue src, QJsonValue target);
};
#endif // DORICSUPERNODE_H

View File

@@ -0,0 +1,36 @@
#include "DoricTextNode.h"
#include "../utils/DoricUtils.h"
QQuickItem *DoricTextNode::build() {
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/text.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
item->setProperty("wrapper", QString::number((qint64)this));
return item;
}
void DoricTextNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
if (name == "text") {
view->setProperty("text", prop.toString());
} else if (name == "textColor") {
QString color = DoricUtils::doricColor(prop.toInt()).name();
view->setProperty("color", color);
} else if (name == "textSize") {
QFont font = view->property("font").value<QFont>();
font.setPixelSize(prop.toInt());
view->setProperty("font", QVariant(font));
} else if (name == "textAlignment") {
view->setProperty("textAlignment", prop.toInt());
} else {
DoricViewNode::blend(view, name, prop);
}
}

View File

@@ -0,0 +1,15 @@
#ifndef DORICTEXTNODE_H
#define DORICTEXTNODE_H
#include "DoricViewNode.h"
class DoricTextNode : public DoricViewNode {
public:
using DoricViewNode::DoricViewNode;
QQuickItem *build() override;
virtual void blend(QQuickItem *view, QString name, QJsonValue prop) override;
};
#endif // DORICTEXTNODE_H

View File

@@ -0,0 +1,31 @@
#include "DoricVLayoutNode.h"
QQuickItem *DoricVLayoutNode::build() {
QQmlComponent component(getContext()->getQmlEngine());
const QUrl url(QStringLiteral("qrc:/doric/qml/vlayout.qml"));
component.loadUrl(url);
if (component.isError()) {
qCritical() << component.errorString();
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
getLayouts()->setLayoutType(DoricLayoutType::DoricVLayout);
item->setProperty("wrapper", QString::number((qint64)this));
return item;
}
void DoricVLayoutNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
QQuickItem *container = view;
if (name == "space") {
getLayouts()->setSpacing(prop.toDouble());
} else if (name == "gravity") {
getLayouts()->setGravity(prop.toInt());
} else {
DoricGroupNode::blend(view, name, prop);
}
}

View File

@@ -0,0 +1,15 @@
#ifndef DORICVLAYOUTNODE_H
#define DORICVLAYOUTNODE_H
#include "DoricGroupNode.h"
class DoricVLayoutNode : public DoricGroupNode {
public:
using DoricGroupNode::DoricGroupNode;
QQuickItem *build() override;
virtual void blend(QQuickItem *view, QString name, QJsonValue prop) override;
};
#endif // DORICVLAYOUTNODE_H

View File

@@ -0,0 +1,177 @@
#include "DoricViewNode.h"
#include "../utils/DoricConstant.h"
#include "../utils/DoricUtils.h"
#include "DoricSuperNode.h"
void DoricViewNode::blendLayoutConfig(QJsonValue jsValue) {
QJsonObject jsObject = jsValue.toObject();
if (jsObject.contains("widthSpec"))
getLayouts()->setWidthSpec(jsObject["widthSpec"].toInt());
if (jsObject.contains("heightSpec"))
getLayouts()->setHeightSpec(jsObject["heightSpec"].toInt());
if (jsObject.contains("margin")) {
QJsonObject margin = jsObject["margin"].toObject();
if (margin.contains("left"))
getLayouts()->setMarginLeft(margin["left"].toDouble());
if (margin.contains("top"))
getLayouts()->setMarginTop(margin["top"].toDouble());
if (margin.contains("right"))
getLayouts()->setMarginRight(margin["right"].toDouble());
if (margin.contains("bottom"))
getLayouts()->setMarginBottom(margin["bottom"].toDouble());
}
if (jsObject.contains("alignment"))
getLayouts()->setAlignment(jsObject["alignment"].toInt());
if (jsObject.contains("weight"))
getLayouts()->setWeight(jsObject["weight"].toInt());
if (jsObject.contains("maxWidth"))
getLayouts()->setMaxWidth(jsObject["maxWidth"].toDouble());
if (jsObject.contains("maxHeight"))
getLayouts()->setMaxHeight(jsObject["maxHeight"].toDouble());
if (jsObject.contains("minWidth"))
getLayouts()->setMinWidth(jsObject["minWidth"].toDouble());
if (jsObject.contains("minHeight"))
getLayouts()->setMinHeight(jsObject["minHeight"].toDouble());
}
void DoricViewNode::createLayouts(QQuickItem *view) {
if (mLayouts == nullptr) {
mLayouts = new DoricLayouts();
mLayouts->setWidth(view->width());
mLayouts->setHeight(view->height());
mLayouts->setView(view);
view->setProperty("doricLayout", QString::number((qint64)mLayouts));
}
}
DoricLayouts *DoricViewNode::getLayouts() { return mLayouts; }
void DoricViewNode::setLayoutConfig(QJsonValue layoutConfig) {
if (mSuperNode != nullptr) {
mSuperNode->blendSubLayoutConfig(this, layoutConfig);
} else {
blendLayoutConfig(layoutConfig);
}
}
void DoricViewNode::init(DoricSuperNode *superNode) {
if (DoricUtils:: instanceof <DoricSuperNode *>(this)) {
DoricSuperNode *thiz = dynamic_cast<DoricSuperNode *>(this);
thiz->mReusable = superNode->mReusable;
}
this->mSuperNode = superNode;
this->mView = build();
getLayouts();
}
QString DoricViewNode::getId() { return mId; }
void DoricViewNode::setId(QString id) { mId = id; }
QString DoricViewNode::getType() { return mType; }
QQuickItem *DoricViewNode::getNodeView() { return mView; }
void DoricViewNode::blend(QJsonValue jsValue) {
QJsonValue value = jsValue["layoutConfig"];
if (value.isObject()) {
setLayoutConfig(value);
}
foreach (const QString &key, jsValue.toObject().keys()) {
QJsonValue value = jsValue[key];
blend(mView, key, value);
}
this->afterBlended(jsValue);
}
void DoricViewNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
if (name == "width") {
getLayouts()->setWidth(prop.toDouble());
} else if (name == "height") {
getLayouts()->setHeight(prop.toDouble());
} else if (name == "backgroundColor") {
view->setProperty(
"backgroundColor",
QVariant::fromValue(DoricUtils::doricColor(prop.toInt())));
} else if (name == "x") {
getLayouts()->setMarginLeft(prop.toDouble());
} else if (name == "y") {
getLayouts()->setMarginTop(prop.toDouble());
} else if (name == "corners") {
view->setProperty("radius", prop.toDouble());
} else if (name == "onClick") {
if (prop.isString())
clickFunction = prop.toString();
} else if (name == "padding") {
getLayouts()->setPaddingLeft(prop["left"].toDouble());
getLayouts()->setPaddingRight(prop["right"].toDouble());
getLayouts()->setPaddingTop(prop["top"].toDouble());
getLayouts()->setPaddingBottom(prop["bottom"].toDouble());
} else if (name == "hidden") {
getLayouts()->setDisabled(prop.toBool());
} else if (name == "border") {
qreal borderWidth = prop["width"].toDouble();
QString borderColor = DoricUtils::doricColor(prop["color"].toInt()).name();
view->setProperty("borderWidth", borderWidth);
view->setProperty("borderColor", borderColor);
} else if (name == "shadow") {
view->setProperty("shadowColor", QVariant::fromValue(DoricUtils::doricColor(
prop["color"].toInt())));
view->setProperty("shadowRadius", prop["radius"].toDouble());
view->setProperty("shadowOffsetX", prop["offsetX"].toDouble());
view->setProperty("shadowOffsetY", prop["offsetY"].toDouble());
view->setProperty("shadowOpacity", prop["opacity"].toDouble());
} else if (name != "layoutConfig") {
qCritical() << name << ": " << prop.toString();
}
}
void DoricViewNode::afterBlended(QJsonValue prop) {}
QList<QString> DoricViewNode::getIdList() {
QList<QString> ids;
DoricViewNode *viewNode = this;
do {
ids.insert(0, viewNode->mId);
viewNode = viewNode->mSuperNode;
} while (viewNode != nullptr);
return ids;
}
void DoricViewNode::requestLayout() {}
void DoricViewNode::callJSResponse(QString funcId, QVariantList args) {
QVariantList nArgs;
QList<QString> idList = getIdList();
nArgs.append(QVariant(idList));
nArgs.append(funcId);
foreach (const QVariant &arg, args)
nArgs.append(arg);
return getContext()->callEntity(DoricConstant::DORIC_ENTITY_RESPONSE, nArgs);
}
void DoricViewNode::onClick() {
if (clickFunction.isEmpty()) {
return;
}
QVariantList args;
callJSResponse(clickFunction, args);
}

View File

@@ -0,0 +1,82 @@
#ifndef DORICVIEWNODE_H
#define DORICVIEWNODE_H
#include <QJsonObject>
#include <QJsonValue>
#include <QQuickItem>
#include "../utils/DoricContextHolder.h"
#include "../utils/DoricLayouts.h"
class DoricSuperNode;
class DoricViewNode : public DoricContextHolder {
protected:
QQuickItem *mView;
DoricLayouts *mLayouts = nullptr;
virtual QQuickItem *build() = 0;
void createLayouts(QQuickItem *view);
DoricLayouts *getLayouts();
void setLayoutConfig(QJsonValue layoutConfig);
private:
QString mId;
QList<QString> getIdList();
QString clickFunction;
public:
QString mType;
DoricSuperNode *mSuperNode = nullptr;
using DoricContextHolder::DoricContextHolder;
void init(DoricSuperNode *superNode);
static DoricViewNode *create(DoricContext *context, QString type) {
bool classRegistered =
context->getDriver()->getRegistry()->acquireNodeInfo(type);
if (classRegistered) {
QObject *node =
context->getDriver()->getRegistry()->nodes.createObject(type);
DoricViewNode *castNode = dynamic_cast<DoricViewNode *>(node);
castNode->setContext(context);
castNode->mType = type;
return castNode;
} else {
qCritical() << "DoricViewNode create error: " + type;
return nullptr;
}
}
QString getId();
void setId(QString id);
QString getType();
QQuickItem *getNodeView();
virtual void blend(QJsonValue jsValue);
virtual void blend(QQuickItem *view, QString name, QJsonValue prop);
virtual void afterBlended(QJsonValue prop);
virtual void blendLayoutConfig(QJsonValue jsObject);
virtual void requestLayout();
void onClick();
void callJSResponse(QString funcId, QVariantList args);
};
#endif // DORICVIEWNODE_H

View File

@@ -0,0 +1,20 @@
#ifndef SINGLETON_H
#define SINGLETON_H
#include <QDebug>
class DoricSingleton {
private:
static DoricSingleton *local_instance;
DoricSingleton() { qDebug() << "constructor"; }
~DoricSingleton() { qDebug() << "destructor"; }
public:
static DoricSingleton *getInstance() {
static DoricSingleton instance;
return &instance;
}
};
#endif // SINGLETON_H

View File

@@ -0,0 +1,38 @@
#include "DoricConstant.h"
const QString DoricConstant::DORIC_BUNDLE_SANDBOX = "doric-sandbox.js";
const QString DoricConstant::DORIC_BUNDLE_LIB = "doric-lib.js";
const QString DoricConstant::DORIC_MODULE_LIB = "doric";
const QString DoricConstant::INJECT_ENVIRONMENT = "Environment";
const QString DoricConstant::INJECT_LOG = "nativeLog";
const QString DoricConstant::INJECT_EMPTY = "nativeEmpty";
const QString DoricConstant::INJECT_REQUIRE = "nativeRequire";
const QString DoricConstant::INJECT_TIMER_SET = "nativeSetTimer";
const QString DoricConstant::INJECT_TIMER_CLEAR = "nativeClearTimer";
const QString DoricConstant::INJECT_BRIDGE = "nativeBridge";
const QString DoricConstant::TEMPLATE_CONTEXT_CREATE =
QString("Reflect.apply(") +
"function(doric,context,Entry,require,exports){" + "\n" + "%s1" + "\n" +
"},undefined,[" + "undefined," + "doric.jsObtainContext(\"%s2\")," +
"doric.jsObtainEntry(\"%s3\")," + "doric.__require__" + ",{}" + "])";
const QString DoricConstant::TEMPLATE_MODULE =
QString("Reflect.apply(doric.jsRegisterModule,this,[") + "\"%s1\"," +
"Reflect.apply(function(__module){" + "(function(module,exports,require){" +
"\n" + "%s2" + "\n" + "})(__module,__module.exports,doric.__require__);" +
"\nreturn __module.exports;" + "},this,[{exports:{}}])" + "])";
const QString DoricConstant::TEMPLATE_CONTEXT_DESTROY =
QString("doric.jsReleaseContext(\"%s\")");
const QString DoricConstant::GLOBAL_DORIC = "doric";
const QString DoricConstant::DORIC_CONTEXT_INVOKE = "jsCallEntityMethod";
const QString DoricConstant::DORIC_TIMER_CALLBACK = "jsCallbackTimer";
const QString DoricConstant::DORIC_BRIDGE_RESOLVE = "jsCallResolve";
const QString DoricConstant::DORIC_BRIDGE_REJECT = "jsCallReject";
const QString DoricConstant::DORIC_ENTITY_RESPONSE = "__response__";
const QString DoricConstant::DORIC_ENTITY_INIT = "__init__";
const QString DoricConstant::DORIC_ENTITY_CREATE = "__onCreate__";
const QString DoricConstant::DORIC_ENTITY_BUILD = "__build__";
const QString DoricConstant::DORIC_ENTITY_DESTROY = "__onDestroy__";

View File

@@ -0,0 +1,38 @@
#ifndef CONSTANT_H
#define CONSTANT_H
#include <QString>
class DoricConstant {
public:
static const QString DORIC_BUNDLE_SANDBOX;
static const QString DORIC_BUNDLE_LIB;
static const QString DORIC_MODULE_LIB;
static const QString INJECT_ENVIRONMENT;
static const QString INJECT_LOG;
static const QString INJECT_EMPTY;
static const QString INJECT_REQUIRE;
static const QString INJECT_TIMER_SET;
static const QString INJECT_TIMER_CLEAR;
static const QString INJECT_BRIDGE;
static const QString TEMPLATE_CONTEXT_CREATE;
static const QString TEMPLATE_MODULE;
static const QString TEMPLATE_CONTEXT_DESTROY;
static const QString GLOBAL_DORIC;
static const QString DORIC_CONTEXT_INVOKE;
static const QString DORIC_TIMER_CALLBACK;
static const QString DORIC_BRIDGE_RESOLVE;
static const QString DORIC_BRIDGE_REJECT;
static const QString DORIC_ENTITY_RESPONSE;
static const QString DORIC_ENTITY_CREATE;
static const QString DORIC_ENTITY_INIT;
static const QString DORIC_ENTITY_BUILD;
static const QString DORIC_ENTITY_DESTROY;
};
#endif // CONSTANT_H

View File

@@ -0,0 +1,9 @@
#include "DoricContextHolder.h"
DoricContextHolder::DoricContextHolder(QObject *parent) { mContext = NULL; }
void DoricContextHolder::setContext(DoricContext *context) {
mContext = context;
}
DoricContext *DoricContextHolder::getContext() { return mContext; }

View File

@@ -0,0 +1,18 @@
#ifndef DORICCONTEXTHOLDER_H
#define DORICCONTEXTHOLDER_H
#include "../DoricContext.h"
class DoricContextHolder : public QObject {
protected:
DoricContext *mContext = NULL;
public:
explicit DoricContextHolder(QObject *parent = nullptr);
void setContext(DoricContext *context);
DoricContext *getContext();
};
#endif // DORICCONTEXTHOLDER_H

View File

@@ -0,0 +1,32 @@
#ifndef COUNTDOWNLATCH_H
#define COUNTDOWNLATCH_H
#include <QSemaphore>
#include <climits>
class DoricCountDownLatch {
Q_DISABLE_COPY(DoricCountDownLatch)
QSemaphore m_sem{INT_MAX};
public:
DoricCountDownLatch() {}
~DoricCountDownLatch() {
m_sem.acquire(INT_MAX);
m_sem.release(INT_MAX);
}
class Locker {
DoricCountDownLatch *sem;
public:
Locker(const Locker &other) : sem{other.sem} { sem->m_sem.acquire(); }
Locker(Locker &&other) : sem{other.sem} { other.sem = nullptr; }
Locker(DoricCountDownLatch *sem) : sem{sem} { sem->m_sem.acquire(); }
~Locker() {
if (sem)
sem->m_sem.release();
}
};
Locker lock() { return Locker{this}; }
};
#endif // COUNTDOWNLATCH_H

View File

@@ -0,0 +1,68 @@
#include "DoricDialogBridge.h"
#include "plugin/DoricModalPlugin.h"
#include <QQuickWindow>
DoricDialogBridge::DoricDialogBridge(QObject *parent) : QObject(parent) {}
void DoricDialogBridge::onAccepted(QString windowPointer, QString pluginPointer,
QString callbackId) {
{
QObject *object = (QObject *)(windowPointer.toULongLong());
QQuickWindow *window = dynamic_cast<QQuickWindow *>(object);
window->deleteLater();
}
{
QObject *object = (QObject *)(pluginPointer.toULongLong());
DoricModalPlugin *modalPlugin = dynamic_cast<DoricModalPlugin *>(object);
modalPlugin->onAccepted(callbackId);
}
}
void DoricDialogBridge::onRejected(QString windowPointer, QString pluginPointer,
QString callbackId) {
{
QObject *object = (QObject *)(windowPointer.toULongLong());
QQuickWindow *window = dynamic_cast<QQuickWindow *>(object);
window->deleteLater();
}
{
QObject *object = (QObject *)(pluginPointer.toULongLong());
DoricModalPlugin *modalPlugin = dynamic_cast<DoricModalPlugin *>(object);
modalPlugin->onRejected(callbackId);
}
}
void DoricDialogBridge::onAcceptedWithInput(QString windowPointer,
QString pluginPointer,
QString callbackId, QString input) {
{
QObject *object = (QObject *)(windowPointer.toULongLong());
QQuickWindow *window = dynamic_cast<QQuickWindow *>(object);
window->deleteLater();
}
{
QObject *object = (QObject *)(pluginPointer.toULongLong());
DoricModalPlugin *modalPlugin = dynamic_cast<DoricModalPlugin *>(object);
modalPlugin->onAcceptedWithInput(callbackId, input);
}
}
void DoricDialogBridge::onRejectedWithInput(QString windowPointer,
QString pluginPointer,
QString callbackId, QString input) {
{
QObject *object = (QObject *)(windowPointer.toULongLong());
QQuickWindow *window = dynamic_cast<QQuickWindow *>(object);
window->deleteLater();
}
{
QObject *object = (QObject *)(pluginPointer.toULongLong());
DoricModalPlugin *modalPlugin = dynamic_cast<DoricModalPlugin *>(object);
modalPlugin->onRejectedWithInput(callbackId, input);
}
}

View File

@@ -0,0 +1,28 @@
#ifndef DORICDIALOGBRIDGE_H
#define DORICDIALOGBRIDGE_H
#include <QObject>
class DoricDialogBridge : public QObject {
Q_OBJECT
public:
explicit DoricDialogBridge(QObject *parent = nullptr);
Q_INVOKABLE
void onAccepted(QString windowPointer, QString pluginPointer,
QString callbackId);
Q_INVOKABLE
void onAcceptedWithInput(QString windowPointer, QString pluginPointer,
QString callbackId, QString input);
Q_INVOKABLE
void onRejected(QString windowPointer, QString pluginPointer,
QString callbackId);
Q_INVOKABLE
void onRejectedWithInput(QString windowPointer, QString pluginPointer,
QString callbackId, QString input);
};
#endif // DORICDIALOGBRIDGE_H

View File

@@ -0,0 +1,20 @@
#include "DoricImageBridge.h"
#include "shader/DoricImageNode.h"
DoricImageBridge::DoricImageBridge(QObject *parent) : QObject(parent) {}
void DoricImageBridge::onNull(QString pointer) {}
void DoricImageBridge::onReady(QString pointer) {
QObject *object = (QObject *)(pointer.toULongLong());
DoricImageNode *imageNode = dynamic_cast<DoricImageNode *>(object);
imageNode->onReady();
}
void DoricImageBridge::onLoading(QString pointer) {}
void DoricImageBridge::onError(QString pointer) {
QObject *object = (QObject *)(pointer.toULongLong());
DoricImageNode *imageNode = dynamic_cast<DoricImageNode *>(object);
imageNode->onError();
}

View File

@@ -0,0 +1,24 @@
#ifndef DORICIMAGEBRIDGE_H
#define DORICIMAGEBRIDGE_H
#include <QObject>
class DoricImageBridge : public QObject {
Q_OBJECT
public:
explicit DoricImageBridge(QObject *parent = nullptr);
Q_INVOKABLE
void onNull(QString pointer);
Q_INVOKABLE
void onReady(QString pointer);
Q_INVOKABLE
void onLoading(QString pointer);
Q_INVOKABLE
void onError(QString pointer);
};
#endif // DORICIMAGEBRIDGE_H

View File

@@ -0,0 +1,752 @@
#include "DoricLayouts.h"
#include "shader/DoricScrollerNode.h"
DoricLayouts::DoricLayouts(QObject *parent) : QObject(parent) {
this->widthSpec = DoricLayoutSpec::DoricLayoutJust;
this->heightSpec = DoricLayoutSpec::DoricLayoutJust;
this->alignment = 0;
this->gravity = 0;
this->width = 0;
this->height = 0;
this->spacing = 0;
this->marginBottom = 0;
this->marginTop = 0;
this->marginLeft = 0;
this->marginRight = 0;
this->paddingLeft = 0;
this->paddingRight = 0;
this->paddingBottom = 0;
this->paddingTop = 0;
this->weight = 0;
this->layoutType = DoricLayoutType::DoricUndefined;
this->disabled = false;
this->maxWidth = INT_MAX;
this->maxHeight = INT_MAX;
this->minWidth = 0;
this->minHeight = 0;
this->measuredWidth = 0;
this->measuredHeight = 0;
this->measuredX = 0;
this->measuredY = 0;
this->undefined = false;
this->contentWidth = 0;
this->contentHeight = 0;
}
void DoricLayouts::setWidthSpec(int widthSpec) { this->widthSpec = widthSpec; }
void DoricLayouts::setHeightSpec(int heightSpec) {
this->heightSpec = heightSpec;
}
void DoricLayouts::setAlignment(int alignment) { this->alignment = alignment; }
void DoricLayouts::setGravity(int gravity) { this->gravity = gravity; }
void DoricLayouts::setWidth(qreal width) { this->width = width; }
void DoricLayouts::setHeight(qreal height) { this->height = height; }
void DoricLayouts::setSpacing(qreal spacing) { this->spacing = spacing; }
void DoricLayouts::setMarginLeft(qreal marginLeft) {
this->marginLeft = marginLeft;
}
void DoricLayouts::setMarginTop(qreal marginTop) {
this->marginTop = marginTop;
}
void DoricLayouts::setMarginRight(qreal marginRight) {
this->marginRight = marginRight;
}
void DoricLayouts::setMarginBottom(qreal marginBottom) {
this->marginBottom = marginBottom;
}
void DoricLayouts::setPaddingLeft(qreal paddingLeft) {
this->paddingLeft = paddingLeft;
}
void DoricLayouts::setPaddingTop(qreal paddingTop) {
this->paddingTop = paddingTop;
}
void DoricLayouts::setPaddingRight(qreal paddingRight) {
this->paddingRight = paddingRight;
}
void DoricLayouts::setPaddingBottom(qreal paddingBottom) {
this->paddingBottom = paddingBottom;
}
void DoricLayouts::setWeight(int weight) { this->weight = weight; }
void DoricLayouts::setView(QQuickItem *view) {
this->view = view;
this->setParent(view);
this->tag = view->property("tag").toString();
}
void DoricLayouts::setLayoutType(int layoutType) {
this->layoutType = layoutType;
}
void DoricLayouts::setDisabled(bool disabled) { this->disabled = disabled; }
void DoricLayouts::setMaxWidth(qreal maxWidth) { this->maxWidth = maxWidth; }
void DoricLayouts::setMaxHeight(qreal maxHeight) {
this->maxHeight = maxHeight;
}
void DoricLayouts::setMinWidth(qreal minWidth) { this->minWidth = minWidth; }
void DoricLayouts::setMinHeight(qreal minHeight) {
this->minHeight = minHeight;
}
void DoricLayouts::apply(QSizeF frameSize) {
this->resolved = false;
this->measure(frameSize);
this->setFrame();
this->resolved = true;
}
void DoricLayouts::apply() {
this->apply(QSizeF(this->view->width(), this->view->height()));
}
void DoricLayouts::measure(QSizeF targetSize) {
this->measureSelf(targetSize);
this->layout();
}
void DoricLayouts::measureSelf(QSizeF targetSize) {
// measure width
qreal width;
if (this->widthSpec == DoricLayoutSpec::DoricLayoutMost) {
QQuickItem *parent = this->view->parentItem();
if (parent == nullptr) {
// incase parent is scroller
width = targetSize.width();
setMeasuredWidth(targetSize.width());
} else {
DoricLayouts *parentDoricLayout =
(DoricLayouts *)(parent->property("doricLayout").toULongLong());
if (parentDoricLayout != nullptr &&
parentDoricLayout->layoutType == DoricLayoutType::DoricHLayout &&
this->weight > 0) {
width = 0;
setMeasuredWidth(0);
} else {
width = targetSize.width();
setMeasuredWidth(targetSize.width());
}
}
} else if (this->widthSpec == DoricLayoutSpec::DoricLayoutJust) {
width = this->width;
setMeasuredWidth(this->width);
} else {
width = targetSize.width();
}
// measure height
qreal height;
if (this->heightSpec == DoricLayoutSpec::DoricLayoutMost) {
QQuickItem *parent = this->view->parentItem();
if (parent == nullptr) {
// incase parent is scroller
height = targetSize.height();
setMeasuredHeight(targetSize.height());
} else {
DoricLayouts *parentDoricLayout =
(DoricLayouts *)(parent->property("doricLayout").toULongLong());
if (parentDoricLayout != nullptr &&
parentDoricLayout->layoutType == DoricLayoutType::DoricVLayout &&
this->weight > 0) {
height = 0;
setMeasuredHeight(0);
} else {
height = targetSize.height();
setMeasuredHeight(targetSize.height());
}
}
} else if (this->heightSpec == DoricLayoutSpec::DoricLayoutJust) {
height = this->height;
setMeasuredHeight(this->height);
} else {
height = targetSize.height();
}
// measure content
this->measureContent(QSizeF(width - this->paddingLeft - this->paddingRight,
height - this->paddingTop - this->paddingBottom));
if (this->restrainSize()) {
this->measureContent(
QSizeF(this->measuredWidth - this->paddingLeft - this->paddingRight,
this->measuredHeight - this->paddingTop - this->paddingBottom));
}
this->restrainSize();
}
void DoricLayouts::measureContent(QSizeF targetSize) {
qCritical() << "measureContent: " << tag << this->view->property("uuid");
switch (this->layoutType) {
case DoricLayoutType::DoricStack: {
this->measureStackContent(targetSize);
break;
}
case DoricLayoutType::DoricVLayout: {
this->measureVLayoutContent(targetSize);
break;
}
case DoricLayoutType::DoricHLayout: {
this->measureHLayoutContent(targetSize);
break;
}
default: {
this->measureUndefinedContent(targetSize);
break;
}
}
QQuickItem *parent = this->view->parentItem();
if (parent != nullptr) {
DoricLayouts *parentDoricLayout =
(DoricLayouts *)(parent->property("doricLayout").toULongLong());
if (parentDoricLayout != nullptr) {
if (parentDoricLayout->layoutType != DoricLayoutType::DoricUndefined &&
parentDoricLayout->widthSpec == DoricLayoutSpec::DoricLayoutFit &&
this->widthSpec == DoricLayoutSpec::DoricLayoutMost) {
setMeasuredWidth(targetSize.width());
}
if (parentDoricLayout->layoutType != DoricLayoutType::DoricUndefined &&
parentDoricLayout->heightSpec == DoricLayoutSpec::DoricLayoutFit &&
this->heightSpec == DoricLayoutSpec::DoricLayoutMost) {
setMeasuredHeight(targetSize.height());
}
}
}
}
void DoricLayouts::measureUndefinedContent(QSizeF targetSize) {
// begin size that fits
QSizeF measuredSize;
if (tag == "Scroller") {
QObject *object =
(QObject *)(this->view->property("wrapper").toULongLong());
DoricScrollerNode *viewNode = dynamic_cast<DoricScrollerNode *>(object);
measuredSize = viewNode->sizeThatFits(targetSize);
} else {
qreal actualWidth = this->view->width();
qreal actualHeight = this->view->height();
measuredSize = QSizeF(actualWidth, actualHeight);
}
// end size that fits
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredWidth(measuredSize.width() + this->paddingLeft +
this->paddingRight);
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredHeight(measuredSize.height() + this->paddingTop +
this->paddingBottom);
}
}
void DoricLayouts::measureStackContent(QSizeF targetSize) {
qreal contentWidth = 0, contentHeight = 0;
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
layout->measure(layout->removeMargin(targetSize));
contentWidth = qMax(contentWidth, layout->takenWidth());
contentHeight = qMax(contentHeight, layout->takenHeight());
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredWidth(contentWidth + this->paddingLeft + this->paddingRight);
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredHeight(contentHeight + this->paddingTop + this->paddingBottom);
}
this->contentWidth = contentWidth;
this->contentHeight = contentHeight;
}
void DoricLayouts::measureVLayoutContent(QSizeF targetSize) {
qreal contentWidth = 0, contentHeight = 0, contentWeight = 0;
bool had = false;
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
had = true;
layout->measure(layout->removeMargin(
QSizeF(targetSize.width(), targetSize.height() - contentHeight)));
contentWidth = qMax(contentWidth, layout->takenWidth());
contentHeight += layout->takenHeight() + this->spacing;
contentWeight += layout->weight;
}
if (had) {
contentHeight -= this->spacing;
}
if (contentWeight > 0) {
qreal remaining = targetSize.height() - contentHeight;
contentWidth = 0;
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
qreal measuredHeight =
layout->measuredHeight + remaining / contentWeight * layout->weight;
layout->measuredHeight = measuredHeight;
// Need Remeasure
layout->measureContent(QSizeF(
layout->measuredWidth - layout->paddingLeft - layout->paddingRight,
measuredHeight - layout->paddingTop - layout->paddingBottom));
layout->measuredHeight = measuredHeight;
contentWidth = qMax(contentWidth, layout->takenWidth());
}
contentHeight = targetSize.height();
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredWidth(contentWidth + this->paddingLeft + this->paddingRight);
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredHeight(contentHeight + this->paddingTop + this->paddingBottom);
}
this->contentWidth = contentWidth;
this->contentHeight = contentHeight;
}
void DoricLayouts::measureHLayoutContent(QSizeF targetSize) {
qreal contentWidth = 0, contentHeight = 0, contentWeight = 0;
bool had = false;
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
had = true;
layout->measure(layout->removeMargin(
QSizeF(targetSize.width() - contentWidth, targetSize.height())));
contentWidth += layout->takenWidth() + this->spacing;
contentHeight = qMax(contentHeight, layout->takenHeight());
contentWeight += layout->weight;
}
if (had) {
contentWidth -= this->spacing;
}
if (contentWeight > 0) {
qreal remaining = targetSize.width() - contentWidth;
contentHeight = 0;
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
qreal measuredWidth =
layout->measuredWidth + remaining / contentWeight * layout->weight;
layout->measuredWidth = measuredWidth;
// Need Remeasure
layout->measureContent(QSizeF(
measuredWidth - layout->paddingLeft - layout->paddingRight,
layout->measuredHeight - layout->paddingTop - layout->paddingBottom));
layout->measuredWidth = measuredWidth;
contentHeight = qMax(contentHeight, layout->takenHeight());
}
contentWidth = targetSize.width();
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredWidth(contentWidth + this->paddingLeft + this->paddingRight);
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
setMeasuredHeight(contentHeight + this->paddingTop + this->paddingBottom);
}
this->contentWidth = contentWidth;
this->contentHeight = contentHeight;
}
qreal DoricLayouts::takenWidth() {
return this->measuredWidth + this->marginLeft + this->marginRight;
}
qreal DoricLayouts::takenHeight() {
return this->measuredHeight + this->marginTop + this->marginBottom;
}
QSizeF DoricLayouts::removeMargin(QSizeF targetSize) {
return QSizeF(targetSize.width() - this->marginLeft - this->marginRight,
targetSize.height() - this->marginTop - this->marginBottom);
}
bool DoricLayouts::restrainSize() {
bool needRemeasure = false;
if (this->measuredWidth > this->maxWidth) {
setMeasuredWidth(this->maxWidth);
needRemeasure = true;
}
if (this->measuredHeight > this->maxHeight) {
setMeasuredHeight(this->maxHeight);
needRemeasure = true;
}
if (this->measuredWidth < this->minWidth) {
setMeasuredWidth(this->minWidth);
needRemeasure = true;
}
if (this->measuredHeight < this->minHeight) {
setMeasuredHeight(this->minHeight);
needRemeasure = true;
}
return needRemeasure;
}
void DoricLayouts::layout() {
switch (this->layoutType) {
case DoricLayoutType::DoricStack: {
this->layoutStack();
break;
}
case DoricLayoutType::DoricVLayout: {
this->layoutVLayout();
break;
}
case DoricLayoutType::DoricHLayout: {
this->layoutHLayout();
break;
}
default: {
break;
}
}
}
void DoricLayouts::setFrame() {
if (this->layoutType != DoricLayoutType::DoricUndefined) {
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
layout->setFrame();
}
}
qCritical() << "DoricLayouts setProperty: " << tag
<< this->view->property("uuid")
<< " measuredWidth: " << this->measuredWidth
<< " measuredHeight: " << this->measuredHeight
<< " width: " << this->view->width()
<< " height: " << this->view->height()
<< " measuredX: " << this->measuredX
<< " measuredY: " << this->measuredY;
if (qAbs(this->measuredWidth - this->view->width()) >= 0.00001f)
this->view->setProperty("width", this->measuredWidth);
if (qAbs(this->measuredHeight - this->view->height()) >= 0.00001f)
this->view->setProperty("height", this->measuredHeight);
this->view->setProperty("x", this->measuredX);
this->view->setProperty("y", this->measuredY);
}
void DoricLayouts::layoutStack() {
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit &&
layout->widthSpec == DoricLayoutSpec::DoricLayoutMost) {
layout->measuredWidth =
this->measuredWidth - layout->marginLeft - layout->marginRight;
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit &&
layout->heightSpec == DoricLayoutSpec::DoricLayoutMost) {
layout->measuredHeight =
this->measuredHeight - layout->marginTop - layout->marginBottom;
}
layout->layout();
int gravity = layout->alignment;
if ((gravity & DoricGravity::DoricGravityLeft) ==
DoricGravity::DoricGravityLeft) {
layout->setMeasuredX(this->paddingLeft);
} else if ((gravity & DoricGravity::DoricGravityRight) ==
DoricGravity::DoricGravityRight) {
layout->setMeasuredX(this->measuredWidth - this->paddingRight -
layout->measuredWidth);
} else if ((gravity & DoricGravity::DoricGravityCenterX) ==
DoricGravity::DoricGravityCenterX) {
layout->setMeasuredX(this->measuredWidth / 2 - layout->measuredWidth / 2);
} else {
if (layout->marginLeft || layout->marginRight) {
layout->setMeasuredX(this->paddingLeft);
} else {
layout->setMeasuredX(0);
}
}
if ((gravity & DoricGravity::DoricGravityTop) ==
DoricGravity::DoricGravityTop) {
layout->setMeasuredY(this->paddingTop);
} else if ((gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom) {
layout->setMeasuredY(this->measuredHeight - this->paddingBottom -
layout->measuredHeight);
} else if ((gravity & DoricGravity::DoricGravityCenterY) ==
DoricGravity::DoricGravityCenterY) {
layout->setMeasuredY(this->measuredHeight / 2 -
layout->measuredHeight / 2);
} else {
if (layout->marginTop || layout->marginBottom) {
layout->setMeasuredY(this->paddingTop);
} else {
layout->setMeasuredY(0);
}
}
if (!gravity) {
gravity = DoricGravity::DoricGravityLeft | DoricGravity::DoricGravityTop;
}
if (layout->marginLeft && !((gravity & DoricGravity::DoricGravityRight) ==
DoricGravity::DoricGravityRight)) {
layout->measuredX += layout->marginLeft;
}
if (layout->marginRight && !((gravity & DoricGravity::DoricGravityLeft) ==
DoricGravity::DoricGravityLeft)) {
layout->measuredX -= layout->marginRight;
}
if (layout->marginTop && !((gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom)) {
layout->measuredY += layout->marginTop;
}
if (layout->marginBottom && !((gravity & DoricGravity::DoricGravityTop) ==
DoricGravity::DoricGravityTop)) {
layout->measuredY -= layout->marginBottom;
}
}
}
void DoricLayouts::layoutVLayout() {
qreal yStart = this->paddingTop;
if ((this->gravity & DoricGravity::DoricGravityTop) ==
DoricGravity::DoricGravityTop) {
yStart = this->paddingTop;
} else if ((this->gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom) {
yStart = this->measuredHeight - this->contentHeight - this->paddingBottom;
} else if ((this->gravity & DoricGravity::DoricGravityCenterY) ==
DoricGravity::DoricGravityCenterY) {
yStart = (this->measuredHeight - this->contentHeight - this->paddingTop -
this->paddingBottom) /
2 +
this->paddingTop;
}
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit &&
layout->widthSpec == DoricLayoutSpec::DoricLayoutMost) {
layout->measuredWidth =
this->measuredWidth - layout->marginLeft - layout->marginRight;
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit &&
layout->heightSpec == DoricLayoutSpec::DoricLayoutMost) {
layout->measuredHeight = this->measuredHeight - yStart -
layout->marginTop - layout->marginBottom;
}
layout->layout();
int gravity = layout->alignment | this->gravity;
if ((gravity & DoricGravity::DoricGravityLeft) ==
DoricGravity::DoricGravityLeft) {
layout->setMeasuredX(this->paddingLeft);
} else if ((gravity & DoricGravity::DoricGravityRight) ==
DoricGravity::DoricGravityRight) {
layout->setMeasuredX(this->measuredWidth - this->paddingRight -
layout->measuredWidth);
} else if ((gravity & DoricGravity::DoricGravityCenterX) ==
DoricGravity::DoricGravityCenterX) {
layout->setMeasuredX(this->measuredWidth / 2 - layout->measuredWidth / 2);
} else {
layout->setMeasuredX(this->paddingLeft);
}
if (!gravity) {
gravity = DoricGravity::DoricGravityLeft;
}
if (layout->marginLeft && !((gravity & DoricGravity::DoricGravityRight) ==
DoricGravity::DoricGravityRight)) {
layout->measuredX += layout->marginLeft;
}
if (layout->marginRight && !((gravity & DoricGravity::DoricGravityLeft) ==
DoricGravity::DoricGravityLeft)) {
layout->measuredX -= layout->marginRight;
}
layout->setMeasuredY(yStart + layout->marginTop);
yStart += this->spacing + layout->takenHeight();
}
}
void DoricLayouts::layoutHLayout() {
qreal xStart = this->paddingLeft;
if ((this->gravity & DoricGravity::DoricGravityLeft) ==
DoricGravity::DoricGravityLeft) {
xStart = this->paddingLeft;
} else if ((this->gravity & DoricGravity::DoricGravityRight) ==
DoricGravity::DoricGravityRight) {
xStart = this->measuredWidth - this->contentWidth - this->paddingRight;
} else if ((this->gravity & DoricGravity::DoricGravityCenterX) ==
DoricGravity::DoricGravityCenterX) {
xStart = (this->measuredWidth - this->contentWidth - this->paddingLeft -
this->paddingRight) /
2 +
this->paddingLeft;
}
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit &&
layout->widthSpec == DoricLayoutSpec::DoricLayoutMost) {
layout->measuredWidth = this->measuredWidth - xStart -
layout->marginLeft - layout->marginRight;
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit &&
layout->heightSpec == DoricLayoutSpec::DoricLayoutMost) {
layout->measuredHeight =
this->measuredHeight - layout->marginTop - layout->marginBottom;
}
layout->layout();
int gravity = layout->alignment | this->gravity;
if ((gravity & DoricGravity::DoricGravityTop) ==
DoricGravity::DoricGravityTop) {
layout->setMeasuredY(this->paddingTop);
} else if ((gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom) {
layout->setMeasuredY(this->measuredHeight - this->paddingBottom -
layout->measuredHeight);
} else if ((gravity & DoricGravity::DoricGravityCenterY) ==
DoricGravity::DoricGravityCenterY) {
layout->setMeasuredY(this->measuredHeight / 2 -
layout->measuredHeight / 2);
} else {
layout->setMeasuredY(this->paddingTop);
}
if (!gravity) {
gravity = DoricGravity::DoricGravityTop;
}
if (layout->marginTop && !((gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom)) {
layout->measuredY += layout->marginTop;
}
if (layout->marginBottom && !((gravity & DoricGravity::DoricGravityTop) ==
DoricGravity::DoricGravityTop)) {
layout->measuredY -= layout->marginBottom;
}
layout->setMeasuredX(xStart + layout->marginLeft);
xStart += this->spacing + layout->takenWidth();
}
}
// Private Section
void DoricLayouts::setMeasuredWidth(qreal measuredWidth) {
this->measuredWidth = measuredWidth;
qCritical() << "DoricLayouts: " << tag << this->view->property("uuid")
<< " measuredWidth: " << this->measuredWidth;
}
qreal DoricLayouts::getMeasuredWidth() { return this->measuredWidth; }
void DoricLayouts::setMeasuredHeight(qreal measuredHeight) {
this->measuredHeight = measuredHeight;
qCritical() << "DoricLayouts: " << tag << this->view->property("uuid")
<< " measuredHeight: " << this->measuredHeight;
}
qreal DoricLayouts::getMeasuredHeight() { return this->measuredHeight; }
void DoricLayouts::setMeasuredX(qreal measuredX) {
this->measuredX = measuredX;
qCritical() << "DoricLayouts: " << tag << this->view->property("uuid")
<< " measuredX: " << this->measuredX;
}
void DoricLayouts::setMeasuredY(qreal measuredY) {
this->measuredY = measuredY;
qCritical() << "DoricLayouts: " << tag << this->view->property("uuid")
<< " measuredY: " << this->measuredY;
}

View File

@@ -0,0 +1,171 @@
#ifndef DORICLAYOUTS_H
#define DORICLAYOUTS_H
#include <QQuickItem>
class DoricLayoutType {
public:
const static int DoricUndefined = 0;
const static int DoricStack = 1;
const static int DoricVLayout = 2;
const static int DoricHLayout = 3;
};
class DoricLayoutSpec {
public:
const static int DoricLayoutJust = 0;
const static int DoricLayoutFit = 1;
const static int DoricLayoutMost = 2;
};
class DoricGravity {
public:
const static int DoricGravitySpecified = 1;
const static int DoricGravityStart = 1 << 1;
const static int DoricGravityEnd = 1 << 2;
const static int DoricGravityShiftX = 0;
const static int DoricGravityShiftY = 4;
const static int DoricGravityLeft =
(DoricGravityStart | DoricGravitySpecified) << DoricGravityShiftX;
const static int DoricGravityRight = (DoricGravityEnd | DoricGravitySpecified)
<< DoricGravityShiftX;
const static int DoricGravityTop = (DoricGravityStart | DoricGravitySpecified)
<< DoricGravityShiftY;
const static int DoricGravityBottom =
(DoricGravityEnd | DoricGravitySpecified) << DoricGravityShiftY;
const static int DoricGravityCenterX = DoricGravitySpecified
<< DoricGravityShiftX;
const static int DoricGravityCenterY = DoricGravitySpecified
<< DoricGravityShiftY;
const static int DoricGravityCenter =
DoricGravityCenterX | DoricGravityCenterY;
};
class DoricLayouts : public QObject {
public:
explicit DoricLayouts(QObject *parent = nullptr);
void setWidthSpec(int widthSpec);
void setHeightSpec(int heightSpec);
void setAlignment(int alignment);
void setGravity(int gravity);
void setWidth(qreal width);
void setHeight(qreal height);
void setSpacing(qreal spacing);
void setMarginLeft(qreal marginLeft);
void setMarginTop(qreal marginTop);
void setMarginRight(qreal marginRight);
void setMarginBottom(qreal marginBottom);
void setPaddingLeft(qreal paddingLeft);
void setPaddingTop(qreal paddingTop);
void setPaddingRight(qreal paddingRight);
void setPaddingBottom(qreal paddingBottom);
void setWeight(int weight);
void setView(QQuickItem *view);
void setLayoutType(int layoutType);
void setDisabled(bool disabled);
void setMaxWidth(qreal maxWidth);
void setMaxHeight(qreal maxHeight);
void setMinWidth(qreal minWidth);
void setMinHeight(qreal minHeight);
void apply(QSizeF frameSize);
void apply();
qreal getMeasuredWidth();
qreal getMeasuredHeight();
private:
QString tag;
int widthSpec;
int heightSpec;
int alignment;
int gravity;
qreal width;
qreal height;
qreal spacing;
qreal marginLeft;
qreal marginTop;
qreal marginRight;
qreal marginBottom;
qreal paddingLeft;
qreal paddingTop;
qreal paddingRight;
qreal paddingBottom;
int weight;
QQuickItem *view;
int layoutType;
bool disabled;
qreal maxWidth;
qreal maxHeight;
qreal minWidth;
qreal minHeight;
bool resolved;
qreal measuredWidth;
void setMeasuredWidth(qreal measuredWidth);
qreal measuredHeight;
void setMeasuredHeight(qreal measuredHeight);
qreal measuredX;
void setMeasuredX(qreal measuredX);
qreal measuredY;
void setMeasuredY(qreal measuredY);
bool undefined;
//
qreal contentWidth;
qreal contentHeight;
void measure(QSizeF targetSize);
void measureSelf(QSizeF targetSize);
void measureContent(QSizeF targetSize);
void measureUndefinedContent(QSizeF targetSize);
void measureStackContent(QSizeF targetSize);
void measureVLayoutContent(QSizeF targetSize);
void measureHLayoutContent(QSizeF targetSize);
qreal takenWidth();
qreal takenHeight();
QSizeF removeMargin(QSizeF targetSize);
bool restrainSize();
void layout();
void layoutStack();
void layoutVLayout();
void layoutHLayout();
void setFrame();
};
#endif // DORICLAYOUTS_H

View File

@@ -0,0 +1,10 @@
#include "DoricMouseAreaBridge.h"
#include "shader/DoricViewNode.h"
DoricMouseAreaBridge::DoricMouseAreaBridge(QObject *parent) : QObject(parent) {}
void DoricMouseAreaBridge::onClick(QString pointer) {
QObject *object = (QObject *)(pointer.toULongLong());
DoricViewNode *viewNode = dynamic_cast<DoricViewNode *>(object);
viewNode->onClick();
}

View File

@@ -0,0 +1,17 @@
#ifndef DORICMOUSEAREABRIDGE_H
#define DORICMOUSEAREABRIDGE_H
#include <QObject>
#include <QVariant>
class DoricMouseAreaBridge : public QObject {
Q_OBJECT
public:
explicit DoricMouseAreaBridge(QObject *parent = nullptr);
Q_INVOKABLE
void onClick(QString pointer);
signals:
};
#endif // DORICMOUSEAREABRIDGE_H

Some files were not shown because too many files have changed in this diff Show More