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 {
69 KoSliderCombo *thePublic;
70 QValidator *m_validator;
72 KoSliderComboContainer *container;
74 QStyle::StateFlag arrowState;
78 bool firstShowOfSlider;
83 void sliderValueChanged(int value);
84 void sliderReleased();
85 void lineEditFinished();
88 KoSliderCombo::KoSliderCombo(QWidget *parent)
90 ,d(new KoSliderComboPrivate())
96 d->container = new KoSliderComboContainer(this);
97 d->container->setAttribute(Qt::WA_WindowPropagation);
98 QStyleOptionComboBox opt;
100 // d->container->setFrameStyle(style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, this));
102 d->slider = new QSlider(Qt::Horizontal);
103 d->slider->setMinimum(0);
104 d->slider->setMaximum(256);
105 d->slider->setPageStep(10);
106 d->slider->setValue(0);
107 // When set to true, causes flicker on Qt 4.6. Any reason to keep it?
108 d->firstShowOfSlider = false; //true;
110 QHBoxLayout * l = new QHBoxLayout();
113 l->addWidget(d->slider);
114 d->container->setLayout(l);
115 d->container->resize(200, 30);
117 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
120 setEditText(KGlobal::locale()->formatNumber(0, d->decimals));
122 connect(d->slider, SIGNAL(valueChanged(int)), SLOT(sliderValueChanged(int)));
123 connect(d->slider, SIGNAL(sliderReleased()), SLOT(sliderReleased()));
124 connect(lineEdit(), SIGNAL(editingFinished()), SLOT(lineEditFinished()));
127 KoSliderCombo::~KoSliderCombo()
132 QSize KoSliderCombo::sizeHint() const
134 return minimumSizeHint();
137 QSize KoSliderCombo::minimumSizeHint() const
141 const QFontMetrics &fm = fontMetrics();
143 sh.setWidth(5 * fm.width(QLatin1Char('8')));
144 sh.setHeight(qMax(fm.lineSpacing(), 14) + 2);
146 // add style and strut values
147 QStyleOptionComboBox opt;
149 opt.subControls = QStyle::SC_All;
151 sh = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, this);
153 return sh.expandedTo(QApplication::globalStrut());
156 void KoSliderCombo::KoSliderComboPrivate::showPopup()
158 if(firstShowOfSlider) {
159 container->show(); //show container a bit early so the slider can be layout'ed
160 firstShowOfSlider = false;
163 QStyleOptionSlider opt;
166 opt.sliderPosition = opt.sliderValue = slider->value();
167 int hdlPos = thePublic->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle).center().x();
169 QStyleOptionComboBox optThis;
170 optThis.init(thePublic);
171 optThis.subControls = QStyle::SC_All;
172 optThis.editable = true;
173 int arrowPos = thePublic->style()->subControlRect(QStyle::CC_ComboBox, &optThis, QStyle::SC_ComboBoxArrow).center().x();
175 QSize popSize = container->size();
176 QRect popupRect(thePublic->mapToGlobal(QPoint(arrowPos - hdlPos - slider->x(), thePublic->size().height())), popSize);
178 // Make sure the popup is not drawn outside the screen area
179 QRect screenRect = QApplication::desktop()->availableGeometry(thePublic);
180 if (popupRect.right() > screenRect.right())
181 popupRect.translate(screenRect.right() - popupRect.right(), 0);
182 if (popupRect.left() < screenRect.left())
183 popupRect.translate(screenRect.left() - popupRect.left(), 0);
184 if (popupRect.bottom() > screenRect.bottom())
185 popupRect.translate(0, -(thePublic->height() + container->height()));
187 container->setGeometry(popupRect);
193 void KoSliderCombo::KoSliderComboPrivate::hidePopup()
198 void KoSliderCombo::hideEvent(QHideEvent *)
203 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())
247 QComboBox::mousePressEvent(e);
250 void KoSliderCombo::keyPressEvent(QKeyEvent *e)
252 if (e->key() == Qt::Key_Up) setValue(value() + d->slider->singleStep() * (maximum() - minimum()) / 256 + 0.5);
253 else if (e->key() == Qt::Key_Down) setValue(value() - d->slider->singleStep() * (maximum() - minimum()) / 256 - 0.5);
254 else QComboBox::keyPressEvent(e);
257 void KoSliderCombo::wheelEvent(QWheelEvent *e)
259 if (e->delta() > 0) setValue(value() + d->slider->singleStep() * (maximum() - minimum()) / 256 + 0.5);
260 else setValue(value() - d->slider->singleStep() * (maximum() - minimum()) / 256 - 0.5);
263 void KoSliderCombo::KoSliderComboPrivate::lineEditFinished()
265 qreal value = thePublic->currentText().toDouble();
266 slider->blockSignals(true);
267 slider->setValue(int((value - minimum) * 256 / (maximum - minimum) + 0.5));
268 slider->blockSignals(false);
269 emit thePublic->valueChanged(value, true);
272 void KoSliderCombo::KoSliderComboPrivate::sliderValueChanged(int slidervalue)
274 thePublic->setEditText(KGlobal::locale()->formatNumber(minimum + (maximum - minimum)*slidervalue/256, decimals));
276 qreal value = thePublic->currentText().toDouble();
277 emit thePublic->valueChanged(value, false);
280 void KoSliderCombo::KoSliderComboPrivate::sliderReleased()
282 qreal value = thePublic->currentText().toDouble();
283 emit thePublic->valueChanged(value, true);
286 qreal KoSliderCombo::maximum() const
291 qreal KoSliderCombo::minimum() const
296 qreal KoSliderCombo::decimals() const
301 qreal KoSliderCombo::value() const
303 return currentText().toDouble();
306 void KoSliderCombo::setDecimals(int dec)
309 if (dec == 0) lineEdit()->setValidator(new QIntValidator(this));
310 else lineEdit()->setValidator(new QDoubleValidator(this));
313 void KoSliderCombo::setMinimum(qreal min)
318 void KoSliderCombo::setMaximum(qreal max)
323 void KoSliderCombo::setValue(qreal value)
325 if(value < d->minimum)
327 if(value > d->maximum)
329 setEditText(KGlobal::locale()->formatNumber(value, d->decimals));
330 d->slider->blockSignals(true);
331 d->slider->setValue(int((value - d->minimum) * 256 / (d->maximum - d->minimum) + 0.5));
332 d->slider->blockSignals(false);
333 emit valueChanged(value, true);
336 #include <KoSliderCombo.moc>