add doric layout

This commit is contained in:
王劲鹏 2021-04-13 21:14:17 +08:00 committed by osborn
parent 40bfd1c6df
commit 46bcaeb772
20 changed files with 956 additions and 316 deletions

View File

@ -46,6 +46,7 @@ SOURCES += \
shader/DoricViewNode.cpp \
utils/DoricConstant.cpp \
utils/DoricContextHolder.cpp \
utils/DoricLayouts.cpp \
utils/DoricMouseAreaBridge.cpp \
widget/flex/FlexLayout.cpp \
widget/flex/FlexLayoutConfig.cpp \
@ -114,6 +115,7 @@ HEADERS += \
utils/DoricConstant.h \
utils/DoricContextHolder.h \
utils/DoricCountDownLatch.h \
utils/DoricLayouts.h \
utils/DoricMouseAreaBridge.h \
utils/DoricObjectFactory.h \
utils/DoricThreadMode.h \

View File

@ -20,10 +20,12 @@ void DoricShaderPlugin::render(QString jsValueString, QString callbackId) {
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 (...) {

View File

@ -3,21 +3,15 @@ import QtQuick.Controls 2.5
import QtQuick.Layouts 1.15
import "util.mjs" as Util
import "gravity.mjs" as Gravity
Rectangle {
property var wrapper
clip: true
property var tag: "HLayout"
property var uuid: Util.uuidv4()
property int widthSpec: 0
property int heightSpec: 0
property int childrenRectWidth: childrenRect.width
property int childrenRectHeight: childrenRect.height
property var tag: "HLayout"
onWidthChanged: {
console.log(tag, uuid + " onWidthChanged: " + this.width)
@ -27,41 +21,6 @@ Rectangle {
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
onWidthSpecChanged: {
console.log(tag, uuid + " onWidthSpecChanged: " + this.widthSpec)
console.log(tag, uuid + " parent width: " + parent.width)
if (this.widthSpec === 2) {
this.width = parent.width
children[1].width = parent.width
}
}
onHeightSpecChanged: {
console.log(tag, uuid + " onHeightSpecChanged: " + this.heightSpec)
console.log(tag, uuid + " parent height: " + parent.height)
if (this.heightSpec === 2) {
this.height = parent.height
children[1].height = parent.height
}
}
onChildrenRectChanged: {
console.log(tag, uuid + " widthSpec: " + widthSpec + " heightSpec: " + heightSpec)
console.log(tag, uuid + " onChildrenRectChanged: " + childrenRect)
this.childrenRectWidth = childrenRect.width
this.childrenRectHeight = childrenRect.height
if (this.widthSpec === 1) {
this.width = childrenRectWidth
}
if (this.heightSpec === 1) {
this.height = childrenRectHeight
}
}
color: 'transparent'
property var backgroundColor
@ -77,47 +36,4 @@ Rectangle {
mouseAreaBridge.onClick(wrapper)
}
}
RowLayout {
property int gravity: 0
spacing: 0
Item {
id: head
objectName: "head"
}
onChildrenChanged: {
console.log(tag, uuid + " gravity: " + gravity)
for (var i = 0;i !== children.length;i++) {
if (children[i] !== head && children[i] !== tail) {
switch(this.gravity) {
case Gravity.enumerate().CENTER_X:
children[i].Layout.alignment = Qt.AlignHCenter
break
case Gravity.enumerate().CENTER:
children[i].Layout.alignment = Qt.AlignCenter
break
}
}
}
if (parent.widthSpec == 1) {
tail.Layout.fillWidth = false
} else {
if (gravity === Gravity.enumerate().CENTER || gravity === Gravity.enumerate().CENTER_X) {
head.Layout.fillWidth = true
} else {
head.Layout.fillWidth = false
}
tail.Layout.fillWidth = true
}
}
Item {
id: tail
objectName: "tail"
}
}
}

View File

@ -11,11 +11,6 @@ Rectangle {
property var uuid: Util.uuidv4()
property int widthSpec: 0
property int heightSpec: 0
property int childrenRectWidth: childrenRect.width
property int childrenRectHeight: childrenRect.height
property var tag: "Stack"
onWidthChanged: {
@ -26,38 +21,6 @@ Rectangle {
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
onWidthSpecChanged: {
console.log(tag, uuid + " onWidthSpecChanged: " + this.widthSpec)
console.log(tag, uuid + " parent width: " + parent.width)
if (this.widthSpec === 2) {
this.width = parent.width
}
}
onHeightSpecChanged: {
console.log(tag, uuid + " onHeightSpecChanged: " + this.heightSpec)
console.log(tag, uuid + " parent height: " + parent.height)
if (this.heightSpec === 2) {
this.height = parent.height
}
}
onChildrenRectChanged: {
console.log(tag, uuid + " widthSpec: " + widthSpec + " heightSpec: " + heightSpec)
console.log(tag, uuid + " onChildrenRectChanged: " + childrenRect)
this.childrenRectWidth = childrenRect.width
this.childrenRectHeight = childrenRect.height
if (this.widthSpec === 1) {
this.width = childrenRectWidth
}
if (this.heightSpec === 1) {
this.height = childrenRectHeight
}
}
color: 'transparent'
property var backgroundColor

View File

@ -39,11 +39,13 @@ TextArea {
}
onWidthChanged: {
bg.implicitWidth = width
// bg.implicitWidth = width
console.log(tag, uuid + " onWidthChanged: " + this.width)
}
onHeightChanged: {
bg.implicitHeight = height
// bg.implicitHeight = height
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
MouseArea {

View File

@ -3,21 +3,15 @@ import QtQuick.Controls 2.5
import QtQuick.Layouts 1.15
import "util.mjs" as Util
import "gravity.mjs" as Gravity
Rectangle {
property var wrapper
clip: true
property var tag: "VLayout"
property var uuid: Util.uuidv4()
property int widthSpec: 0
property int heightSpec: 0
property int childrenRectWidth: childrenRect.width
property int childrenRectHeight: childrenRect.height
property var tag: "VLayout"
onWidthChanged: {
console.log(tag, uuid + " onWidthChanged: " + this.width)
@ -27,41 +21,6 @@ Rectangle {
console.log(tag, uuid + " onHeightChanged: " + this.height)
}
onWidthSpecChanged: {
console.log(tag, uuid + " onWidthSpecChanged: " + this.widthSpec)
console.log(tag, uuid + " parent width: " + parent.width)
if (this.widthSpec === 2) {
this.width = parent.width
children[1].width = parent.width
}
}
onHeightSpecChanged: {
console.log(tag, uuid + " onHeightSpecChanged: " + this.heightSpec)
console.log(tag, uuid + " parent height: " + parent.height)
if (this.heightSpec === 2) {
this.height = parent.height
children[1].height = parent.height
}
}
onChildrenRectChanged: {
console.log(tag, uuid + " widthSpec: " + widthSpec + " heightSpec: " + heightSpec)
console.log(tag, uuid + " onChildrenRectChanged: " + childrenRect)
this.childrenRectWidth = childrenRect.width
this.childrenRectHeight = childrenRect.height
if (this.widthSpec === 1) {
this.width = childrenRectWidth
}
if (this.heightSpec === 1) {
this.height = childrenRectHeight
}
}
color: 'transparent'
property var backgroundColor
@ -77,48 +36,4 @@ Rectangle {
mouseAreaBridge.onClick(wrapper)
}
}
ColumnLayout {
property int gravity: 0
spacing: 0
Item {
id: head
objectName: "head"
}
onChildrenChanged: {
console.log(tag, uuid + " gravity: " + gravity)
for (var i = 0;i !== children.length;i++) {
if (children[i] !== head && children[i] !== tail) {
switch(this.gravity) {
case Gravity.enumerate().CENTER_X:
children[i].Layout.alignment = Qt.AlignHCenter
break
case Gravity.enumerate().CENTER:
children[i].Layout.alignment = Qt.AlignCenter
break
}
}
}
if (parent.heightSpec == 1) {
tail.Layout.fillHeight = false
} else {
if (gravity === Gravity.enumerate().CENTER || gravity === Gravity.enumerate().CENTER_Y) {
head.Layout.fillHeight = true
} else {
head.Layout.fillHeight = false
}
tail.Layout.fillHeight = true
}
}
Item {
id: tail
objectName: "tail"
}
}
}

View File

@ -20,16 +20,13 @@ void DoricGroupNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
void DoricGroupNode::blend(QJsonValue jsValue) {
DoricViewNode::blend(jsValue);
configChildNode();
}
void DoricGroupNode::afterBlended(QJsonValue props) { configChildNode(); }
void DoricGroupNode::configChildNode() {
QQuickItem *parent = nullptr;
if (mType == "HLayout" || mType == "VLayout") {
parent = mView->childItems().at(1);
} else {
parent = mView;
}
QQuickItem *parent = mView;
for (int idx = 0; idx < mChildViewIds.size(); idx++) {
QString id = mChildViewIds.at(idx);
QJsonValue model = getSubModel(id);
@ -140,23 +137,6 @@ void DoricGroupNode::configChildNode() {
viewNode->getNodeView()->setParentItem(nullptr);
viewNode->getNodeView()->deleteLater();
}
// handle tail
if (mType == "VLayout" || mType == "HLayout") {
int tailIndex = -1;
for (int idx = 0; idx < parent->childItems().size(); idx++) {
if (parent->childItems().at(idx)->objectName() == "tail") {
tailIndex = idx;
break;
}
}
if (tailIndex != -1 && tailIndex != parent->childItems().size() - 1) {
QQuickItem *tail = parent->childItems().at(tailIndex);
tail->setParentItem(nullptr);
tail->setParentItem(parent);
}
}
}
void DoricGroupNode::blendSubNode(QJsonValue subProperties) {
@ -168,3 +148,8 @@ void DoricGroupNode::blendSubNode(QJsonValue subProperties) {
}
}
}
void DoricGroupNode::requestLayout() {
DoricSuperNode::requestLayout();
foreach (DoricViewNode *node, this->mChildNodes) { node->requestLayout(); }
}

View File

@ -19,6 +19,10 @@ protected:
void configChildNode();
virtual void blendSubNode(QJsonValue subProperties) override;
virtual void afterBlended(QJsonValue props) override;
virtual void requestLayout() override;
};
#endif // DORICGROUPNODE_H

View File

@ -11,16 +11,20 @@ QQuickItem *DoricHLayoutNode::build() {
}
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->childItems().at(1);
QQuickItem *container = view;
if (name == "space") {
container->setProperty("spacing", prop.toInt());
getLayouts()->setSpacing(prop.toInt());
} else if (name == "gravity") {
container->setProperty("gravity", prop.toInt());
getLayouts()->setGravity(prop.toInt());
} else {
DoricGroupNode::blend(view, name, prop);
}

View File

@ -2,4 +2,12 @@
void DoricRootNode::setRootView(QQuickItem *rootView) {
this->mView = rootView;
this->createLayouts(rootView);
this->getLayouts()->setLayoutType(DoricLayoutType::DoricStack);
}
void DoricRootNode::requestLayout() {
getLayouts()->apply();
DoricStackNode::requestLayout();
}

View File

@ -10,6 +10,8 @@ public:
using DoricStackNode::DoricStackNode;
void setRootView(QQuickItem *rootView);
virtual void requestLayout() override;
};
#endif // ROOTNODE_H

View File

@ -11,6 +11,10 @@ QQuickItem *DoricStackNode::build() {
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
getLayouts()->setLayoutType(DoricLayoutType::DoricStack);
item->setProperty("wrapper", QString::number((qint64)this));
return item;
}

View File

@ -54,10 +54,3 @@ void DoricSuperNode::blendSubLayoutConfig(DoricViewNode *viewNode,
QJsonValue jsValue) {
viewNode->blendLayoutConfig(jsValue);
}
QJsonValue DoricSuperNode::generateDefaultLayoutConfig() {
QJsonObject layoutConfig;
layoutConfig.insert("widthSpec", SpecMode::JUST);
layoutConfig.insert("heightSpec", SpecMode::JUST);
return layoutConfig;
}

View File

@ -23,8 +23,6 @@ public:
void blendSubLayoutConfig(DoricViewNode *viewNode, QJsonValue jsValue);
QJsonValue generateDefaultLayoutConfig();
private:
void mixinSubNode(QJsonValue subNode);

View File

@ -12,6 +12,7 @@ QQuickItem *DoricTextNode::build() {
}
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
this->createLayouts(item);
item->setProperty("wrapper", QString::number((qint64)this));
return item;

View File

@ -11,16 +11,20 @@ QQuickItem *DoricVLayoutNode::build() {
}
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->childItems().at(1);
QQuickItem *container = view;
if (name == "space") {
container->setProperty("spacing", prop.toInt());
getLayouts()->setSpacing(prop.toInt());
} else if (name == "gravity") {
container->setProperty("gravity", prop.toInt());
getLayouts()->setGravity(prop.toInt());
} else {
DoricGroupNode::blend(view, name, prop);
}

View File

@ -3,42 +3,62 @@
#include "../utils/DoricUtils.h"
#include "DoricSuperNode.h"
void DoricViewNode::blendLayoutConfig(QJsonValue jsObject) {
this->mLayoutConfig = jsObject;
void DoricViewNode::blendLayoutConfig(QJsonValue jsValue) {
QJsonObject jsObject = jsValue.toObject();
if (jsObject.contains("widthSpec"))
getLayouts()->setWidthSpec(jsObject["widthSpec"].toInt());
QJsonValue margin = jsObject["margin"];
QJsonValue widthSpec = jsObject["widthSpec"];
QJsonValue heightSpec = jsObject["heightSpec"];
if (jsObject.contains("heightSpec"))
getLayouts()->setHeightSpec(jsObject["heightSpec"].toInt());
if (widthSpec.isDouble()) {
switch (widthSpec.toInt()) {
case SpecMode::JUST:
mView->setProperty("widthSpec", SpecMode::JUST);
break;
case SpecMode::FIT:
mView->setProperty("widthSpec", SpecMode::FIT);
break;
case SpecMode::MOST:
mView->setProperty("widthSpec", SpecMode::MOST);
break;
}
if (jsObject.contains("margin")) {
QJsonObject margin = jsObject["margin"].toObject();
if (margin.contains("left"))
getLayouts()->setMarginLeft(margin["left"].toInt());
if (margin.contains("top"))
getLayouts()->setMarginTop(margin["top"].toInt());
if (margin.contains("right"))
getLayouts()->setMarginRight(margin["right"].toInt());
if (margin.contains("bottom"))
getLayouts()->setMarginBottom(margin["bottom"].toInt());
}
if (heightSpec.isDouble()) {
switch (heightSpec.toInt()) {
case SpecMode::JUST:
mView->setProperty("heightSpec", SpecMode::JUST);
break;
case SpecMode::FIT:
mView->setProperty("heightSpec", SpecMode::FIT);
break;
case SpecMode::MOST:
mView->setProperty("heightSpec", SpecMode::MOST);
break;
}
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"].toInt());
if (jsObject.contains("maxHeight"))
getLayouts()->setMaxHeight(jsObject["maxHeight"].toInt());
if (jsObject.contains("minWidth"))
getLayouts()->setMinWidth(jsObject["minWidth"].toInt());
if (jsObject.contains("minHeight"))
getLayouts()->setMinHeight(jsObject["minHeight"].toInt());
}
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);
@ -53,8 +73,8 @@ void DoricViewNode::init(DoricSuperNode *superNode) {
thiz->mReusable = superNode->mReusable;
}
this->mSuperNode = superNode;
this->mLayoutConfig = superNode->generateDefaultLayoutConfig();
this->mView = build();
getLayouts();
}
QString DoricViewNode::getId() { return mId; }
@ -75,54 +95,41 @@ void DoricViewNode::blend(QJsonValue jsValue) {
QJsonValue value = jsValue[key];
blend(mView, key, value);
}
this->afterBlended(jsValue);
}
void DoricViewNode::blend(QQuickItem *view, QString name, QJsonValue prop) {
if (name == "width") {
if (!prop.isDouble()) {
return;
}
if (this->mLayoutConfig.isUndefined()) {
view->setWidth(prop.toInt());
} else {
QJsonValue widthSpec = this->mLayoutConfig["widthSpec"];
if (widthSpec.isDouble()) {
if (widthSpec.toInt() == SpecMode::JUST) {
view->setWidth(prop.toInt());
}
}
}
getLayouts()->setWidth(prop.toInt());
} else if (name == "height") {
if (!prop.isDouble()) {
return;
}
if (this->mLayoutConfig.isUndefined()) {
view->setHeight(prop.toInt());
} else {
QJsonValue heightSpec = this->mLayoutConfig["heightSpec"];
if (heightSpec.isDouble()) {
if (heightSpec.toInt() == SpecMode::JUST) {
view->setHeight(prop.toInt());
}
}
}
getLayouts()->setHeight(prop.toInt());
} else if (name == "backgroundColor") {
QString color = DoricUtils::doricColor(prop.toInt()).name();
view->setProperty("backgroundColor", color);
} else if (name == "x") {
view->setProperty("x", prop.toInt());
getLayouts()->setMarginLeft(prop.toInt());
} else if (name == "y") {
view->setProperty("y", prop.toInt());
getLayouts()->setMarginRight(prop.toInt());
} else if (name == "corners") {
view->setProperty("radius", prop.toInt());
} else if (name == "onClick") {
if (prop.isString())
clickFunction = prop.toString();
} else if (name == "padding") {
getLayouts()->setPaddingLeft(prop["left"].toInt());
getLayouts()->setPaddingRight(prop["right"].toInt());
getLayouts()->setPaddingTop(prop["top"].toInt());
getLayouts()->setPaddingBottom(prop["bottom"].toInt());
} else if (name == "hidden") {
getLayouts()->setDisabled(prop.toBool());
} else if (name != "layoutConfig") {
qCritical() << name << ": " << prop.toString();
}
}
void DoricViewNode::afterBlended(QJsonValue prop) {}
QList<QString> DoricViewNode::getIdList() {
QList<QString> ids;
@ -135,6 +142,8 @@ QList<QString> DoricViewNode::getIdList() {
return ids;
}
void DoricViewNode::requestLayout() {}
void DoricViewNode::callJSResponse(QString funcId, QVariantList args) {
QVariantList nArgs;
QList<QString> idList = getIdList();

View File

@ -6,13 +6,7 @@
#include <QQuickItem>
#include "../utils/DoricContextHolder.h"
class SpecMode {
public:
const static int JUST = 0;
const static int FIT = 1;
const static int MOST = 2;
};
#include "../utils/DoricLayouts.h"
class DoricSuperNode;
@ -21,17 +15,21 @@ class DoricViewNode : public DoricContextHolder {
protected:
QQuickItem *mView;
DoricLayouts *mLayouts = nullptr;
DoricSuperNode *mSuperNode = nullptr;
virtual QQuickItem *build() = 0;
void createLayouts(QQuickItem *view);
DoricLayouts *getLayouts();
void setLayoutConfig(QJsonValue layoutConfig);
private:
QString mId;
QJsonValue mLayoutConfig;
QList<QString> getIdList();
QString clickFunction;
@ -70,8 +68,12 @@ public:
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);

View File

@ -0,0 +1,660 @@
#include "DoricLayouts.h"
DoricLayouts::DoricLayouts() {
this->widthSpec = DoricLayoutSpec::DoricLayoutJust;
this->heightSpec = DoricLayoutSpec::DoricLayoutJust;
this->maxWidth = 32767;
this->maxHeight = 32767;
this->minWidth = 0;
this->minHeight = 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(int width) { this->width = width; }
void DoricLayouts::setHeight(int height) { this->height = height; }
void DoricLayouts::setSpacing(int spacing) { this->spacing = spacing; }
void DoricLayouts::setMarginLeft(int marginLeft) {
this->marginLeft = marginLeft;
}
void DoricLayouts::setMarginTop(int marginTop) { this->marginTop = marginTop; }
void DoricLayouts::setMarginRight(int marginRight) {
this->marginRight = marginRight;
}
void DoricLayouts::setMarginBottom(int marginBottom) {
this->marginBottom = marginBottom;
}
void DoricLayouts::setPaddingLeft(int paddingLeft) {
this->paddingLeft = paddingLeft;
}
void DoricLayouts::setPaddingTop(int paddingTop) {
this->paddingTop = paddingTop;
}
void DoricLayouts::setPaddingRight(int paddingRight) {
this->paddingRight = paddingRight;
}
void DoricLayouts::setPaddingBottom(int paddingBottom) {
this->paddingBottom = paddingBottom;
}
void DoricLayouts::setWeight(int weight) { this->weight = weight; }
void DoricLayouts::setView(QQuickItem *view) {
this->view = 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(int maxWidth) { this->maxWidth = maxWidth; }
void DoricLayouts::setMaxHeight(int maxHeight) { this->maxHeight = maxHeight; }
void DoricLayouts::setMinWidth(int minWidth) { this->minWidth = minWidth; }
void DoricLayouts::setMinHeight(int minHeight) { this->minHeight = minHeight; }
void DoricLayouts::apply(int targetWidth, int targetHeight) {
this->resolved = false;
this->measure(targetWidth, targetHeight);
this->setFrame();
this->resolved = true;
}
void DoricLayouts::apply() {
this->apply(this->view->width(), this->view->height());
}
void DoricLayouts::measure(int targetWidth, int targetHeight) {
this->measureSelf(targetWidth, targetHeight);
this->layout();
}
void DoricLayouts::measureSelf(int targetWidth, int targetHeight) {
// measure width
int width;
if (this->widthSpec == DoricLayoutSpec::DoricLayoutMost) {
QQuickItem *parent = this->view->parentItem();
DoricLayouts *parentDoricLayout =
(DoricLayouts *)(parent->property("doricLayout").toULongLong());
if (parentDoricLayout->layoutType == DoricLayoutType::DoricHLayout &&
this->weight > 0) {
width = this->measuredWidth = 0;
setMeasuredWidth();
} else {
width = this->measuredWidth = targetWidth;
setMeasuredWidth();
}
} else if (this->widthSpec == DoricLayoutSpec::DoricLayoutJust) {
width = this->measuredWidth = this->width;
setMeasuredWidth();
} else {
width = targetWidth;
}
// measure height
int height;
if (this->heightSpec == DoricLayoutSpec::DoricLayoutMost) {
QQuickItem *parent = this->view->parentItem();
DoricLayouts *parentDoricLayout =
(DoricLayouts *)(parent->property("doricLayout").toULongLong());
if (parentDoricLayout->layoutType == DoricLayoutType::DoricVLayout &&
this->weight > 0) {
height = this->measuredHeight = 0;
} else {
height = this->measuredHeight = targetHeight;
}
} else if (this->heightSpec == DoricLayoutSpec::DoricLayoutJust) {
height = this->measuredHeight = this->height;
} else {
height = targetHeight;
}
// measure content
this->measureContent(width - this->paddingLeft - this->paddingRight,
height - this->paddingTop - this->paddingBottom);
if (this->restrainSize()) {
this->measureContent(
this->measuredWidth - this->paddingLeft - this->paddingRight,
this->measuredHeight - this->paddingTop - this->paddingBottom);
}
this->restrainSize();
}
void DoricLayouts::measureContent(int targetWidth, int targetHeight) {
switch (this->layoutType) {
case DoricLayoutType::DoricStack: {
this->measureStackContent(targetWidth, targetHeight);
break;
}
case DoricLayoutType::DoricVLayout: {
this->measureVLayoutContent(targetWidth, targetHeight);
break;
}
case DoricLayoutType::DoricHLayout: {
this->measureHLayoutContent(targetWidth, targetHeight);
break;
}
default: {
this->measureUndefinedContent(targetWidth, targetHeight);
break;
}
}
QQuickItem *parent = this->view->parentItem();
DoricLayouts *parentDoricLayout =
(DoricLayouts *)(parent->property("doricLayout").toULongLong());
if (parentDoricLayout != nullptr) {
if (parentDoricLayout->layoutType != DoricLayoutType::DoricUndefined &&
parentDoricLayout->widthSpec == DoricLayoutSpec::DoricLayoutFit &&
this->widthSpec == DoricLayoutSpec::DoricLayoutMost) {
this->measuredWidth = 0;
setMeasuredWidth();
}
if (parentDoricLayout->layoutType != DoricLayoutType::DoricUndefined &&
parentDoricLayout->heightSpec == DoricLayoutSpec::DoricLayoutFit &&
this->heightSpec == DoricLayoutSpec::DoricLayoutMost) {
this->measuredHeight = 0;
}
}
}
void DoricLayouts::measureUndefinedContent(int targetWidth, int targetHeight) {
int width = this->view->width();
int height = this->view->height();
if (width > targetWidth) {
width = targetWidth;
}
if (height > targetHeight) {
height = targetHeight;
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredWidth = width + this->paddingLeft + this->paddingRight;
setMeasuredWidth();
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredHeight = height + this->paddingTop + this->paddingBottom;
}
}
void DoricLayouts::measureStackContent(int targetWidth, int targetHeight) {
int 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;
}
QPair<int, int> size = layout->removeMargin(targetWidth, targetHeight);
layout->measure(size.first, size.second);
contentWidth = qMax(contentWidth, layout->takenWidth());
contentHeight = qMax(contentHeight, layout->takenHeight());
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredWidth = contentWidth + this->paddingLeft + this->paddingRight;
setMeasuredWidth();
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredHeight =
contentHeight + this->paddingTop + this->paddingBottom;
}
this->contentWidth = contentWidth;
this->contentHeight = contentHeight;
}
void DoricLayouts::measureVLayoutContent(int targetWidth, int targetHeight) {
int 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;
QPair<int, int> pair =
layout->removeMargin(targetWidth, targetHeight - contentHeight);
layout->measure(pair.first, pair.second);
contentWidth = qMax(contentWidth, layout->takenWidth());
contentHeight += layout->takenHeight() + this->spacing;
contentWeight += layout->weight;
}
if (had) {
contentHeight -= this->spacing;
}
if (contentWeight > 0) {
int remaining = targetHeight - contentHeight;
contentWidth = 0;
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
int measuredHeight =
layout->measuredHeight + remaining / contentWeight * layout->weight;
layout->measuredHeight = measuredHeight;
// Need Remeasure
layout->measureContent(
layout->measuredWidth - layout->paddingLeft - layout->paddingRight,
measuredHeight - layout->paddingTop - layout->paddingBottom);
layout->measuredHeight = measuredHeight;
contentWidth = qMax(contentWidth, layout->takenWidth());
}
contentHeight = targetHeight;
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredWidth = contentWidth + this->paddingLeft + this->paddingRight;
setMeasuredWidth();
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredHeight =
contentHeight + this->paddingTop + this->paddingBottom;
}
this->contentWidth = contentWidth;
this->contentHeight = contentHeight;
}
void DoricLayouts::measureHLayoutContent(int targetWidth, int targetHeight) {
int 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;
QPair<int, int> pair =
layout->removeMargin(targetWidth - contentWidth, targetHeight);
layout->measure(pair.first, pair.second);
contentWidth += layout->takenWidth() + this->spacing;
contentHeight = qMax(contentHeight, layout->takenHeight());
contentWeight += layout->weight;
}
if (had) {
contentWidth -= this->spacing;
}
if (contentWeight > 0) {
int remaining = targetWidth - contentWidth;
contentHeight = 0;
foreach (QQuickItem *subview, this->view->childItems()) {
DoricLayouts *layout =
(DoricLayouts *)(subview->property("doricLayout").toULongLong());
if (layout == nullptr) {
continue;
}
if (layout->disabled) {
continue;
}
int measuredWidth =
layout->measuredWidth + remaining / contentWeight * layout->weight;
layout->measuredWidth = measuredWidth;
// Need Remeasure
layout->measureContent(
measuredWidth - layout->paddingLeft - layout->paddingRight,
layout->measuredHeight - layout->paddingTop - layout->paddingBottom);
layout->measuredWidth = measuredWidth;
contentHeight = qMax(contentHeight, layout->takenHeight());
}
contentWidth = targetWidth;
}
if (this->widthSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredWidth = contentWidth + this->paddingLeft + this->paddingRight;
setMeasuredWidth();
}
if (this->heightSpec == DoricLayoutSpec::DoricLayoutFit) {
this->measuredHeight =
contentHeight + this->paddingTop + this->paddingBottom;
}
this->contentWidth = contentWidth;
this->contentHeight = contentHeight;
}
int DoricLayouts::takenWidth() {
return this->measuredWidth + this->marginLeft + this->marginRight;
}
int DoricLayouts::takenHeight() {
return this->measuredHeight + this->marginTop + this->marginBottom;
}
QPair<int, int> DoricLayouts::removeMargin(int targetWidth, int targetHeight) {
QPair<int, int> pair(targetWidth - this->marginLeft - this->marginRight,
targetHeight - this->marginTop - this->marginBottom);
return pair;
}
bool DoricLayouts::restrainSize() {
bool needRemeasure = false;
if (this->measuredWidth > this->maxWidth) {
this->measuredWidth = this->maxWidth;
setMeasuredWidth();
needRemeasure = true;
}
if (this->measuredHeight > this->maxHeight) {
this->measuredHeight = this->maxHeight;
needRemeasure = true;
}
if (this->measuredWidth < this->minWidth) {
this->measuredWidth = this->minWidth;
setMeasuredWidth();
needRemeasure = true;
}
if (this->measuredHeight < this->minHeight) {
this->measuredHeight = 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();
}
}
this->view->setProperty("width", this->measuredWidth);
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->measuredX = this->paddingLeft;
} else if ((gravity & DoricGravity::DoricGravityRight) ==
DoricGravity::DoricGravityRight) {
layout->measuredX =
this->measuredWidth - this->paddingRight - layout->measuredWidth;
} else if ((gravity & DoricGravity::DoricGravityCenterX) ==
DoricGravity::DoricGravityCenterX) {
layout->measuredX = this->measuredWidth / 2 - layout->measuredWidth / 2;
} else {
if (layout->marginLeft || layout->marginRight) {
layout->measuredX = this->paddingLeft;
} else {
layout->measuredX = 0;
}
}
if ((gravity & DoricGravity::DoricGravityTop) ==
DoricGravity::DoricGravityTop) {
layout->measuredY = this->paddingTop;
} else if ((gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom) {
layout->measuredY =
this->measuredHeight - this->paddingBottom - layout->measuredHeight;
} else if ((gravity & DoricGravity::DoricGravityCenterY) ==
DoricGravity::DoricGravityCenterY) {
layout->measuredY = this->measuredHeight / 2 - layout->measuredHeight / 2;
} else {
if (layout->marginTop || layout->marginBottom) {
layout->measuredY = this->paddingTop;
} else {
layout->measuredY = 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() {
int 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->measuredX = this->paddingLeft;
} else if ((gravity & DoricGravity::DoricGravityRight) ==
DoricGravity::DoricGravityRight) {
layout->measuredX =
this->measuredWidth - this->paddingRight - layout->measuredWidth;
} else if ((gravity & DoricGravity::DoricGravityCenterX) ==
DoricGravity::DoricGravityCenterX) {
layout->measuredX = this->measuredWidth / 2 - layout->measuredWidth / 2;
} else {
layout->measuredX = 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->measuredY = yStart + layout->marginTop;
yStart += this->spacing + layout->takenHeight();
}
}
void DoricLayouts::layoutHLayout() {
int 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->measuredY = this->paddingTop;
} else if ((gravity & DoricGravity::DoricGravityBottom) ==
DoricGravity::DoricGravityBottom) {
layout->measuredY =
this->measuredHeight - this->paddingBottom - layout->measuredHeight;
} else if ((gravity & DoricGravity::DoricGravityCenterY) ==
DoricGravity::DoricGravityCenterY) {
layout->measuredY = this->measuredHeight / 2 - layout->measuredHeight / 2;
} else {
layout->measuredY = 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->measuredX = xStart + layout->marginLeft;
xStart += this->spacing + layout->takenWidth();
}
}
// Private Section
void DoricLayouts::setMeasuredWidth() {
qCritical() << "DoricLayouts: " << tag << this->view->property("uuid")
<< " measuredWidth: " << this->measuredWidth;
}
void DoricLayouts::setMeasuredHeight() {
qCritical() << "DoricLayouts: " << tag
<< " measuredHeight: " << this->measuredHeight;
}

View File

@ -0,0 +1,166 @@
#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:
DoricLayouts();
void setWidthSpec(int widthSpec);
void setHeightSpec(int heightSpec);
void setAlignment(int alignment);
void setGravity(int gravity);
void setWidth(int width);
void setHeight(int height);
void setSpacing(int spacing);
void setMarginLeft(int marginLeft);
void setMarginTop(int marginTop);
void setMarginRight(int marginRight);
void setMarginBottom(int marginBottom);
void setPaddingLeft(int paddingLeft);
void setPaddingTop(int paddingTop);
void setPaddingRight(int paddingRight);
void setPaddingBottom(int paddingBottom);
void setWeight(int weight);
void setView(QQuickItem *view);
void setLayoutType(int layoutType);
void setDisabled(bool disabled);
void setMaxWidth(int maxWidth);
void setMaxHeight(int maxHeight);
void setMinWidth(int minWidth);
void setMinHeight(int minHeight);
void apply(int targetWidth, int targetHeight);
void apply();
void measure(int targetWidth, int targetHeight);
void measureSelf(int targetWidth, int targetHeight);
void measureContent(int targetWidth, int targetHeight);
void measureUndefinedContent(int targetWidth, int targetHeight);
void measureStackContent(int targetWidth, int targetHeight);
void measureVLayoutContent(int targetWidth, int targetHeight);
void measureHLayoutContent(int targetWidth, int targetHeight);
int takenWidth();
int takenHeight();
QPair<int, int> removeMargin(int targetWidth, int targetHeight);
bool restrainSize();
void layout();
void layoutStack();
void layoutVLayout();
void layoutHLayout();
void setFrame();
private:
QString tag;
int widthSpec;
int heightSpec;
int alignment;
int gravity;
int width;
int height;
int spacing;
int marginLeft;
int marginTop;
int marginRight;
int marginBottom;
int paddingLeft;
int paddingTop;
int paddingRight;
int paddingBottom;
int weight;
QQuickItem *view;
int layoutType;
bool disabled;
int maxWidth;
int maxHeight;
int minWidth;
int minHeight;
bool resolved;
int measuredWidth;
void setMeasuredWidth();
int measuredHeight;
void setMeasuredHeight();
int measuredX;
int measuredY;
bool undefined;
//
int contentWidth;
int contentHeight;
};
#endif // DORICLAYOUTS_H