Fixes dynamic layout sizes after widget show (#241)
* handles most cases * Works with every edge case Works similar to QGridLayout * performance fix * Adds calculate to sizehint
This commit is contained in:
parent
420f6db56b
commit
bae4776747
@ -23,11 +23,14 @@ class FlexLayout : public QLayout, public EventWidget {
|
||||
YGNodeRef node;
|
||||
YGNodeRef getRootNode(YGNodeRef node) const;
|
||||
void calculateLayout() const;
|
||||
void restoreNodeMinStyle(YGValue &previousMinWidth,
|
||||
YGValue &previousMinHeight);
|
||||
|
||||
public:
|
||||
FlexLayout(QWidget *parentWidget = nullptr, YGNodeRef parentNode = nullptr);
|
||||
~FlexLayout() override;
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSize() const override;
|
||||
void addItem(QLayoutItem *) override;
|
||||
QLayoutItem *itemAt(int index) const override;
|
||||
QLayoutItem *takeAt(int index) override;
|
||||
@ -38,7 +41,6 @@ class FlexLayout : public QLayout, public EventWidget {
|
||||
void removeWidget(QWidget *childWidget, YGNodeRef childNode);
|
||||
void setGeometry(const QRect &rect) override;
|
||||
void setFlexNode(YGNodeRef parentNode);
|
||||
Qt::Orientations expandingDirections() const override;
|
||||
bool hasHeightForWidth() const override;
|
||||
|
||||
EVENTWIDGET_IMPLEMENTATIONS(QLayout)
|
||||
|
||||
@ -19,9 +19,10 @@ class FlexNodeContext {
|
||||
namespace flexutils {
|
||||
YGSize measureQtWidget(YGNodeRef node, float width, YGMeasureMode widthMode,
|
||||
float height, YGMeasureMode heightMode);
|
||||
const QRect getFlexNodeGeometry(YGNodeRef node);
|
||||
QRect getFlexNodeGeometry(YGNodeRef node);
|
||||
void setFlexNodeGeometry(YGNodeRef node, const QRect& geometry);
|
||||
FlexNodeContext* getFlexNodeContext(YGNodeRef node);
|
||||
bool isFlexNodeSizeControlled(YGNodeRef node);
|
||||
void configureFlexNode(QWidget* widget, YGNodeRef node,
|
||||
bool isLeafNode = false);
|
||||
|
||||
|
||||
@ -131,57 +131,72 @@ YGNodeRef FlexLayout::getRootNode(YGNodeRef node) const {
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Orientations FlexLayout::expandingDirections() const {
|
||||
return Qt::Vertical | Qt::Horizontal;
|
||||
}
|
||||
|
||||
bool FlexLayout::hasHeightForWidth() const { return false; }
|
||||
|
||||
QSize FlexLayout::sizeHint() const {
|
||||
calculateLayout();
|
||||
QSize sizeHint = QSize(YGNodeLayoutGetWidth(this->node),
|
||||
YGNodeLayoutGetHeight(this->node));
|
||||
// qDebug() << "sizeHint" << this->parentWidget() << sizeHint;
|
||||
return sizeHint;
|
||||
return QSize(YGNodeLayoutGetWidth(this->node),
|
||||
YGNodeLayoutGetHeight(this->node));
|
||||
}
|
||||
|
||||
QSize FlexLayout::minimumSize() const {
|
||||
calculateLayout();
|
||||
QSize minSize = QSize(YGNodeLayoutGetWidth(this->node),
|
||||
YGNodeLayoutGetHeight(this->node));
|
||||
return minSize;
|
||||
}
|
||||
|
||||
void FlexLayout::setGeometry(const QRect& rect) {
|
||||
if (!this->node) {
|
||||
return;
|
||||
}
|
||||
// qDebug() << "setGeometry" << rect << this->parentWidget();
|
||||
FlexNodeContext* layoutNodeCtx = flexutils::getFlexNodeContext(this->node);
|
||||
if (parentWidget()->isWindow() || layoutNodeCtx->isSizeControlled) {
|
||||
// qDebug() << "controlled" << this->parentWidget();
|
||||
YGNodeStyleSetWidth(this->node, rect.width());
|
||||
YGNodeStyleSetHeight(this->node, rect.height());
|
||||
}
|
||||
|
||||
calculateLayout();
|
||||
QRect calculatedRect = flexutils::getFlexNodeGeometry(this->node);
|
||||
QLayout::setGeometry(calculatedRect);
|
||||
// qDebug() << "calculatedRect" << calculatedRect << this->parentWidget();
|
||||
|
||||
uint count = YGNodeGetChildCount(this->node);
|
||||
|
||||
for (uint i = 0; i < count; ++i) {
|
||||
YGNode* childNode = YGNodeGetChild(this->node, i);
|
||||
QRect childRect = flexutils::getFlexNodeGeometry(childNode);
|
||||
FlexNodeContext* ctx = flexutils::getFlexNodeContext(childNode);
|
||||
QLayoutItem* childItem = ctx->layoutItem();
|
||||
// qDebug() << "child" << childRect << childItem->widget();
|
||||
childItem->setGeometry(childRect);
|
||||
if (!rect.isValid() || rect != geometry()) {
|
||||
bool isSizeControlled = flexutils::isFlexNodeSizeControlled(this->node);
|
||||
YGNodeMarkDirtyAndPropogateToDescendants(this->node);
|
||||
YGValue prevStyleMinWidth = YGNodeStyleGetMinWidth(this->node);
|
||||
YGValue prevStyleMinHeight = YGNodeStyleGetMinHeight(this->node);
|
||||
if (isSizeControlled) {
|
||||
YGNodeStyleSetMinHeight(this->node, rect.height());
|
||||
YGNodeStyleSetMinWidth(this->node, rect.width());
|
||||
}
|
||||
|
||||
calculateLayout();
|
||||
|
||||
uint count = YGNodeGetChildCount(this->node);
|
||||
for (uint i = 0; i < count; ++i) {
|
||||
YGNode* childNode = YGNodeGetChild(this->node, i);
|
||||
QRect childRect = flexutils::getFlexNodeGeometry(childNode);
|
||||
FlexNodeContext* ctx = flexutils::getFlexNodeContext(childNode);
|
||||
QLayoutItem* childItem = ctx->layoutItem();
|
||||
childItem->setGeometry(childRect);
|
||||
}
|
||||
if (isSizeControlled) {
|
||||
restoreNodeMinStyle(prevStyleMinWidth, prevStyleMinHeight);
|
||||
}
|
||||
}
|
||||
QLayout::setGeometry(rect);
|
||||
}
|
||||
|
||||
void FlexLayout::setFlexNode(YGNodeRef parentNode) { this->node = parentNode; }
|
||||
|
||||
void FlexLayout::calculateLayout() const {
|
||||
YGNodeRef parentNode = this->node;
|
||||
YGNodeRef rootNode = getRootNode(parentNode);
|
||||
YGDirection rootDirection = YGNodeStyleGetDirection(rootNode);
|
||||
float rootWidth = YGNodeLayoutGetWidth(rootNode);
|
||||
float rootHeight = YGNodeLayoutGetHeight(rootNode);
|
||||
|
||||
YGNodeCalculateLayout(rootNode, rootWidth, rootHeight, rootDirection);
|
||||
if (YGNodeIsDirty(this->node)) {
|
||||
YGNodeRef rootNode = getRootNode(this->node);
|
||||
YGDirection rootDirection = YGNodeStyleGetDirection(rootNode);
|
||||
YGNodeCalculateLayout(rootNode, YGUndefined, YGUndefined, rootDirection);
|
||||
}
|
||||
}
|
||||
|
||||
void FlexLayout::restoreNodeMinStyle(YGValue& previousMinWidth,
|
||||
YGValue& previousMinHeight) {
|
||||
if (previousMinHeight.unit == YGUnitPercent) {
|
||||
YGNodeStyleSetMinHeightPercent(this->node, previousMinHeight.value);
|
||||
} else {
|
||||
YGNodeStyleSetMinHeight(this->node, previousMinHeight.value);
|
||||
}
|
||||
if (previousMinWidth.unit == YGUnitPercent) {
|
||||
YGNodeStyleSetMinWidthPercent(this->node, previousMinWidth.value);
|
||||
} else {
|
||||
YGNodeStyleSetMinWidth(this->node, previousMinWidth.value);
|
||||
}
|
||||
}
|
||||
@ -17,11 +17,11 @@ void FlexNodeContext::setLayoutItem(QLayoutItem* item) {
|
||||
this->_layoutItem = item;
|
||||
}
|
||||
|
||||
const QRect flexutils::getFlexNodeGeometry(YGNodeRef node) {
|
||||
int width = static_cast<uint>(YGNodeLayoutGetWidth(node));
|
||||
int height = static_cast<uint>(YGNodeLayoutGetHeight(node));
|
||||
int left = static_cast<uint>(YGNodeLayoutGetLeft(node));
|
||||
int top = static_cast<uint>(YGNodeLayoutGetTop(node));
|
||||
QRect flexutils::getFlexNodeGeometry(YGNodeRef node) {
|
||||
int width = static_cast<int>(YGNodeLayoutGetWidth(node));
|
||||
int height = static_cast<int>(YGNodeLayoutGetHeight(node));
|
||||
int left = static_cast<int>(YGNodeLayoutGetLeft(node));
|
||||
int top = static_cast<int>(YGNodeLayoutGetTop(node));
|
||||
const QRect geometry(left, top, width, height);
|
||||
return geometry;
|
||||
}
|
||||
@ -47,6 +47,19 @@ FlexNodeContext* flexutils::getFlexNodeContext(YGNodeRef node) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// if true, it means this node's size can controlled by external things like
|
||||
// resize handles in case of qmainwindow etc
|
||||
bool flexutils::isFlexNodeSizeControlled(YGNodeRef node) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
FlexNodeContext* ctx = getFlexNodeContext(node);
|
||||
if (ctx->widget()->isWindow() || ctx->isSizeControlled) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
YGSize flexutils::measureQtWidget(YGNodeRef node, float _width,
|
||||
YGMeasureMode widthMode, float _height,
|
||||
YGMeasureMode heightMode) {
|
||||
|
||||
72
src/demo.ts
72
src/demo.ts
@ -1,50 +1,40 @@
|
||||
import { QWidget, QMainWindow, FlexLayout, QLabel } from './index';
|
||||
import { QWidget, QMainWindow, FlexLayout, QGridLayout, QLabel } from './index';
|
||||
import { QScrollArea } from './lib/QtWidgets/QScrollArea';
|
||||
|
||||
const win = new QMainWindow();
|
||||
const center = new QWidget();
|
||||
const label = new QLabel();
|
||||
const scrollArea = new QScrollArea();
|
||||
scrollArea.setObjectName('scrollArea');
|
||||
scrollArea.setWidgetResizable(true);
|
||||
// scrollArea.resize(500, 500);
|
||||
const center = new QWidget();
|
||||
center.setObjectName('center');
|
||||
const label = new QLabel();
|
||||
label.setObjectName('label');
|
||||
|
||||
label.setText(`
|
||||
😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
Hellloooooo
|
||||
`);
|
||||
Hellloooooo123
|
||||
Hellloooooo
|
||||
`);
|
||||
|
||||
center.setInlineStyle(`border: 3px solid blue;`);
|
||||
label.setInlineStyle(`border: 2px solid green;padding: 10;font-family: "Sans serif";`);
|
||||
scrollArea.setWidget(label);
|
||||
label.setInlineStyle(`border: 2px solid green;padding: 10;flex:1;font-family: "Sans serif";`);
|
||||
// center.setLayout(new QGridLayout());
|
||||
center.setLayout(new FlexLayout());
|
||||
center.layout?.addWidget(scrollArea);
|
||||
win.setCentralWidget(center);
|
||||
win.show();
|
||||
scrollArea.setInlineStyle(`flex: 1;`);
|
||||
center.layout?.addWidget(label);
|
||||
scrollArea.setWidget(center);
|
||||
console.log('SHOW scrollArea');
|
||||
scrollArea.show();
|
||||
console.log('SET TEXT');
|
||||
setTimeout(() => {
|
||||
label.setText(`Heloo
|
||||
Heloo
|
||||
Jello
|
||||
Hoell
|
||||
jaksjd
|
||||
asjdkajdk
|
||||
aksjdkajsdkja
|
||||
ajksjdakjsd
|
||||
jkasjdkajd
|
||||
ajksdjakjs`);
|
||||
}, 3000);
|
||||
|
||||
(global as any).win = win;
|
||||
(global as any).scrollArea = scrollArea;
|
||||
|
||||
@ -25,6 +25,7 @@ export class QScrollArea extends QAbstractScrollArea {
|
||||
// react:✓, //TODO:getter
|
||||
this.contentWidget = widget;
|
||||
this.native.setWidget(widget.native);
|
||||
this.contentWidget.setFlexNodeSizeControlled(this.widgetResizable());
|
||||
}
|
||||
takeWidget(): NodeWidget | null {
|
||||
// react:✓
|
||||
@ -38,6 +39,9 @@ export class QScrollArea extends QAbstractScrollArea {
|
||||
}
|
||||
setWidgetResizable(resizable: boolean): void {
|
||||
this.native.setWidgetResizable(resizable);
|
||||
if (this.contentWidget) {
|
||||
this.contentWidget.setFlexNodeSizeControlled(resizable);
|
||||
}
|
||||
}
|
||||
widgetResizable(): boolean {
|
||||
return this.native.widgetResizable();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user