File indexing completed on 2024-09-22 05:16:07

0001 /*
0002     This file is part of the Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2008-2009 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "zoomslider.hpp"
0010 
0011 // Kasten gui
0012 #include <Kasten/Zoomable>
0013 // Kasten core
0014 #include <Kasten/AbstractModel>
0015 // KF
0016 #include <KLocalizedString>
0017 // Qt
0018 #include <QSlider>
0019 #include <QToolButton>
0020 #include <QHBoxLayout>
0021 #include <QApplication>
0022 #include <QHelpEvent>
0023 
0024 namespace Kasten {
0025 
0026 static constexpr int ZoomSliderWidth = 150;
0027 
0028 // TODO: look at Dolphin/Krita/KOffice zoom tool
0029 
0030 // TODO: different zoom strategies: fixed step size, relative step size
0031 // where to put this, behind interface? or better into a zoomtool?
0032 
0033 ZoomSlider::ZoomSlider(QWidget* parent)
0034     : QWidget(parent)
0035 {
0036     mZoomOutButton = new QToolButton(this);
0037     mZoomOutButton->setIcon(QIcon::fromTheme(QStringLiteral("zoom-out")));
0038     mZoomOutButton->setAutoRaise(true);
0039 
0040     mSlider = new QSlider(Qt::Horizontal, this);
0041 
0042     mZoomInButton = new QToolButton(this);
0043     mZoomInButton->setIcon(QIcon::fromTheme(QStringLiteral("zoom-in")));
0044     mZoomInButton->setAutoRaise(true);
0045 
0046     auto* layout = new QHBoxLayout(this);
0047     layout->setSpacing(0);
0048     layout->setContentsMargins(0, 0, 0, 0);
0049     layout->addWidget(mZoomOutButton);
0050     layout->addWidget(mSlider);
0051     layout->addWidget(mZoomInButton);
0052 
0053     connect(mZoomOutButton, &QAbstractButton::clicked,
0054             this, &ZoomSlider::zoomOut);
0055     connect(mZoomInButton, &QAbstractButton::clicked,
0056             this, &ZoomSlider::zoomIn);
0057     connect(mSlider, &QSlider::valueChanged,
0058             this, &ZoomSlider::onSliderValueChanged);
0059     connect(mSlider, &QSlider::sliderMoved,
0060             this, &ZoomSlider::onSliderMoved);
0061 
0062     setFixedWidth(ZoomSliderWidth);
0063 
0064     setTargetModel(nullptr);
0065 }
0066 
0067 ZoomSlider::~ZoomSlider() = default;
0068 
0069 void ZoomSlider::setTargetModel(AbstractModel* model)
0070 {
0071     if (mModel) {
0072         mModel->disconnect(this);
0073     }
0074 
0075     mModel = model ? model->findBaseModelWithInterface<If::Zoomable*>() : nullptr;
0076     mZoomControl = mModel ? qobject_cast<If::Zoomable*>(mModel) : nullptr;
0077 
0078     const bool hasView = (mZoomControl != nullptr);
0079     if (hasView) {
0080         mSlider->setSingleStep(1);   // mZoomControl->zoomLevelSingleStep()?
0081         mSlider->setPageStep(5);   // mZoomControl->zoomLevelPageStep()?
0082 
0083         const int min = 0; // mZoomControl->minimumZoomLevel();
0084         const int max = 99; // mZoomControl->maximumZoomLevel();
0085         mSlider->setRange(min, max);
0086 
0087         onZoomLevelChange(mZoomControl->zoomLevel());
0088         const int sliderValue = mSlider->value();
0089         mZoomOutButton->setEnabled(sliderValue > mSlider->minimum());
0090         mZoomInButton->setEnabled(sliderValue < mSlider->maximum());
0091         connect(mModel, SIGNAL(zoomLevelChanged(double)), SLOT(onZoomLevelChange(double)));
0092     } else {
0093         mZoomOutButton->setEnabled(false);
0094         mZoomInButton->setEnabled(false);
0095         // put slider in the middle
0096         mSlider->setRange(0, 99);
0097         mSlider->setValue(50);
0098     }
0099 
0100     mSlider->setEnabled(hasView);
0101 }
0102 
0103 void ZoomSlider::updateToolTip(int sliderValue)
0104 {
0105     const float zoomLevel = 50.0 / (100 - sliderValue);
0106     const int zoomPercent = static_cast<int>(zoomLevel * 100 + 0.5);
0107     mSlider->setToolTip(i18nc("@info:tooltip", "Zoom: %1%", zoomPercent));
0108 // TODO: get the text by a signal toolTipNeeded( int zoomLevel, QString* toolTipText ); ?
0109 }
0110 
0111 void ZoomSlider::zoomOut()
0112 {
0113     const int newValue = mSlider->value() - mSlider->singleStep();
0114     mSlider->setValue(newValue);
0115 }
0116 
0117 void ZoomSlider::zoomIn()
0118 {
0119     const int newValue = mSlider->value() + mSlider->singleStep();
0120     mSlider->setValue(newValue);
0121 }
0122 
0123 void ZoomSlider::onSliderValueChanged(int sliderValue)
0124 {
0125     updateToolTip(sliderValue);
0126     mZoomOutButton->setEnabled(sliderValue > mSlider->minimum());
0127     mZoomInButton->setEnabled(sliderValue < mSlider->maximum());
0128 
0129     if (mZoomControl) {
0130         mZoomControl->setZoomLevel(50.0 / (100 - sliderValue));
0131     }
0132 }
0133 
0134 // TODO: which signal comes first, valueChanged or sliderMoved?
0135 // ensure correct calculation of zoomLevel, best by model
0136 // but can be timeconsuming?
0137 // use timer to delay resize, so that sliding is not delayed by resizing
0138 void ZoomSlider::onSliderMoved(int sliderValue)
0139 {
0140     Q_UNUSED(sliderValue)
0141 
0142     QPoint toolTipPoint = mSlider->rect().topLeft();
0143     toolTipPoint.ry() += mSlider->height() / 2;
0144     toolTipPoint = mSlider->mapToGlobal(toolTipPoint);
0145 
0146     QHelpEvent toolTipEvent(QEvent::ToolTip, QPoint(0, 0), toolTipPoint);
0147     QApplication::sendEvent(mSlider, &toolTipEvent);
0148 }
0149 
0150 void ZoomSlider::onZoomLevelChange(double level)
0151 {
0152     mZoomLevel = level;
0153     const int newSliderValue = 100 - static_cast<int>(50.0 / mZoomLevel + 0.5);
0154     if (newSliderValue != mSlider->value()) {
0155         disconnect(mSlider, &QSlider::valueChanged,
0156                    this, &ZoomSlider::onSliderValueChanged);
0157         mSlider->setSliderPosition(newSliderValue);
0158         updateToolTip(mSlider->value());
0159         connect(mSlider, &QSlider::valueChanged,
0160                 this, &ZoomSlider::onSliderValueChanged);
0161     }
0162 }
0163 
0164 }
0165 
0166 #include "moc_zoomslider.cpp"