quickshell/src/widgets/marginwrapper.cpp
outfoxxed af14a416c1
widgets/wrapper: update child geometry when implicit size changes
The implicit size update from a child item of a MarginWrapper
component triggers an implicit size update of the wrapper component,
but this does not necessarily result in the actual size of the wrapper
changing (e.g. when it is positioned by a layout).
2024-11-29 02:03:54 -08:00

161 lines
4.3 KiB
C++

#include "marginwrapper.hpp"
#include <algorithm>
#include <qobject.h>
#include <qquickitem.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include "wrapper.hpp"
namespace qs::widgets {
MarginWrapperManager::MarginWrapperManager(QObject* parent): WrapperManager(parent) {
QObject::connect(
this,
&WrapperManager::initializedChildChanged,
this,
&MarginWrapperManager::onChildChanged
);
}
void MarginWrapperManager::componentComplete() {
this->WrapperManager::componentComplete();
if (this->mWrapper) {
QObject::connect(
this->mWrapper,
&QQuickItem::widthChanged,
this,
&MarginWrapperManager::updateChildX
);
QObject::connect(
this->mWrapper,
&QQuickItem::heightChanged,
this,
&MarginWrapperManager::updateChildY
);
}
if (!this->mChild) this->updateGeometry();
}
qreal MarginWrapperManager::margin() const { return this->mMargin; }
void MarginWrapperManager::setMargin(qreal margin) {
if (margin == this->mMargin) return;
this->mMargin = margin;
this->updateGeometry();
emit this->marginChanged();
}
bool MarginWrapperManager::resizeChild() const { return this->mResizeChild; }
void MarginWrapperManager::setResizeChild(bool resizeChild) {
if (resizeChild == this->mResizeChild) return;
this->mResizeChild = resizeChild;
this->updateGeometry();
emit this->resizeChildChanged();
}
void MarginWrapperManager::onChildChanged() {
// QObject::disconnect in MarginWrapper handles disconnecting old item
if (this->mChild) {
QObject::connect(
this->mChild,
&QQuickItem::implicitWidthChanged,
this,
&MarginWrapperManager::onChildImplicitWidthChanged
);
QObject::connect(
this->mChild,
&QQuickItem::implicitHeightChanged,
this,
&MarginWrapperManager::onChildImplicitHeightChanged
);
}
this->updateGeometry();
}
qreal MarginWrapperManager::targetChildWidth() const {
auto max = this->mWrapper->width() - this->mMargin * 2;
if (this->mResizeChild) return max;
else return std::min(this->mChild->implicitWidth(), max);
}
qreal MarginWrapperManager::targetChildHeight() const {
auto max = this->mWrapper->height() - this->mMargin * 2;
if (this->mResizeChild) return max;
else return std::min(this->mChild->implicitHeight(), max);
}
qreal MarginWrapperManager::targetChildX() const {
if (this->mResizeChild) return this->mMargin;
else {
return std::max(this->mMargin, this->mWrapper->width() / 2 - this->mChild->implicitWidth() / 2);
}
}
qreal MarginWrapperManager::targetChildY() const {
if (this->mResizeChild) return this->mMargin;
else {
return std::max(
this->mMargin,
this->mWrapper->height() / 2 - this->mChild->implicitHeight() / 2
);
}
}
void MarginWrapperManager::updateChildX() {
if (!this->mChild || !this->mWrapper) return;
this->mChild->setX(this->targetChildX());
this->mChild->setWidth(this->targetChildWidth());
}
void MarginWrapperManager::updateChildY() {
if (!this->mChild || !this->mWrapper) return;
this->mChild->setY(this->targetChildY());
this->mChild->setHeight(this->targetChildHeight());
}
void MarginWrapperManager::onChildImplicitWidthChanged() {
if (!this->mChild || !this->mWrapper) return;
this->mWrapper->setImplicitWidth(this->mChild->implicitWidth() + this->mMargin * 2);
// If the implicit width change does not result in an actual width change,
// this will not be called anywhere else.
this->updateChildX();
}
void MarginWrapperManager::onChildImplicitHeightChanged() {
if (!this->mChild || !this->mWrapper) return;
this->mWrapper->setImplicitHeight(this->mChild->implicitHeight() + this->mMargin * 2);
// If the implicit height change does not result in an actual height change,
// this will not be called anywhere else.
this->updateChildY();
}
void MarginWrapperManager::updateGeometry() {
if (!this->mWrapper) return;
if (this->mChild) {
this->mWrapper->setImplicitWidth(this->mChild->implicitWidth() + this->mMargin * 2);
this->mWrapper->setImplicitHeight(this->mChild->implicitHeight() + this->mMargin * 2);
this->mChild->setX(this->targetChildX());
this->mChild->setY(this->targetChildY());
this->mChild->setWidth(this->targetChildWidth());
this->mChild->setHeight(this->targetChildHeight());
} else {
this->mWrapper->setImplicitWidth(this->mMargin * 2);
this->mWrapper->setImplicitHeight(this->mMargin * 2);
}
}
} // namespace qs::widgets