mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 23:42:51 -05:00
better fuzzy search, sweeping clean and qmlfmt of Widgets
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import "../Common/fuzzysort.js" as FuzzySort
|
||||
import "../Common/fzf.js" as Fzf
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
@@ -11,10 +11,10 @@ Rectangle {
|
||||
property string description: ""
|
||||
property string currentValue: ""
|
||||
property var options: []
|
||||
property var optionIcons: [] // Array of icon names corresponding to options
|
||||
property var optionIcons: []
|
||||
property bool forceRecreate: false
|
||||
property bool enableFuzzySearch: false
|
||||
property int popupWidthOffset: 0 // How much wider the popup should be than the button
|
||||
property int popupWidthOffset: 0
|
||||
property int maxPopupHeight: 400
|
||||
|
||||
signal valueChanged(string value)
|
||||
@@ -23,20 +23,20 @@ Rectangle {
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
Component.onCompleted: {
|
||||
forceRecreateTimer.start()
|
||||
}
|
||||
Component.onCompleted: forceRecreateTimer.start()
|
||||
Component.onDestruction: {
|
||||
var popup = popupLoader.item
|
||||
if (popup && popup.visible)
|
||||
const popup = popupLoader.item
|
||||
if (popup && popup.visible) {
|
||||
popup.close()
|
||||
}
|
||||
}
|
||||
onVisibleChanged: {
|
||||
var popup = popupLoader.item
|
||||
if (!visible && popup && popup.visible)
|
||||
const popup = popupLoader.item
|
||||
if (!visible && popup && popup.visible) {
|
||||
popup.close()
|
||||
else if (visible)
|
||||
} else if (visible) {
|
||||
forceRecreateTimer.start()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -44,12 +44,9 @@ Rectangle {
|
||||
|
||||
interval: 50
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
root.forceRecreate = !root.forceRecreate
|
||||
}
|
||||
onTriggered: root.forceRecreate = !root.forceRecreate
|
||||
}
|
||||
|
||||
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
anchors.right: dropdown.left
|
||||
@@ -95,16 +92,20 @@ Rectangle {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var popup = popupLoader.item
|
||||
if (popup && popup.visible) {
|
||||
popup.close()
|
||||
} else if (popup) {
|
||||
var pos = dropdown.mapToItem(Overlay.overlay, 0,
|
||||
dropdown.height + 4)
|
||||
popup.x = pos.x - (root.popupWidthOffset / 2)
|
||||
popup.y = pos.y
|
||||
popup.open()
|
||||
const popup = popupLoader.item
|
||||
if (!popup) {
|
||||
return
|
||||
}
|
||||
|
||||
if (popup.visible) {
|
||||
popup.close()
|
||||
return
|
||||
}
|
||||
|
||||
const pos = dropdown.mapToItem(Overlay.overlay, 0, dropdown.height + 4)
|
||||
popup.x = pos.x - (root.popupWidthOffset / 2)
|
||||
popup.y = pos.y
|
||||
popup.open()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +119,8 @@ Rectangle {
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
var currentIndex = root.options.indexOf(root.currentValue)
|
||||
return root.optionIcons.length > currentIndex
|
||||
&& currentIndex >= 0 ? root.optionIcons[currentIndex] : ""
|
||||
const currentIndex = root.options.indexOf(root.currentValue)
|
||||
return currentIndex >= 0 && root.optionIcons.length > currentIndex ? root.optionIcons[currentIndex] : ""
|
||||
}
|
||||
size: 18
|
||||
color: Theme.surfaceVariantText
|
||||
@@ -131,9 +131,7 @@ Rectangle {
|
||||
text: root.currentValue
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
width: root.width <= 60 ?
|
||||
(dropdown.width - expandIcon.width - Theme.spacingS * 2) :
|
||||
(dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS)
|
||||
width: root.width <= 60 ? dropdown.width - expandIcon.width - Theme.spacingS * 2 : dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS
|
||||
elide: root.width <= 60 ? Text.ElideNone : Text.ElideRight
|
||||
horizontalAlignment: root.width <= 60 ? Text.AlignHCenter : Text.AlignLeft
|
||||
}
|
||||
@@ -169,61 +167,61 @@ Rectangle {
|
||||
property string searchQuery: ""
|
||||
property var filteredOptions: []
|
||||
property int selectedIndex: -1
|
||||
property var fzfFinder: new Fzf.Finder(root.options, {
|
||||
"selector": option => option,
|
||||
"limit": 50,
|
||||
"casing": "case-insensitive"
|
||||
})
|
||||
|
||||
function updateFilteredOptions() {
|
||||
if (!root.enableFuzzySearch || searchQuery.length === 0) {
|
||||
filteredOptions = root.options
|
||||
} else {
|
||||
var results = FuzzySort.go(searchQuery, root.options, {
|
||||
"limit": 50,
|
||||
"threshold": -10000
|
||||
})
|
||||
filteredOptions = results.map(function (result) {
|
||||
return result.target
|
||||
})
|
||||
selectedIndex = -1
|
||||
return
|
||||
}
|
||||
|
||||
const results = fzfFinder.find(searchQuery)
|
||||
filteredOptions = results.map(result => result.item)
|
||||
selectedIndex = -1
|
||||
}
|
||||
|
||||
function selectNext() {
|
||||
if (filteredOptions.length > 0) {
|
||||
selectedIndex = (selectedIndex + 1) % filteredOptions.length
|
||||
listView.positionViewAtIndex(selectedIndex,
|
||||
ListView.Contain)
|
||||
if (filteredOptions.length === 0) {
|
||||
return
|
||||
}
|
||||
selectedIndex = (selectedIndex + 1) % filteredOptions.length
|
||||
listView.positionViewAtIndex(selectedIndex, ListView.Contain)
|
||||
}
|
||||
|
||||
function selectPrevious() {
|
||||
if (filteredOptions.length > 0) {
|
||||
selectedIndex = selectedIndex
|
||||
<= 0 ? filteredOptions.length - 1 : selectedIndex - 1
|
||||
listView.positionViewAtIndex(selectedIndex,
|
||||
ListView.Contain)
|
||||
if (filteredOptions.length === 0) {
|
||||
return
|
||||
}
|
||||
selectedIndex = selectedIndex <= 0 ? filteredOptions.length - 1 : selectedIndex - 1
|
||||
listView.positionViewAtIndex(selectedIndex, ListView.Contain)
|
||||
}
|
||||
|
||||
function selectCurrent() {
|
||||
if (selectedIndex >= 0
|
||||
&& selectedIndex < filteredOptions.length) {
|
||||
root.currentValue = filteredOptions[selectedIndex]
|
||||
root.valueChanged(filteredOptions[selectedIndex])
|
||||
close()
|
||||
if (selectedIndex < 0 || selectedIndex >= filteredOptions.length) {
|
||||
return
|
||||
}
|
||||
root.currentValue = filteredOptions[selectedIndex]
|
||||
root.valueChanged(filteredOptions[selectedIndex])
|
||||
close()
|
||||
}
|
||||
|
||||
parent: Overlay.overlay
|
||||
width: 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)
|
||||
padding: 0
|
||||
modal: true
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
onOpened: {
|
||||
searchQuery = ""
|
||||
updateFilteredOptions()
|
||||
if (root.enableFuzzySearch && searchField.visible)
|
||||
if (root.enableFuzzySearch && searchField.visible) {
|
||||
searchField.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
@@ -231,9 +229,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
contentItem: Rectangle {
|
||||
color: Qt.rgba(Theme.surfaceContainer.r,
|
||||
Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 1)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1)
|
||||
border.color: Theme.primarySelected
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadius
|
||||
@@ -288,28 +284,18 @@ Rectangle {
|
||||
model: filteredOptions
|
||||
spacing: 2
|
||||
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
interactive: true
|
||||
flickDeceleration: 1500 // Touch only in Qt 6.9+ // Lower = more momentum, longer scrolling
|
||||
maximumFlickVelocity: 2000 // Touch only in Qt 6.9+ // Higher = faster maximum scroll speed
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||
boundsMovement: Flickable.FollowBoundsBehavior
|
||||
pressDelay: 0
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
ScrollBar.horizontal: ScrollBar {
|
||||
policy: ScrollBar.AlwaysOff
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
property bool isSelected: selectedIndex === index
|
||||
property bool isCurrentValue: root.currentValue === modelData
|
||||
property int optionIndex: root.options.indexOf(
|
||||
modelData)
|
||||
property int optionIndex: root.options.indexOf(modelData)
|
||||
|
||||
width: ListView.view.width
|
||||
height: 32
|
||||
@@ -323,9 +309,7 @@ Rectangle {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: optionIndex >= 0
|
||||
&& root.optionIcons.length
|
||||
> optionIndex ? root.optionIcons[optionIndex] : ""
|
||||
name: optionIndex >= 0 && root.optionIcons.length > optionIndex ? root.optionIcons[optionIndex] : ""
|
||||
size: 18
|
||||
color: isCurrentValue ? Theme.primary : Theme.surfaceVariantText
|
||||
visible: name !== ""
|
||||
|
||||
Reference in New Issue
Block a user