[QtUtils] Add parent lookup, layout clearing, scroll area and monospace helpers (#7617)

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-10-24 08:26:02 +02:00 • committed by GitHub
parent bbc6003f0a
commit 1e0fc35d94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 82 additions and 7 deletions

View file

@ -27,6 +27,7 @@ set(UTILITY_HEADERS
libcockatrice/utility/macros.h
libcockatrice/utility/passwordhasher.h
libcockatrice/utility/playmat_params.h
libcockatrice/utility/qt_utils.h
libcockatrice/utility/report_categories.h
libcockatrice/utility/string_limits.h
libcockatrice/utility/dice_limits.h

View file

@ -1,13 +1,29 @@
#ifndef COCKATRICE_QT_UTILS_H
#define COCKATRICE_QT_UTILS_H
#include <QFont>
#include <QFontDatabase>
#include <QLayout>
#include <QObject>
#include <QScrollArea>
#include <QString>
#include <QWidget>
namespace QtUtils
{
template <typename T> T *findParentOfType(const QObject *obj)
/**
* @brief Returns the nearest ancestor of @p obj that casts to @c T.
*
* Walks the QObject parent chain. QWidget::parentWidget() is the same pointer as
* QObject::parent() for widgets, so this also covers the common "find the parent tab,
* splitter or scroll area" lookups.
*
* @param obj Object to start from. May be null.
* @param includeSelf Also test @p obj itself before walking upwards.
* @return The first matching ancestor, or nullptr if there is none.
*/
template <typename T> T *findParentOfType(const QObject *obj, bool includeSelf = false)
{
const QObject *p = obj ? obj->parent() : nullptr;
const QObject *p = includeSelf ? obj : (obj ? obj->parent() : nullptr);
while (p) {
if (auto casted = qobject_cast<T *>(const_cast<QObject *>(p))) {
return casted;
@ -17,22 +33,80 @@ template <typename T> T *findParentOfType(const QObject *obj)
return nullptr;
}
static inline void clearLayoutRec(QLayout *l)
/**
* @brief How clearLayoutRec() disposes of the widgets it removes.
*
* Deferred is the safe default: deleteLater() lets a widget finish handling the event that
* triggered the rebuild. Use Immediate when the caller rebuilds the same layout right away
* and a lingering widget would be visible or otherwise in the way until the next event loop
* turn.
*/
enum class DeletePolicy
{
Deferred,
Immediate
};
/**
* @brief Removes and deletes every item in @p l, recursing into nested layouts.
*
* Widgets are disposed of according to @p policy; spacers and nested layouts are simply
* deleted.
*/
static inline void clearLayoutRec(QLayout *l, DeletePolicy policy = DeletePolicy::Deferred)
{
if (!l) {
return;
}
QLayoutItem *it;
while ((it = l->takeAt(0)) != nullptr) {
while (QLayoutItem *it = l->takeAt(0)) {
if (QWidget *w = it->widget()) {
w->deleteLater();
if (policy == DeletePolicy::Immediate) {
delete w;
} else {
w->deleteLater();
}
}
if (QLayout *sub = it->layout()) {
clearLayoutRec(sub);
clearLayoutRec(sub, policy);
}
delete it;
}
}
/**
* @brief Creates a QScrollArea using the conventions the client applies nearly everywhere:
* the inner widget resizes with the viewport and the horizontal bar is disabled.
*
* @param parent Parent widget, or nullptr for a parentless scroll area.
* @param verticalPolicy Vertical scroll bar policy.
* @param horizontalPolicy Horizontal scroll bar policy.
*/
static inline QScrollArea *makeScrollArea(QWidget *parent = nullptr,
Qt::ScrollBarPolicy verticalPolicy = Qt::ScrollBarAsNeeded,
Qt::ScrollBarPolicy horizontalPolicy = Qt::ScrollBarAlwaysOff)
{
auto *scrollArea = new QScrollArea(parent);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(verticalPolicy);
scrollArea->setHorizontalScrollBarPolicy(horizontalPolicy);
return scrollArea;
}
/**
* @brief A monospace font at the system UI font's point size.
*
* Used for log dumps, deck codes and other text that has to line up.
*/
static inline QFont monospaceFont()
{
QFont font(QStringLiteral("monospace"));
font.setStyleHint(QFont::Monospace);
const int systemPointSize = QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize();
if (systemPointSize > 0) {
font.setPointSize(systemPointSize);
}
return font;
}
} // namespace QtUtils
#endif // COCKATRICE_QT_UTILS_H