File indexing completed on 2024-06-23 05:14:18

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     utils/scrollarea.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 <config-kleopatra.h>
0013 
0014 #include "scrollarea.h"
0015 
0016 #include <QApplication>
0017 #include <QResizeEvent>
0018 #include <QScreen>
0019 #include <QScrollBar>
0020 #include <QVBoxLayout>
0021 
0022 using namespace Kleo;
0023 
0024 ScrollArea::ScrollArea(QWidget *parent)
0025     : QScrollArea{parent}
0026 {
0027     auto w = new QWidget;
0028     w->setObjectName(QLatin1StringView("scrollarea_widget"));
0029     new QVBoxLayout{w};
0030     setWidget(w);
0031     setWidgetResizable(true);
0032     w->installEventFilter(this);
0033 
0034     connect(qApp, &QApplication::focusChanged, this, [this](QWidget *old, QWidget *now) {
0035         Q_UNUSED(old);
0036         ensureWidgetVisible(now);
0037     });
0038 }
0039 
0040 ScrollArea::~ScrollArea()
0041 {
0042     widget()->removeEventFilter(this);
0043 }
0044 
0045 QSize ScrollArea::minimumSizeHint() const
0046 {
0047     const int fw = frameWidth();
0048     QSize sz{2 * fw, 2 * fw};
0049     sz += {widget()->minimumSizeHint().width(), 0};
0050     if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0051         sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
0052     }
0053     if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0054         sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
0055     }
0056     return QScrollArea::minimumSizeHint().expandedTo(sz);
0057 }
0058 
0059 QSize ScrollArea::sizeHint() const
0060 {
0061     const int fw = frameWidth();
0062     QSize sz{2 * fw, 2 * fw};
0063     sz += viewportSizeHint();
0064     if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0065         sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
0066     }
0067     if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
0068         sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
0069     }
0070     sz = QScrollArea::sizeHint().expandedTo(sz);
0071     return sz;
0072 }
0073 
0074 void ScrollArea::adjustSizeOfWindowBy(const QSize &extent)
0075 {
0076     if (auto w = window()) {
0077         const auto currentSize = w->size();
0078         // we limit the automatic size adjustment to 2/3 of the screen's size
0079         const auto maxWindowSize = screen()->geometry().size() * 2 / 3;
0080         const auto newWindowSize = currentSize.expandedTo((currentSize + extent).boundedTo(maxWindowSize));
0081         if (newWindowSize != currentSize) {
0082             w->resize(newWindowSize);
0083         }
0084     }
0085 }
0086 
0087 bool ScrollArea::eventFilter(QObject *obj, QEvent *ev)
0088 {
0089     if (ev->type() == QEvent::Resize && obj == widget() && sizeAdjustPolicy() == AdjustToContents) {
0090         const auto *const event = static_cast<QResizeEvent *>(ev);
0091         if (event->size().height() > event->oldSize().height()) {
0092             const auto currentViewportHeight = viewport()->height();
0093             const auto wantedViewportHeight = event->size().height();
0094             const auto wantedAdditionalHeight = wantedViewportHeight - currentViewportHeight;
0095             if (wantedAdditionalHeight > 0) {
0096                 adjustSizeOfWindowBy(QSize{0, wantedAdditionalHeight});
0097             }
0098         }
0099     }
0100     return QScrollArea::eventFilter(obj, ev);
0101 }
0102 
0103 #include "moc_scrollarea.cpp"