blob: 4b8f0c54dfa0711c64423926c68f5c946ac7ca4e [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifdef __cplusplus
#ifndef WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H
#define WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H
#include "style.h"
#include "flex_enum.h"
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
namespace WeexCore {
class WXCoreLayoutNode;
class WXCoreFlexLine;
enum FormattingContext {
kBFC,
kNonBFC,
} ;
enum MeasureMode {
kUnspecified = 0,
kExactly,
} ;
struct WXCoreSize {
private:
float hypotheticalWidth;
float hypotheticalHeight;
public:
friend class WXCoreLayoutNode;
float width;
float height;
WXCoreSize() : hypotheticalWidth(NAN),
hypotheticalHeight(NAN),
width(0), height(0) {}
inline void reset() {
hypotheticalWidth = NAN ;
hypotheticalHeight = NAN;
width = 0;
height = 0;
}
inline bool isNAN() {
return isnan(width) || isnan(height);
}
};
/**
* layout-result:layout-height、layout-width、position(left、right、top、bottom)
*/
struct WXCorelayoutResult {
WXCoreSize mLayoutSize;
WXCorePosition mLayoutPosition;
inline bool isNAN() {
return mLayoutSize.isNAN() || mLayoutPosition.isNAN();
}
inline void reset() {
mLayoutSize.reset();
mLayoutPosition.reset();
}
};
typedef WXCoreSize(*WXCoreMeasureFunc)(WXCoreLayoutNode *node, float width,
MeasureMode widthMeasureMode,
float height, MeasureMode heightMeasureMode);
using Index = std::vector<WXCoreLayoutNode *>::size_type;
/**
* flie line
*/
class WXCoreFlexLine {
public:
float mMainSize;
float mCrossSize;
Index mItemCount;
float mTotalFlexGrow;
float mTotalFlexibleSize;
/**
* Store the indices of the children views whose mAlignSelf property is stretch.
* The stored indices are the absolute indices including all children in the Flexbox,
* not the relative indices in this flex line.
*/
std::vector<Index> mIndicesAlignSelfStretch;
WXCoreFlexLine() : mMainSize(0),
mCrossSize(0),
mItemCount(0),
mTotalFlexGrow(0),
mTotalFlexibleSize(0) {
}
~WXCoreFlexLine() {
mMainSize = 0;
mCrossSize = 0;
mItemCount = 0;
mTotalFlexGrow = 0;
mTotalFlexibleSize = 0;
mIndicesAlignSelfStretch.clear();
}
};
/**
* Layout node
*/
class WXCoreLayoutNode {
public:
WXCoreLayoutNode() :
mParent(nullptr),
dirty(true),
widthDirty{false},
heightDirty{false},
mHasNewLayout(true),
mIsDestroy(false),
measureFunc(nullptr) {
mCssStyle = new WXCoreCSSStyle();
mLayoutResult = new WXCorelayoutResult();
}
virtual ~WXCoreLayoutNode() {
mIsDestroy = true;
mHasNewLayout = true;
dirty = true;
measureFunc = nullptr;
mParent = nullptr;
mChildList.clear();
BFCs.clear();
NonBFCs.clear();
mChildrenFrozen.clear();
for (WXCoreFlexLine *flexLine : mFlexLines) {
if (flexLine != nullptr) {
delete flexLine;
flexLine = nullptr;
}
}
mFlexLines.clear();
if (mCssStyle != nullptr) {
delete mCssStyle;
mCssStyle = nullptr;
}
if (mLayoutResult != nullptr) {
delete mLayoutResult;
mLayoutResult = nullptr;
}
}
private:
/**
* Holds the 'frozen' state of children during measure. If a view is frozen it will no longer
* expand regardless of mFlexGrow. Items are indexed by the child's
* reordered index.
*/
std::vector<bool> mChildrenFrozen;
std::vector<WXCoreFlexLine *> mFlexLines;
std::vector<WXCoreLayoutNode *> mChildList;
std::vector<WXCoreLayoutNode *> BFCs;
std::vector<WXCoreLayoutNode *> NonBFCs;
WXCoreLayoutNode *mParent = nullptr;
WXCoreCSSStyle *mCssStyle = nullptr;
MeasureMode widthMeasureMode = kUnspecified;
MeasureMode heightMeasureMode = kUnspecified;
WXCorelayoutResult *mLayoutResult = nullptr;
WXCorePosition *absoultePositon = nullptr;
bool mHasNewLayout;
bool dirty, widthDirty, heightDirty;
bool mIsDestroy = true;
bool mNeedsPlatformDependentLayout = false;
WXCoreMeasureFunc measureFunc = nullptr;
void *context = nullptr;
/** ================================ Cache:Last calculate result =================================== **/
public:
/** ================================ Engine Entry Function =================================== **/
void calculateLayout(const std::pair<float,float>&);
/** ================================ measureFunc =================================== **/
inline void setMeasureFunc(WXCoreMeasureFunc measure) {
measureFunc = measure;
markDirty();
}
inline bool haveMeasureFunc() const {
return nullptr != measureFunc;
}
inline WXCoreMeasureFunc getMeasureFunc() const {
return measureFunc;
}
/** ================================ context =================================== **/
inline void *getContext() const {
return context;
}
inline void setContext(void * const context) {
this->context = context;
}
inline void copyStyle(WXCoreLayoutNode *srcNode) {
if (memcmp(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle)) != 0) {
memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle));
markDirty();
}
}
void copyFrom(WXCoreLayoutNode* srcNode){
memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle));
}
inline void copyMeasureFunc(WXCoreLayoutNode *srcNode) {
if (memcmp(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)) != 0) {
memcpy(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc));
markDirty();
}
}
/** ================================ custom =================================== **/
inline bool getNeedsPlatformDependentLayout() const {
return mNeedsPlatformDependentLayout;
}
inline void setNeedsPlatformDependentLayout(bool v) {
this->mNeedsPlatformDependentLayout = v;
}
private:
/** ================================ measure =================================== **/
inline void reset() {
if (isDirty()) {
mLayoutResult->reset();
for (WXCoreFlexLine *flexLine : mFlexLines) {
if (flexLine != nullptr) {
delete flexLine;
flexLine = nullptr;
}
}
mFlexLines.clear();
mChildrenFrozen.assign(getChildCount(kNonBFC), false);
}
widthMeasureMode = isnan(mCssStyle->mStyleWidth) ? kUnspecified : kExactly;
heightMeasureMode = isnan(mCssStyle->mStyleHeight) ? kUnspecified : kExactly;
}
inline void setLayoutWidth(const float width) {
if (mLayoutResult->mLayoutSize.width != width &&
(!isnan(width) || !isnan(mLayoutResult->mLayoutSize.width))) {
mLayoutResult->mLayoutSize.width = width;
widthDirty = true;
markDirty(false);
}
}
inline void setLayoutHeight(const float height) {
if (mLayoutResult->mLayoutSize.height != height &&
(!isnan(height) || !isnan(mLayoutResult->mLayoutSize.height))) {
mLayoutResult->mLayoutSize.height = height;
heightDirty = true;
markDirty(false);
}
}
inline void setWidthMeasureMode(const MeasureMode measureMode) {
if (widthMeasureMode != measureMode) {
widthMeasureMode = measureMode;
if (getChildCount(kNonBFC) > 0) {
widthDirty = true;
}
}
}
inline void setHeightMeasureMode(const MeasureMode measureMode) {
if (heightMeasureMode != measureMode) {
heightMeasureMode = measureMode;
if (getChildCount(kNonBFC) > 0) {
heightDirty = true;
}
}
}
inline float firstLineCrossSize() const {
float sum = sumPaddingBorderAlongAxis(this, !isMainAxisHorizontal(this));
if (!mFlexLines.empty()) {
sum += mFlexLines[0]->mCrossSize;
}
return sum;
}
inline float getSumOfCrossSize() const {
float sum = sumPaddingBorderAlongAxis(this, !isMainAxisHorizontal(this));
for (WXCoreFlexLine *flexLine: mFlexLines) {
sum += flexLine->mCrossSize;
}
return sum;
}
inline bool isMainAxisHorizontal(const WXCoreLayoutNode* const node) const {
return node->mCssStyle->mFlexDirection == kFlexDirectionRow ||
node->mCssStyle->mFlexDirection == kFlexDirectionRowReverse;
}
inline bool isCrossExactly() const {
return isMainAxisHorizontal(this) ? heightMeasureMode == kExactly
: widthMeasureMode == kExactly;
}
inline float sumPaddingBorderAlongAxis(const WXCoreLayoutNode* const node, bool horizontal) const {
float paddingBorderAlongAxis;
if (horizontal) {
paddingBorderAlongAxis =
node->mCssStyle->mPadding.getPadding(kPaddingLeft) +
node->mCssStyle->mPadding.getPadding(kPaddingRight) +
node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthLeft) +
node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthRight);
} else {
paddingBorderAlongAxis =
node->mCssStyle->mPadding.getPadding(kPaddingTop) +
node->mCssStyle->mPadding.getPadding(kPaddingBottom) +
node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthTop) +
node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthBottom);
}
return paddingBorderAlongAxis;
}
inline bool isWrapRequired(const float &width, const float &height,
const float &currentLength, const float &childLength) const {
float freeMainSize = CalculateFreeSpaceAlongMainAxis(width, height, currentLength);
return !isSingleFlexLine(freeMainSize) && freeMainSize < childLength;
}
//If width/height is NAN, ret is NAN, which property we use on purpose.
virtual float CalculateFreeSpaceAlongMainAxis(const float &width, const float &height,
const float &currentLength) const{
float ret;
if(isMainAxisHorizontal(this)){
ret = width - sumPaddingBorderAlongAxis(this, true) - currentLength;
}
else{
ret = height - sumPaddingBorderAlongAxis(this, false) - currentLength;
}
return ret;
}
inline bool isSingleFlexLine(const float &mainSize) const {
return mCssStyle->mFlexWrap == kNoWrap || isnan(mainSize);
}
inline void sumFlexGrow(const WXCoreLayoutNode* const child, WXCoreFlexLine* const flexLine, Index i){
if (child->mCssStyle->mFlexGrow > 0) {
flexLine->mTotalFlexGrow += child->mCssStyle->mFlexGrow;
mChildrenFrozen[i] = false;
if (isMainAxisHorizontal(this)) {
if (!isnan(child->mLayoutResult->mLayoutSize.hypotheticalWidth)) {
flexLine->mTotalFlexibleSize += child->mLayoutResult->mLayoutSize.hypotheticalWidth;
}
} else {
if (!isnan(child->mLayoutResult->mLayoutSize.hypotheticalHeight)) {
flexLine->mTotalFlexibleSize += child->mLayoutResult->mLayoutSize.hypotheticalHeight;
}
}
} else {
mChildrenFrozen[i] = true;
}
}
inline void setMeasuredDimensionForFlex(
const float width, const MeasureMode widthMeasureMode,
const float height, const MeasureMode heightMeasureMode){
float actualWidth, actualHeight;
if (isMainAxisHorizontal(this)) {
actualWidth = widthMeasureMode == kExactly ? width : getLargestMainSize();
actualHeight = heightMeasureMode == kExactly ? height : getSumOfCrossSize();
} else {
actualHeight = heightMeasureMode == kExactly ? height : getLargestMainSize();
actualWidth = widthMeasureMode == kExactly ? width : firstLineCrossSize();
}
setMeasuredDimension(actualWidth, actualHeight);
}
inline float calcItemSizeAlongAxis(const WXCoreLayoutNode* const node, const bool horizontal, const bool useHypotheticalSize = false) const {
float ret;
if (horizontal) {
ret = node->mCssStyle->mMargin.getMargin(kMarginLeft) +
node->mCssStyle->mMargin.getMargin(kMarginRight);
ret += useHypotheticalSize ? node->mLayoutResult->mLayoutSize.hypotheticalWidth
: node->mLayoutResult->mLayoutSize.width;
} else {
ret = node->mCssStyle->mMargin.getMargin(kMarginTop) +
node->mCssStyle->mMargin.getMargin(kMarginBottom);
ret += useHypotheticalSize ? node->mLayoutResult->mLayoutSize.hypotheticalHeight
: node->mLayoutResult->mLayoutSize.height;
}
return ret;
}
inline void limitMainSizeForFlexGrow(WXCoreFlexLine* const flexLine, const Index childIndex,
const float flexGrow) {
mChildrenFrozen[childIndex] = true;
flexLine->mTotalFlexGrow -= flexGrow;
}
inline void setMeasuredDimension(const float width, const float height) {
mLayoutResult->mLayoutSize.width = width;
mLayoutResult->mLayoutSize.height = height;
}
inline std::pair<bool, float> limitChildMainSize(WXCoreFlexLine* const flexLine, const WXCoreLayoutNode* const child,
float childSizeAlongMainAxis, const Index childIndex){
bool needsReexpand = false;
if (isMainAxisHorizontal(this)) {
if (!isnan(child->mCssStyle->mMaxWidth) &&
childSizeAlongMainAxis > child->mCssStyle->mMaxWidth) {
needsReexpand = true;
childSizeAlongMainAxis = child->mCssStyle->mMaxWidth;
} else if (!isnan(child->mCssStyle->mMinWidth) &&
childSizeAlongMainAxis < child->mCssStyle->mMinWidth) {
needsReexpand = true;
childSizeAlongMainAxis = child->mCssStyle->mMinWidth;
}
} else {
if (!isnan(child->mCssStyle->mMaxHeight) &&
childSizeAlongMainAxis > child->mCssStyle->mMaxHeight) {
needsReexpand = true;
childSizeAlongMainAxis = child->mCssStyle->mMaxHeight;
} else if (!isnan(child->mCssStyle->mMinHeight) &&
childSizeAlongMainAxis < child->mCssStyle->mMinHeight) {
needsReexpand = true;
childSizeAlongMainAxis = child->mCssStyle->mMinHeight;
}
}
limitMainSizeForFlexGrow(flexLine, childIndex, child->mCssStyle->mFlexGrow);
return std::make_pair(needsReexpand, childSizeAlongMainAxis);
}
void updateLeftRightForAbsolute(float &left, float &right,
const WXCorePadding &parentPadding,
const WXCoreBorderWidth &parentBorder,
const WXCoreSize &parentSize) const {
if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft))) {
if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeRight))) {
;
} else {
right += parentSize.width -
(parentBorder.getBorderWidth(kBorderWidthRight) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeRight)
+ mLayoutResult->mLayoutSize.width);
left += parentSize.width -
(parentBorder.getBorderWidth(kBorderWidthRight) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeRight)
+ mLayoutResult->mLayoutSize.width);
}
} else {
left += parentBorder.getBorderWidth(kBorderWidthLeft) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
right += parentBorder.getBorderWidth(kBorderWidthLeft) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
}
}
void updateTopBottomForAbsolute(float &top, float &bottom,
const WXCorePadding &parentPadding,
const WXCoreBorderWidth &parentBorder,
const WXCoreSize &parentSize) const {
if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeTop))) {
if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom))) {
;
} else {
top += parentSize.height -
(parentBorder.getBorderWidth(kBorderWidthBottom) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom)
+ mLayoutResult->mLayoutSize.height);
bottom += parentSize.height -
(parentBorder.getBorderWidth(kBorderWidthBottom) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom)
+ mLayoutResult->mLayoutSize.height);
}
} else {
top += parentBorder.getBorderWidth(kBorderWidthTop) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
bottom += parentBorder.getBorderWidth(kBorderWidthTop) +
mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
}
}
/** ================================ other =================================== **/
inline void clearDirty() {
dirty = false;
widthDirty = false;
heightDirty = false;
}
void
measure(float, float, bool);
void hypotheticalMeasure(float, float, bool = false);
void measureLeafNode(float, float, bool, bool);
void measureInternalNode(float, float, bool, bool);
void updateCurrentFlexline(Index, WXCoreFlexLine *, Index, const WXCoreLayoutNode *, bool);
void measureChild(WXCoreLayoutNode* , float, float, float, bool, bool);
void adjustChildSize(WXCoreLayoutNode *, float);
void adjustChildSize(const WXCoreLayoutNode *child,
const float currentMainSize,
const float parentWidth,
const float parentHeight,
float &childWidth,
float &childHeight) const;
void stretchViewCrossSize();
void stretchViewCrossSize(WXCoreLayoutNode *, float);
Index expandItemsInFlexLine(WXCoreFlexLine *, float, Index);
void checkSizeConstraints(WXCoreLayoutNode *, bool);
void
determineMainSize(float width, float height);
void
determineCrossSize(float, float, bool);
void
determineCrossSize(float, float, WXCoreFlexLine *);
void setFrame(float, float, float, float);
void setFrame(WXCorePosition*,float, float, float, float);
/** ================================ layout =================================== **/
void layout(float left, float top, float right, float bottom, bool, const std::pair<float,float>* = nullptr);
void calcRelativeOffset(float &left, float &top, float &right, float &bottom) const ;
void calcAbsoluteOffset(float &left, float &top, float &right, float &bottom, const std::pair<float,float>* = nullptr);
void positionAbsoluteFlexItem(float &left, float &top, float &right, float &bottom);
void onLayout(float left, float top, float right, float bottom, WXCoreLayoutNode* = nullptr, WXCoreFlexLine *const flexLine = nullptr);
void layoutHorizontal(bool isRtl, float left, float top, float right, float bottom,
WXCoreLayoutNode*, WXCoreFlexLine *const flexLine);
void layoutFlexlineHorizontal(const float width,
const WXCoreFlexLine *const flexLine,
float &childLeft,
float &childRight,
float &spaceBetweenItem) const;
void layoutSingleChildHorizontal(WXCoreLayoutNode *node, WXCoreFlexLine *flexLine,
WXCoreFlexWrap flexWrap, WXCoreAlignItems alignItems,
float, float, float, float, bool);
void layoutSingleChildHorizontal(const bool isRtl,
const bool,
float childBottom, float childTop,
WXCoreFlexLine *const flexLine,
WXCoreLayoutNode *const child,
float&, float&);
void layoutVertical(bool isRtl, bool fromBottomToTop, float left, float top, float right, float bottom,
WXCoreLayoutNode*, WXCoreFlexLine *const flexLine);
void layoutFlexlineVertical(const float height,
const WXCoreFlexLine *const flexLine,
float &childTop,
float &childBottom,
float &spaceBetweenItem) const;
void layoutSingleChildVertical(WXCoreLayoutNode *node, WXCoreFlexLine *flexLine,
bool isRtl, WXCoreAlignItems alignItems,
float, float, float, float, bool);
void layoutSingleChildVertical(const bool isRtl, const bool fromBottomToTop,
const bool absoluteFlexItem,
const float childLeft, const float childRight,
WXCoreFlexLine *const flexLine,
WXCoreLayoutNode *const child,
float& ,float&);
void updateFlexLineForAbsoluteItem(WXCoreLayoutNode *const absoluteFlexItem, WXCoreFlexLine *const flexLine);
void initFormatingContext(std::vector<WXCoreLayoutNode *> &BFCs);
std::pair<bool,float> calculateBFCWidth(float, float);
std::pair<bool,float> calculateBFCHeight(float, float);
std::tuple<bool, float, float> calculateBFCDimension(const std::pair<float,float>&);
virtual void OnLayoutBefore() {
}
virtual void OnLayoutAfter(float width, float height) {
}
public:
/** ================================ tree =================================== **/
inline Index getChildCount(FormattingContext formattingContext) const {
switch (formattingContext) {
case kNonBFC:
return NonBFCs.size();
case kBFC:
return BFCs.size();
default:
return mChildList.size();
}
}
inline Index getChildCount() const {
return mChildList.size();
}
inline std::vector<WXCoreLayoutNode *>::const_iterator ChildListIterBegin() {
return mChildList.cbegin();
}
inline std::vector<WXCoreLayoutNode *>::const_iterator ChildListIterEnd() {
return mChildList.cend();
}
inline bool hasChild(const WXCoreLayoutNode* const child){
if(std::find(mChildList.begin(), mChildList.end(), child) != mChildList.end()){
return true;
}else{
return false;
}
}
inline void removeChild(const WXCoreLayoutNode* const child) {
for (int index = 0; index < mChildList.size(); index++) {
if (child == mChildList[index]) {
mChildList.erase(mChildList.begin() + index);
break;
}
}
markDirty();
}
inline void addChildAt(WXCoreLayoutNode* const child, Index index) {
mChildList.insert(mChildList.begin() + index, child);
child->mParent = this;
markDirty();
}
inline WXCoreLayoutNode *getChildAt(const FormattingContext formattingContext, const Index index) const {
switch (formattingContext) {
case kNonBFC:
return NonBFCs[index];
case kBFC:
return BFCs[index];
default:
return mChildList[index];
}
}
inline WXCoreLayoutNode *getChildAt(const Index index) const {
return mChildList[index];
}
inline WXCoreLayoutNode *getParent() const {
return mParent;
}
inline void setParent(WXCoreLayoutNode * const parent, WXCoreLayoutNode * const child) const {
child->mParent = parent;
}
inline bool isBFC(WXCoreLayoutNode* const node) const {
return node->mCssStyle->mPositionType == kAbsolute || node->mCssStyle->mPositionType == kFixed;
}
/** ================================ margin =================================== **/
inline float getMarginTop() const {
return mCssStyle->mMargin.getMargin(kMarginTop);
}
inline float getMarginBottom() const {
return mCssStyle->mMargin.getMargin(kMarginBottom);
}
inline float getMarginLeft() const {
return mCssStyle->mMargin.getMargin(kMarginLeft);
}
inline float getMarginRight() const {
return mCssStyle->mMargin.getMargin(kMarginRight);
}
inline void setMargin(const WXCoreMarginEdge &edge, const float margin) {
if (mCssStyle->mMargin.setMargin(edge, margin)) {
markDirty();
}
}
inline const WXCoreMargin &GetMargins() const {
return mCssStyle->mMargin;
}
/** ================================ padding =================================== **/
inline float getPaddingLeft() const {
return mCssStyle->mPadding.getPadding(kPaddingLeft);
}
inline float getPaddingRight() const {
return mCssStyle->mPadding.getPadding(kPaddingRight);
}
inline float getPaddingTop() const {
return mCssStyle->mPadding.getPadding(kPaddingTop);
}
inline float getPaddingBottom() const {
return mCssStyle->mPadding.getPadding(kPaddingBottom);
}
inline void setPadding(const WXCorePaddingEdge edge, const float padding) {
if (mCssStyle->mPadding.setPadding(edge, padding)) {
markDirty();
}
}
inline const WXCorePadding &GetPaddings() const {
return mCssStyle->mPadding;
}
/** ================================ border-width =================================== **/
inline float getBorderWidthLeft() const {
return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthLeft);
}
inline float getBorderWidthRight() const {
return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthRight);
}
inline float getBorderWidthTop() const {
return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthTop);
}
inline float getBorderWidthBottom() const {
return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthBottom);
}
inline void setBorderWidth(const WXCoreBorderWidthEdge edge, const float borderWidth) {
if (mCssStyle->mBorderWidth.setBorderWidth(edge, borderWidth)) {
markDirty();
}
}
inline const WXCoreBorderWidth &GetBorders() const {
return mCssStyle->mBorderWidth;
}
/** ================================ position-type =================================== **/
inline void setStylePositionType(const WXCorePositionType positionType) {
if (mCssStyle->mPositionType != positionType) {
mCssStyle->mPositionType = positionType;
markDirty();
}
}
inline WXCorePositionType getStylePositionType() const {
return mCssStyle->mPositionType;
}
/** ================================ position =================================== **/
inline float getStylePositionTop() const {
return mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
}
inline float getStylePositionBottom() const {
return mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom);
}
inline float getStylePositionLeft() const {
return mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
}
inline float getStylePositionRight() const {
return mCssStyle->mStylePosition.getPosition(kPositionEdgeRight);
}
inline void setStylePosition(const WXCorePositionEdge edge, const float positionRight) {
if (mCssStyle->mStylePosition.setPosition(edge, positionRight))
markDirty();
}
/** ================================ dimension =================================== **/
inline void setStyleWidthLevel(const DimensionLevel level) const {
if (mCssStyle->mStyleWidthLevel != level) {
mCssStyle->mStyleWidthLevel = level;
}
}
inline void setStyleHeightLevel(const DimensionLevel level) const {
if (mCssStyle->mStyleHeightLevel != level) {
mCssStyle->mStyleHeightLevel = level;
}
}
inline DimensionLevel getStyleHeightLevel() const {
return mCssStyle->mStyleHeightLevel;
}
inline DimensionLevel getStyleWidthLevel() const {
return mCssStyle->mStyleWidthLevel;
}
inline void setStyleWidth(const float width, const bool updating) {
if (mCssStyle->mStyleWidth != width) {
mCssStyle->mStyleWidth = width;
markDirty();
if(updating) {
markChildrenDirty(true);
}
}
}
inline void setStyleWidthToNAN() {
if (!isnan(mCssStyle->mStyleWidth)) {
mCssStyle->mStyleWidth = NAN;
markDirty();
markChildrenDirty(true);
}
}
inline float getStyleWidth() const {
return mCssStyle->mStyleWidth;
}
inline void setStyleHeight(const float height) {
if (mCssStyle->mStyleHeight != height) {
mCssStyle->mStyleHeight = height;
markDirty();
}
}
inline float getStyleHeight() const {
return mCssStyle->mStyleHeight;
}
inline void setMinWidth(const float minWidth, const bool updating) {
if (mCssStyle->mMinWidth != minWidth) {
mCssStyle->mMinWidth = minWidth;
markDirty();
if(updating) {
markChildrenDirty(true);
}
}
}
inline float getMinWidth() const {
return mCssStyle->mMinWidth;
}
inline void setMaxWidth(const float maxWidth, const bool updating) {
if (mCssStyle->mMaxWidth != maxWidth) {
mCssStyle->mMaxWidth = maxWidth;
markDirty();
if(updating) {
markChildrenDirty(true);
}
}
}
inline float getMaxWidth() const {
return mCssStyle->mMaxWidth;
}
inline void setMinHeight(const float minHeight) {
if (mCssStyle->mMinHeight != minHeight) {
mCssStyle->mMinHeight = minHeight;
markDirty();
}
}
inline float getMinHeight() const {
return mCssStyle->mMinHeight;
}
inline void setMaxHeight(const float maxHeight) {
if (mCssStyle->mMaxHeight != maxHeight) {
mCssStyle->mMaxHeight = maxHeight;
markDirty();
}
}
inline float getMaxHeight() const {
return mCssStyle->mMaxHeight;
}
/** ================================ flex-style =================================== **/
inline void setFlexDirection(const WXCoreFlexDirection flexDirection, const bool updating) {
if (mCssStyle->mFlexDirection != flexDirection) {
mCssStyle->mFlexDirection = flexDirection;
markDirty();
if (updating) {
for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
(*it)->markDirty(false);
}
}
}
}
inline WXCoreFlexDirection getFlexDirection() const {
return mCssStyle->mFlexDirection;
}
inline void setFlexWrap(const WXCoreFlexWrap flexWrap) {
if (mCssStyle->mFlexWrap != flexWrap) {
mCssStyle->mFlexWrap = flexWrap;
markDirty();
}
}
inline WXCoreFlexWrap getFlexWrap() const {
return mCssStyle->mFlexWrap;
}
inline void setJustifyContent(const WXCoreJustifyContent justifyContent) {
if (mCssStyle->mJustifyContent != justifyContent) {
mCssStyle->mJustifyContent = justifyContent;
}
}
inline WXCoreJustifyContent getJustifyContent() const {
return mCssStyle->mJustifyContent;
}
inline void setAlignItems(const WXCoreAlignItems alignItems) {
if (mCssStyle->mAlignItems != alignItems) {
mCssStyle->mAlignItems = alignItems;
markDirty();
}
}
inline WXCoreAlignItems getAlignItems() const {
return mCssStyle->mAlignItems;
}
inline void setAlignSelf(const WXCoreAlignSelf alignSelf) {
if (mCssStyle->mAlignSelf != alignSelf) {
mCssStyle->mAlignSelf = alignSelf;
markDirty();
}
}
inline WXCoreAlignSelf getAlignSelf() const {
return mCssStyle->mAlignSelf;
}
virtual void set_flex(const float flex) {
if (mCssStyle->mFlexGrow != flex) {
mCssStyle->mFlexGrow = flex;
markDirty();
}
}
inline float getFlex() const {
return mCssStyle->mFlexGrow;
}
/** ================================ layout-result =================================== **/
inline float getLayoutWidth() const {
return mLayoutResult->mLayoutSize.width;
}
inline float getLayoutHeight() const {
return mLayoutResult->mLayoutSize.height;
}
inline float getLayoutPositionTop() const {
return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeTop);
}
inline float getLayoutPositionBottom() const {
return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeBottom);
}
inline float getLayoutPositionLeft() const {
return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeLeft);
}
inline float getLayoutPositionRight() const {
return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeRight);
}
inline bool hasNewLayout() const {
return mHasNewLayout;
}
inline bool isDirty() const {
return dirty;
}
inline void markDirty(const bool recursion = true) {
if (!isDirty()) {
dirty = true;
if (getParent() != nullptr && recursion) {
getParent()->markDirty();
}
}
}
void markAllDirty() {
markDirty(false);
for (WXCoreLayoutNode* c : mChildList) {
c->markAllDirty();
}
}
bool markChildrenDirty(const bool updatedNode = false) {
bool ret = false;
if(getChildCount() == 0){
if(measureFunc!= nullptr){
ret = true;
}
}
else {
//isnan(mCssStyle->mStyleWidth) XOR updatedNode
if(isnan(mCssStyle->mStyleWidth) != updatedNode){
for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
ret = ((*it)->markChildrenDirty() || ret) ;
}
}
}
dirty = ret || dirty;
return ret;
}
inline void setHasNewLayout(const bool hasNewLayout) {
this->mHasNewLayout = hasNewLayout;
}
inline float getLargestMainSize() const {
float largestSize = 0;
for (WXCoreFlexLine *flexLine : mFlexLines) {
largestSize = std::max(largestSize, flexLine->mMainSize);
}
return largestSize + sumPaddingBorderAlongAxis(this, isMainAxisHorizontal(this));
}
inline void rewriteLayoutResult(float left, float top, float width, float height) {
if (mLayoutResult != nullptr) {
mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeLeft, left);
mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeTop, top);
mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeRight, left + width);
mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeBottom, top + height);
mLayoutResult->mLayoutSize.width = width;
mLayoutResult->mLayoutSize.height = height;
}
}
};
}
#endif //WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H
#endif