1 /* This file is part of the KDE project
2 Copyright (c) 2007 Casper Boemann <cbr@boemann.dk>
3 Copyright (c) 2010 Jean-Baptiste Mardelle <jb@kdenlive.org>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
20 #include "KoSliderCombo.h"
23 #include <QApplication>
27 #include <QStylePainter>
28 #include <QStyleOptionSlider>
31 #include <QHBoxLayout>
34 #include <QMouseEvent>
35 #include <QDoubleSpinBox>
36 #include <QDesktopWidget>
42 class KoSliderComboContainer : public QMenu
45 KoSliderComboContainer(KoSliderCombo *parent) : QMenu(parent), m_parent(parent) {}
48 virtual void mousePressEvent(QMouseEvent *e);
50 KoSliderCombo *m_parent;
53 void KoSliderComboContainer::mousePressEvent(QMouseEvent *e)
55 QStyleOptionComboBox opt;
57 opt.subControls = QStyle::SC_All;
58 opt.activeSubControls = QStyle::SC_ComboBoxArrow;
59 QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
60 m_parent->mapFromGlobal(e->globalPos()),
62 if (sc == QStyle::SC_ComboBoxArrow)
63 setAttribute(Qt::WA_NoMouseReplay);
64 QMenu::mousePressEvent(e);
67 class KoSliderCombo::KoSliderComboPrivate
70 KoSliderCombo *thePublic;
71 QValidator *m_validator;
73 KoSliderComboContainer *container;
75 QStyle::StateFlag arrowState;
79 bool firstShowOfSlider;
84 void sliderValueChanged(int value);
85 void sliderReleased();
86 void lineEditFinished();
89 KoSliderCombo::KoSliderCombo(QWidget *parent)
91 , d(new KoSliderComboPrivate())
97 d->container = new KoSliderComboContainer(this);
98 d->container->setAttribute(Qt::WA_WindowPropagation);
99 QStyleOptionComboBox opt;
101 // d->container->setFrameStyle(style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, this));
103 d->slider = new QSlider(Qt::Horizontal);
104 d->slider->setMinimum(0);
105 d->slider->setMaximum(256);
106 d->slider->setPageStep(10);
107 d->slider->setValue(0);
108 // When set to true, causes flicker on Qt 4.6. Any reason to keep it?
109 d->firstShowOfSlider = false; //true;
111 QHBoxLayout * l = new QHBoxLayout();
114 l->addWidget(d->slider);
115 d->container->setLayout(l);
116 d->container->resize(200, 30);
118 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
121 setEditText(KGlobal::locale()->formatNumber(0, d->decimals));
123 connect(d->slider, SIGNAL(valueChanged(int)), SLOT(sliderValueChanged(int)));
124 connect(d->slider, SIGNAL(sliderReleased()), SLOT(sliderReleased()));
125 connect(lineEdit(), SIGNAL(editingFinished()), SLOT(lineEditFinished()));
128 KoSliderCombo::~KoSliderCombo()
133 QSize KoSliderCombo::sizeHint() const
135 return minimumSizeHint();
138 QSize KoSliderCombo::minimumSizeHint() const
142 const QFontMetrics &fm = fontMetrics();
144 sh.setWidth(5 * fm.width(QLatin1Char('8')));
145 sh.setHeight(qMax(fm.lineSpacing(), 14) + 2);
147 // add style and strut values
148 QStyleOptionComboBox opt;
150 opt.subControls = QStyle::SC_All;
152 sh = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, this);
154 return sh.expandedTo(QApplication::globalStrut());
157 void KoSliderCombo::KoSliderComboPrivate::showPopup()
159 if (firstShowOfSlider) {
160 container->show(); //show container a bit early so the slider can be layout'ed
161 firstShowOfSlider = false;
164 QStyleOptionSlider opt;
167 opt.sliderPosition = opt.sliderValue = slider->value();
168 int hdlPos = thePublic->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle).center().x();
170 QStyleOptionComboBox optThis;
171 optThis.init(thePublic);
172 optThis.subControls = QStyle::SC_All;
173 optThis.editable = true;
174 int arrowPos = thePublic->style()->subControlRect(QStyle::CC_ComboBox, &optThis, QStyle::SC_ComboBoxArrow).center().x();
176 QSize popSize = container->size();
177 QRect popupRect(thePublic->mapToGlobal(QPoint(arrowPos - hdlPos - slider->x(), thePublic->size().height())), popSize);
179 // Make sure the popup is not drawn outside the screen area
180 QRect screenRect = QApplication::desktop()->availableGeometry(thePublic);
181 if (popupRect.right() > screenRect.right())
182 popupRect.translate(screenRect.right() - popupRect.right(), 0);
183 if (popupRect.left() < screenRect.left())
184 popupRect.translate(screenRect.left() - popupRect.left(), 0);
185 if (popupRect.bottom() > screenRect.bottom())
186 popupRect.translate(0, -(thePublic->height() + container->height()));
188 container->setGeometry(popupRect);
194 void KoSliderCombo::KoSliderComboPrivate::hidePopup()
199 void KoSliderCombo::hideEvent(QHideEvent *)
204 void KoSliderCombo::changeEvent(QEvent *e)
207 case QEvent::EnabledChange:
211 case QEvent::PaletteChange:
212 d->container->setPalette(palette());
217 QComboBox::changeEvent(e);
220 void KoSliderCombo::paintEvent(QPaintEvent *)
222 QStylePainter gc(this);
224 gc.setPen(palette().color(QPalette::Text));
226 QStyleOptionComboBox opt;
228 opt.subControls = QStyle::SC_All;
230 gc.drawComplexControl(QStyle::CC_ComboBox, opt);
231 gc.drawControl(QStyle::CE_ComboBoxLabel, opt);
234 void KoSliderCombo::mousePressEvent(QMouseEvent *e)
236 QStyleOptionComboBox opt;
238 opt.subControls = QStyle::SC_All;
240 QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->pos(),
242 if (sc == QStyle::SC_ComboBoxArrow && !d->container->isVisible()) {
245 QComboBox::mousePressEvent(e);
248 void KoSliderCombo::keyPressEvent(QKeyEvent *e)
250 if (e->key() == Qt::Key_Up) setValue(value() + d->slider->singleStep() *(maximum() - minimum()) / 256 + 0.5);
251 else if (e->key() == Qt::Key_Down) setValue(value() - d->slider->singleStep() *(maximum() - minimum()) / 256 - 0.5);
252 else QComboBox::keyPressEvent(e);
255 void KoSliderCombo::wheelEvent(QWheelEvent *e)
257 if (e->delta() > 0) setValue(value() + d->slider->singleStep() *(maximum() - minimum()) / 256 + 0.5);
258 else setValue(value() - d->slider->singleStep() *(maximum() - minimum()) / 256 - 0.5);
261 void KoSliderCombo::KoSliderComboPrivate::lineEditFinished()
263 qreal value = thePublic->currentText().toDouble();
264 slider->blockSignals(true);
265 slider->setValue(int((value - minimum) * 256 / (maximum - minimum) + 0.5));
266 slider->blockSignals(false);
267 emit thePublic->valueChanged(value, true);
270 void KoSliderCombo::KoSliderComboPrivate::sliderValueChanged(int slidervalue)
272 thePublic->setEditText(KGlobal::locale()->formatNumber(minimum + (maximum - minimum)*slidervalue / 256, decimals));
274 qreal value = thePublic->currentText().toDouble();
275 emit thePublic->valueChanged(value, false);
278 void KoSliderCombo::KoSliderComboPrivate::sliderReleased()
280 qreal value = thePublic->currentText().toDouble();
281 emit thePublic->valueChanged(value, true);
284 qreal KoSliderCombo::maximum() const
289 qreal KoSliderCombo::minimum() const
294 qreal KoSliderCombo::decimals() const
299 qreal KoSliderCombo::value() const
301 return currentText().toDouble();
304 void KoSliderCombo::setDecimals(int dec)
307 if (dec == 0) lineEdit()->setValidator(new QIntValidator(this));
308 else lineEdit()->setValidator(new QDoubleValidator(this));
311 void KoSliderCombo::setMinimum(qreal min)
316 void KoSliderCombo::setMaximum(qreal max)
321 void KoSliderCombo::setValue(qreal value)
323 if (value < d->minimum)
325 if (value > d->maximum)
327 setEditText(KGlobal::locale()->formatNumber(value, d->decimals));
328 d->slider->blockSignals(true);
329 d->slider->setValue(int((value - d->minimum) * 256 / (d->maximum - d->minimum) + 0.5));
330 d->slider->blockSignals(false);
331 emit valueChanged(value, true);
334 #include <KoSliderCombo.moc>