File indexing completed on 2024-04-28 04:18:54
0001 // vim: set tabstop=4 shiftwidth=4 expandtab: 0002 /* 0003 Gwenview: an image viewer 0004 Copyright 2008 Aurélien Gâteau <agateau@kde.org> 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License 0008 as published by the Free Software Foundation; either version 2 0009 of the License, or (at your option) any later version. 0010 0011 This program is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU General Public License for more details. 0015 0016 You should have received a copy of the GNU General Public License 0017 along with this program; if not, write to the Free Software 0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. 0019 0020 */ 0021 // Self 0022 #include "zoomwidget.h" 0023 0024 // stdc++ 0025 #include <cmath> 0026 0027 // Qt 0028 #include <QAction> 0029 #include <QActionGroup> 0030 #include <QHBoxLayout> 0031 #include <QSlider> 0032 #include <QToolButton> 0033 // KF 0034 0035 // Local 0036 #include "signalblocker.h" 0037 #include "zoomcombobox/zoomcombobox.h" 0038 #include "zoomslider.h" 0039 0040 namespace Gwenview 0041 { 0042 static const qreal MAGIC_K = 1.04; 0043 static const qreal MAGIC_OFFSET = 16.; 0044 static const qreal PRECISION = 100.; 0045 inline int sliderValueForZoom(qreal zoom) 0046 { 0047 return int(PRECISION * (log(zoom) / log(MAGIC_K) + MAGIC_OFFSET)); 0048 } 0049 0050 inline qreal zoomForSliderValue(int sliderValue) 0051 { 0052 return pow(MAGIC_K, sliderValue / PRECISION - MAGIC_OFFSET); 0053 } 0054 0055 struct ZoomWidgetPrivate { 0056 ZoomWidget *q = nullptr; 0057 0058 QToolButton *mFitButton = nullptr; 0059 ZoomSlider *mZoomSlider = nullptr; 0060 ZoomComboBox *mZoomComboBox = nullptr; 0061 QAction *mActualSizeAction = nullptr; 0062 0063 bool mZoomUpdatedBySlider; 0064 0065 void emitZoomChanged() 0066 { 0067 // Use QSlider::sliderPosition(), not QSlider::value() because when we are 0068 // called from slotZoomSliderActionTriggered(), QSlider::value() has not 0069 // been updated yet. 0070 qreal zoom = zoomForSliderValue(mZoomSlider->slider()->sliderPosition()); 0071 mZoomUpdatedBySlider = true; 0072 Q_EMIT q->zoomChanged(zoom); 0073 mZoomUpdatedBySlider = false; 0074 } 0075 }; 0076 0077 ZoomWidget::ZoomWidget(QWidget *parent) 0078 : QFrame(parent) 0079 , d(new ZoomWidgetPrivate) 0080 { 0081 d->q = this; 0082 d->mZoomUpdatedBySlider = false; 0083 0084 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); 0085 0086 d->mFitButton = new QToolButton(this); 0087 0088 d->mZoomSlider = new ZoomSlider(this); 0089 d->mZoomSlider->setMinimumWidth(150); 0090 d->mZoomSlider->slider()->setSingleStep(int(PRECISION)); 0091 d->mZoomSlider->slider()->setPageStep(3 * int(PRECISION)); 0092 connect(d->mZoomSlider->slider(), &QAbstractSlider::actionTriggered, this, &ZoomWidget::slotZoomSliderActionTriggered); 0093 0094 d->mZoomComboBox = new ZoomComboBox(this); 0095 connect(d->mZoomComboBox, &ZoomComboBox::zoomChanged, this, &ZoomWidget::zoomChanged); 0096 0097 // Layout 0098 auto layout = new QHBoxLayout(this); 0099 layout->setContentsMargins(0, 0, 0, 0); 0100 layout->setSpacing(0); 0101 layout->addWidget(d->mFitButton); 0102 layout->addWidget(d->mZoomSlider); 0103 layout->addWidget(d->mZoomComboBox); 0104 } 0105 0106 ZoomWidget::~ZoomWidget() 0107 { 0108 delete d; 0109 } 0110 0111 void ZoomWidget::setActions(QAction *zoomToFitAction, QAction *actualSizeAction, QAction *zoomInAction, QAction *zoomOutAction, QAction *zoomToFillAction) 0112 { 0113 d->mFitButton->setDefaultAction(zoomToFitAction); 0114 d->mFitButton->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextOnly); 0115 0116 d->mZoomSlider->setZoomInAction(zoomInAction); 0117 d->mZoomSlider->setZoomOutAction(zoomOutAction); 0118 0119 d->mZoomComboBox->setActions(zoomToFitAction, zoomToFillAction, actualSizeAction); 0120 0121 auto actionGroup = new QActionGroup(d->q); 0122 actionGroup->addAction(zoomToFitAction); 0123 actionGroup->addAction(zoomToFillAction); 0124 actionGroup->addAction(actualSizeAction); 0125 actionGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional); 0126 0127 d->mActualSizeAction = actualSizeAction; 0128 } 0129 0130 void ZoomWidget::slotZoomSliderActionTriggered() 0131 { 0132 // The slider value changed because of the user (not because of range 0133 // changes). In this case disable zoom and apply slider value. 0134 d->emitZoomChanged(); 0135 } 0136 0137 void ZoomWidget::setZoom(qreal zoom) 0138 { 0139 if (zoom != 1.0) { 0140 d->mActualSizeAction->setChecked(false); 0141 } 0142 d->mZoomComboBox->setValue(zoom); 0143 0144 // Don't change slider value if we come here because the slider change, 0145 // avoids choppy sliding scroll. 0146 if (!d->mZoomUpdatedBySlider) { 0147 QSlider *slider = d->mZoomSlider->slider(); 0148 SignalBlocker blocker(slider); 0149 int value = sliderValueForZoom(zoom); 0150 0151 if (value < slider->minimum()) { 0152 // It is possible that we are called *before* setMinimumZoom() as 0153 // been called. In this case, define the minimum ourself. 0154 d->mZoomSlider->setMinimum(value); 0155 } 0156 d->mZoomSlider->setValue(value); 0157 } 0158 } 0159 0160 void ZoomWidget::setMinimumZoom(qreal minimumZoom) 0161 { 0162 d->mZoomSlider->setMinimum(sliderValueForZoom(minimumZoom)); 0163 d->mZoomComboBox->setMinimum(minimumZoom); 0164 } 0165 0166 void ZoomWidget::setMaximumZoom(qreal zoom) 0167 { 0168 d->mZoomSlider->setMaximum(sliderValueForZoom(zoom)); 0169 d->mZoomComboBox->setMaximum(zoom); 0170 } 0171 0172 } // namespace 0173 0174 #include "moc_zoomwidget.cpp"