File indexing completed on 2024-05-12 17:07:15
0001 /* 0002 kcmmisc.cpp 0003 0004 SPDX-FileCopyrightText: 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca> 0005 0006 Layout management, cleanups: 0007 SPDX-FileCopyrightText: 1999 Dirk A. Mueller <dmuell@gmx.net> 0008 0009 SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com> 0010 0011 SPDX-License-Identifier: GPL-2.0-or-later 0012 */ 0013 0014 #include "kcmmisc.h" 0015 #include "ui_kcmmiscwidget.h" 0016 #include "keyboardmiscsettings.h" 0017 0018 #include <QButtonGroup> 0019 #include <QCheckBox> 0020 #include <QDoubleSpinBox> 0021 #include <QSpinBox> 0022 #include <QWhatsThis> 0023 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0024 #include <QX11Info> 0025 #else 0026 #include <QtGui/private/qtx11extras_p.h> 0027 #endif 0028 0029 #include <KConfig> 0030 #include <KConfigGroup> 0031 #include <KLocalizedString> 0032 #include <KSharedConfig> 0033 0034 #include <X11/Xlib.h> 0035 #include <cmath> 0036 0037 namespace 0038 { 0039 bool hasAccentSupport() 0040 { 0041 static bool isPlasmaIM = (qgetenv("QT_IM_MODULE") == "plasmaim"); 0042 return isPlasmaIM; 0043 } 0044 } 0045 0046 KCMiscKeyboardWidget::KCMiscKeyboardWidget(QWidget *parent, KeyboardMiscSettings *settings) 0047 : QWidget(parent) 0048 , ui(*new Ui_KeyboardConfigWidget) 0049 , m_settings(settings) 0050 { 0051 ui.setupUi(this); 0052 0053 ui.kcfg_repeatDelay->setSingleStep(50); 0054 ui.kcfg_repeatRate->setSingleStep(5); 0055 0056 sliderMax = (int)floor(0.5 + 2 * (log(5000.0L) - log(100.0L)) / (log(5000.0L) - log(4999.0L))); 0057 ui.delaySlider->setRange(0, sliderMax); 0058 ui.delaySlider->setSingleStep(sliderMax / 100); 0059 ui.delaySlider->setPageStep(sliderMax / 10); 0060 ui.delaySlider->setTickInterval(sliderMax / 10); 0061 0062 ui.rateSlider->setRange(20, 10000); 0063 ui.rateSlider->setSingleStep(30); 0064 ui.rateSlider->setPageStep(500); 0065 ui.rateSlider->setTickInterval(498); 0066 0067 connect(ui.kcfg_repeatDelay, SIGNAL(valueChanged(int)), this, SLOT(delaySpinboxChanged(int))); 0068 connect(ui.delaySlider, &QAbstractSlider::valueChanged, this, &KCMiscKeyboardWidget::delaySliderChanged); 0069 connect(ui.kcfg_repeatRate, SIGNAL(valueChanged(double)), this, SLOT(rateSpinboxChanged(double))); 0070 connect(ui.rateSlider, &QAbstractSlider::valueChanged, this, &KCMiscKeyboardWidget::rateSliderChanged); 0071 0072 _numlockButtonGroup = new QButtonGroup(ui.numlockButtonGroup); 0073 _numlockButtonGroup->addButton(ui.radioButton1, 0); 0074 _numlockButtonGroup->addButton(ui.radioButton2, 1); 0075 _numlockButtonGroup->addButton(ui.radioButton3, 2); 0076 0077 connect(_numlockButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed())); 0078 0079 _keyboardRepeatButtonGroup = new QButtonGroup(ui.repeatFormLayout); 0080 if (hasAccentSupport()) { 0081 _keyboardRepeatButtonGroup->addButton(ui.accentMenuRadioButton, 0); 0082 } else { 0083 ui.accentMenuRadioButton->setVisible(false); 0084 } 0085 _keyboardRepeatButtonGroup->addButton(ui.repeatRadioButton, 1); 0086 _keyboardRepeatButtonGroup->addButton(ui.nothingRadioButton, 2); 0087 0088 connect(_keyboardRepeatButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed())); 0089 connect(_keyboardRepeatButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(keyboardRepeatStateChanged(int))); 0090 0091 connect(_numlockButtonGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), 0092 this, &KCMiscKeyboardWidget::updateUiDefaultIndicator); 0093 connect(_keyboardRepeatButtonGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), 0094 this, &KCMiscKeyboardWidget::updateUiDefaultIndicator); 0095 } 0096 0097 KCMiscKeyboardWidget::~KCMiscKeyboardWidget() 0098 { 0099 delete &ui; 0100 } 0101 0102 // set the slider and LCD values 0103 void KCMiscKeyboardWidget::setRepeat(KeyBehaviour keyboardRepeat, int delay_, double rate_) 0104 { 0105 _keyboardRepeatButtonGroup->button(keyboardRepeat)->click(); 0106 0107 delaySpinboxChanged(delay_); 0108 rateSpinboxChanged(rate_); 0109 } 0110 0111 TriState TriStateHelper::getTriState(const QButtonGroup *group) 0112 { 0113 int selected = group->checkedId(); 0114 return selected < 0 ? STATE_UNCHANGED : getTriState(selected); 0115 } 0116 0117 void TriStateHelper::setTriState(QButtonGroup *group, TriState state) 0118 { 0119 group->button(getInt(state))->click(); 0120 } 0121 0122 void KCMiscKeyboardWidget::load() 0123 { 0124 // need to read as string to support old "true/false" parameter 0125 QString key = m_settings->keyboardRepeat(); 0126 if (key == QLatin1String("true") || key == TriStateHelper::getString(STATE_ON) || key == QLatin1String("accent")) { 0127 keyboardRepeat = KeyBehaviour::AccentMenu; 0128 } else if (key == QLatin1String("false") || key == TriStateHelper::getString(STATE_OFF) || key == QLatin1String("nothing")) { 0129 keyboardRepeat = KeyBehaviour::DoNothing; 0130 } else if (key == QLatin1String("repeat")) { 0131 keyboardRepeat = KeyBehaviour::RepeatKey; 0132 } 0133 setRepeat(keyboardRepeat, m_settings->repeatDelay(), m_settings->repeatRate()); 0134 0135 numlockState = TriStateHelper::getTriState(m_settings->numLock()); 0136 TriStateHelper::setTriState(_numlockButtonGroup, numlockState); 0137 } 0138 0139 void KCMiscKeyboardWidget::save() 0140 { 0141 numlockState = TriStateHelper::getTriState(_numlockButtonGroup); 0142 keyboardRepeat = KeyBehaviour(_keyboardRepeatButtonGroup->checkedId()); 0143 0144 m_settings->setKeyboardRepeat(keybehaviourNames[keyboardRepeat]); 0145 m_settings->setNumLock(TriStateHelper::getInt(numlockState)); 0146 } 0147 0148 void KCMiscKeyboardWidget::defaults() 0149 { 0150 setRepeat(defaultValueKeyboardRepeat(), m_settings->defaultRepeatDelayValue(), m_settings->defaultRepeatRateValue()); 0151 TriStateHelper::setTriState(_numlockButtonGroup, static_cast<TriState>(m_settings->defaultNumLockValue())); 0152 Q_EMIT changed(true); 0153 } 0154 0155 QString KCMiscKeyboardWidget::quickHelp() const 0156 { 0157 return QString(); 0158 0159 /* "<h1>Keyboard</h1> This module allows you to choose options" 0160 " for the way in which your keyboard works. The actual effect of" 0161 " setting these options depends upon the features provided by your" 0162 " keyboard hardware and the X server on which Plasma is running.<p>" 0163 " For example, you may find that changing the key click volume" 0164 " has no effect because this feature is not available on your system." */ 0165 } 0166 0167 bool KCMiscKeyboardWidget::isSaveNeeded() const 0168 { 0169 return m_settings->keyboardRepeat() != keybehaviourNames[KeyBehaviour(_keyboardRepeatButtonGroup->checkedId())] 0170 || m_settings->numLock() != TriStateHelper::getInt(TriStateHelper::getTriState(_numlockButtonGroup)); 0171 } 0172 0173 bool KCMiscKeyboardWidget::isDefault() const 0174 { 0175 return defaultValueKeyboardRepeat() == KeyBehaviour(_keyboardRepeatButtonGroup->checkedId()) 0176 && m_settings->defaultNumLockValue() == TriStateHelper::getInt(TriStateHelper::getTriState(_numlockButtonGroup)); 0177 } 0178 0179 void KCMiscKeyboardWidget::setDefaultIndicator(bool visible) 0180 { 0181 m_highlightVisible = visible; 0182 updateUiDefaultIndicator(); 0183 } 0184 0185 void KCMiscKeyboardWidget::updateUiDefaultIndicator() 0186 { 0187 const auto isNumLockDefault = m_settings->defaultNumLockValue() == TriStateHelper::getInt(TriStateHelper::getTriState(_numlockButtonGroup)); 0188 for (auto button : _numlockButtonGroup->buttons()) { 0189 setDefaultIndicatorVisible(button, m_highlightVisible && !isNumLockDefault && _numlockButtonGroup->checkedButton() == button); 0190 } 0191 0192 const auto isKeyboardRepeatDefault = defaultValueKeyboardRepeat() == KeyBehaviour(_keyboardRepeatButtonGroup->checkedId()); 0193 for (auto button : _keyboardRepeatButtonGroup->buttons()) { 0194 setDefaultIndicatorVisible(button, m_highlightVisible && !isKeyboardRepeatDefault && _keyboardRepeatButtonGroup->checkedButton() == button); 0195 } 0196 0197 setDefaultIndicatorVisible(ui.delaySlider, m_highlightVisible && ui.kcfg_repeatDelay->value() != m_settings->defaultRepeatDelayValue()); 0198 setDefaultIndicatorVisible(ui.rateSlider, m_highlightVisible && ui.kcfg_repeatRate->value() != m_settings->defaultRepeatRateValue()); 0199 } 0200 0201 void KCMiscKeyboardWidget::delaySliderChanged(int value) 0202 { 0203 double alpha = sliderMax / (log(5000.0L) - log(100.0L)); 0204 double linearValue = exp(value / alpha + log(100.0L)); 0205 0206 ui.kcfg_repeatDelay->setValue((int)floor(0.5 + linearValue)); 0207 updateUiDefaultIndicator(); 0208 0209 Q_EMIT changed(true); 0210 } 0211 0212 void KCMiscKeyboardWidget::delaySpinboxChanged(int value) 0213 { 0214 double alpha = sliderMax / (log(5000.0L) - log(100.0L)); 0215 double logVal = alpha * (log((double)value) - log(100.0L)); 0216 0217 ui.delaySlider->setValue((int)floor(0.5 + logVal)); 0218 0219 Q_EMIT changed(true); 0220 } 0221 0222 void KCMiscKeyboardWidget::rateSliderChanged(int value) 0223 { 0224 ui.kcfg_repeatRate->setValue(value / 100.0); 0225 updateUiDefaultIndicator(); 0226 0227 Q_EMIT changed(true); 0228 } 0229 0230 void KCMiscKeyboardWidget::rateSpinboxChanged(double value) 0231 { 0232 ui.rateSlider->setValue((int)(value * 100)); 0233 Q_EMIT changed(true); 0234 } 0235 0236 void KCMiscKeyboardWidget::changed() 0237 { 0238 Q_EMIT changed(true); 0239 } 0240 0241 void KCMiscKeyboardWidget::keyboardRepeatStateChanged(int selection) 0242 { 0243 ui.keyboardRepeatParamsGroupBox->setVisible(selection == KeyBehaviour::RepeatKey); 0244 changed(); 0245 } 0246 0247 void KCMiscKeyboardWidget::setDefaultIndicatorVisible(QWidget *widget, bool visible) 0248 { 0249 widget->setProperty("_kde_highlight_neutral", visible); 0250 widget->update(); 0251 } 0252 0253 KeyBehaviour KCMiscKeyboardWidget::defaultValueKeyboardRepeat() const 0254 { 0255 if (m_settings->defaultKeyboardRepeatValue() == keybehaviourNames[KeyBehaviour::AccentMenu] && !hasAccentSupport()) { 0256 return KeyBehaviour::RepeatKey; 0257 } 0258 0259 const auto keys = keybehaviourNames.keys(); 0260 auto defaultRepeat = std::find_if(keys.constBegin(), keys.constEnd(), [=](const KeyBehaviour &key) { 0261 return keybehaviourNames[key] == m_settings->defaultKeyboardRepeatValue(); 0262 }); 0263 0264 return *defaultRepeat; 0265 }