File indexing completed on 2024-11-10 04:42:40

0001 /*
0002  *  stackedwidgets.cpp  -  classes implementing stacked widgets
0003  *  Program:  kalarm
0004  *  SPDX-FileCopyrightText: 2008-2022 David Jarvie <djarvie@kde.org>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "stackedwidgets.h"
0010 
0011 #include "desktop.h"
0012 #include "kalarm_debug.h"
0013 
0014 #include <QDialog>
0015 #include <QStyle>
0016 
0017 
0018 QSize StackedWidget::sizeHint() const
0019 {
0020     QSize sz;
0021     for (int i = count();  --i >= 0;  )
0022         sz = sz.expandedTo(widget(i)->sizeHint());
0023     return sz;
0024 }
0025 
0026 QSize StackedWidget::minimumSizeHint() const
0027 {
0028     QSize sz;
0029     for (int i = count();  --i >= 0;  )
0030         sz = sz.expandedTo(widget(i)->minimumSizeHint());
0031     return sz;
0032 }
0033 
0034 
0035 /******************************************************************************
0036 */
0037 StackedScrollWidget::StackedScrollWidget(StackedScrollGroup* group, QWidget* parent)
0038     : StackedGroupWidgetT<QScrollArea>(group, parent)
0039 {
0040     setFrameStyle(QFrame::NoFrame);
0041     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0042     setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
0043     setWidgetResizable(true);
0044     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
0045 }
0046 
0047 StackedScrollGroup::StackedScrollGroup(QDialog* dlg, QWidget* container)
0048     : StackedGroupT<QScrollArea>(container)
0049     , mDialog(dlg)
0050 {
0051 }
0052 
0053 /******************************************************************************
0054 * Return the minimum size for the tabs, constrained if necessary to a height
0055 * that fits the screen.
0056 * In order to make the widget containing the tabs take the correct size, the
0057 * value returned is actually the minimum size of the largest tab.
0058 * Otherwise, only the currently visible tab would be taken into account with
0059 * the result that the dialog would initially be displayed too small.
0060 */
0061 QSize StackedScrollGroup::minimumSizeHint() const
0062 {
0063     const QSize s = maxMinimumSizeHint();
0064     if (!s.isEmpty()  &&  mMinHeight > 0  &&  mMinHeight < s.height())
0065         return {s.width() + mWidgets[0]->style()->pixelMetric(QStyle::PM_ScrollBarExtent), mMinHeight};
0066     return s;
0067 }
0068 
0069 /******************************************************************************
0070 * Return the maximum minimum size for any instance.
0071 */
0072 QSize StackedScrollGroup::maxMinimumSizeHint() const
0073 {
0074     QSize sz;
0075     for (const auto& sw : mWidgets)
0076     {
0077         QWidget* w = static_cast<StackedScrollWidget*>(sw)->widget();
0078         if (!w)
0079             return {};
0080         const QSize s = w->minimumSizeHint();
0081         if (!s.isValid())
0082             return {};
0083         sz = sz.expandedTo(s);
0084     }
0085     return sz;
0086 }
0087 
0088 /******************************************************************************
0089 * Return the minimum size for the dialog.
0090 * If the minimum size would be too high to fit the desktop, the tab contents
0091 * are made scrollable.
0092 */
0093 QSize StackedScrollGroup::adjustSize(bool force)
0094 {
0095     if (force)
0096         mSized = false;
0097     if (mSized)
0098         return {};
0099 
0100     // Cancel any previous minimum height and set the height of the
0101     // scroll widget contents widgets.
0102     mMinHeight = -1;
0103     mHeightReduction = 0;
0104     const QSize s = maxMinimumSizeHint();
0105     if (s.isEmpty())
0106         return {};
0107     const int maxTabHeight = s.height();
0108     for (auto& sw : mWidgets)
0109     {
0110         sw->setMinimumHeight(maxTabHeight);
0111         QWidget* w = static_cast<StackedScrollWidget*>(sw)->widget();
0112         if (w)
0113             w->resize(s);
0114     }
0115     for (QWidget* w = mWidgets.at(0)->parentWidget();  w && w != mDialog;  w = w->parentWidget())
0116     {
0117         w->setMinimumHeight(0);
0118         w->adjustSize();
0119     }
0120     mDialog->setMinimumHeight(0);
0121 
0122     int decoration = mDialog->frameGeometry().height() - mDialog->geometry().height();
0123     if (!decoration)
0124     {
0125         // On X11 at least, the window decoration height may not be
0126         // available, so use a guess of 25 pixels.
0127         decoration = 25;
0128     }
0129     const int desk = Desktop::workArea().height();
0130     // There is no stored size, or the deferral group is visible.
0131     // Allow the tab contents to be scrolled vertically if that is necessary
0132     // to avoid the dialog exceeding the screen height.
0133     QSize dlgsize = mDialog->QDialog::minimumSizeHint();
0134     const int y = dlgsize.height() + decoration - desk;
0135     if (y > 0)
0136     {
0137         mHeightReduction = y;
0138         mMinHeight = maxTabHeight - y;
0139         qCDebug(KALARM_LOG) << "StackedScrollGroup::adjustSize: Scrolling: max tab height=" << maxTabHeight << ", reduction=" << mHeightReduction << "-> min tab height=" << mMinHeight;
0140         if (mMinHeight > 0)
0141         {
0142             for (auto& sw : mWidgets)
0143             {
0144                 sw->setMinimumHeight(mMinHeight);
0145                 sw->resize(QSize(sw->width(), mMinHeight));
0146             }
0147         }
0148         mSized = true;
0149         QSize sz = mWidgets.at(0)->parentWidget()->sizeHint();
0150         if (sz.height() < mMinHeight)
0151             sz.setHeight(mMinHeight);
0152         mWidgets.at(0)->parentWidget()->resize(sz);
0153         for (QWidget* w = mWidgets.at(0)->parentWidget();  w && w != mDialog;  w = w->parentWidget())
0154             w->setMinimumHeight(qMin(w->minimumSizeHint().height(), w->sizeHint().height()));
0155         dlgsize.setHeight(dlgsize.height() - mHeightReduction);
0156         sz = mDialog->QDialog::minimumSizeHint();
0157         if (sz.height() > dlgsize.height())
0158             dlgsize.setHeight(sz.height());
0159         mDialog->setMinimumHeight(dlgsize.height());
0160     }
0161     mSized = true;
0162     mDialog->resize(dlgsize);
0163     return s;
0164 }
0165 
0166 // vim: et sw=4: