| 1 | /* This file is part of the KDE project |
| 2 | Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org> |
| 3 | |
| 4 | This library is free software; you can redistribute it and/or |
| 5 | modify it under the terms of the GNU Lesser General Public |
| 6 | License as published by the Free Software Foundation; either |
| 7 | version 2.1 of the License, or (at your option) version 3, or any |
| 8 | later version accepted by the membership of KDE e.V. (or its |
| 9 | successor approved by the membership of KDE e.V.), Nokia Corporation |
| 10 | (or its successors, if any) and the KDE Free Qt Foundation, which shall |
| 11 | act as a proxy defined in Section 6 of version 3 of the license. |
| 12 | |
| 13 | This library is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 | Lesser General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU Lesser General Public |
| 19 | License along with this library. If not, see <http://www.gnu.org/licenses/>. |
| 20 | |
| 21 | */ |
| 22 | |
| 23 | #include "effectwidget.h" |
| 24 | #include "effectwidget_p.h" |
| 25 | |
| 26 | #include <QtAlgorithms> |
| 27 | #include <QList> |
| 28 | |
| 29 | #include "effect.h" |
| 30 | #include "effectparameter.h" |
| 31 | #include "phonondefs_p.h" |
| 32 | #include <QBoxLayout> |
| 33 | #include <QLabel> |
| 34 | #include <QSpinBox> |
| 35 | #include <QCheckBox> |
| 36 | #include <QComboBox> |
| 37 | #include <QSlider> |
| 38 | #include <limits> |
| 39 | |
| 40 | #ifdef min |
| 41 | #undef min |
| 42 | #endif |
| 43 | #ifdef max |
| 44 | #undef max |
| 45 | #endif |
| 46 | static const qreal DEFAULT_MIN = std::numeric_limits<qreal>::min(); |
| 47 | static const qreal DEFAULT_MAX = std::numeric_limits<qreal>::max(); |
| 48 | static const int DEFAULT_MIN_INT = std::numeric_limits<int>::min(); |
| 49 | static const int DEFAULT_MAX_INT = std::numeric_limits<int>::max(); |
| 50 | static const int SLIDER_RANGE = 8; |
| 51 | static const int TICKINTERVAL = 4; |
| 52 | |
| 53 | |
| 54 | #ifndef QT_NO_PHONON_EFFECTWIDGET |
| 55 | |
| 56 | namespace Phonon |
| 57 | { |
| 58 | |
| 59 | EffectWidget::EffectWidget(Effect *effect, QWidget *parent) |
| 60 | : QWidget(parent), |
| 61 | k_ptr(new EffectWidgetPrivate(effect)) |
| 62 | { |
| 63 | P_D(EffectWidget); |
| 64 | d->q_ptr = this; |
| 65 | d->autogenerateUi(); |
| 66 | } |
| 67 | |
| 68 | EffectWidget::~EffectWidget() |
| 69 | { |
| 70 | delete k_ptr; |
| 71 | } |
| 72 | |
| 73 | /* |
| 74 | EffectWidget::EffectWidget(EffectWidgetPrivate &dd, QWidget *parent) |
| 75 | : QWidget(parent) |
| 76 | , k_ptr(&dd) |
| 77 | { |
| 78 | P_D(EffectWidget); |
| 79 | d->q_ptr = this; |
| 80 | d->autogenerateUi(); |
| 81 | } |
| 82 | */ |
| 83 | |
| 84 | EffectWidgetPrivate::EffectWidgetPrivate(Effect *e) |
| 85 | : effect(e) |
| 86 | { |
| 87 | //TODO: look up whether there is a specialized widget for this effect. This |
| 88 | //could be a DSO or a Designer ui file found via KTrader. |
| 89 | // |
| 90 | //if no specialized widget is available: |
| 91 | } |
| 92 | |
| 93 | void EffectWidgetPrivate::autogenerateUi() |
| 94 | { |
| 95 | P_Q(EffectWidget); |
| 96 | QVBoxLayout *mainLayout = new QVBoxLayout(q); |
| 97 | mainLayout->setContentsMargins(QMargins()); |
| 98 | const QList<Phonon::EffectParameter> parameters = effect->parameters(); |
| 99 | for (int i = 0; i < parameters.count(); ++i) { |
| 100 | const EffectParameter ¶ = parameters.at(i); |
| 101 | QVariant value = effect->parameterValue(para); |
| 102 | QHBoxLayout *pLayout = new QHBoxLayout; |
| 103 | mainLayout->addLayout(layout: pLayout); |
| 104 | |
| 105 | QLabel *label = new QLabel(q); |
| 106 | pLayout->addWidget(label); |
| 107 | label->setText(para.name()); |
| 108 | #ifndef QT_NO_TOOLTIP |
| 109 | label->setToolTip(para.description()); |
| 110 | #endif |
| 111 | |
| 112 | QWidget *control = nullptr; |
| 113 | switch (int(para.type())) { |
| 114 | case QVariant::String: |
| 115 | { |
| 116 | QComboBox *cb = new QComboBox(q); |
| 117 | control = cb; |
| 118 | if (value.type() == QVariant::Int) { |
| 119 | //value just defines the item index |
| 120 | for (int i = 0; i < para.possibleValues().count(); ++i) { |
| 121 | cb->addItem(atext: para.possibleValues().at(i).toString()); |
| 122 | } |
| 123 | cb->setCurrentIndex(value.toInt()); |
| 124 | QObject::connect(sender: cb, SIGNAL(currentIndexChanged(int)), receiver: q, SLOT(_k_setIntParameter(int))); |
| 125 | } else { |
| 126 | for (int i = 0; i < para.possibleValues().count(); ++i) { |
| 127 | const QVariant &item = para.possibleValues().at(i); |
| 128 | cb->addItem(atext: item.toString()); |
| 129 | if (item == value) { |
| 130 | cb->setCurrentIndex(cb->count() - 1); |
| 131 | } |
| 132 | } |
| 133 | QObject::connect(sender: cb, SIGNAL(currentIndexChanged(QString)), receiver: q, SLOT(_k_setStringParameter(QString))); |
| 134 | } |
| 135 | } |
| 136 | break; |
| 137 | case QVariant::Bool: |
| 138 | { |
| 139 | QCheckBox *cb = new QCheckBox(q); |
| 140 | control = cb; |
| 141 | cb->setChecked(value.toBool()); |
| 142 | QObject::connect(sender: cb, SIGNAL(toggled(bool)), receiver: q, SLOT(_k_setToggleParameter(bool))); |
| 143 | } |
| 144 | break; |
| 145 | case QVariant::Int: |
| 146 | { |
| 147 | QSpinBox *sb = new QSpinBox(q); |
| 148 | control = sb; |
| 149 | bool minValueOk = false; |
| 150 | bool maxValueOk = false; |
| 151 | const int minValue = para.minimumValue().toInt(ok: &minValueOk); |
| 152 | const int maxValue = para.maximumValue().toInt(ok: &maxValueOk); |
| 153 | |
| 154 | sb->setRange(min: minValueOk ? minValue : DEFAULT_MIN_INT, max: maxValueOk ? maxValue : DEFAULT_MAX_INT); |
| 155 | sb->setValue(value.toInt()); |
| 156 | QObject::connect(sender: sb, SIGNAL(valueChanged(int)), receiver: q, SLOT(_k_setIntParameter(int))); |
| 157 | } |
| 158 | break; |
| 159 | case QMetaType::Float: |
| 160 | case QVariant::Double: |
| 161 | { |
| 162 | const qreal minValue = para.minimumValue().canConvert(targetTypeId: QVariant::Double) ? |
| 163 | para.minimumValue().toReal() : DEFAULT_MIN; |
| 164 | const qreal maxValue = para.maximumValue().canConvert(targetTypeId: QVariant::Double) ? |
| 165 | para.maximumValue().toReal() : DEFAULT_MAX; |
| 166 | |
| 167 | if (minValue == -1. && maxValue == 1.) { |
| 168 | //Special case values between -1 and 1.0 to use a slider for improved usability |
| 169 | QSlider *slider = new QSlider(Qt::Horizontal, q); |
| 170 | control = slider; |
| 171 | slider->setRange(min: -SLIDER_RANGE, max: +SLIDER_RANGE); |
| 172 | slider->setValue(int(SLIDER_RANGE * value.toReal())); |
| 173 | slider->setTickPosition(QSlider::TicksBelow); |
| 174 | slider->setTickInterval(TICKINTERVAL); |
| 175 | QObject::connect(sender: slider, SIGNAL(valueChanged(int)), receiver: q, SLOT(_k_setSliderParameter(int))); |
| 176 | } else { |
| 177 | double step = 0.1; |
| 178 | if (qAbs(t: maxValue - minValue) > 50) |
| 179 | step = 1.0; |
| 180 | QDoubleSpinBox *sb = new QDoubleSpinBox(q); |
| 181 | control = sb; |
| 182 | sb->setRange(min: minValue, max: maxValue); |
| 183 | sb->setValue(value.toDouble()); |
| 184 | sb->setSingleStep(step); |
| 185 | QObject::connect(sender: sb, SIGNAL(valueChanged(double)), receiver: q, |
| 186 | SLOT(_k_setDoubleParameter(double))); |
| 187 | } |
| 188 | } |
| 189 | break; |
| 190 | default: |
| 191 | break; |
| 192 | } |
| 193 | |
| 194 | if (control) { |
| 195 | #ifndef QT_NO_TOOLTIP |
| 196 | control->setToolTip(para.description()); |
| 197 | #endif |
| 198 | #ifndef QT_NO_SHORTCUT |
| 199 | label->setBuddy(control); |
| 200 | #endif |
| 201 | pLayout->addWidget(control); |
| 202 | parameterForObject.insert(key: control, value: para); |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | void EffectWidgetPrivate::_k_setToggleParameter(bool checked) |
| 208 | { |
| 209 | P_Q(EffectWidget); |
| 210 | if (parameterForObject.contains(key: q->sender())) { |
| 211 | effect->setParameterValue(parameterForObject[q->sender()], value: checked); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | void EffectWidgetPrivate::_k_setIntParameter(int value) |
| 216 | { |
| 217 | P_Q(EffectWidget); |
| 218 | if (parameterForObject.contains(key: q->sender())) { |
| 219 | effect->setParameterValue(parameterForObject[q->sender()], value); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | void EffectWidgetPrivate::_k_setDoubleParameter(double value) |
| 224 | { |
| 225 | P_Q(EffectWidget); |
| 226 | if (parameterForObject.contains(key: q->sender())) { |
| 227 | effect->setParameterValue(parameterForObject[q->sender()], value); |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | void EffectWidgetPrivate::_k_setStringParameter(const QString &value) |
| 232 | { |
| 233 | P_Q(EffectWidget); |
| 234 | if (parameterForObject.contains(key: q->sender())) { |
| 235 | effect->setParameterValue(parameterForObject[q->sender()], value); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | void EffectWidgetPrivate::_k_setSliderParameter(int value) |
| 240 | { |
| 241 | P_Q(EffectWidget); |
| 242 | if (parameterForObject.contains(key: q->sender())) { |
| 243 | effect->setParameterValue(parameterForObject[q->sender()], value: double(value) / double(SLIDER_RANGE)); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | |
| 248 | } // namespace Phonon |
| 249 | |
| 250 | |
| 251 | #endif // QT_NO_PHONON_EFFECTWIDGET |
| 252 | |
| 253 | #include "moc_effectwidget.cpp" |
| 254 | |
| 255 | // vim: sw=4 ts=4 |
| 256 | |