queue change of minimum/maximum size

the layout size hints can change all together, in any order possible.
the only way to have a deterministic behavior is to compress them
and do the sync of the size all at once.
also being sure to do a single adjustGeometry (one X call) instead of
separate setWidth/setHeight

a test for the issue is dialog_resizeWithParent.qml

BUG:339478
Change-Id: Ia7c3c55e40ff89971beb734dcd205df05bfba687
This commit is contained in:
Marco Martin 2014-09-29 14:31:04 +02:00
parent 1dfd55d999
commit afe0524fa7
3 changed files with 85 additions and 118 deletions

View File

@ -66,6 +66,9 @@ public:
componentComplete(dialog->parent() == 0),
backgroundHints(Dialog::StandardBackground)
{
hintsCommitTimer.setSingleShot(true);
hintsCommitTimer.setInterval(0);
QObject::connect(&hintsCommitTimer, SIGNAL(timeout()), q, SLOT(updateLayoutParameters()));
}
void updateInputShape();
@ -119,6 +122,7 @@ public:
Plasma::FrameSvgItem *frameSvgItem;
QPointer<QQuickItem> mainItem;
QPointer<QQuickItem> visualParent;
QTimer hintsCommitTimer;
QRect cachedGeometry;
Dialog::WindowType type;
@ -300,34 +304,18 @@ void DialogPrivate::updateMinimumWidth()
return;
}
mainItem->disconnect(q);
q->setMinimumWidth(0);
syncBorders(q->geometry());
int minimumWidth = mainItemLayout->property("minimumWidth").toInt();
//this is to try to get the internal item resized a tad before, but
//the flicker almost always happen anyways, so is *probably* useless
//this other kind of flicker is the view not being always focused exactly
//on the scene
auto margin = frameSvgItem->margins();
int minimumWidth = mainItemLayout->property("minimumWidth").toInt() + margin->left() + margin->right();
q->contentItem()->setHeight(qMax(q->width(), minimumWidth));
q->setHeight(qMax(q->width(), minimumWidth));
int oldWidth = q->width();
q->setMinimumWidth(minimumWidth + margin->left() + margin->right());
q->setWidth(qMax(q->width(), q->minimumWidth()));
mainItem->setWidth(q->width() - margin->left() - margin->right());
frameSvgItem->setWidth(q->width());
if (location == Plasma::Types::RightEdge) {
q->setX(q->x() + (oldWidth - q->size().width()));
}
repositionIfOffScreen();
if (visualParent) {
const QRect geom(q->popupPosition(visualParent, q->size()), q->size());
q->adjustGeometry(geom);
}
updateTheme();
QObject::connect(mainItem, SIGNAL(widthChanged()), q, SLOT(slotMainItemSizeChanged()));
QObject::connect(mainItem, SIGNAL(heightChanged()), q, SLOT(slotMainItemSizeChanged()));
hintsCommitTimer.start();
}
void DialogPrivate::updateMinimumHeight()
@ -339,34 +327,18 @@ void DialogPrivate::updateMinimumHeight()
return;
}
mainItem->disconnect(q);
q->setMinimumHeight(0);
syncBorders(q->geometry());
int minimumHeight = mainItemLayout->property("minimumHeight").toInt();
//this is to try to get the internal item resized a tad before, but
//the flicker almost always happen anyways, so is *probably* useless
//this other kind of flicker is the view not being always focused exactly
//on the scene
auto margin = frameSvgItem->margins();
int minimumHeight = mainItemLayout->property("minimumHeight").toInt() + margin->top() + margin->bottom();
q->contentItem()->setHeight(qMax(q->height(), minimumHeight));
q->setHeight(qMax(q->height(), minimumHeight));
int oldHeight = mainItem->height();
q->setMinimumHeight(minimumHeight + margin->top() + margin->bottom());
q->setHeight(qMax(q->height(), q->minimumHeight()));
mainItem->setHeight(q->height() - margin->top() - margin->bottom());
frameSvgItem->setHeight(q->height());
if (location == Plasma::Types::BottomEdge) {
q->setY(q->y() + (oldHeight - q->size().height()));
}
repositionIfOffScreen();
if (visualParent) {
const QRect geom(q->popupPosition(visualParent, q->size()), q->size());
q->adjustGeometry(geom);
}
updateTheme();
QObject::connect(mainItem, SIGNAL(widthChanged()), q, SLOT(slotMainItemSizeChanged()));
QObject::connect(mainItem, SIGNAL(heightChanged()), q, SLOT(slotMainItemSizeChanged()));
hintsCommitTimer.start();
}
void DialogPrivate::updateMaximumWidth()
@ -378,29 +350,14 @@ void DialogPrivate::updateMaximumWidth()
return;
}
mainItem->disconnect(q);
q->setMaximumWidth(DIALOGSIZE_MAX);
syncBorders(q->geometry());
int maximumWidth = mainItemLayout->property("maximumWidth").toInt();
maximumWidth = maximumWidth ? maximumWidth : DIALOGSIZE_MAX;
auto margin = frameSvgItem->margins();
int maximumWidth = mainItemLayout->property("maximumWidth").toInt() + margin->left() + margin->right();
q->contentItem()->setHeight(qMax(q->width(), maximumWidth));
q->setHeight(qMax(q->width(), maximumWidth));
q->setMaximumWidth(maximumWidth + margin->left() + margin->right());
q->setWidth(qBound(q->minimumWidth(), q->width(), q->maximumWidth()));
mainItem->setWidth(q->width() - margin->left() - margin->right());
frameSvgItem->setWidth(q->width());
repositionIfOffScreen();
if (visualParent) {
const QRect geom(q->popupPosition(visualParent, q->size()), q->size());
q->adjustGeometry(geom);
}
updateTheme();
QObject::connect(mainItem, SIGNAL(widthChanged()), q, SLOT(slotMainItemSizeChanged()));
QObject::connect(mainItem, SIGNAL(heightChanged()), q, SLOT(slotMainItemSizeChanged()));
hintsCommitTimer.start();
}
void DialogPrivate::updateMaximumHeight()
@ -412,30 +369,14 @@ void DialogPrivate::updateMaximumHeight()
return;
}
mainItem->disconnect(q);
q->setMaximumHeight(DIALOGSIZE_MAX);
syncBorders(q->geometry());
int maximumHeight = mainItemLayout->property("maximumHeight").toInt();
maximumHeight = maximumHeight ? maximumHeight : DIALOGSIZE_MAX;
auto margin = frameSvgItem->margins();
int maximumHeight = mainItemLayout->property("maximumHeight").toInt() + margin->top() + margin->bottom();
q->contentItem()->setHeight(qMax(q->height(), maximumHeight));
q->setHeight(qMin(q->height(), maximumHeight));
q->setMaximumHeight(maximumHeight + margin->top() + margin->bottom());
q->setHeight(qBound(q->minimumHeight(), q->height(), q->maximumHeight()));
mainItem->setHeight(q->height() - margin->top() - margin->bottom());
frameSvgItem->setHeight(q->height());
repositionIfOffScreen();
if (visualParent) {
const QRect geom(q->popupPosition(visualParent, q->size()), q->size());
q->adjustGeometry(geom);
}
updateTheme();
QObject::connect(mainItem, SIGNAL(widthChanged()), q, SLOT(slotMainItemSizeChanged()));
QObject::connect(mainItem, SIGNAL(heightChanged()), q, SLOT(slotMainItemSizeChanged()));
hintsCommitTimer.start();
}
void DialogPrivate::updateLayoutParameters()
@ -448,6 +389,8 @@ void DialogPrivate::updateLayoutParameters()
mainItem->disconnect(q);
auto margin = frameSvgItem->margins();
int minimumHeight = mainItemLayout->property("minimumHeight").toInt();
int maximumHeight = mainItemLayout->property("maximumHeight").toInt();
maximumHeight = maximumHeight ? maximumHeight : DIALOGSIZE_MAX;
@ -456,27 +399,40 @@ void DialogPrivate::updateLayoutParameters()
int maximumWidth = mainItemLayout->property("maximumWidth").toInt();
maximumWidth = maximumWidth ? maximumWidth : DIALOGSIZE_MAX;
auto margin = frameSvgItem->margins();
minimumHeight += margin->top() + margin->bottom();
maximumHeight += margin->top() + margin->bottom();
minimumWidth += margin->left() + margin->right();
maximumWidth += margin->left() + margin->right();
q->setMinimumHeight(minimumHeight + margin->top() + margin->bottom());
q->setMaximumHeight(maximumHeight + margin->top() + margin->bottom());
q->setHeight(qBound(q->minimumHeight(), q->height(), q->maximumHeight()));
q->setMinimumWidth(minimumWidth + margin->left() + margin->right());
q->setMaximumWidth(maximumWidth + margin->left() + margin->right());
q->setWidth(qBound(q->minimumWidth(), q->width(), q->maximumWidth()));
const QSize finalSize(qBound(minimumWidth, q->width(), maximumWidth),
qBound(minimumHeight, q->height(), maximumHeight));
mainItem->setX(margin->left());
mainItem->setY(margin->top());
mainItem->setWidth(q->width() - margin->left() - margin->right());
mainItem->setHeight(q->height() - margin->top() - margin->bottom());
if (visualParent) {
//it's important here that we're using re->size() as size, we don't want to do recursive resizeEvents
const QRect geom(q->popupPosition(visualParent, finalSize), finalSize);
q->adjustGeometry(geom);
} else {
q->resize(finalSize);
}
frameSvgItem->setWidth(q->width());
frameSvgItem->setHeight(q->height());
mainItem->setPosition(QPointF(margin->left(),
margin->top()));
mainItem->setSize(QSizeF(q->width() - margin->left() - margin->right(),
q->height() - margin->top() - margin->bottom()));
frameSvgItem->setSize(QSizeF(q->width(),
q->height()));
repositionIfOffScreen();
updateTheme();
//FIXME: this seems to interfere with the geometry change that
//sometimes is still going on, causing flicker (this one is two repositions happening in quick succession).
//it may have to be delayed further
q->setMinimumSize(QSize(minimumWidth, minimumHeight));
q->setMaximumSize(QSize(maximumWidth, maximumHeight));
QObject::connect(mainItem, SIGNAL(widthChanged()), q, SLOT(slotMainItemSizeChanged()));
QObject::connect(mainItem, SIGNAL(heightChanged()), q, SLOT(slotMainItemSizeChanged()));
}
@ -585,10 +541,9 @@ void DialogPrivate::syncToMainItemSize()
QSize(frameSvgItem->margins()->left() + frameSvgItem->margins()->right(),
frameSvgItem->margins()->top() + frameSvgItem->margins()->bottom());
frameSvgItem->setX(0);
frameSvgItem->setY(0);
frameSvgItem->setWidth(s.width());
frameSvgItem->setHeight(s.height());
q->contentItem()->setSize(s);
frameSvgItem->setSize(s);
if (visualParent) {
const QRect geom(q->popupPosition(visualParent, s), s);
@ -600,12 +555,13 @@ void DialogPrivate::syncToMainItemSize()
// The borders will instantly be updated but the geometry might take a
// while as sub-classes can reimplement adjustGeometry and animate it.
syncBorders(geom);
} else {
q->resize(s);
}
mainItem->setX(frameSvgItem->margins()->left());
mainItem->setY(frameSvgItem->margins()->top());
mainItem->setPosition(QPointF(frameSvgItem->margins()->left(),
frameSvgItem->margins()->top()));
updateTheme();
}
@ -676,13 +632,14 @@ void Dialog::setMainItem(QQuickItem *mainItem)
{
if (d->mainItem != mainItem) {
if (d->mainItem) {
d->mainItem->setParentItem(0);
d->mainItem->setParent(parent());
}
d->mainItem = mainItem;
if (mainItem) {
mainItem->setParent(contentItem());
mainItem->setParentItem(contentItem());
mainItem->setProperty("parent", QVariant::fromValue(contentItem()));
connect(mainItem, SIGNAL(widthChanged()), this, SLOT(slotMainItemSizeChanged()));
@ -712,6 +669,9 @@ void Dialog::setMainItem(QQuickItem *mainItem)
d->mainItemLayout = layout;
if (layout) {
//Why queued connections?
//we need to be sure that the properties are
//already *all* updated when we call the management code
connect(layout, SIGNAL(minimumWidthChanged()), this, SLOT(updateMinimumWidth()));
connect(layout, SIGNAL(minimumHeightChanged()), this, SLOT(updateMinimumHeight()));
connect(layout, SIGNAL(maximumWidthChanged()), this, SLOT(updateMaximumWidth()));
@ -926,13 +886,13 @@ void Dialog::resizeEvent(QResizeEvent* re)
d->mainItem->disconnect(this);
d->frameSvgItem->setWidth(re->size().width());
d->frameSvgItem->setHeight(re->size().height());
d->frameSvgItem->setSize(QSizeF(re->size().width(),
re->size().height()));
auto margin = d->frameSvgItem->margins();
d->mainItem->setX(margin->left());
d->mainItem->setY(margin->top());
d->mainItem->setWidth(re->size().width() - margin->left() - margin->right());
d->mainItem->setHeight(re->size().height() - margin->top() - margin->bottom());
d->mainItem->setPosition(QPointF(margin->left(),
margin->top()));
d->mainItem->setSize(QSize(re->size().width() - margin->left() - margin->right(),
re->size().height() - margin->top() - margin->bottom()));
QObject::connect(d->mainItem, SIGNAL(widthChanged()), this, SLOT(slotMainItemSizeChanged()));
QObject::connect(d->mainItem, SIGNAL(heightChanged()), this, SLOT(slotMainItemSizeChanged()));

View File

@ -249,6 +249,7 @@ private:
Q_PRIVATE_SLOT(d, void updateMinimumHeight())
Q_PRIVATE_SLOT(d, void updateMaximumWidth())
Q_PRIVATE_SLOT(d, void updateMaximumHeight())
Q_PRIVATE_SLOT(d, void updateLayoutParameters())
Q_PRIVATE_SLOT(d, void slotMainItemSizeChanged())
};

View File

@ -56,13 +56,19 @@ Item {
width: 500
height: fixedHeight
color: "white"
color: "red"
border {
color: "blue"
width: 3
}
Controls.Button {
text: "Resize"
anchors.centerIn: parent
onClicked: {
rect.fixedHeight = rect.Layout.minimumHeight = rect.Layout.maximumHeight = (rect.fixedHeight == 500 ? rect.fixedHeight = 100 : rect.fixedHeight = 500)
//subDialog.height = (subDialog.height == 500 ? subDialog.height = 100 : subDialog.height = 500)
}
}
}