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

0001 /*
0002  *  stackedwidgets.h  -  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 #pragma once
0010 
0011 #include <QList>
0012 #include <QScrollArea>
0013 #include <QStackedWidget>
0014 class QDialog;
0015 
0016 /**
0017  *  A QStackedWidget, whose size hint is that of the largest widget in the stack.
0018  *
0019  *  @author David Jarvie <djarvie@kde.org>
0020  */
0021 class StackedWidget : public QStackedWidget
0022 {
0023 public:
0024     /** Constructor.
0025      *  @param parent The parent object of this widget.
0026      */
0027     explicit StackedWidget(QWidget* parent = nullptr)
0028           : QStackedWidget(parent)  {}
0029     QSize sizeHint() const override;
0030     QSize minimumSizeHint() const override;
0031 };
0032 
0033 template <class T> class StackedGroupT;
0034 
0035 /**
0036  *  A widget contained in a stack, whose minimum size hint is that of the largest
0037  *  widget in the stack. This class works together with StackedGroup.
0038  *
0039  *  Do not use this class for widgets contained in a QStackedWidget or
0040  *  StackedWidget.
0041  *
0042  *  @tparam T  The base class for this widget. Must be derived from QWidget.
0043 
0044  *  @author David Jarvie <djarvie@kde.org>
0045  */
0046 template <class T>
0047 class StackedGroupWidgetT : public T
0048 {
0049 public:
0050     /** Constructor.
0051      *  @param group  The stack group to insert this widget into.
0052      *  @param parent The parent object of this widget.
0053      */
0054     explicit StackedGroupWidgetT(StackedGroupT<T>* group, QWidget* parent = nullptr)
0055           : T(parent),
0056             mGroup(group)
0057     {
0058         mGroup->addWidget(this);
0059     }
0060     ~StackedGroupWidgetT() override  { mGroup->removeWidget(this); }
0061     QSize sizeHint() const         override { return minimumSizeHint(); }
0062     QSize minimumSizeHint() const  override { return mGroup->minimumSizeHint(); }
0063 
0064 private:
0065     StackedGroupT<T>* mGroup;
0066 };
0067 
0068 /**
0069  *  A group of stacked widgets whose minimum size hints are all equal to the
0070  *  largest widget's minimum size hint. Use this alongside the widgets' container,
0071  *  e.g. QTabWidget.
0072  *
0073  *  It is inherited from QObject solely to ensure automatic deletion when its
0074  *  parent widget is deleted.
0075  *
0076  *  @author David Jarvie <djarvie@kde.org>
0077  */
0078 template <class T>
0079 class StackedGroupT : public QObject
0080 {
0081 public:
0082     /** Constructor.
0083      *  @param container  The parent widget. This should be set to the container
0084      *                    for the stacked widgets, which will ensure that this
0085      *                    object is deleted when the container is deleted.
0086      */
0087     explicit StackedGroupT(QWidget* container) : QObject(container) {}
0088 
0089     void  addWidget(StackedGroupWidgetT<T>* w)     { mWidgets += w; }
0090     void  removeWidget(StackedGroupWidgetT<T>* w)  { mWidgets.removeAll(w); }
0091     virtual QSize minimumSizeHint() const;
0092 
0093 protected:
0094     QList<StackedGroupWidgetT<T>*> mWidgets;
0095 };
0096 
0097 template <class T>
0098 QSize StackedGroupT<T>::minimumSizeHint() const
0099 {
0100     QSize sz;
0101     for (const auto& w : mWidgets)
0102         sz = sz.expandedTo(w->T::minimumSizeHint());
0103     return sz;
0104 }
0105 
0106 /** A non-scrollable stacked QWidget. */
0107 using StackedGroupWidget = StackedGroupWidgetT<QWidget>;
0108 /** A group of non-scrollable stacked widgets which are each derived from QWidget. */
0109 using StackedGroup = StackedGroupT<QWidget>;
0110 
0111 
0112 class StackedScrollGroup;
0113 
0114 /**
0115  *  A stacked QScrollArea widget, which becomes scrollable when necessary to
0116  *  fit the height of the screen.
0117  *
0118  *  Do not use this class for widgets contained in a QStackedWidget or
0119  *  StackedWidget.
0120  *
0121  *  @author David Jarvie <djarvie@kde.org>
0122  */
0123 class StackedScrollWidget : public StackedGroupWidgetT<QScrollArea>
0124 {
0125 public:
0126     explicit StackedScrollWidget(StackedScrollGroup* group, QWidget* parent = nullptr);
0127     QWidget* widget() const  { return viewport()->findChild<QWidget*>(); }
0128 };
0129 
0130 /**
0131  *  A group of stacked StackedScrollWidget widgets, which individually become
0132  *  scrollable when necessary to fit the height of the screen.
0133  *
0134  *  @author David Jarvie <djarvie@kde.org>
0135  */
0136 class StackedScrollGroup : public StackedGroupT<QScrollArea>
0137 {
0138 public:
0139     /** Constructor.
0140      *  @param dialog     The dialog which contains the widgets.
0141      *  @param container  The parent widget. This should be set to the container
0142      *                    for the stacked widgets, which will ensure that this
0143      *                    object is deleted when the container is deleted.
0144      */
0145     StackedScrollGroup(QDialog* dialog, QWidget* container);
0146 
0147     /** Return the minimum size for the tabs, constrained if necessary to a height
0148      *  that fits the dialog into the screen. The dialog height must have been
0149      *  previously evaluated by calling adjustSize().
0150      */
0151     QSize minimumSizeHint() const override;
0152 
0153     /** Return the reduction in dialog height which adjustSize() performed in
0154      *  order to fit the dialog to the desktop.
0155      */
0156     int heightReduction() const  { return mHeightReduction; }
0157 
0158     /** Set the minimum height for the dialog, so as to accommodate the tabs,
0159      *  but constrained to fit the desktop. If necessary, the tab contents are
0160      *  made scrollable.
0161      *  @param force  If false, this method will only evaluate and set the
0162      *                minimum dialog height the first time it is called. Set
0163      *                true to force re-evaluation.
0164      *  @return The minimum size for the dialog, or null if the size was not evaluated.
0165      */
0166     QSize adjustSize(bool force = false);
0167 
0168     /** Prevent adjustSize(false) from evaluating or setting the dialog height. */
0169     void setSized()              { mSized = true; }
0170 
0171     /** Return whether the dialog size has already been set, e.g. by adjustSize(). */
0172     bool sized() const           { return mSized; }
0173 
0174 private:
0175     QSize    maxMinimumSizeHint() const;
0176 
0177     QDialog* mDialog;
0178     int      mMinHeight {-1};
0179     int      mHeightReduction {0};
0180     bool     mSized {false};
0181 };
0182 
0183 // vim: et sw=4: