widgets: add wrapper components and managers

This commit is contained in:
outfoxxed 2024-11-19 02:02:55 -08:00
parent 79fca3cab8
commit 401ee4cec6
Signed by untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
8 changed files with 578 additions and 0 deletions

127
src/widgets/wrapper.cpp Normal file
View file

@ -0,0 +1,127 @@
#include "wrapper.hpp"
#include <QtQml/qqmlinfo.h>
#include <QtQml/qqmllist.h>
#include <qlogging.h>
#include <qnamespace.h>
#include <qobject.h>
#include <qquickitem.h>
#include <qtmetamacros.h>
namespace qs::widgets {
void WrapperManager::componentComplete() {
this->mWrapper = qobject_cast<QQuickItem*>(this->parent());
if (!this->mWrapper) {
QString pstr;
QDebug(&pstr) << this->parent();
qmlWarning(this) << "Parent of WrapperManager is not a QQuickItem. Parent: " << pstr;
return;
}
QQuickItem* child = this->mChild;
this->mChild = nullptr; // avoids checks for the old item in setChild.
const auto& childItems = this->mWrapper->childItems();
if (childItems.length() == 1) {
this->mDefaultChild = childItems.first();
} else if (childItems.length() != 0) {
this->flags.setFlag(WrapperManager::HasMultipleChildren);
if (!child && !this->flags.testFlags(WrapperManager::NullChild)) {
this->printChildCountWarning();
}
}
for (auto* item: childItems) {
if (item != child) item->setParentItem(nullptr);
}
if (child && !this->flags.testFlag(WrapperManager::NullChild)) {
this->setChild(child);
}
}
QQuickItem* WrapperManager::child() const { return this->mChild; }
void WrapperManager::setChild(QQuickItem* child) {
if (child && child == this->mChild) return;
if (this->mChild != nullptr) {
QObject::disconnect(this->mChild, nullptr, this, nullptr);
if (this->mChild->parentItem() == this->mWrapper) {
this->mChild->setParentItem(nullptr);
}
}
this->mChild = child;
this->flags.setFlag(WrapperManager::NullChild, child == nullptr);
if (child) {
QObject::connect(
child,
&QObject::destroyed,
this,
&WrapperManager::onChildDestroyed,
Qt::UniqueConnection
);
if (auto* wrapper = this->mWrapper) {
child->setParentItem(wrapper);
}
}
emit this->initializedChildChanged();
emit this->childChanged();
}
void WrapperManager::setProspectiveChild(QQuickItem* child) {
if (child && child == this->mChild) return;
if (!this->mWrapper) {
if (this->mChild) {
QObject::disconnect(this->mChild, nullptr, this, nullptr);
}
this->mChild = child;
this->flags.setFlag(WrapperManager::NullChild, child == nullptr);
if (child) {
QObject::connect(child, &QObject::destroyed, this, &WrapperManager::onChildDestroyed);
}
} else {
this->setChild(child);
}
}
void WrapperManager::unsetChild() {
if (!this->mWrapper) {
this->setProspectiveChild(nullptr);
} else {
this->setChild(this->mDefaultChild);
if (!this->mDefaultChild && this->flags.testFlag(WrapperManager::HasMultipleChildren)) {
this->printChildCountWarning();
}
}
this->flags.setFlag(WrapperManager::NullChild, false);
}
void WrapperManager::onChildDestroyed() {
this->mChild = nullptr;
this->unsetChild();
emit this->childChanged();
}
void WrapperManager::printChildCountWarning() const {
qmlWarning(this->mWrapper) << "Wrapper component cannot have more than one visual child.";
qmlWarning(this->mWrapper) << "Remove all additional children, or pick a specific component "
"to wrap using the child property.";
}
} // namespace qs::widgets