// A searchable list of choices, for settings with far too many values to put in // a dropdown and no useful preview to show. // // SearchPicker { // items: Locale.locales // [{ value, label, detail }] // current: Locale.current // placeholder: "Search languages" // onPicked: value => Locale.set(value) // } // // FontPicker is the same idea specialised: it draws each candidate in its own // family, which is the whole reason it is a list rather than a text field. This // one is for choices whose only useful preview is their name. import QtQuick import qs.config // SearchField lives with the clipboard module, which is where it was first // needed; FontPicker imports it from the same place. import qs.modules.clipboard Column { id: root // [{ value, label, detail }] property var items: [] property string current: "" property string emptyText: "Nothing to choose from" property string placeholder: "Search" signal picked(string value) spacing: 0 // Capped and filtered rather than listing everything: 327 locales inside a // page that is already scrolling is worse than a search box. readonly property var matches: { const needle = filter.text.trim().toLowerCase(); const list = root.items.filter(item => needle === "" ? true : (String(item.label).toLowerCase().indexOf(needle) >= 0 || String(item.detail).toLowerCase().indexOf(needle) >= 0)); // The current choice stays visible while browsing, so it is always // clear what would be replaced. const selected = list.find(item => item.value === root.current); if (needle === "" && selected !== undefined) return [selected].concat(list.filter(item => item.value !== root.current)).slice(0, 12); return list.slice(0, 12); } SearchField { id: filter width: parent.width placeholder: root.placeholder } Repeater { model: root.matches SettingRow { id: candidate required property var modelData required property int index readonly property bool selected: candidate.modelData.value === root.current label: candidate.modelData.label detail: candidate.selected ? "Currently in use" : candidate.modelData.detail controlWidth: 120 divider: candidate.index < root.matches.length - 1 activatable: !candidate.selected onActivated: root.picked(candidate.modelData.value) Text { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter visible: candidate.selected text: "✓" font.family: Theme.fontFamily font.pixelSize: Theme.fontSize + 2 color: Theme.accent } } } SettingRow { width: parent.width visible: root.matches.length === 0 label: root.emptyText divider: false } }