1 /*
2 This file is part of the Kasten Framework, made within the KDE community.
3
4 SPDX-FileCopyrightText: 2008-2009 Friedrich W. H. Kossebau <kossebau@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9 #include "zoomslider.hpp"
10
11 // Kasten gui
12 #include <Kasten/Zoomable>
13 // Kasten core
14 #include <Kasten/AbstractModel>
15 // KF
16 #include <KLocalizedString>
17 // Qt
18 #include <QSlider>
19 #include <QToolButton>
20 #include <QLayout>
21 #include <QApplication>
22 #include <QHelpEvent>
23
24 namespace Kasten {
25
26 static constexpr int ZoomSliderWidth = 150;
27
28 // TODO: look at Dolphin/Krita/KOffice zoom tool
29
30 // TODO: different zoom strategies: fixed step size, relative step size
31 // where to put this, behind interface? or better into a zoomtool?
32
ZoomSlider(QWidget * parent)33 ZoomSlider::ZoomSlider(QWidget* parent)
34 : QWidget(parent)
35 {
36 mZoomOutButton = new QToolButton(this);
37 mZoomOutButton->setIcon(QIcon::fromTheme(QStringLiteral("zoom-out")));
38 mZoomOutButton->setAutoRaise(true);
39
40 mSlider = new QSlider(Qt::Horizontal, this);
41
42 mZoomInButton = new QToolButton(this);
43 mZoomInButton->setIcon(QIcon::fromTheme(QStringLiteral("zoom-in")));
44 mZoomInButton->setAutoRaise(true);
45
46 auto* layout = new QHBoxLayout(this);
47 layout->setSpacing(0);
48 layout->setContentsMargins(0, 0, 0, 0);
49 layout->addWidget(mZoomOutButton);
50 layout->addWidget(mSlider);
51 layout->addWidget(mZoomInButton);
52
53 connect(mZoomOutButton, &QAbstractButton::clicked,
54 this, &ZoomSlider::zoomOut);
55 connect(mZoomInButton, &QAbstractButton::clicked,
56 this, &ZoomSlider::zoomIn);
57 connect(mSlider, &QSlider::valueChanged,
58 this, &ZoomSlider::onSliderValueChanged);
59 connect(mSlider, &QSlider::sliderMoved,
60 this, &ZoomSlider::onSliderMoved);
61
62 setFixedWidth(ZoomSliderWidth);
63
64 setTargetModel(nullptr);
65 }
66
67 ZoomSlider::~ZoomSlider() = default;
68
setTargetModel(AbstractModel * model)69 void ZoomSlider::setTargetModel(AbstractModel* model)
70 {
71 if (mModel) {
72 mModel->disconnect(this);
73 }
74
75 mModel = model ? model->findBaseModelWithInterface<If::Zoomable*>() : nullptr;
76 mZoomControl = mModel ? qobject_cast<If::Zoomable*>(mModel) : nullptr;
77
78 const bool hasView = (mZoomControl != nullptr);
79 if (hasView) {
80 mSlider->setSingleStep(1); // mZoomControl->zoomLevelSingleStep()?
81 mSlider->setPageStep(5); // mZoomControl->zoomLevelPageStep()?
82
83 const int min = 0; // mZoomControl->minimumZoomLevel();
84 const int max = 99; // mZoomControl->maximumZoomLevel();
85 mSlider->setRange(min, max);
86
87 onZoomLevelChange(mZoomControl->zoomLevel());
88 const int sliderValue = mSlider->value();
89 mZoomOutButton->setEnabled(sliderValue > mSlider->minimum());
90 mZoomInButton->setEnabled(sliderValue < mSlider->maximum());
91 connect(mModel, SIGNAL(zoomLevelChanged(double)), SLOT(onZoomLevelChange(double)));
92 } else {
93 mZoomOutButton->setEnabled(false);
94 mZoomInButton->setEnabled(false);
95 // put slider in the middle
96 mSlider->setRange(0, 99);
97 mSlider->setValue(50);
98 }
99
100 mSlider->setEnabled(hasView);
101 }
102
updateToolTip(int sliderValue)103 void ZoomSlider::updateToolTip(int sliderValue)
104 {
105 const float zoomLevel = 50.0 / (100 - sliderValue);
106 const int zoomPercent = static_cast<int>(zoomLevel * 100 + 0.5);
107 mSlider->setToolTip(i18nc("@info:tooltip", "Zoom: %1%", zoomPercent));
108 // TODO: get the text by a signal toolTipNeeded( int zoomLevel, QString* toolTipText ); ?
109 }
110
zoomOut()111 void ZoomSlider::zoomOut()
112 {
113 const int newValue = mSlider->value() - mSlider->singleStep();
114 mSlider->setValue(newValue);
115 }
116
zoomIn()117 void ZoomSlider::zoomIn()
118 {
119 const int newValue = mSlider->value() + mSlider->singleStep();
120 mSlider->setValue(newValue);
121 }
122
onSliderValueChanged(int sliderValue)123 void ZoomSlider::onSliderValueChanged(int sliderValue)
124 {
125 updateToolTip(sliderValue);
126 mZoomOutButton->setEnabled(sliderValue > mSlider->minimum());
127 mZoomInButton->setEnabled(sliderValue < mSlider->maximum());
128
129 if (mZoomControl) {
130 mZoomControl->setZoomLevel(50.0 / (100 - sliderValue));
131 }
132 }
133
134 // TODO: which signal comes first, valueChanged or sliderMoved?
135 // ensure correct calculation of zoomLevel, best by model
136 // but can be timeconsuming?
137 // use timer to delay resize, so that sliding is not delayed by resizing
onSliderMoved(int sliderValue)138 void ZoomSlider::onSliderMoved(int sliderValue)
139 {
140 Q_UNUSED(sliderValue)
141
142 QPoint toolTipPoint = mSlider->rect().topLeft();
143 toolTipPoint.ry() += mSlider->height() / 2;
144 toolTipPoint = mSlider->mapToGlobal(toolTipPoint);
145
146 QHelpEvent toolTipEvent(QEvent::ToolTip, QPoint(0, 0), toolTipPoint);
147 QApplication::sendEvent(mSlider, &toolTipEvent);
148 }
149
onZoomLevelChange(double level)150 void ZoomSlider::onZoomLevelChange(double level)
151 {
152 mZoomLevel = level;
153 const int newSliderValue = 100 - static_cast<int>(50.0 / mZoomLevel + 0.5);
154 if (newSliderValue != mSlider->value()) {
155 disconnect(mSlider, &QSlider::valueChanged,
156 this, &ZoomSlider::onSliderValueChanged);
157 mSlider->setSliderPosition(newSliderValue);
158 updateToolTip(mSlider->value());
159 connect(mSlider, &QSlider::valueChanged,
160 this, &ZoomSlider::onSliderValueChanged);
161 }
162 }
163
164 }
165