[ui] Controls: add SearchBar component + better keyboard focus handling

* use it in MetadataListView and GraphEditor 'add Node' menu
* GraphEditor: forward MenuItem key events to searchBar to be able to continue editing the filter even if it lost active focus
This commit is contained in:
Yann Lanthony 2019-01-07 16:48:17 +01:00
parent b5c985b3fb
commit b46a2dbba1
4 changed files with 62 additions and 28 deletions

View file

@ -0,0 +1,41 @@
import QtQuick 2.9
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import MaterialIcons 2.2
/**
* Basic SearchBar component with an appropriate icon and a TextField.
*/
FocusScope {
property alias textField: field
property alias text: field.text
implicitHeight: childrenRect.height
Keys.forwardTo: [field]
function forceActiveFocus() {
field.forceActiveFocus()
}
function clear() {
field.clear()
}
RowLayout {
width: parent.width
MaterialLabel {
text: MaterialIcons.search
}
TextField {
id: field
focus: true
Layout.fillWidth: true
selectByMouse: true
}
}
}

View file

@ -4,3 +4,4 @@ FloatingPane 1.0 FloatingPane.qml
Group 1.0 Group.qml
MessageDialog 1.0 MessageDialog.qml
Panel 1.0 Panel.qml
SearchBar 1.0 SearchBar.qml

View file

@ -142,18 +142,14 @@ Item {
if(visible) {
// when menu is shown,
// clear and give focus to the TextField filter
filterTextField.clear()
filterTextField.forceActiveFocus()
searchBar.clear()
searchBar.forceActiveFocus()
}
}
TextField {
id: filterTextField
selectByMouse: true
SearchBar {
id: searchBar
width: parent.width
// ensure down arrow give focus to the first MenuItem
// (without this, we have to pressed the down key twice to do so)
Keys.onDownPressed: nextItemInFocusChain().forceActiveFocus()
}
Repeater {
@ -164,24 +160,28 @@ Item {
id: menuItemDelegate
font.pointSize: 8
padding: 3
// Hide items that does not match the filter text
visible: modelData.toLowerCase().indexOf(filterTextField.text.toLocaleLowerCase()) > -1
visible: modelData.toLowerCase().indexOf(searchBar.text.toLowerCase()) > -1
// Reset menu currentIndex if highlighted items gets filtered out
onVisibleChanged: if(highlighted) newNodeMenu.currentIndex = 0
text: modelData
// Forward key events to the search bar to continue typing seamlessly
// even if this delegate took the activeFocus due to mouse hovering
Keys.forwardTo: [searchBar.textField]
Keys.onPressed: {
event.accepted = false;
switch(event.key)
{
case Qt.Key_Return:
case Qt.Key_Enter:
// create node on validation (Enter/Return keys)
newNodeMenu.createNode(modelData)
newNodeMenu.dismiss()
break;
case Qt.Key_Home:
// give focus back to filter
filterTextField.forceActiveFocus()
newNodeMenu.createNode(modelData);
newNodeMenu.close();
event.accepted = true;
break;
default:
break;
searchBar.textField.forceActiveFocus();
}
}
// Create node on mouse click

View file

@ -121,17 +121,9 @@ FloatingPane {
ColumnLayout {
anchors.fill: parent
// Search toolbar
RowLayout {
Label {
text: MaterialIcons.search
font.family: MaterialIcons.fontFamily
}
TextField {
id: filter
SearchBar {
id: searchBar
Layout.fillWidth: true
z: 2
}
}
// Metadata ListView
@ -148,7 +140,7 @@ FloatingPane {
model: metadataModel
sortRole: "raw"
filterRole: "raw"
filterValue: filter.text
filterValue: searchBar.text
delegate: RowLayout {
width: parent.width
Label {