mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-23 05:56:36 +02:00
[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:
parent
b5c985b3fb
commit
b46a2dbba1
4 changed files with 62 additions and 28 deletions
41
meshroom/ui/qml/Controls/SearchBar.qml
Normal file
41
meshroom/ui/qml/Controls/SearchBar.qml
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,4 @@ FloatingPane 1.0 FloatingPane.qml
|
||||||
Group 1.0 Group.qml
|
Group 1.0 Group.qml
|
||||||
MessageDialog 1.0 MessageDialog.qml
|
MessageDialog 1.0 MessageDialog.qml
|
||||||
Panel 1.0 Panel.qml
|
Panel 1.0 Panel.qml
|
||||||
|
SearchBar 1.0 SearchBar.qml
|
||||||
|
|
|
@ -142,18 +142,14 @@ Item {
|
||||||
if(visible) {
|
if(visible) {
|
||||||
// when menu is shown,
|
// when menu is shown,
|
||||||
// clear and give focus to the TextField filter
|
// clear and give focus to the TextField filter
|
||||||
filterTextField.clear()
|
searchBar.clear()
|
||||||
filterTextField.forceActiveFocus()
|
searchBar.forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
SearchBar {
|
||||||
id: filterTextField
|
id: searchBar
|
||||||
selectByMouse: true
|
|
||||||
width: parent.width
|
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 {
|
Repeater {
|
||||||
|
@ -164,24 +160,28 @@ Item {
|
||||||
id: menuItemDelegate
|
id: menuItemDelegate
|
||||||
font.pointSize: 8
|
font.pointSize: 8
|
||||||
padding: 3
|
padding: 3
|
||||||
|
|
||||||
// Hide items that does not match the filter text
|
// 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
|
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: {
|
Keys.onPressed: {
|
||||||
|
event.accepted = false;
|
||||||
switch(event.key)
|
switch(event.key)
|
||||||
{
|
{
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
case Qt.Key_Enter:
|
case Qt.Key_Enter:
|
||||||
// create node on validation (Enter/Return keys)
|
// create node on validation (Enter/Return keys)
|
||||||
newNodeMenu.createNode(modelData)
|
newNodeMenu.createNode(modelData);
|
||||||
newNodeMenu.dismiss()
|
newNodeMenu.close();
|
||||||
break;
|
event.accepted = true;
|
||||||
case Qt.Key_Home:
|
|
||||||
// give focus back to filter
|
|
||||||
filterTextField.forceActiveFocus()
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
searchBar.textField.forceActiveFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Create node on mouse click
|
// Create node on mouse click
|
||||||
|
|
|
@ -121,17 +121,9 @@ FloatingPane {
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
// Search toolbar
|
SearchBar {
|
||||||
RowLayout {
|
id: searchBar
|
||||||
Label {
|
|
||||||
text: MaterialIcons.search
|
|
||||||
font.family: MaterialIcons.fontFamily
|
|
||||||
}
|
|
||||||
TextField {
|
|
||||||
id: filter
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
z: 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata ListView
|
// Metadata ListView
|
||||||
|
@ -148,7 +140,7 @@ FloatingPane {
|
||||||
model: metadataModel
|
model: metadataModel
|
||||||
sortRole: "raw"
|
sortRole: "raw"
|
||||||
filterRole: "raw"
|
filterRole: "raw"
|
||||||
filterValue: filter.text
|
filterValue: searchBar.text
|
||||||
delegate: RowLayout {
|
delegate: RowLayout {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
Label {
|
Label {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue