/*SPDX-FileCopyrightText: 2024 Evgeny Chesnokov <echesnokov@astralinux.ru>SPDX-License-Identifier: GPL-2.0-or-later*/import QtQuickimport QtQuick.Layoutsimport QtQuick.Controls as QQC2import org.kde.kquickcontrols as KQuickControlsimport org.kde.kitemmodels as KItemModelsimport org.kde.kirigami as Kirigamiimport org.kde.kcmutils as KCMimport org.kde.plasma.private.kcm_keyboard as KCMKeyboardKCM.ScrollViewKCM {id: rootimplicitWidth: Kirigami.Units.gridUnit * 44implicitHeight: Kirigami.Units.gridUnit * 25actions: [keyBindingsPageAction]extraFooterTopPadding: true // re-add separator lineKItemModels.KSortFilterProxyModel {id: keyboardsProxysourceModel: KCMKeyboard.KeyboardModel {}sortRoleName: "description"sortOrder: Qt.AscendingOrder}readonly property Kirigami.Action switchingPageAction: Kirigami.Action {icon.name: "input-keyboard-symbolic"text: i18nc("@action:button", "Configure Switchingβ¦")Accessible.name: i18nc("@action:button accessible", "Configure Switching")onTriggered: kcm.push("Switching.qml")}readonly property Kirigami.Action keyBindingsPageAction: Kirigami.Action {icon.name: "settings-configure-symbolic"text: i18nc("@action:button", "Key Bindings")Accessible.name: i18nc("@action:button accessible", "Key Bindings")onTriggered: kcm.push("KeyBindings.qml")}readonly property Kirigami.Action addLayoutAction: Kirigami.Action {icon.name: "list-add-symbolic"text: i18nc("@action:button Layout", "Addβ¦")Accessible.name: i18nc("@action:button accessible", "Add layout")onTriggered: _cLayoutDialog.incubateObject(root, {}, Qt.Asynchronous)enabled: kcm.keyboardSettings.configureLayouts}readonly property Kirigami.Action configureLayoutsAction: Kirigami.Action {displayComponent: QQC2.Switch {text: i18nc("@label:checkbox configure layouts option", "Enable")Accessible.name: i18nc("@label:checkbox accessible", "Configure Layouts")checked: kcm.keyboardSettings.configureLayoutsonToggled: kcm.keyboardSettings.configureLayouts = checkedKCM.SettingStateBinding {configObject: kcm.keyboardSettingssettingName: "configureLayouts"}}}header: Kirigami.FormLayout {id: headerFormLayoutQQC2.ComboBox {id: keyboardModelComboBoxKirigami.FormData.label: i18nc("@label:listbox Keyboard model", "Model:")model: keyboardsProxytextRole: "description"valueRole: "name"onActivated: kcm.keyboardSettings.keyboardModel = currentValueComponent.onCompleted: selectCurrent()Connections {target: kcm?.keyboardSettings ?? undefinedfunction onKeyboardModelChanged(): void {keyboardModelComboBox.selectCurrent()}}function selectCurrent(): void {currentIndex = indexOfValue(kcm.keyboardSettings.keyboardModel);}KCM.SettingStateBinding {configObject: kcm.keyboardSettingssettingName: "keyboardModel"}}QQC2.ComboBox {id: numlockComboboxKirigami.FormData.label: i18nc("@label:listbox", "NumLock on startup:")Layout.preferredWidth: keyboardModelComboBox.widthtextRole: "text"valueRole: "value"onActivated: kcm.miscSettings.numLock = currentValuemodel: [{"text": i18nc("@item:inlistbox Turn on \"NumLock\" on startup", "Turn on"),"value": KCMKeyboard.NumLockState.NumLockOn},{"text": i18nc("@item:inlistbox Turn off \"NumLock\" on startup", "Turn off"),"value": KCMKeyboard.NumLockState.NumLockOff},{"text": i18nc("@item:inlistbox Leave \"NumLock\" at whatever it was set to before Plasma started up", "Leave unchanged"),"value": KCMKeyboard.NumLockState.NumLockUnchanged},]Component.onCompleted: selectCurrent()Connections {target: kcm?.miscSettings ?? undefinedfunction onNumLockChanged(): void {numlockCombobox.selectCurrent()}}function selectCurrent(): void {currentIndex = indexOfValue(kcm.miscSettings.numLock);}KCM.SettingStateBinding {configObject: kcm.miscSettingssettingName: "numLock"}}RowLayout {Kirigami.FormData.label: i18nc("@label:checkbox", "Key repeat:")spacing: Kirigami.Units.smallSpacingQQC2.CheckBox {checked: kcm.miscSettings.keyboardRepeat === __internal.keyboardRepeatRepeatonToggled: kcm.miscSettings.keyboardRepeat = checked? __internal.keyboardRepeatRepeat: __internal.keyboardRepeatNothingAccessible.name: i18nc("@label:checkbox accessible", "Key repeat")KCM.SettingStateBinding {configObject: kcm.miscSettingssettingName: "keyboardRepeat"}}QQC2.Label {// Force the label to use its own Kirigami.Theme objectKirigami.Theme.inherit: falsetext: i18nc("@label:textbox Key repeat delay", "Delay:")enabled: kcm.miscSettings.keyboardRepeat !== __internal.keyboardRepeatNothing}QQC2.SpinBox {id: repeatDelaySpinboxLayout.preferredWidth: Kirigami.Units.gridUnit * 8from: 100to: 5000stepSize: 50value: kcm.miscSettings.repeatDelayonValueModified: kcm.miscSettings.repeatDelay = valueAccessible.name: i18nc("@label:spinbox accessible", "Key repeat delay %1", textFromValue(value))validator: IntValidator {bottom: Math.min(repeatDelaySpinbox.from, repeatDelaySpinbox.to)top: Math.max(repeatDelaySpinbox.from, repeatDelaySpinbox.to)}textFromValue: (value, locale) => {return i18nc("@spinbox:value Repeat delay interval", "%1 ms", value)}valueFromText: (text, locale) => {return Number.fromLocaleString(locale, text.replace(i18nc("@spinbox:value Repeat delay interval", "ms"), ""))}KCM.SettingStateBinding {configObject: kcm.miscSettingssettingName: "repeatDelay"extraEnabledConditions: kcm.miscSettings.keyboardRepeat !== __internal.keyboardRepeatNothing}}QQC2.Label {// Force the label to use its own Kirigami.Theme objectKirigami.Theme.inherit: falsetext: i18nc("@label:textbox Key repeat rate", "Rate:")enabled: kcm.miscSettings.keyboardRepeat !== __internal.keyboardRepeatNothing}QQC2.SpinBox {id: repeatRateSpinboxLayout.preferredWidth: Kirigami.Units.gridUnit * 8from: 20to: 20000stepSize: 500value: Math.round(kcm.miscSettings.repeatRate * 100)onValueModified: kcm.miscSettings.repeatRate = value / 100Accessible.name: i18nc("@label:spinbox accessible", "Key repeat rate %1", textFromValue(value))validator: DoubleValidator {bottom: Math.min(repeatRateSpinbox.from, repeatRateSpinbox.to)top: Math.max(repeatRateSpinbox.from, repeatRateSpinbox.to)}textFromValue: (value, locale) => {return i18nc("@spinbox:value Key repeat rate", "%1 repeats/s", value / 100)}valueFromText: (text, locale) => {return Number.fromLocaleString(locale, text.replace(i18nc("@spinbox:value Key repeat rate", "repeats/s"), "")) * 100}KCM.SettingStateBinding {configObject: kcm.miscSettingssettingName: "repeatRate"extraEnabledConditions: kcm.miscSettings.keyboardRepeat !== __internal.keyboardRepeatNothing}}}QQC2.TextField {Kirigami.FormData.label: i18nc("@label:textbox", "Test area:")Layout.preferredWidth: keyboardModelComboBox.widthplaceholderText: i18nc("@info:placeholder", "Type here to test settings")}}view: ListView {id: listmodel: kcm.userLayoutModelheaderPositioning: ListView.OverlayHeaderheader: Kirigami.InlineViewHeader {width: list.widthtext: i18nc("@title:view", "Layouts")actions: [ configureLayoutsAction, addLayoutAction ]}readonly property int maxKeySequenceItemWidth: Math.max(...contentItem.children.map(item => item?.keySequenceItemWidth || 0))delegate: LayoutDelegate {id: delegateonMove: (oldIndex, newIndex) => kcm.userLayoutModel.move(oldIndex, newIndex)isLoopingLayout: layoutLoopingCheckBox.checked && (index + 1) > layoutLoopCountSpinBox.valueactions: [Kirigami.Action {icon.name: "arrow-up-symbolic"text: i18nc("@action:button", "Move Up")Accessible.name: i18nc("@action:button accessible", "Move %1 layout up", delegate.layoutName)onTriggered: kcm.userLayoutModel.move(index, index - 1)enabled: index > 0},Kirigami.Action {icon.name: "arrow-down-symbolic"text: i18nc("@action:button", "Move Down")Accessible.name: i18nc("@action:button accessible", "Move %1 layout Down", delegate.layoutName)onTriggered: kcm.userLayoutModel.move(index, index + 1)enabled: index < list.count - 1},Kirigami.Action {separator: true},Kirigami.Action {icon.name: "input-keyboard-virtual-symbolic"text: i18nc("@action:button", "Preview")Accessible.name: i18nc("@action:button accessible", "Preview")onTriggered: kcm.requestPreview(kcm.keyboardSettings.keyboardModel, layout, variant, variantName)},Kirigami.Action {separator: true},Kirigami.Action {icon.name: "edit-delete-remove-symbolic"text: i18nc("@action:button", "Remove")Accessible.name: i18nc("@action:button accessible", "Remove layout %1", delegate.layoutName)onTriggered: kcm.userLayoutModel.remove(index)}]}}footer: Kirigami.FormLayout {twinFormLayouts: headerFormLayoutRowLayout {spacing: Kirigami.Units.smallSpacingKirigami.FormData.label: i18nc("@label:checkbox", "Spare layouts:")QQC2.CheckBox {id: layoutLoopingCheckBoxonToggled: {const count = checked ? __internal.minimumAvailableLoops : __internal.noLooping;kcm.keyboardSettings.layoutLoopCount = count;}checked: {// If the configureLayouts is turned off or the available value is less than the minimum, then the option is disabledif (!kcm.keyboardSettings.configureLayouts || __internal.minimumAvailableLoops < __internal.minimumLoopingCount) {return false;}// If the number of layouts is not the default value// or the available number of layouts is greater than the limit from X.org, then enable the optionreturn kcm.keyboardSettings.layoutLoopCount !== __internal.noLooping|| __internal.minimumAvailableLoops >= kcm.maxGroupCount}enabled: {// If the configureLayouts is turned off, then the element is disabledif (!kcm.keyboardSettings.configureLayouts) {return false;}// If the number of layouts is within the range of acceptable values, then enable the elementreturn __internal.minimumAvailableLoops >= __internal.minimumLoopingCount&& __internal.minimumAvailableLoops < kcm.maxGroupCount}}QQC2.SpinBox {id: layoutLoopCountSpinBoxLayout.minimumWidth: Kirigami.Units.gridUnit * 4Accessible.name: i18nc("@label:spinbox", "Number of spared main layouts")enabled: layoutLoopingCheckBox.checked && kcm.keyboardSettings.configureLayoutsto: Math.max(from, __internal.minimumAvailableLoops)from: {if (layoutLoopingCheckBox.checked) {return __internal.minimumLoopingCount;}return __internal.noLooping;}value: {if (!kcm.keyboardSettings.configureLayouts) {return __internal.noLooping;}if (kcm.keyboardSettings.layoutLoopCount > to){return to}return kcm.keyboardSettings.layoutLoopCount;}textFromValue: (value, locale) => value < 0 ? "" : Number(value).toLocaleString(locale, "f", 0)onValueModified: kcm.keyboardSettings.layoutLoopCount = value;}QQC2.Label {// Force the label to use its own Kirigami.Theme objectKirigami.Theme.inherit: falseenabled: layoutLoopCountSpinBox.enabledtext: i18nc("@label:textbox completes spinbox, x main layouts", "main layouts")}Kirigami.ContextualHelpButton {toolTipText: i18nc("@info", "You can have up to 4 main layouts, all other layouts are spare. Spare layouts are not included when cycling through the layouts, but can be accessed through the keyboard indicator applet or by setting a custom shortcut.")}}RowLayout {Kirigami.FormData.label: i18nc("@label:group Shortcut to change the keyboard layout. Keep it short", "Change layout shortcut:")spacing: Kirigami.Units.smallSpacingKQuickControls.KeySequenceItem {id: alternativeShortcutpatterns: KQuickControls.ShortcutPattern.Modifier | KQuickControls.ShortcutPattern.ModifierAndKeykeySequence: kcm.shortcutHelper.alternativeShortcutonKeySequenceModified: kcm.shortcutHelper.alternativeShortcut = keySequenceBinding {target: alternativeShortcutproperty: "keySequence"value: kcm.shortcutHelper.alternativeShortcut}KCM.SettingHighlighter {target: alternativeShortcuthighlight: alternativeShortcut.keySequence !== kcm.shortcutHelper.defaultAlternativeShortcut()}}QQC2.Label {text: i18nc("@label Change layout shortcut or \"Configure Switching\"", "or")}QQC2.Button {action: switchingPageAction}}}Component {id: _cLayoutDialogLayoutDialog {visible: falseComponent.onCompleted: open()onAccepted: destroy()onRejected: destroy()}}KeyboardInternal {id: __internal}}