mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 16:02:51 -05:00
dropdown: improve perf + add fuzzy search to printers
This commit is contained in:
@@ -2,6 +2,8 @@ package cups
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -156,9 +158,42 @@ func (m *Manager) PurgeJobs(printerName string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveIPFromURI(uri string) string {
|
||||||
|
parsed, err := url.Parse(uri)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
host := parsed.Hostname()
|
||||||
|
if host == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
|
return ip.String()
|
||||||
|
}
|
||||||
|
addrs, err := net.LookupIP(host)
|
||||||
|
if err != nil || len(addrs) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if v4 := addr.To4(); v4 != nil {
|
||||||
|
return v4.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addrs[0].String()
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) GetDevices() ([]Device, error) {
|
func (m *Manager) GetDevices() ([]Device, error) {
|
||||||
if m.pkHelper != nil {
|
if m.pkHelper != nil {
|
||||||
return m.pkHelper.DevicesGet(10, 0, nil, nil)
|
devices, err := m.pkHelper.DevicesGet(10, 0, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range devices {
|
||||||
|
if devices[i].Class == "network" {
|
||||||
|
devices[i].IP = resolveIPFromURI(devices[i].URI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return devices, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceAttrs, err := m.client.GetDevices()
|
deviceAttrs, err := m.client.GetDevices()
|
||||||
@@ -176,6 +211,9 @@ func (m *Manager) GetDevices() ([]Device, error) {
|
|||||||
ID: getStringAttr(attrs, "device-id"),
|
ID: getStringAttr(attrs, "device-id"),
|
||||||
Location: getStringAttr(attrs, "device-location"),
|
Location: getStringAttr(attrs, "device-location"),
|
||||||
}
|
}
|
||||||
|
if device.Class == "network" {
|
||||||
|
device.IP = resolveIPFromURI(uri)
|
||||||
|
}
|
||||||
devices = append(devices, device)
|
devices = append(devices, device)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type Device struct {
|
|||||||
MakeModel string `json:"makeModel"`
|
MakeModel string `json:"makeModel"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Location string `json:"location"`
|
Location string `json:"location"`
|
||||||
|
IP string `json:"ip,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PPD struct {
|
type PPD struct {
|
||||||
|
|||||||
@@ -287,6 +287,8 @@ Item {
|
|||||||
id: deviceDropdown
|
id: deviceDropdown
|
||||||
dropdownWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2
|
dropdownWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2
|
||||||
popupWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2
|
popupWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2
|
||||||
|
enableFuzzySearch: true
|
||||||
|
emptyText: I18n.tr("No devices found")
|
||||||
currentValue: {
|
currentValue: {
|
||||||
if (CupsService.loadingDevices)
|
if (CupsService.loadingDevices)
|
||||||
return I18n.tr("Scanning...");
|
return I18n.tr("Scanning...");
|
||||||
@@ -294,20 +296,12 @@ Item {
|
|||||||
return CupsService.getDeviceDisplayName(printerTab.selectedDevice);
|
return CupsService.getDeviceDisplayName(printerTab.selectedDevice);
|
||||||
return I18n.tr("Select device...");
|
return I18n.tr("Select device...");
|
||||||
}
|
}
|
||||||
options: {
|
options: CupsService.filteredDevices.map(d => CupsService.getDeviceDisplayName(d))
|
||||||
const filtered = CupsService.filteredDevices;
|
|
||||||
if (filtered.length === 0)
|
|
||||||
return [I18n.tr("No devices found")];
|
|
||||||
return filtered.map(d => CupsService.getDeviceDisplayName(d));
|
|
||||||
}
|
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
if (value === I18n.tr("No devices found") || value === I18n.tr("Scanning..."))
|
|
||||||
return;
|
|
||||||
const filtered = CupsService.filteredDevices;
|
const filtered = CupsService.filteredDevices;
|
||||||
const device = filtered.find(d => CupsService.getDeviceDisplayName(d) === value);
|
const device = filtered.find(d => CupsService.getDeviceDisplayName(d) === value);
|
||||||
if (device) {
|
if (device)
|
||||||
printerTab.selectDevice(device);
|
printerTab.selectDevice(device);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,6 +359,8 @@ Item {
|
|||||||
id: ppdDropdown
|
id: ppdDropdown
|
||||||
dropdownWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2
|
dropdownWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2
|
||||||
popupWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2
|
popupWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2
|
||||||
|
enableFuzzySearch: true
|
||||||
|
emptyText: I18n.tr("No drivers found")
|
||||||
currentValue: {
|
currentValue: {
|
||||||
if (CupsService.loadingPPDs)
|
if (CupsService.loadingPPDs)
|
||||||
return I18n.tr("Loading...");
|
return I18n.tr("Loading...");
|
||||||
@@ -379,20 +375,15 @@ Item {
|
|||||||
return printerTab.suggestedPPDs.length > 0 ? I18n.tr("Recommended available") : I18n.tr("Select driver...");
|
return printerTab.suggestedPPDs.length > 0 ? I18n.tr("Recommended available") : I18n.tr("Select driver...");
|
||||||
}
|
}
|
||||||
options: {
|
options: {
|
||||||
if (CupsService.ppds.length === 0)
|
|
||||||
return [I18n.tr("No drivers found")];
|
|
||||||
const suggested = printerTab.suggestedPPDs.map(p => "★ " + (p.makeModel || p.name));
|
const suggested = printerTab.suggestedPPDs.map(p => "★ " + (p.makeModel || p.name));
|
||||||
const others = CupsService.ppds.filter(p => !printerTab.suggestedPPDs.some(s => s.name === p.name)).map(p => p.makeModel || p.name);
|
const others = CupsService.ppds.filter(p => !printerTab.suggestedPPDs.some(s => s.name === p.name)).map(p => p.makeModel || p.name);
|
||||||
return suggested.concat(others);
|
return suggested.concat(others);
|
||||||
}
|
}
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
if (value === I18n.tr("No drivers found") || value === I18n.tr("Loading..."))
|
|
||||||
return;
|
|
||||||
const cleanValue = value.replace(/^★ /, "");
|
const cleanValue = value.replace(/^★ /, "");
|
||||||
const ppd = CupsService.ppds.find(p => (p.makeModel || p.name) === cleanValue);
|
const ppd = CupsService.ppds.find(p => (p.makeModel || p.name) === cleanValue);
|
||||||
if (ppd) {
|
if (ppd)
|
||||||
printerTab.selectedPpd = ppd.name;
|
printerTab.selectedPpd = ppd.name;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,33 +109,36 @@ Singleton {
|
|||||||
function getDeviceDisplayName(device) {
|
function getDeviceDisplayName(device) {
|
||||||
if (!device)
|
if (!device)
|
||||||
return "";
|
return "";
|
||||||
|
let name = "";
|
||||||
if (device.info && device.info.length > 0) {
|
if (device.info && device.info.length > 0) {
|
||||||
return decodeUri(device.info);
|
name = decodeUri(device.info);
|
||||||
|
} else if (device.makeModel && device.makeModel.length > 0) {
|
||||||
|
name = decodeUri(device.makeModel);
|
||||||
|
} else {
|
||||||
|
return decodeUri(device.uri);
|
||||||
}
|
}
|
||||||
if (device.makeModel && device.makeModel.length > 0) {
|
if (device.ip)
|
||||||
return decodeUri(device.makeModel);
|
return name + " (" + device.ip + ")";
|
||||||
}
|
return name;
|
||||||
return decodeUri(device.uri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeviceSubtitle(device) {
|
function getDeviceSubtitle(device) {
|
||||||
if (!device)
|
if (!device)
|
||||||
return "";
|
return "";
|
||||||
const parts = [];
|
const parts = [];
|
||||||
if (device.class) {
|
switch (device.class) {
|
||||||
switch (device.class) {
|
case "direct":
|
||||||
case "direct":
|
parts.push(I18n.tr("Local"));
|
||||||
parts.push(I18n.tr("Local"));
|
break;
|
||||||
break;
|
case "network":
|
||||||
case "network":
|
parts.push(I18n.tr("Network"));
|
||||||
parts.push(I18n.tr("Network"));
|
break;
|
||||||
break;
|
case "file":
|
||||||
case "file":
|
parts.push(I18n.tr("File"));
|
||||||
parts.push(I18n.tr("File"));
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
if (device.class)
|
||||||
parts.push(device.class);
|
parts.push(device.class);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (device.location)
|
if (device.location)
|
||||||
parts.push(decodeUri(device.location));
|
parts.push(decodeUri(device.location));
|
||||||
|
|||||||
@@ -18,17 +18,20 @@ Item {
|
|||||||
property var options: []
|
property var options: []
|
||||||
property var optionIcons: []
|
property var optionIcons: []
|
||||||
property bool enableFuzzySearch: false
|
property bool enableFuzzySearch: false
|
||||||
|
property var optionIconMap: ({})
|
||||||
|
|
||||||
onOptionsChanged: {
|
function rebuildIconMap() {
|
||||||
if (dropdownMenu.visible) {
|
const map = {};
|
||||||
dropdownMenu.fzfFinder = new Fzf.Finder(options, {
|
for (let i = 0; i < options.length; i++) {
|
||||||
"selector": option => option,
|
if (optionIcons.length > i)
|
||||||
"limit": 50,
|
map[options[i]] = optionIcons[i];
|
||||||
"casing": "case-insensitive"
|
|
||||||
});
|
|
||||||
dropdownMenu.updateFilteredOptions();
|
|
||||||
}
|
}
|
||||||
|
optionIconMap = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOptionsChanged: rebuildIconMap()
|
||||||
|
onOptionIconsChanged: rebuildIconMap()
|
||||||
|
|
||||||
property int popupWidthOffset: 0
|
property int popupWidthOffset: 0
|
||||||
property int maxPopupHeight: 400
|
property int maxPopupHeight: 400
|
||||||
property bool openUpwards: false
|
property bool openUpwards: false
|
||||||
@@ -37,6 +40,7 @@ Item {
|
|||||||
property int dropdownWidth: 200
|
property int dropdownWidth: 200
|
||||||
property bool compactMode: text === "" && description === ""
|
property bool compactMode: text === "" && description === ""
|
||||||
property bool addHorizontalPadding: false
|
property bool addHorizontalPadding: false
|
||||||
|
property string emptyText: ""
|
||||||
|
|
||||||
signal valueChanged(string value)
|
signal valueChanged(string value)
|
||||||
|
|
||||||
@@ -44,10 +48,8 @@ Item {
|
|||||||
implicitHeight: compactMode ? 40 : Math.max(60, labelColumn.implicitHeight + Theme.spacingM)
|
implicitHeight: compactMode ? 40 : Math.max(60, labelColumn.implicitHeight + Theme.spacingM)
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
const popup = dropdownMenu;
|
if (dropdownMenu.visible)
|
||||||
if (popup && popup.visible) {
|
dropdownMenu.close();
|
||||||
popup.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -105,36 +107,16 @@ Item {
|
|||||||
dropdownMenu.close();
|
dropdownMenu.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dropdownMenu.searchQuery = "";
|
|
||||||
dropdownMenu.updateFilteredOptions();
|
|
||||||
|
|
||||||
dropdownMenu.open();
|
dropdownMenu.open();
|
||||||
|
|
||||||
const pos = dropdown.mapToItem(Overlay.overlay, 0, 0);
|
const pos = dropdown.mapToItem(Overlay.overlay, 0, 0);
|
||||||
const popupWidth = dropdownMenu.width;
|
const popupW = dropdownMenu.width;
|
||||||
const popupHeight = dropdownMenu.height;
|
const popupH = dropdownMenu.height;
|
||||||
const overlayHeight = Overlay.overlay.height;
|
const overlayH = Overlay.overlay.height;
|
||||||
|
const goUp = root.openUpwards || pos.y + dropdown.height + popupH + 4 > overlayH;
|
||||||
if (root.openUpwards || pos.y + dropdown.height + popupHeight + 4 > overlayHeight) {
|
dropdownMenu.x = root.alignPopupRight ? pos.x + dropdown.width - popupW : pos.x - (root.popupWidthOffset / 2);
|
||||||
if (root.alignPopupRight) {
|
dropdownMenu.y = goUp ? pos.y - popupH - 4 : pos.y + dropdown.height + 4;
|
||||||
dropdownMenu.x = pos.x + dropdown.width - popupWidth;
|
if (root.enableFuzzySearch)
|
||||||
} else {
|
|
||||||
dropdownMenu.x = pos.x - (root.popupWidthOffset / 2);
|
|
||||||
}
|
|
||||||
dropdownMenu.y = pos.y - popupHeight - 4;
|
|
||||||
} else {
|
|
||||||
if (root.alignPopupRight) {
|
|
||||||
dropdownMenu.x = pos.x + dropdown.width - popupWidth;
|
|
||||||
} else {
|
|
||||||
dropdownMenu.x = pos.x - (root.popupWidthOffset / 2);
|
|
||||||
}
|
|
||||||
dropdownMenu.y = pos.y + dropdown.height + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root.enableFuzzySearch && searchField.visible) {
|
|
||||||
searchField.forceActiveFocus();
|
searchField.forceActiveFocus();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,10 +131,7 @@ Item {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: {
|
name: root.optionIconMap[root.currentValue] ?? ""
|
||||||
const currentIndex = root.options.indexOf(root.currentValue);
|
|
||||||
return currentIndex >= 0 && root.optionIcons.length > currentIndex ? root.optionIcons[currentIndex] : "";
|
|
||||||
}
|
|
||||||
size: 18
|
size: 18
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -193,51 +172,52 @@ Item {
|
|||||||
id: dropdownMenu
|
id: dropdownMenu
|
||||||
|
|
||||||
property string searchQuery: ""
|
property string searchQuery: ""
|
||||||
property var filteredOptions: []
|
property var filteredOptions: {
|
||||||
|
if (!root.enableFuzzySearch || searchQuery.length === 0)
|
||||||
|
return root.options;
|
||||||
|
if (!fzfFinder)
|
||||||
|
return root.options;
|
||||||
|
return fzfFinder.find(searchQuery).map(r => r.item);
|
||||||
|
}
|
||||||
property int selectedIndex: -1
|
property int selectedIndex: -1
|
||||||
property var fzfFinder: new Fzf.Finder(root.options, {
|
property var fzfFinder: null
|
||||||
"selector": option => option,
|
|
||||||
"limit": 50,
|
|
||||||
"casing": "case-insensitive"
|
|
||||||
})
|
|
||||||
|
|
||||||
function updateFilteredOptions() {
|
function initFinder() {
|
||||||
if (!root.enableFuzzySearch || searchQuery.length === 0) {
|
fzfFinder = new Fzf.Finder(root.options, {
|
||||||
filteredOptions = root.options;
|
"selector": option => option,
|
||||||
selectedIndex = -1;
|
"limit": 50,
|
||||||
return;
|
"casing": "case-insensitive"
|
||||||
}
|
});
|
||||||
|
|
||||||
const results = fzfFinder.find(searchQuery);
|
|
||||||
filteredOptions = results.map(result => result.item);
|
|
||||||
selectedIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNext() {
|
function selectNext() {
|
||||||
if (filteredOptions.length === 0) {
|
if (filteredOptions.length === 0)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
selectedIndex = (selectedIndex + 1) % filteredOptions.length;
|
selectedIndex = (selectedIndex + 1) % filteredOptions.length;
|
||||||
listView.positionViewAtIndex(selectedIndex, ListView.Contain);
|
listView.positionViewAtIndex(selectedIndex, ListView.Contain);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPrevious() {
|
function selectPrevious() {
|
||||||
if (filteredOptions.length === 0) {
|
if (filteredOptions.length === 0)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
selectedIndex = selectedIndex <= 0 ? filteredOptions.length - 1 : selectedIndex - 1;
|
selectedIndex = selectedIndex <= 0 ? filteredOptions.length - 1 : selectedIndex - 1;
|
||||||
listView.positionViewAtIndex(selectedIndex, ListView.Contain);
|
listView.positionViewAtIndex(selectedIndex, ListView.Contain);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectCurrent() {
|
function selectCurrent() {
|
||||||
if (selectedIndex < 0 || selectedIndex >= filteredOptions.length) {
|
if (selectedIndex < 0 || selectedIndex >= filteredOptions.length)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
root.currentValue = filteredOptions[selectedIndex];
|
root.currentValue = filteredOptions[selectedIndex];
|
||||||
root.valueChanged(filteredOptions[selectedIndex]);
|
root.valueChanged(filteredOptions[selectedIndex]);
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
fzfFinder = null;
|
||||||
|
searchQuery = "";
|
||||||
|
selectedIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
parent: Overlay.overlay
|
parent: Overlay.overlay
|
||||||
width: root.popupWidth === -1 ? undefined : (root.popupWidth > 0 ? root.popupWidth : (dropdown.width + root.popupWidthOffset))
|
width: root.popupWidth === -1 ? undefined : (root.popupWidth > 0 ? root.popupWidth : (dropdown.width + root.popupWidthOffset))
|
||||||
height: Math.min(root.maxPopupHeight, (root.enableFuzzySearch ? 54 : 0) + Math.min(filteredOptions.length, 10) * 36 + 16)
|
height: Math.min(root.maxPopupHeight, (root.enableFuzzySearch ? 54 : 0) + Math.min(filteredOptions.length, 10) * 36 + 16)
|
||||||
@@ -283,30 +263,38 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 1
|
anchors.margins: 1
|
||||||
placeholderText: I18n.tr("Search...")
|
placeholderText: I18n.tr("Search...")
|
||||||
text: dropdownMenu.searchQuery
|
|
||||||
topPadding: Theme.spacingS
|
topPadding: Theme.spacingS
|
||||||
bottomPadding: Theme.spacingS
|
bottomPadding: Theme.spacingS
|
||||||
onTextChanged: {
|
onTextChanged: searchDebounce.restart()
|
||||||
dropdownMenu.searchQuery = text;
|
|
||||||
dropdownMenu.updateFilteredOptions();
|
|
||||||
}
|
|
||||||
Keys.onDownPressed: dropdownMenu.selectNext()
|
Keys.onDownPressed: dropdownMenu.selectNext()
|
||||||
Keys.onUpPressed: dropdownMenu.selectPrevious()
|
Keys.onUpPressed: dropdownMenu.selectPrevious()
|
||||||
Keys.onReturnPressed: dropdownMenu.selectCurrent()
|
Keys.onReturnPressed: dropdownMenu.selectCurrent()
|
||||||
Keys.onEnterPressed: dropdownMenu.selectCurrent()
|
Keys.onEnterPressed: dropdownMenu.selectCurrent()
|
||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
if (!(event.modifiers & Qt.ControlModifier))
|
||||||
|
return;
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_N:
|
||||||
|
case Qt.Key_J:
|
||||||
dropdownMenu.selectNext();
|
dropdownMenu.selectNext();
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
break;
|
||||||
dropdownMenu.selectPrevious();
|
case Qt.Key_P:
|
||||||
event.accepted = true;
|
case Qt.Key_K:
|
||||||
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
|
||||||
dropdownMenu.selectNext();
|
|
||||||
event.accepted = true;
|
|
||||||
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
|
||||||
dropdownMenu.selectPrevious();
|
dropdownMenu.selectPrevious();
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: searchDebounce
|
||||||
|
interval: 50
|
||||||
|
onTriggered: {
|
||||||
|
if (!dropdownMenu.fzfFinder)
|
||||||
|
dropdownMenu.initFinder();
|
||||||
|
dropdownMenu.searchQuery = searchField.text;
|
||||||
|
dropdownMenu.selectedIndex = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,12 +306,28 @@ Item {
|
|||||||
visible: root.enableFuzzySearch
|
visible: root.enableFuzzySearch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: 32
|
||||||
|
visible: root.options.length === 0 && root.emptyText !== ""
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: root.emptyText
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DankListView {
|
DankListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - (root.enableFuzzySearch ? searchContainer.height + Theme.spacingXS : 0)
|
height: parent.height - (root.enableFuzzySearch ? searchContainer.height + Theme.spacingXS : 0) - (root.options.length === 0 && root.emptyText !== "" ? 32 : 0)
|
||||||
clip: true
|
clip: true
|
||||||
|
visible: root.options.length > 0
|
||||||
model: ScriptModel {
|
model: ScriptModel {
|
||||||
values: dropdownMenu.filteredOptions
|
values: dropdownMenu.filteredOptions
|
||||||
}
|
}
|
||||||
@@ -338,9 +342,13 @@ Item {
|
|||||||
flickableDirection: Flickable.VerticalFlick
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
|
id: delegateRoot
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
property bool isSelected: dropdownMenu.selectedIndex === index
|
property bool isSelected: dropdownMenu.selectedIndex === index
|
||||||
property bool isCurrentValue: root.currentValue === modelData
|
property bool isCurrentValue: root.currentValue === modelData
|
||||||
property int optionIndex: root.options.indexOf(modelData)
|
property string iconName: root.optionIconMap[modelData] ?? ""
|
||||||
|
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
height: 32
|
height: 32
|
||||||
@@ -354,19 +362,19 @@ Item {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: optionIndex >= 0 && root.optionIcons.length > optionIndex ? root.optionIcons[optionIndex] : ""
|
name: delegateRoot.iconName
|
||||||
size: 18
|
size: 18
|
||||||
color: isCurrentValue ? Theme.primary : Theme.surfaceText
|
color: delegateRoot.isCurrentValue ? Theme.primary : Theme.surfaceText
|
||||||
visible: name !== ""
|
visible: name !== ""
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: modelData
|
text: delegateRoot.modelData
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: isCurrentValue ? Theme.primary : Theme.surfaceText
|
color: delegateRoot.isCurrentValue ? Theme.primary : Theme.surfaceText
|
||||||
font.weight: isCurrentValue ? Font.Medium : Font.Normal
|
font.weight: delegateRoot.isCurrentValue ? Font.Medium : Font.Normal
|
||||||
width: root.popupWidth > 0 ? undefined : (parent.parent.width - parent.x - Theme.spacingS)
|
width: root.popupWidth > 0 ? undefined : (delegateRoot.width - parent.x - Theme.spacingS)
|
||||||
elide: root.popupWidth > 0 ? Text.ElideNone : Text.ElideRight
|
elide: root.popupWidth > 0 ? Text.ElideNone : Text.ElideRight
|
||||||
wrapMode: Text.NoWrap
|
wrapMode: Text.NoWrap
|
||||||
}
|
}
|
||||||
@@ -379,8 +387,8 @@ Item {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.currentValue = modelData;
|
root.currentValue = delegateRoot.modelData;
|
||||||
root.valueChanged(modelData);
|
root.valueChanged(delegateRoot.modelData);
|
||||||
dropdownMenu.close();
|
dropdownMenu.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user