diff --git a/src/utils/scrollarea.cpp b/src/utils/scrollarea.cpp index 83ae05426..c4def5cf6 100644 --- a/src/utils/scrollarea.cpp +++ b/src/utils/scrollarea.cpp @@ -1,59 +1,96 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/scrollarea.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB + SPDX-FileCopyrightText: 2022 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "scrollarea.h" +#include +#include #include #include using namespace Kleo; ScrollArea::ScrollArea(QWidget *parent) : QScrollArea{parent} { auto w = new QWidget; w->setObjectName(QLatin1String("scrollarea_widget")); new QVBoxLayout{w}; setWidget(w); setWidgetResizable(true); + w->installEventFilter(this); } -ScrollArea::~ScrollArea() = default; +ScrollArea::~ScrollArea() +{ + widget()->removeEventFilter(this); +} + +void ScrollArea::setMaximumAutoAdjustHeight(int maxHeight) +{ + mMaximumAutoAdjustHeight = maxHeight; +} + +int ScrollArea::maximumAutoAdjustHeight() const +{ + if (mMaximumAutoAdjustHeight < 0) { + // if no height is set then use 2/3 of the desktop's height, i.e. + // the same as Qt uses for top-level widgets + return screen()->availableGeometry().height() * 2 / 3; + } + return mMaximumAutoAdjustHeight; +} QSize ScrollArea::minimumSizeHint() const { const int fw = frameWidth(); QSize sz{2 * fw, 2 * fw}; sz += widget()->minimumSizeHint(); if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) { sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width()); } if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) { sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height()); } return QScrollArea::minimumSizeHint().expandedTo(sz); } QSize ScrollArea::sizeHint() const { const int fw = frameWidth(); QSize sz{2 * fw, 2 * fw}; sz += viewportSizeHint(); if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) { sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width()); } if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) { sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height()); } sz = QScrollArea::sizeHint().expandedTo(sz); return sz; } +bool ScrollArea::eventFilter(QObject *obj, QEvent *ev) +{ + if (ev->type() == QEvent::Resize && obj == widget() && sizeAdjustPolicy() == AdjustToContents) { + const auto *const event = static_cast(ev); + if (event->size().height() > event->oldSize().height()) { + const auto currentViewportHeight = viewport()->height(); + const auto wantedViewportHeight = std::min(event->size().height(), maximumAutoAdjustHeight()); + if (currentViewportHeight < wantedViewportHeight) { + setMinimumHeight(height() - currentViewportHeight + wantedViewportHeight); + } + } + } + return QScrollArea::eventFilter(obj, ev); +} diff --git a/src/utils/scrollarea.h b/src/utils/scrollarea.h index f4ef29fe2..d542c37b4 100644 --- a/src/utils/scrollarea.h +++ b/src/utils/scrollarea.h @@ -1,48 +1,73 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/scrollarea.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB + SPDX-FileCopyrightText: 2022 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include namespace Kleo { /** * This class improves a few aspects of QScrollArea for usage by us, in * particular, for vertically scrollable widgets. + * + * If sizeAdjustPolicy is set to QAbstractScrollArea::AdjustToContents, + * then the scroll area will (try to) adjust its size to the widget to avoid + * scroll bars as much as possible. */ class ScrollArea : public QScrollArea { Q_OBJECT public: /** * Creates a scroll area with a QWidget with QVBoxLayout that is flagged * as resizable. */ explicit ScrollArea(QWidget *parent = nullptr); ~ScrollArea() override; + /** + * Sets the maximum height that the scroll area should automatically resize + * to to \p maxHeight. By default, or if \p maxHeight is negative, the + * scroll area will resize to at most 2/3 of the desktop's height. + */ + void setMaximumAutoAdjustHeight(int maxHeight); + + /** + * Returns the maximum height that the scroll area will automatically resize + * to. + */ + int maximumAutoAdjustHeight() const; + /** * Reimplemented to add the minimum size hint of the widget. */ QSize minimumSizeHint() const override; /** * Reimplemented to remove the caching of the size/size hint of the * widget and to add the horizontal size hint of the vertical scroll bar * unless it is explicitly turned off. */ QSize sizeHint() const override; + +private: + bool eventFilter(QObject *obj, QEvent *ev) override; + +private: + int mMaximumAutoAdjustHeight = -1; }; }