Warning, file /office/calligra/libs/widgets/KoSliderCombo.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (c) 2007 C. Boemann <cbo@boemann.dk>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 #include "KoSliderCombo.h"
0020 #include "KoSliderCombo_p.h"
0021 
0022 #include <QTimer>
0023 #include <QApplication>
0024 #include <QSize>
0025 #include <QSlider>
0026 #include <QStyle>
0027 #include <QStylePainter>
0028 #include <QStyleOptionSlider>
0029 #include <QLineEdit>
0030 #include <QValidator>
0031 #include <QHBoxLayout>
0032 #include <QFrame>
0033 #include <QMenu>
0034 #include <QMouseEvent>
0035 #include <QDoubleSpinBox>
0036 #include <QDesktopWidget>
0037 
0038 
0039 #include <klocalizedstring.h>
0040 #include <WidgetsDebug.h>
0041 
0042 KoSliderCombo::KoSliderCombo(QWidget *parent)
0043    : QComboBox(parent)
0044     ,d(new KoSliderComboPrivate())
0045 {
0046     d->thePublic = this;
0047     d->minimum = 0.0;
0048     d->maximum = 100.0;
0049     d->decimals = 2;
0050     d->container = new KoSliderComboContainer(this);
0051     d->container->setAttribute(Qt::WA_WindowPropagation);
0052     QStyleOptionComboBox opt;
0053     opt.initFrom(this);
0054 //    d->container->setFrameStyle(style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, this));
0055 
0056     d->slider = new QSlider(Qt::Horizontal);
0057     d->slider->setMinimum(0);
0058     d->slider->setMaximum(256);
0059     d->slider->setPageStep(10);
0060     d->slider->setValue(0);
0061     // When set to true, causes flicker on Qt 4.6. Any reason to keep it?
0062     d->firstShowOfSlider = false; //true;
0063 
0064     QHBoxLayout * l = new QHBoxLayout();
0065     l->setMargin(2);
0066     l->setSpacing(2);
0067     l->addWidget(d->slider);
0068     d->container->setLayout(l);
0069     d->container->resize(200, 30);
0070 
0071     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
0072 
0073     setEditable(true);
0074     setEditText(QLocale().toString(0.0, d->decimals));
0075 
0076     connect(d->slider, SIGNAL(valueChanged(int)), SLOT(sliderValueChanged(int)));
0077     connect(d->slider, SIGNAL(sliderReleased()), SLOT(sliderReleased()));
0078     connect(lineEdit(), SIGNAL(editingFinished()), SLOT(lineEditFinished()));
0079 }
0080 
0081 KoSliderCombo::~KoSliderCombo()
0082 {
0083     delete d;
0084 }
0085 
0086 QSize KoSliderCombo::sizeHint() const
0087 {
0088     return minimumSizeHint();
0089 }
0090 
0091 QSize KoSliderCombo::minimumSizeHint() const
0092 {
0093     QSize sh;
0094 
0095     const QFontMetrics &fm = fontMetrics();
0096 
0097     sh.setWidth(5 * fm.width(QLatin1Char('8')));
0098     sh.setHeight(qMax(fm.lineSpacing(), 14) + 2);
0099 
0100     // add style and strut values
0101     QStyleOptionComboBox opt;
0102     opt.initFrom(this);
0103     opt.subControls = QStyle::SC_All;
0104     opt.editable = true;
0105     sh = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, this);
0106 
0107     return sh.expandedTo(QApplication::globalStrut());
0108 }
0109 
0110 void KoSliderCombo::KoSliderComboPrivate::showPopup()
0111 {
0112     if(firstShowOfSlider) {
0113         container->show(); //show container a bit early so the slider can be layout'ed
0114         firstShowOfSlider = false;
0115     }
0116 
0117     QStyleOptionSlider opt;
0118     opt.initFrom(slider);
0119     opt.maximum=256;
0120     opt.sliderPosition = opt.sliderValue = slider->value();
0121     int hdlPos = thePublic->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle).center().x();
0122 
0123     QStyleOptionComboBox optThis;
0124     optThis.initFrom(thePublic);
0125     optThis.subControls = QStyle::SC_All;
0126     optThis.editable = true;
0127     int arrowPos = thePublic->style()->subControlRect(QStyle::CC_ComboBox, &optThis, QStyle::SC_ComboBoxArrow).center().x();
0128 
0129     QSize popSize = container->size();
0130     QRect popupRect(thePublic->mapToGlobal(QPoint(arrowPos - hdlPos - slider->x(), thePublic->size().height())), popSize);
0131 
0132     // Make sure the popup is not drawn outside the screen area
0133     QRect screenRect = QApplication::desktop()->availableGeometry(thePublic);
0134     if (popupRect.right() > screenRect.right())
0135         popupRect.translate(screenRect.right() - popupRect.right(), 0);
0136     if (popupRect.left() < screenRect.left())
0137         popupRect.translate(screenRect.left() - popupRect.left(), 0);
0138     if (popupRect.bottom() > screenRect.bottom())
0139         popupRect.translate(0, -(thePublic->height() + container->height()));
0140 
0141     container->setGeometry(popupRect);
0142     container->raise();
0143     container->show();
0144     slider->setFocus();
0145 }
0146 
0147 void KoSliderCombo::KoSliderComboPrivate::hidePopup()
0148 {
0149     container->hide();
0150 }
0151 
0152 void KoSliderCombo::hideEvent(QHideEvent *)
0153 {
0154     d->hidePopup();
0155 }
0156 
0157 void KoSliderCombo::changeEvent(QEvent *e)
0158 {
0159     switch (e->type())
0160     {
0161         case QEvent::EnabledChange:
0162             if (!isEnabled())
0163                 d->hidePopup();
0164             break;
0165         case QEvent::PaletteChange:
0166             d->container->setPalette(palette());
0167             break;
0168         default:
0169             break;
0170     }
0171     QComboBox::changeEvent(e);
0172 }
0173 
0174 void KoSliderCombo::paintEvent(QPaintEvent *)
0175 {
0176     QStylePainter gc(this);
0177 
0178     gc.setPen(palette().color(QPalette::Text));
0179 
0180     QStyleOptionComboBox opt;
0181     opt.initFrom(this);
0182     opt.subControls = QStyle::SC_All;
0183     opt.editable = true;
0184     gc.drawComplexControl(QStyle::CC_ComboBox, opt);
0185     gc.drawControl(QStyle::CE_ComboBoxLabel, opt);
0186 }
0187 
0188 void KoSliderCombo::mousePressEvent(QMouseEvent *e)
0189 {
0190     QStyleOptionComboBox opt;
0191     opt.initFrom(this);
0192     opt.subControls = QStyle::SC_All;
0193     opt.editable = true;
0194     QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->pos(),
0195                                                            this);
0196     if (sc == QStyle::SC_ComboBoxArrow && !d->container->isVisible())
0197     {
0198         d->showPopup();
0199     }
0200     else
0201         QComboBox::mousePressEvent(e);
0202 }
0203 
0204 void KoSliderCombo::keyPressEvent(QKeyEvent *e)
0205 {
0206     if (e->key() == Qt::Key_Up) setValue(value() + d->slider->singleStep() * (maximum() - minimum()) / 256 + 0.5);
0207     else if (e->key() == Qt::Key_Down) setValue(value() - d->slider->singleStep() * (maximum() - minimum()) / 256 - 0.5);
0208     else QComboBox::keyPressEvent(e);
0209 }
0210 
0211 void KoSliderCombo::wheelEvent(QWheelEvent *e)
0212 {
0213     if (e->delta() > 0) setValue(value() + d->slider->singleStep() * (maximum() - minimum()) / 256 + 0.5);
0214     else setValue(value() - d->slider->singleStep() * (maximum() - minimum()) / 256 - 0.5);
0215 }
0216 
0217 void KoSliderCombo::KoSliderComboPrivate::lineEditFinished()
0218 {
0219     qreal value = QLocale().toDouble(thePublic->currentText());
0220     slider->blockSignals(true);
0221     slider->setValue(int((value - minimum) * 256 / (maximum - minimum) + 0.5));
0222     slider->blockSignals(false);
0223     emit thePublic->valueChanged(value, true);
0224 }
0225 
0226 void KoSliderCombo::KoSliderComboPrivate::sliderValueChanged(int slidervalue)
0227 {
0228     thePublic->setEditText(QLocale().toString(minimum + (maximum - minimum)*slidervalue/256, decimals));
0229 
0230     qreal value = QLocale().toDouble(thePublic->currentText());
0231     emit thePublic->valueChanged(value, false);
0232 }
0233 
0234 void KoSliderCombo::KoSliderComboPrivate::sliderReleased()
0235 {
0236     qreal value = QLocale().toDouble(thePublic->currentText());
0237     emit thePublic->valueChanged(value, true);
0238 }
0239 
0240 qreal KoSliderCombo::maximum() const
0241 {
0242     return d->maximum;
0243 }
0244 
0245 qreal KoSliderCombo::minimum() const
0246 {
0247     return d->minimum;
0248 }
0249 
0250 qreal KoSliderCombo::decimals() const
0251 {
0252     return d->decimals;
0253 }
0254 
0255 qreal KoSliderCombo::value() const
0256 {
0257     return QLocale().toDouble(currentText());
0258 }
0259 
0260 void KoSliderCombo::setDecimals(int dec)
0261 {
0262     d->decimals = dec;
0263     if (dec == 0) lineEdit()->setValidator(new QIntValidator(this));
0264     else lineEdit()->setValidator(new QDoubleValidator(this));
0265 }
0266 
0267 void KoSliderCombo::setMinimum(qreal min)
0268 {
0269     d->minimum = min;
0270 }
0271 
0272 void KoSliderCombo::setMaximum(qreal max)
0273 {
0274     d->maximum = max;
0275 }
0276 
0277 void KoSliderCombo::setValue(qreal value)
0278 {
0279     if(value < d->minimum)
0280         value = d->minimum;
0281     if(value > d->maximum)
0282         value = d->maximum;
0283     setEditText(QLocale().toString(value, d->decimals));
0284     d->slider->blockSignals(true);
0285     d->slider->setValue(int((value - d->minimum) * 256 / (d->maximum - d->minimum) + 0.5));
0286     d->slider->blockSignals(false);
0287     emit valueChanged(value, true);
0288 }
0289 
0290 void KoSliderComboContainer::mousePressEvent(QMouseEvent *e)
0291 {
0292     QStyleOptionComboBox opt;
0293     opt.init(m_parent);
0294     opt.subControls = QStyle::SC_All;
0295     opt.activeSubControls = QStyle::SC_ComboBoxArrow;
0296     QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
0297                                                            m_parent->mapFromGlobal(e->globalPos()),
0298                                                            m_parent);
0299     if (sc == QStyle::SC_ComboBoxArrow)
0300         setAttribute(Qt::WA_NoMouseReplay);
0301     QMenu::mousePressEvent(e);
0302 }
0303 
0304 //have to include this because of Q_PRIVATE_SLOT
0305 #include <moc_KoSliderCombo.cpp>