File indexing completed on 2025-04-27 03:58:31
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-15-08 0007 * Description : A floatable/dockable widget for thumbnail bars, 0008 * providing i drag handle similar to the 0009 * one on toolbars and a standard QAction to show/hide the 0010 * thumbnail bar. It inherits QDockWidget and can be used in 0011 * the dock area's of a QMainWindow. 0012 * 0013 * SPDX-FileCopyrightText: 2009 by Pieter Edelman <p dot edelman at gmx dot net> 0014 * 0015 * SPDX-License-Identifier: GPL-2.0-or-later 0016 * 0017 * ============================================================ */ 0018 0019 #include "thumbbardock.h" 0020 0021 // Qt includes 0022 0023 #include <QKeySequence> 0024 0025 // KDE includes 0026 0027 #include <klocalizedstring.h> 0028 0029 namespace Digikam 0030 { 0031 0032 class Q_DECL_HIDDEN DragHandle::Private 0033 { 0034 0035 public: 0036 0037 explicit Private() 0038 : parent (nullptr), 0039 currentArea(Qt::LeftDockWidgetArea) 0040 { 0041 } 0042 0043 QDockWidget* parent; 0044 Qt::DockWidgetArea currentArea; 0045 }; 0046 0047 DragHandle::DragHandle(QDockWidget* const parent) 0048 : QWidget(), 0049 d (new Private) 0050 { 0051 d->parent = parent; 0052 0053 setCursor(Qt::PointingHandCursor); 0054 setToolTip(i18n("Drag to reposition")); 0055 0056 // When the dock location changes, check if the orientation has changed. 0057 0058 connect(d->parent, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), 0059 this, SLOT(dockLocationChanged(Qt::DockWidgetArea))); 0060 } 0061 0062 DragHandle::~DragHandle() 0063 { 0064 delete d; 0065 } 0066 0067 void DragHandle::paintEvent(QPaintEvent*) 0068 { 0069 QPainter p(this); 0070 QStyle* const style = d->parent->style(); 0071 0072 // The QStyleOptionToolBar contains every parameter needed to draw the 0073 // handle. 0074 0075 QStyleOptionToolBar opt; 0076 opt.initFrom(d->parent); 0077 opt.features = QStyleOptionToolBar::Movable; 0078 0079 // If the thumbnail bar is laid out horizontally, the state should be set 0080 // to horizontal to draw the handle in the proper orientation. 0081 0082 if ((d->currentArea == Qt::LeftDockWidgetArea) || (d->currentArea == Qt::RightDockWidgetArea)) 0083 { 0084 opt.rect = QRect(opt.rect.x(), opt.rect.y(), 0085 d->parent->width(), 0086 style->pixelMetric(QStyle::PM_ToolBarHandleExtent)); 0087 } 0088 else 0089 { 0090 opt.state |= QStyle::State_Horizontal; 0091 opt.rect = QRect(opt.rect.x(), opt.rect.y(), 0092 style->pixelMetric(QStyle::PM_ToolBarHandleExtent), 0093 d->parent->height()); 0094 } 0095 0096 // Draw the toolbar handle. 0097 0098 style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this); 0099 } 0100 0101 void DragHandle::dockLocationChanged(Qt::DockWidgetArea area) 0102 { 0103 d->currentArea = area; 0104 0105 // When the dock widget that contains this handle changes to a different 0106 // orientation, the DockWidgetVerticalTitleBar feature needs to be adjusted: 0107 // present when the thumbbar orientation is horizontal, absent when it is 0108 // vertical(!) 0109 0110 if ((d->currentArea == Qt::LeftDockWidgetArea) || (d->currentArea == Qt::RightDockWidgetArea)) 0111 { 0112 d->parent->setFeatures(d->parent->features() & ~QDockWidget::DockWidgetVerticalTitleBar); 0113 } 0114 else 0115 { 0116 d->parent->setFeatures(d->parent->features() | QDockWidget::DockWidgetVerticalTitleBar); 0117 } 0118 } 0119 0120 QSize DragHandle::sizeHint() const 0121 { 0122 // Size is the sum of the margin, frame width and the handle itself. 0123 0124 QStyle* const style = d->parent->style(); 0125 int handleWidth = style->pixelMetric(QStyle::PM_ToolBarHandleExtent); 0126 int margin = style->pixelMetric(QStyle::PM_ToolBarItemMargin) + 0127 style->pixelMetric(QStyle::PM_ToolBarFrameWidth); 0128 0129 if ((d->currentArea == Qt::LeftDockWidgetArea) || (d->currentArea == Qt::RightDockWidgetArea)) 0130 { 0131 return QSize(d->parent->width(), handleWidth + 2*margin); 0132 } 0133 else 0134 { 0135 return QSize(handleWidth + 2*margin, d->parent->height()); 0136 } 0137 } 0138 0139 QSize DragHandle::minimumSizeHint() const 0140 { 0141 return QSize(0, 0); 0142 } 0143 0144 // ---------------------------------------------------------------------------- 0145 0146 ThumbBarDock::ThumbBarDock(QWidget* const parent, Qt::WindowFlags flags) 0147 : QDockWidget(parent, flags), 0148 m_visible (SHOULD_BE_SHOWN) 0149 { 0150 // Use a DragHandle as title bar widget. 0151 0152 setTitleBarWidget(new DragHandle(this)); 0153 setContextMenuPolicy(Qt::PreventContextMenu); 0154 } 0155 0156 ThumbBarDock::~ThumbBarDock() 0157 { 0158 } 0159 0160 void ThumbBarDock::reInitialize() 0161 { 0162 // Measure orientation of the widget and adjust the child thumbbar to this 0163 // orientation and size. 0164 0165 QMainWindow* const parent = qobject_cast<QMainWindow*>(parentWidget()); 0166 Q_EMIT dockLocationChanged(parent->dockWidgetArea(this)); 0167 widget()->resize(size()); 0168 update(); 0169 } 0170 0171 QAction* ThumbBarDock::getToggleAction(QObject* const parent, const QString& caption) const 0172 { 0173 QAction* const action = new QAction(QIcon::fromTheme(QLatin1String("view-choose")), 0174 caption.isNull() ? i18n("Show Thumbbar") : caption, 0175 parent); 0176 0177 action->setCheckable(true); 0178 0179 // Connect the triggered signal, which is only emitted after a user action 0180 // and not programmatically, to the show/hide method. 0181 0182 connect(action, SIGNAL(triggered(bool)), 0183 this, SLOT(showThumbBar(bool))); 0184 0185 // Connect the show/hide signal to the state of the toggle action. 0186 0187 connect(this, SIGNAL(visibilityChanged(bool)), 0188 action, SLOT(setChecked(bool))); 0189 0190 return action; 0191 } 0192 0193 void ThumbBarDock::restoreVisibility() 0194 { 0195 // Set the visibility to what it should be or to what it was. Reset 0196 // SHOULD_BE_ values to their WAS_ values, to implement correct behavior 0197 // on subsequent calls. 0198 0199 if (m_visible == SHOULD_BE_SHOWN) 0200 { 0201 m_visible = WAS_SHOWN; 0202 } 0203 else if (m_visible == SHOULD_BE_HIDDEN) 0204 { 0205 m_visible = WAS_HIDDEN; 0206 } 0207 0208 setVisible(m_visible == WAS_SHOWN); 0209 } 0210 0211 bool ThumbBarDock::shouldBeVisible() const 0212 { 0213 if ((m_visible == WAS_SHOWN) || (m_visible == SHOULD_BE_SHOWN)) 0214 { 0215 return true; 0216 } 0217 0218 return false; 0219 } 0220 0221 void ThumbBarDock::setShouldBeVisible(bool status) 0222 { 0223 if (status) 0224 { 0225 m_visible = SHOULD_BE_SHOWN; 0226 } 0227 else 0228 { 0229 m_visible = SHOULD_BE_HIDDEN; 0230 } 0231 } 0232 0233 void ThumbBarDock::showThumbBar(bool status) 0234 { 0235 if (status) 0236 { 0237 m_visible = WAS_SHOWN; 0238 } 0239 else 0240 { 0241 m_visible = WAS_HIDDEN; 0242 } 0243 0244 setVisible(status); 0245 } 0246 0247 QPixmap ThumbBarDock::generateFuzzyRect(const QSize& size, const QColor& color, int radius, const QColor& fillColor) 0248 { 0249 QPixmap pix(size); 0250 pix.fill(fillColor); 0251 0252 QPainter painter(&pix); 0253 painter.setRenderHint(QPainter::Antialiasing, true); 0254 0255 // Draw corners ---------------------------------- 0256 0257 QRadialGradient gradient; 0258 gradient.setColorAt(1, Qt::transparent); 0259 gradient.setColorAt(0, color); 0260 gradient.setRadius(radius); 0261 QPoint center; 0262 0263 // Top Left 0264 0265 center = QPoint(radius, radius); 0266 gradient.setCenter(center); 0267 gradient.setFocalPoint(center); 0268 painter.fillRect(0, 0, radius, radius, gradient); 0269 0270 // Top right 0271 0272 center = QPoint(size.width() - radius, radius); 0273 gradient.setCenter(center); 0274 gradient.setFocalPoint(center); 0275 painter.fillRect(center.x(), 0, radius, radius, gradient); 0276 0277 // Bottom left 0278 0279 center = QPoint(radius, size.height() - radius); 0280 gradient.setCenter(center); 0281 gradient.setFocalPoint(center); 0282 painter.fillRect(0, center.y(), radius, radius, gradient); 0283 0284 // Bottom right 0285 0286 center = QPoint(size.width() - radius, size.height() - radius); 0287 gradient.setCenter(center); 0288 gradient.setFocalPoint(center); 0289 painter.fillRect(center.x(), center.y(), radius, radius, gradient); 0290 0291 // Draw borders ---------------------------------- 0292 0293 QLinearGradient linearGradient; 0294 linearGradient.setColorAt(1, Qt::transparent); 0295 linearGradient.setColorAt(0, color); 0296 0297 // Top 0298 0299 linearGradient.setStart(0, radius); 0300 linearGradient.setFinalStop(0, 0); 0301 painter.fillRect(radius, 0, size.width() - 2*radius, radius, linearGradient); 0302 0303 // Bottom 0304 0305 linearGradient.setStart(0, size.height() - radius); 0306 linearGradient.setFinalStop(0, size.height()); 0307 painter.fillRect(radius, int(linearGradient.start().y()), size.width() - 2*radius, radius, linearGradient); 0308 0309 // Left 0310 0311 linearGradient.setStart(radius, 0); 0312 linearGradient.setFinalStop(0, 0); 0313 painter.fillRect(0, radius, radius, size.height() - 2*radius, linearGradient); 0314 0315 // Right 0316 0317 linearGradient.setStart(size.width() - radius, 0); 0318 linearGradient.setFinalStop(size.width(), 0); 0319 painter.fillRect(int(linearGradient.start().x()), radius, radius, size.height() - 2*radius, linearGradient); 0320 0321 return pix; 0322 } 0323 0324 QPixmap ThumbBarDock::generateFuzzyRectForGroup(const QSize& size, const QColor& color, int radius) 0325 { 0326 // Create two normal borders 0327 0328 QSize groupSize = size.scaled(size.width()-10, size.height()-10, Qt::KeepAspectRatio); 0329 QPixmap border1 = generateFuzzyRect(groupSize, color, radius, Qt::white); 0330 QPixmap border2 = border1.copy(); 0331 0332 QTransform rm; 0333 0334 // Rotate first border right by 4 degrees 0335 0336 rm.rotate(4); 0337 border1 = border1.transformed(rm, Qt::SmoothTransformation); 0338 0339 // Rotate second border left by 4 degrees 0340 0341 rm.rotate(-8); 0342 border2 = border2.transformed(rm, Qt::SmoothTransformation); 0343 0344 // Combine both borders 0345 0346 int width = qMax(border1.size().width(), border2.size().width()); 0347 int height = qMax(border1.size().height(), border2.size().height()); 0348 0349 QPixmap result(QSize(width, height)); 0350 result.fill(Qt::transparent); // force alpha channel 0351 0352 { 0353 QPainter painter(&result); 0354 painter.setRenderHints(QPainter::Antialiasing, true); 0355 painter.drawPixmap(0, 0, border1); 0356 painter.drawPixmap(0, 0, border2); 0357 } 0358 0359 return result; 0360 } 0361 0362 } // namespace Digikam 0363 0364 #include "moc_thumbbardock.cpp"