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