File indexing completed on 2025-04-27 03:58:32
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2007-04-15 0007 * Description : a zoom bar used in status bar. 0008 * 0009 * SPDX-FileCopyrightText: 2007-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "dzoombar.h" 0016 0017 // C++ includes 0018 0019 #include <cmath> 0020 0021 // Qt includes 0022 0023 #include <QLineEdit> 0024 #include <QAction> 0025 #include <QLayout> 0026 #include <QSlider> 0027 #include <QTimer> 0028 #include <QToolButton> 0029 #include <QList> 0030 #include <QComboBox> 0031 #include <QLocale> 0032 0033 // KDE includes 0034 0035 #include <klocalizedstring.h> 0036 0037 // Local includes 0038 0039 #include "digikam_debug.h" 0040 #include "dcursortracker.h" 0041 #include "thumbnailsize.h" 0042 0043 namespace Digikam 0044 { 0045 0046 class Q_DECL_HIDDEN DZoomBar::Private 0047 { 0048 public: 0049 0050 explicit Private() 0051 : zoomToFitButton(nullptr), 0052 zoomTo100Button(nullptr), 0053 zoomPlusButton (nullptr), 0054 zoomMinusButton(nullptr), 0055 zoomTimer (nullptr), 0056 zoomSlider (nullptr), 0057 zoomCombo (nullptr), 0058 zoomTracker (nullptr) 0059 { 0060 } 0061 0062 QToolButton* zoomToFitButton; 0063 QToolButton* zoomTo100Button; 0064 QToolButton* zoomPlusButton; 0065 QToolButton* zoomMinusButton; 0066 0067 QTimer* zoomTimer; 0068 0069 QSlider* zoomSlider; 0070 0071 QComboBox* zoomCombo; 0072 0073 DCursorTracker* zoomTracker; 0074 }; 0075 0076 DZoomBar::DZoomBar(QWidget* const parent) 0077 : DHBox(parent), 0078 d(new Private) 0079 { 0080 setAttribute(Qt::WA_DeleteOnClose); 0081 setFocusPolicy(Qt::NoFocus); 0082 0083 d->zoomToFitButton = new QToolButton(this); 0084 d->zoomToFitButton->setAutoRaise(true); 0085 d->zoomToFitButton->setFocusPolicy(Qt::NoFocus); 0086 0087 d->zoomTo100Button = new QToolButton(this); 0088 d->zoomTo100Button->setAutoRaise(true); 0089 d->zoomTo100Button->setFocusPolicy(Qt::NoFocus); 0090 0091 d->zoomMinusButton = new QToolButton(this); 0092 d->zoomMinusButton->setAutoRaise(true); 0093 d->zoomMinusButton->setFocusPolicy(Qt::NoFocus); 0094 0095 d->zoomSlider = new QSlider(Qt::Horizontal, this); 0096 d->zoomTracker = new DCursorTracker(QLatin1String(""), d->zoomSlider); 0097 d->zoomSlider->setRange(ThumbnailSize::Small, ThumbnailSize::maxThumbsSize()); 0098 d->zoomSlider->setSingleStep(ThumbnailSize::Step); 0099 d->zoomSlider->setValue(ThumbnailSize::Medium); 0100 d->zoomSlider->setFixedWidth(120); 0101 d->zoomSlider->setFocusPolicy(Qt::NoFocus); 0102 d->zoomSlider->setInvertedControls(true); // See bug #161087 0103 0104 d->zoomPlusButton = new QToolButton(this); 0105 d->zoomPlusButton->setAutoRaise(true); 0106 d->zoomPlusButton->setFocusPolicy(Qt::NoFocus); 0107 0108 d->zoomCombo = new QComboBox(this); 0109 d->zoomCombo->setEditable(true); 0110 d->zoomCombo->setDuplicatesEnabled(false); 0111 d->zoomCombo->setFocusPolicy(Qt::ClickFocus); 0112 d->zoomCombo->setInsertPolicy(QComboBox::NoInsert); 0113 0114 QList<double> zoomLevels; 0115 zoomLevels << 10.0; 0116 zoomLevels << 25.0; 0117 zoomLevels << 50.0; 0118 zoomLevels << 75.0; 0119 zoomLevels << 100.0; 0120 zoomLevels << 150.0; 0121 zoomLevels << 200.0; 0122 zoomLevels << 300.0; 0123 zoomLevels << 450.0; 0124 zoomLevels << 600.0; 0125 zoomLevels << 800.0; 0126 zoomLevels << 1200.0; 0127 0128 Q_FOREACH (const double zoom, zoomLevels) 0129 { 0130 d->zoomCombo->addItem(QString::fromLatin1("%1%").arg((int)zoom), QVariant(zoom)); 0131 } 0132 0133 layout()->setContentsMargins(QMargins()); 0134 layout()->setSpacing(0); 0135 0136 // ------------------------------------------------------------- 0137 0138 connect(d->zoomSlider, SIGNAL(valueChanged(int)), 0139 this, SIGNAL(signalZoomSliderChanged(int))); 0140 0141 connect(d->zoomSlider, SIGNAL(valueChanged(int)), 0142 this, SLOT(slotZoomSliderChanged(int))); 0143 0144 connect(d->zoomSlider, SIGNAL(sliderReleased()), 0145 this, SLOT(slotZoomSliderReleased())); 0146 0147 connect(d->zoomCombo, SIGNAL(activated(int)), 0148 this, SLOT(slotZoomSelected(int))); 0149 0150 connect(d->zoomCombo->lineEdit(), SIGNAL(returnPressed()), 0151 this, SLOT(slotZoomTextChanged())); 0152 0153 // ------------------------------------------------------------- 0154 0155 setBarMode(PreviewZoomCtrl); 0156 } 0157 0158 DZoomBar::~DZoomBar() 0159 { 0160 delete d->zoomTimer; 0161 delete d; 0162 } 0163 0164 void DZoomBar::setZoomToFitAction(QAction* const action) 0165 { 0166 d->zoomToFitButton->setDefaultAction(action); 0167 } 0168 0169 void DZoomBar::setZoomTo100Action(QAction* const action) 0170 { 0171 d->zoomTo100Button->setDefaultAction(action); 0172 } 0173 0174 void DZoomBar::setZoomPlusAction(QAction* const action) 0175 { 0176 d->zoomPlusButton->setDefaultAction(action); 0177 } 0178 0179 void DZoomBar::setZoomMinusAction(QAction* const action) 0180 { 0181 d->zoomMinusButton->setDefaultAction(action); 0182 } 0183 0184 void DZoomBar::slotZoomSliderChanged(int) 0185 { 0186 if (d->zoomTimer) 0187 { 0188 d->zoomTimer->stop(); 0189 delete d->zoomTimer; 0190 } 0191 0192 d->zoomTimer = new QTimer( this ); 0193 0194 connect(d->zoomTimer, SIGNAL(timeout()), 0195 this, SLOT(slotDelayedZoomSliderChanged()) ); 0196 0197 d->zoomTimer->setSingleShot(true); 0198 d->zoomTimer->start(300); 0199 } 0200 0201 void DZoomBar::slotDelayedZoomSliderChanged() 0202 { 0203 Q_EMIT signalDelayedZoomSliderChanged(d->zoomSlider->value()); 0204 } 0205 0206 void DZoomBar::slotZoomSliderReleased() 0207 { 0208 Q_EMIT signalZoomSliderReleased(d->zoomSlider->value()); 0209 } 0210 0211 void DZoomBar::setZoom(double zoom, double zmin, double zmax) 0212 { 0213 int size = sizeFromZoom(zoom, zmin, zmax); 0214 0215 d->zoomSlider->blockSignals(true); 0216 d->zoomSlider->setValue(size); 0217 d->zoomSlider->blockSignals(false); 0218 0219 QString ztxt = QString::number(lround(zoom*100.0)) + QLatin1String("%"); 0220 d->zoomCombo->blockSignals(true); 0221 d->zoomCombo->setCurrentIndex(-1); 0222 d->zoomCombo->setEditText(ztxt); 0223 d->zoomCombo->blockSignals(false); 0224 } 0225 0226 void DZoomBar::setThumbsSize(int size) 0227 { 0228 d->zoomSlider->blockSignals(true); 0229 d->zoomSlider->setValue(size); 0230 d->zoomSlider->blockSignals(false); 0231 0232 d->zoomTracker->setText(i18n("Size: %1", size)); 0233 triggerZoomTrackerToolTip(); 0234 } 0235 0236 int DZoomBar::sizeFromZoom(double zoom, double zmin, double zmax) 0237 { 0238 double h = (double)ThumbnailSize::maxThumbsSize(); 0239 double s = (double)ThumbnailSize::Small; 0240 double zoomN = log(zoom)/log(2); 0241 double zminN = log(zmin)/log(2); 0242 double zmaxN = log(zmax)/log(2); 0243 double zval = (zoomN-zminN)/(zmaxN-zminN); 0244 0245 return (int)(zval*(h - s) + s); 0246 } 0247 0248 double DZoomBar::zoomFromSize(int size, double zmin, double zmax) 0249 { 0250 double h = (double)ThumbnailSize::maxThumbsSize(); 0251 double s = (double)ThumbnailSize::Small; 0252 double zminN = log(zmin)/log(2); 0253 double zmaxN = log(zmax)/log(2); 0254 double zval = (size - s)/(h - s); 0255 0256 return pow(2, zval*(zmaxN-zminN) + zminN); 0257 } 0258 0259 void DZoomBar::triggerZoomTrackerToolTip() 0260 { 0261 d->zoomTracker->triggerAutoShow(); 0262 } 0263 0264 void DZoomBar::slotUpdateTrackerPos() 0265 { 0266 d->zoomTracker->refresh(); 0267 } 0268 0269 void DZoomBar::slotZoomSelected(int index) 0270 { 0271 bool ok = false; 0272 double zoom = d->zoomCombo->itemData(index).toDouble(&ok) / 100.0; 0273 0274 if (ok && (zoom > 0.0)) 0275 { 0276 Q_EMIT signalZoomValueEdited(zoom); 0277 } 0278 } 0279 0280 void DZoomBar::slotZoomTextChanged() 0281 { 0282 QString txt = d->zoomCombo->currentText(); 0283 bool ok = false; 0284 double zoom = QLocale().toDouble(txt, &ok) / 100.0; 0285 0286 if (ok && (zoom > 0.0) && (zoom <= 48.0)) 0287 { 0288 Q_EMIT signalZoomValueEdited(zoom); 0289 } 0290 } 0291 0292 void DZoomBar::setBarMode(BarMode mode) 0293 { 0294 QAction* const zfitAction = d->zoomToFitButton->defaultAction(); 0295 QAction* const z100Action = d->zoomTo100Button->defaultAction(); 0296 0297 switch (mode) 0298 { 0299 case PreviewZoomCtrl: 0300 { 0301 d->zoomToFitButton->show(); 0302 0303 if (zfitAction) 0304 { 0305 zfitAction->setEnabled(true); 0306 } 0307 0308 d->zoomTo100Button->show(); 0309 0310 if (z100Action) 0311 { 0312 z100Action->setEnabled(true); 0313 } 0314 0315 d->zoomCombo->show(); 0316 d->zoomCombo->setEnabled(true); 0317 d->zoomTracker->setEnable(false); 0318 break; 0319 } 0320 0321 case ThumbsSizeCtrl: 0322 { 0323 d->zoomToFitButton->show(); 0324 0325 if (zfitAction) 0326 { 0327 zfitAction->setEnabled(true); 0328 } 0329 0330 d->zoomTo100Button->show(); 0331 0332 if (z100Action) 0333 { 0334 z100Action->setEnabled(false); 0335 } 0336 0337 d->zoomCombo->show(); 0338 d->zoomCombo->setEnabled(false); 0339 d->zoomTracker->setEnable(true); 0340 break; 0341 } 0342 0343 default: // NoPreviewZoomCtrl 0344 { 0345 d->zoomToFitButton->hide(); 0346 d->zoomTo100Button->hide(); 0347 d->zoomCombo->hide(); 0348 d->zoomTracker->setEnable(true); 0349 break; 0350 } 0351 } 0352 } 0353 0354 } // namespace Digikam 0355 0356 #include "moc_dzoombar.cpp"