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"