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