File indexing completed on 2025-04-27 03:58:30

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-03-22
0007  * Description : a widget to manage sidebar in GUI.
0008  *
0009  * SPDX-FileCopyrightText: 2005-2006 by Joern Ahrens <joern dot ahrens at kdemail dot net>
0010  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2008-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0012  * SPDX-FileCopyrightText: 2001-2003 by Joseph Wenninger <jowenn at kde dot org>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #ifndef DIGIKAM_SIDE_BAR_H
0019 #define DIGIKAM_SIDE_BAR_H
0020 
0021 // Qt includes
0022 
0023 #include <QIcon>
0024 #include <QPixmap>
0025 #include <QSplitter>
0026 #include <QPushButton>
0027 #include <QWidget>
0028 #include <QList>
0029 #include <QStyleOptionToolButton>
0030 #include <QBoxLayout>
0031 
0032 // Local includes
0033 
0034 #include "digikam_export.h"
0035 #include "statesavingobject.h"
0036 
0037 class KConfigGroup;
0038 
0039 namespace Digikam
0040 {
0041 
0042 class DMultiTabBarButton;
0043 class DMultiTabBarTab;
0044 
0045 /**
0046  * A Widget for horizontal and vertical tabs.
0047  */
0048 class DIGIKAM_EXPORT DMultiTabBar : public QWidget
0049 {
0050     Q_OBJECT
0051 
0052 public:
0053 
0054     /**
0055      * The list of available styles for DMultiTabBar
0056      */
0057     enum TextStyle
0058     {
0059         ActiveIconText = 0, ///< Always shows icon, only show the text of active tabs.
0060         AllIconsText   = 2  ///< Always shows the text and icons.
0061     };
0062 
0063 public:
0064 
0065     explicit DMultiTabBar(Qt::Edge pos, QWidget* const parent = nullptr);
0066     ~DMultiTabBar() override;
0067 
0068     /**
0069      * append  a new button to the button area. The button can later on be accessed with button(ID)
0070      * eg for connecting signals to it
0071      * @param pic a icon for the button
0072      * @param id an arbitrary ID value. It will be emitted in the clicked signal for identifying the button
0073      *  if more than one button is connected to a signals.
0074      * @param popup A popup menu which should be displayed if the button is clicked
0075      * @param not_used_yet will be used for a popup text in the future
0076      */
0077     void appendButton(const QIcon& pic,
0078                       int id = -1,
0079                       QMenu* const popup = nullptr,
0080                       const QString& not_used_yet = QString());
0081 
0082     /**
0083      * remove a button with the given ID
0084      */
0085     void removeButton(int id);
0086 
0087     /**
0088      * append a new tab to the tab area. It can be accessed later on with tabb(id);
0089      * @param pic a icon for the tab
0090      * @param id an arbitrary ID which can be used later on to identify the tab
0091      * @param text if a mode with text is used it will be the tab text, otherwise a mouse over hint
0092      */
0093     void appendTab(const QIcon& pic,
0094                    int id = -1,
0095                    const QString& text = QString());
0096 
0097     /**
0098      * remove a tab with a given ID
0099      */
0100     void removeTab(int id);
0101 
0102     /**
0103      * set a tab to "raised"
0104      * @param id The ID of the tab to manipulate
0105      * @param state true == activated/raised, false == not active
0106      */
0107     void setTab(int id, bool state);
0108 
0109     /**
0110      * return the state of a tab, identified by its ID
0111      */
0112     bool isTabRaised(int id)           const;
0113 
0114     /**
0115      * get a pointer to a button within the button area identified by its ID
0116      */
0117     DMultiTabBarButton* button(int id) const;
0118 
0119     /**
0120      * get a pointer to a tab within the tab area, identified by its ID
0121      */
0122     DMultiTabBarTab* tab(int id)       const;
0123 
0124     /**
0125      * set the real position of the widget.
0126      * @param pos if the mode is horizontal, only use top, bottom, if it is vertical use left or right
0127      */
0128     void setPosition(Qt::Edge pos);
0129 
0130     /**
0131      * get the tabbar position.
0132      * @return position
0133      */
0134     Qt::Edge position()                const;
0135 
0136     /**
0137      * set the display style of the tabs
0138      */
0139     void setStyle(TextStyle style);
0140 
0141     /**
0142      * get the display style of the tabs
0143      * @return display style
0144      */
0145     TextStyle tabStyle()               const;
0146 
0147 protected:
0148 
0149     void updateSeparator();
0150 
0151     virtual void fontChange(const QFont&);
0152 
0153 private:
0154 
0155     friend class DMultiTabBarButton;
0156 
0157     class Private;
0158     Private* const d;
0159 };
0160 
0161 // -------------------------------------------------------------------------------------
0162 
0163 class DIGIKAM_EXPORT DMultiTabBarButton: public QPushButton
0164 {
0165     Q_OBJECT
0166 
0167 public:
0168 
0169     ~DMultiTabBarButton()         override;
0170 
0171     int id() const;
0172 
0173 public Q_SLOTS:
0174 
0175     void setText(const QString& text);
0176 
0177 Q_SIGNALS:
0178 
0179     /**
0180      * this is emitted if the button is clicked
0181      * @param id the ID identifying the button
0182      */
0183     void signalClicked(int id);
0184 
0185 protected Q_SLOTS:
0186 
0187     virtual void slotClicked();
0188 
0189 protected:
0190 
0191     DMultiTabBarButton(const QIcon& pic,
0192                        const QString&,
0193                        int id,
0194                        QWidget* const parent);
0195 
0196     void hideEvent(QHideEvent*)   override;
0197     void showEvent(QShowEvent*)   override;
0198     void paintEvent(QPaintEvent*) override;
0199 
0200 private:
0201 
0202     friend class DMultiTabBar;
0203 
0204     int m_id;
0205 };
0206 
0207 // -------------------------------------------------------------------------------------
0208 
0209 class DIGIKAM_EXPORT DMultiTabBarTab: public DMultiTabBarButton
0210 {
0211     Q_OBJECT
0212 
0213 public:
0214 
0215     ~DMultiTabBarTab()            override;
0216 
0217     QSize sizeHint()        const override;
0218     QSize minimumSizeHint() const override;
0219 
0220 public Q_SLOTS:
0221 
0222     /**
0223      * this is used internally, but can be used by the user.
0224      * It the according call of DMultiTabBar is invoked though this modifications will be overwritten
0225      */
0226     void setPosition(Qt::Edge);
0227 
0228     /**
0229      * this is used internally, but can be used by the user.
0230      * It the according call of DMultiTabBar is invoked though this modifications will be overwritten
0231      */
0232     void setStyle(DMultiTabBar::TextStyle);
0233 
0234     /**
0235      * set the active state of the tab
0236      * @param  state true==active false==not active
0237      */
0238     void setState(bool state);
0239 
0240     void setIcon(const QString&);
0241     void setIcon(const QIcon&);
0242 
0243 protected:
0244 
0245     void    computeMargins (int* hMargin, int* vMargin)        const;
0246     QSize   computeSizeHint(bool withText)                     const;
0247     bool    shouldDrawText()                                   const;
0248     bool    isVertical()                                       const;
0249     QPixmap iconPixmap()                                       const;
0250     void    initButtonStyleOption(QStyleOptionToolButton* opt) const;
0251 
0252     friend class DMultiTabBarFrame;
0253 
0254     /**
0255      * This class should never be created except with the appendTab call of DMultiTabBar
0256      */
0257     DMultiTabBarTab(const QIcon& pic,
0258                     const QString&,
0259                     int id,
0260                     QWidget* const parent,
0261                     Qt::Edge pos,
0262                     DMultiTabBar::TextStyle style);
0263 
0264     void paintEvent(QPaintEvent*) override;
0265 
0266 private:
0267 
0268     class Private;
0269     Private* const d;
0270 };
0271 
0272 // -------------------------------------------------------------------------------------
0273 
0274 class DMultiTabBarFrame: public QFrame
0275 {
0276     Q_OBJECT
0277 
0278 public:
0279 
0280     explicit DMultiTabBarFrame(QWidget* const parent, Qt::Edge pos);
0281     ~DMultiTabBarFrame()                override;
0282 
0283     void appendTab(const QIcon&, int = -1, const QString& = QString());
0284     DMultiTabBarTab* tab(int) const;
0285     void removeTab(int);
0286     void setPosition(Qt::Edge pos);
0287     void setStyle(DMultiTabBar::TextStyle style);
0288     void showActiveTabTexts(bool show);
0289     QList<DMultiTabBarTab*>* tabs();
0290 
0291 protected:
0292 
0293     /**
0294      * Reimplemented from QScrollView
0295      * in order to ignore all mouseEvents on the viewport, so that the
0296      * parent can handle them.
0297      */
0298     virtual void contentsMousePressEvent(QMouseEvent*);
0299     void mousePressEvent(QMouseEvent*)  override;
0300 
0301 private:
0302 
0303     friend class DMultiTabBar;
0304 
0305     class Private;
0306     Private* const d;
0307 };
0308 
0309 // -------------------------------------------------------------------------------------
0310 
0311 class SidebarSplitter;
0312 
0313 /**
0314  * This class handles a sidebar view
0315  *
0316  * Since this class derives from StateSavingObject, you can call
0317  * StateSavingObject#loadState() and StateSavingObject#saveState()
0318  * for loading/saving of settings. However, if you use multiple
0319  * sidebar instances in your program, you have to remember to either
0320  * call QObject#setObjectName(), StateSavingObject#setEntryPrefix() or
0321  * StateSavingObject#setConfigGroup() first.
0322  */
0323 class DIGIKAM_EXPORT Sidebar : public DMultiTabBar,
0324                                public StateSavingObject
0325 {
0326     Q_OBJECT
0327 
0328 public:
0329 
0330     /**
0331      * Creates a new sidebar
0332      * @param parent sidebar's parent
0333      * @param sp sets the splitter, which should handle the width. The splitter normally
0334      *           is part of the main view. Internally, the width of the widget stack can
0335      *           be changed by a QSplitter.
0336      * @param side where the sidebar should be displayed. At the left or right border.
0337      *             Use Qt::LeftEdge or Qt::RightEdge.
0338      * @param minimizedDefault hide the sidebar when the program is started the first time.
0339      */
0340     explicit Sidebar(QWidget* const parent,
0341                      SidebarSplitter* const sp,
0342                      Qt::Edge side = Qt::LeftEdge,
0343                      bool minimizedDefault = false);
0344 
0345     ~Sidebar()                              override;
0346 
0347     SidebarSplitter* splitter()       const;
0348 
0349     /**
0350      * Appends a new tab to the sidebar
0351      * @param w widget which is activated by this tab
0352      * @param pic icon which is shown in this tab
0353      * @param title text which is shown it this tab
0354      */
0355     void appendTab(QWidget* const w, const QIcon& pic, const QString& title);
0356 
0357     /**
0358      * Deletes a tab from the tabbar
0359      */
0360     void deleteTab(QWidget* const w);
0361 
0362     /**
0363      * Activates a tab
0364      */
0365     void setActiveTab(QWidget* const w);
0366 
0367     /**
0368      * Activates a next tab from current one. If current one is last, first one is activated.
0369      */
0370     void activeNextTab();
0371 
0372     /**
0373      * Activates a previous tab from current one. If current one is first, last one is activated.
0374      */
0375     void activePreviousTab();
0376 
0377     /**
0378      * Returns the currently activated tab, or 0 if no tab is active
0379      */
0380     QWidget* getActiveTab()           const;
0381 
0382     /**
0383      * Hides the sidebar (display only the activation buttons)
0384      */
0385     void shrink();
0386 
0387     /**
0388      * Redisplays the whole sidebar
0389      */
0390     void expand();
0391 
0392     /**
0393      * Hide sidebar and backup minimized state.
0394      */
0395     void backup();
0396 
0397     /**
0398      * Hide sidebar and backup minimized state.
0399      * If there are other widgets in this splitter, stores
0400      * their sizes in the provided list.
0401      */
0402     void backup(const QList<QWidget*>& thirdWidgetsToBackup, QList<int>* const sizes);
0403 
0404     /**
0405      * Show sidebar and restore minimized state.
0406      */
0407     void restore();
0408 
0409     /**
0410      * Show sidebar and restore minimized state.
0411      * Restores other widgets' sizes in splitter.
0412      */
0413     void restore(const QList<QWidget*>& thirdWidgetsToRestore, const QList<int>& sizes);
0414 
0415     /**
0416      * Return the visible status of current sidebar tab.
0417      */
0418     bool isExpanded()                 const;
0419 
0420 protected:
0421 
0422     /**
0423      * Load the last view state from disk - called by StateSavingObject#loadState()
0424      */
0425     void doLoadState()                      override;
0426 
0427     /**
0428      * Save the view state to disk - called by StateSavingObject#saveState()
0429      */
0430     void doSaveState()                      override;
0431 
0432 private:
0433 
0434     bool eventFilter(QObject* o, QEvent* e) override;
0435     void switchTabAndStackToTab(int tab);
0436 
0437 private Q_SLOTS:
0438 
0439     /**
0440      * Activates a tab
0441      */
0442     void slotClicked(int tab);
0443 
0444     void slotExpandTimer();
0445     void slotDragSwitchTimer();
0446 
0447     void slotSplitterBtnClicked();
0448 
0449 Q_SIGNALS:
0450 
0451     /**
0452      * Is emitted, when another tab is activated
0453      */
0454     void signalChangedTab(QWidget* w);
0455 
0456     /**
0457      * Is emitted, when tab is shrink or expanded
0458      */
0459     void signalViewChanged();
0460 
0461 private:
0462 
0463     friend class SidebarSplitter;
0464 
0465     class Private;
0466     Private* const d;
0467 };
0468 
0469 // -----------------------------------------------------------------------------
0470 
0471 class DIGIKAM_EXPORT SidebarSplitter : public QSplitter
0472 {
0473     Q_OBJECT
0474 
0475 public:
0476 
0477     const static QString DEFAULT_CONFIG_KEY;
0478 
0479     /**
0480      *  This is a QSplitter with better support for storing its state
0481      *  in config files, especially if Sidebars are contained in the splitter.
0482      */
0483     explicit SidebarSplitter(QWidget* const parent = nullptr);
0484     explicit SidebarSplitter(Qt::Orientation orientation, QWidget* const parent = nullptr);
0485 
0486     ~SidebarSplitter()                    override;
0487 
0488     /**
0489      * Saves the splitter state to group, handling minimized sidebars correctly.
0490      * DEFAULT_CONFIG_KEY is used for storing the state.
0491      */
0492     void saveState(KConfigGroup& group);
0493 
0494     /**
0495      * Saves the splitter state to group, handling minimized sidebars correctly.
0496      * This version uses a specified key in the config group.
0497      */
0498     void saveState(KConfigGroup& group, const QString& key);
0499 
0500     /**
0501      * Restores the splitter state from group, handling minimized sidebars correctly.
0502      * DEFAULT_CONFIG_KEY is used for restoring the state.
0503      */
0504     void restoreState(KConfigGroup& group);
0505 
0506     /**
0507      * Restores the splitter state from group, handling minimized sidebars correctly.
0508      * This version uses a specified key in the config group.
0509      */
0510     void restoreState(KConfigGroup& group, const QString& key);
0511 
0512     /**
0513      * Returns the value of sizes() that corresponds to the given Sidebar or splitter child widget.
0514      */
0515     int size(Sidebar* const bar)    const;
0516     int size(QWidget* const widget) const;
0517 
0518     /**
0519      * Sets the splitter size for the given sidebar or splitter child widget to size.
0520      * Special value -1: Sets the minimum size hint of the widget.
0521      */
0522     void setSize(Sidebar* const bar, int size);
0523     void setSize(QWidget* const widget, int size);
0524 
0525     void addSplitterCollapserButton(QWidget* const widget);
0526 
0527 private Q_SLOTS:
0528 
0529     void slotSplitterMoved(int pos, int index);
0530 
0531 private:
0532 
0533     friend class Sidebar;
0534 
0535     class Private;
0536     Private* const d;
0537 };
0538 
0539 } // namespace Digikam
0540 
0541 #endif // DIGIKAM_SIDE_BAR_H