File indexing completed on 2024-05-12 16:02:09
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2007 Marijn Kruisselbrink <mkruisselbrink@kde.org> 0003 SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org> 0004 SPDX-FileCopyrightText: 2021 Alvin Wong <alvin@alvinhc.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "KoDockWidgetTitleBar.h" 0010 #include "KoDockWidgetTitleBar_p.h" 0011 #include "KoDockWidgetTitleBarButton.h" 0012 0013 #include <KoIcon.h> 0014 #include <kis_icon_utils.h> 0015 0016 #include <WidgetsDebug.h> 0017 #include <klocalizedstring.h> 0018 0019 #include <QAbstractButton> 0020 #include <QAction> 0021 #include <QHBoxLayout> 0022 #include <QLabel> 0023 #include <QStyle> 0024 #include <QStylePainter> 0025 #include <QStyleOptionFrame> 0026 0027 #include <KSqueezedTextLabel> 0028 0029 static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature) 0030 { 0031 return (dockwidget->features() & feature) == feature; 0032 } 0033 0034 constexpr int SPACING = 6; 0035 0036 KoDockWidgetTitleBar::KoDockWidgetTitleBar(QDockWidget* dockWidget) 0037 : QWidget(dockWidget), d(new Private(this)) 0038 { 0039 d->floatIcon = kisIcon("docker_float"); 0040 d->floatButton = new KoDockWidgetTitleBarButton(this); 0041 d->floatButton->setIcon(d->floatIcon); 0042 connect(d->floatButton, SIGNAL(clicked()), SLOT(toggleFloating())); 0043 d->floatButton->setVisible(true); 0044 d->floatButton->setToolTip(i18nc("@info:tooltip", "Float Docker")); 0045 d->floatButton->setStyleSheet("border: 0"); 0046 0047 d->removeIcon = kisIcon("docker_close"); 0048 d->closeButton = new KoDockWidgetTitleBarButton(this); 0049 d->closeButton->setIcon(d->removeIcon); 0050 connect(d->closeButton, SIGNAL(clicked()), dockWidget, SLOT(close())); 0051 d->closeButton->setVisible(true); 0052 d->closeButton->setToolTip(i18nc("@info:tooltip", "Close Docker")); 0053 d->closeButton->setStyleSheet("border: 0"); // border makes the header busy looking (appears on some OSs) 0054 0055 d->lockIcon = kisIcon("docker_lock_a"); 0056 d->lockButton = new KoDockWidgetTitleBarButton(this); 0057 d->lockButton->setCheckable(true); 0058 d->lockButton->setIcon(d->lockIcon); 0059 connect(d->lockButton, SIGNAL(toggled(bool)), SLOT(setLocked(bool))); 0060 d->lockButton->setVisible(true); 0061 d->lockButton->setToolTip(i18nc("@info:tooltip", "Lock Docker")); 0062 d->lockButton->setStyleSheet("border: 0"); 0063 0064 d->updateButtonSizes(); 0065 0066 d->titleLabel = new KSqueezedTextLabel(this); 0067 d->titleLabel->setTextElideMode(Qt::ElideRight); 0068 d->titleLabel->setText(dockWidget->windowTitle()); 0069 0070 QHBoxLayout *layout = new QHBoxLayout(this); 0071 layout->setContentsMargins(2, 0, 2, 0); 0072 layout->setSpacing(SPACING); 0073 layout->addWidget(d->lockButton); 0074 layout->addWidget(d->titleLabel, 1); 0075 layout->addWidget(d->floatButton); 0076 layout->addWidget(d->closeButton); 0077 0078 connect(dockWidget, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), SLOT(featuresChanged(QDockWidget::DockWidgetFeatures))); 0079 connect(dockWidget, SIGNAL(topLevelChanged(bool)), SLOT(topLevelChanged(bool))); 0080 connect(dockWidget, SIGNAL(windowTitleChanged(const QString &)), SLOT(dockWidgetTitleChanged(const QString &))); 0081 0082 d->featuresChanged(QDockWidget::NoDockWidgetFeatures); 0083 } 0084 0085 KoDockWidgetTitleBar::~KoDockWidgetTitleBar() 0086 { 0087 delete d; 0088 } 0089 0090 void KoDockWidgetTitleBar::paintEvent(QPaintEvent*) 0091 { 0092 QStylePainter p(this); 0093 0094 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget()); 0095 0096 int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q) : 0; 0097 int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q); 0098 0099 QStyleOptionDockWidget titleOpt; 0100 titleOpt.initFrom(q); 0101 0102 QSize lockButtonSize(0,0); 0103 if (d->lockButton->isVisible()) { 0104 lockButtonSize = d->lockButton->size(); 0105 } 0106 0107 // To improve the look with Fusion which has weird 13x15 button sizes 0108 int fusionTextOffset = 0; 0109 QRect styleTestRect = q->style()->subElementRect(QStyle::SE_DockWidgetFloatButton, &titleOpt, q); 0110 if (styleTestRect.width() < 16) { 0111 fusionTextOffset = d->lockButton->x(); 0112 } 0113 0114 titleOpt.rect = QRect(QPoint(fw + mw + lockButtonSize.width() + fusionTextOffset, 0), 0115 QSize(geometry().width() - (fw * 2) - mw - lockButtonSize.width(), geometry().height())); 0116 // We don't print the title text here. Instead, we have a QLabel. 0117 // titleOpt.title = q->windowTitle(); 0118 // FIXME: Maybe we just shouldn't use a QStylePainter at all? 0119 titleOpt.title = QString(); 0120 titleOpt.closable = hasFeature(q, QDockWidget::DockWidgetClosable); 0121 titleOpt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable); 0122 p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt); 0123 } 0124 0125 void KoDockWidgetTitleBar::resizeEvent(QResizeEvent*) 0126 { 0127 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget()); 0128 0129 if (q->isFloating() || (width() < (d->closeButton->width() + d->floatButton->width() + d->lockButton->width()) + 32)) { 0130 d->lockButton->setVisible(false); 0131 } else { 0132 d->lockButton->setVisible(true); 0133 } 0134 } 0135 0136 void KoDockWidgetTitleBar::setLocked(bool locked) 0137 { 0138 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget()); 0139 0140 d->locked = locked; 0141 d->lockButton->blockSignals(true); 0142 d->lockButton->setChecked(locked); 0143 d->lockButton->blockSignals(false); 0144 0145 if (locked) { 0146 d->features = q->features(); 0147 q->setFeatures(QDockWidget::NoDockWidgetFeatures); 0148 } 0149 else { 0150 q->setFeatures(d->features); 0151 } 0152 0153 q->toggleViewAction()->setEnabled(!locked); 0154 d->closeButton->setEnabled(!locked); 0155 d->floatButton->setEnabled(!locked); 0156 d->floatButton->setVisible(!locked); 0157 0158 d->updateIcons(); 0159 q->setProperty("Locked", locked); 0160 } 0161 0162 void KoDockWidgetTitleBar::updateIcons() 0163 { 0164 d->updateIcons(); 0165 } 0166 0167 void KoDockWidgetTitleBar::Private::toggleFloating() 0168 { 0169 QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget()); 0170 0171 q->setFloating(!q->isFloating()); 0172 updateIcons(); 0173 } 0174 0175 void KoDockWidgetTitleBar::Private::topLevelChanged(bool topLevel) 0176 { 0177 lockButton->setEnabled(!topLevel); 0178 updateIcons(); 0179 } 0180 0181 void KoDockWidgetTitleBar::Private::featuresChanged(QDockWidget::DockWidgetFeatures) 0182 { 0183 QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget()); 0184 0185 closeButton->setVisible(hasFeature(q, QDockWidget::DockWidgetClosable)); 0186 floatButton->setVisible(hasFeature(q, QDockWidget::DockWidgetFloatable)); 0187 0188 updateButtonSizes(); 0189 thePublic->resizeEvent(0); 0190 } 0191 0192 void KoDockWidgetTitleBar::Private::dockWidgetTitleChanged(const QString &title) 0193 { 0194 titleLabel->setText(title); 0195 } 0196 0197 0198 void KoDockWidgetTitleBar::Private::updateIcons() 0199 { 0200 lockIcon = (!locked) ? kisIcon("docker_lock_a") : kisIcon("docker_lock_b"); 0201 lockButton->setIcon(lockIcon); 0202 0203 // this method gets called when switching themes, so update all of the themed icons now 0204 floatButton->setIcon(kisIcon("docker_float")); 0205 closeButton->setIcon(kisIcon("docker_close")); 0206 0207 thePublic->resizeEvent(0); 0208 } 0209 0210 void KoDockWidgetTitleBar::Private::updateButtonSizes() 0211 { 0212 const QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget()); 0213 0214 const int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q) : 0; 0215 0216 QStyleOptionDockWidget opt; 0217 opt.initFrom(q); 0218 opt.rect = QRect(QPoint(fw, fw), QSize(thePublic->geometry().width() - (fw * 2), thePublic->geometry().height() - (fw * 2))); 0219 opt.title = q->windowTitle(); 0220 // Originally it was: 0221 // opt.closable = hasFeature(q, QDockWidget::DockWidgetClosable); 0222 // but I think we better just always pretend the close button is visible to 0223 // get the button size. 0224 opt.closable = true; 0225 opt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable); 0226 0227 // Again, we just always use the size of the close button, so we don't 0228 // need to get the size of the float button... 0229 // QRect floatRect = q->style()->subElementRect(QStyle::SE_DockWidgetFloatButton, &opt, q); 0230 const QRect closeRect = q->style()->subElementRect(QStyle::SE_DockWidgetCloseButton, &opt, q); 0231 QSize buttonSize = closeRect.size(); 0232 if (buttonSize.width() < 16) { 0233 // To improve the look with Fusion which has weird 13x15 button sizes 0234 buttonSize = QSize(16, 16); 0235 } else if (buttonSize.width() != buttonSize.height()) { 0236 // Just make sure the button is square... 0237 buttonSize.setHeight(buttonSize.width()); 0238 } 0239 0240 floatButton->setFixedSize(buttonSize); 0241 closeButton->setFixedSize(buttonSize); 0242 lockButton->setFixedSize(buttonSize); 0243 } 0244 0245 //have to include this because of Q_PRIVATE_SLOT 0246 #include "moc_KoDockWidgetTitleBar.cpp"