File indexing completed on 2025-01-05 04:55:46

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     ui/adjustingscrollarea.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
0006     SPDX-FileCopyrightText: 2022 g10 Code GmbH
0007     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "adjustingscrollarea.h"
0013 
0014 #include <QApplication>
0015 #include <QResizeEvent>
0016 #include <QScreen>
0017 #include <QScrollBar>
0018 #include <QVBoxLayout>
0019 
0020 using namespace Kleo;
0021 
0022 AdjustingScrollArea::AdjustingScrollArea(QWidget *parent)
0023     : QScrollArea{parent}
0024 {
0025     auto w = new QWidget;
0026     w->setObjectName(QLatin1StringView("scrollarea_widget"));
0027     new QVBoxLayout{w};
0028     setWidget(w);
0029     setWidgetResizable(true);
0030     w->installEventFilter(this);
0031 
0032     connect(qApp, &QApplication::focusChanged, this, [this](QWidget *old, QWidget *now) {
0033         Q_UNUSED(old);
0034         ensureWidgetVisible(now);
0035     });
0036 }
0037 
0038 AdjustingScrollArea::~AdjustingScrollArea()
0039 {
0040     widget()->removeEventFilter(this);
0041 }
0042 
0043 QSize AdjustingScrollArea::minimumSizeHint() const
0044 {
0045     const int fw = frameWidth();
0046     QSize sz{2 * fw, 2 * fw};
0047     sz += {widget()->minimumSizeHint().width(), 0};
0048     if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0049         sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
0050     }
0051     if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0052         sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
0053     }
0054     return QScrollArea::minimumSizeHint().expandedTo(sz);
0055 }
0056 
0057 QSize AdjustingScrollArea::sizeHint() const
0058 {
0059     const int fw = frameWidth();
0060     QSize sz{2 * fw, 2 * fw};
0061     sz += viewportSizeHint();
0062     if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0063         sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
0064     }
0065     if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0066         sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
0067     }
0068     sz = QScrollArea::sizeHint().expandedTo(sz);
0069     return sz;
0070 }
0071 
0072 void AdjustingScrollArea::adjustSizeOfWindowBy(const QSize &extent)
0073 {
0074     if (auto w = window()) {
0075         const auto currentSize = w->size();
0076         // we limit the automatic size adjustment to 2/3 of the screen's size
0077         const auto maxWindowSize = screen()->geometry().size() * 2 / 3;
0078         const auto newWindowSize = currentSize.expandedTo((currentSize + extent).boundedTo(maxWindowSize));
0079         if (newWindowSize != currentSize) {
0080             w->resize(newWindowSize);
0081         }
0082     }
0083 }
0084 
0085 bool AdjustingScrollArea::eventFilter(QObject *obj, QEvent *ev)
0086 {
0087     if (ev->type() == QEvent::Resize && obj == widget() && sizeAdjustPolicy() == AdjustToContents) {
0088         const auto *const event = static_cast<QResizeEvent *>(ev);
0089         if (event->size().height() > event->oldSize().height()) {
0090             const auto currentViewportHeight = viewport()->height();
0091             const auto wantedViewportHeight = event->size().height();
0092             const auto wantedAdditionalHeight = wantedViewportHeight - currentViewportHeight;
0093             if (wantedAdditionalHeight > 0) {
0094                 adjustSizeOfWindowBy(QSize{0, wantedAdditionalHeight});
0095             }
0096         }
0097     }
0098     return QScrollArea::eventFilter(obj, ev);
0099 }