1// SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
2// SPDX-FileCopyrightText: 2022 g10 Code GmbH
3// SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
4// SPDX-FileContributor: Carl Schwan <carl.schwan@gnupg.com>
5//
6// SPDX-License-Identifier: LGPL-2.1-or-later
7
8#include "kadjustingscrollarea.h"
9
10#include <QApplication>
11#include <QResizeEvent>
12#include <QScreen>
13#include <QScrollBar>
14#include <QVBoxLayout>
15
16KAdjustingScrollArea::KAdjustingScrollArea(QWidget *parent)
17 : QScrollArea{parent}
18{
19 setWidgetResizable(true);
20
21 connect(qApp, signal: &QApplication::focusChanged, context: this, slot: [this](QWidget *old, QWidget *now) {
22 Q_UNUSED(old);
23 ensureWidgetVisible(childWidget: now);
24 });
25
26 viewport()->installEventFilter(filterObj: this);
27}
28
29KAdjustingScrollArea::~KAdjustingScrollArea()
30{
31 viewport()->removeEventFilter(obj: this);
32 if (auto w = widget()) {
33 w->removeEventFilter(obj: this);
34 }
35}
36
37QSize KAdjustingScrollArea::minimumSizeHint() const
38{
39 const int fw = frameWidth();
40 QSize sz{2 * fw, 2 * fw};
41 sz += {widget()->minimumSizeHint().width(), 0};
42 if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
43 sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
44 }
45 if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
46 sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
47 }
48 return QScrollArea::minimumSizeHint().expandedTo(otherSize: sz);
49}
50
51QSize KAdjustingScrollArea::sizeHint() const
52{
53 const int fw = frameWidth();
54 QSize sz{2 * fw, 2 * fw};
55 sz += viewportSizeHint();
56 if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
57 sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
58 }
59 if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
60 sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
61 }
62 sz = QScrollArea::sizeHint().expandedTo(otherSize: sz);
63 return sz;
64}
65
66static void adjustSizeOfWindowBy(const QSize &extent, QWidget *window)
67{
68 if (window) {
69 const auto currentSize = window->size();
70 // we limit the automatic size adjustment to 2/3 of the screen's size
71 const auto maxWindowSize = window->screen()->geometry().size() * 2 / 3;
72 const auto newWindowSize = currentSize.expandedTo(otherSize: (currentSize + extent).boundedTo(otherSize: maxWindowSize));
73 if (newWindowSize != currentSize) {
74 window->resize(newWindowSize);
75 }
76 }
77}
78
79bool KAdjustingScrollArea::eventFilter(QObject *obj, QEvent *ev)
80{
81 if (ev->type() == QEvent::ChildAdded && viewport() == obj) {
82 auto childAddedEvent = static_cast<QChildEvent *>(ev);
83 auto widget = childAddedEvent->child();
84 if (widget->objectName().isEmpty()) {
85 widget->setObjectName(QLatin1StringView("scrollarea_widget"));
86 }
87 widget->installEventFilter(filterObj: this);
88 }
89 if (ev->type() == QEvent::ChildRemoved && viewport() == obj) {
90 auto childRemovedEvent = static_cast<QChildEvent *>(ev);
91 auto widget = childRemovedEvent->child();
92 widget->removeEventFilter(obj: this);
93 }
94 if (ev->type() == QEvent::Resize && obj == widget() && sizeAdjustPolicy() == AdjustToContents) {
95 const auto *const event = static_cast<QResizeEvent *>(ev);
96 if (event->size().height() > event->oldSize().height()) {
97 const auto currentViewportHeight = viewport()->height();
98 const auto wantedViewportHeight = event->size().height();
99 const auto wantedAdditionalHeight = wantedViewportHeight - currentViewportHeight;
100 if (wantedAdditionalHeight > 0) {
101 adjustSizeOfWindowBy(extent: QSize{0, wantedAdditionalHeight}, window: window());
102 }
103 }
104 }
105 return QScrollArea::eventFilter(obj, ev);
106}
107
108bool KAdjustingScrollArea::event(QEvent *event)
109{
110 return QScrollArea::event(event);
111}
112
113#include "moc_kadjustingscrollarea.cpp"
114

source code of kwidgetsaddons/src/kadjustingscrollarea.cpp