status-desktop/ui/app/AppLayouts/Chat/panels/InlineSelectorPanel.qml

249 lines
9.6 KiB
QML

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.0
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Popups.Dialog 0.1
import utils 1.0
Item {
id: root
property alias model: listView.model
property alias delegate: listView.delegate
property alias suggestionsModel: suggestionsListView.model
property alias suggestionsDelegate: suggestionsListView.delegate
readonly property alias label: label
readonly property alias warningLabel: warningLabel
readonly property alias edit: edit
property bool confirmBtnEnabled: (listView.count > 0)
signal confirmed()
signal rejected()
signal enterKeyPressed()
signal upKeyPressed()
signal downKeyPressed()
signal entryAccepted(var suggestionsDelegate)
signal entryRemoved(var delegate)
signal textPasted(string text)
implicitWidth: mainLayout.implicitWidth
implicitHeight: mainLayout.implicitHeight
RowLayout {
id: mainLayout
anchors.fill: parent
spacing: Style.current.padding
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 44
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: Style.current.halfPadding
color: Theme.palette.baseColor2
radius: Style.current.radius
RowLayout {
anchors.fill: parent
spacing: Style.current.halfPadding
StatusBaseText {
id: label
Layout.leftMargin: Style.current.padding
Layout.alignment: Qt.AlignVCenter
visible: text !== ""
font.pixelSize: 15
color: Theme.palette.baseColor1
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
onWidthChanged: {
listView.positionViewAtEnd();
}
RowLayout {
anchors.fill: parent
Item {
//40 px least space for input
Layout.preferredWidth: (listView.contentWidth < (parent.width - 40)) ?
listView.contentWidth : (parent.width - 40)
Layout.preferredHeight: 44
StatusListView {
clip: true
id: listView
width: parent.width
height: 30
anchors.verticalCenter: parent.verticalCenter
orientation: ListView.Horizontal
spacing: Style.current.halfPadding
ScrollBar.horizontal: scrollBar
onCountChanged: {
positionViewAtEnd();
}
}
StatusScrollBar {
id: scrollBar
parent: listView.parent
anchors.top: listView.bottom
anchors.left: listView.left
anchors.right: listView.right
policy: ScrollBar.AsNeeded
visible: resolveVisibility(policy, listView.width, listView.contentWidth)
}
}
TextInput {
id: edit
Layout.fillWidth: true
Layout.fillHeight: true
verticalAlignment: Text.AlignVCenter
font.pixelSize: 15
color: Theme.palette.directColor1
clip: true
selectByMouse: true
selectionColor: Theme.palette.primaryColor2
selectedTextColor: color
cursorDelegate: Rectangle {
color: Theme.palette.primaryColor1
implicitWidth: 2
radius: 1
visible: edit.cursorVisible
SequentialAnimation on visible {
loops: Animation.Infinite
running: edit.cursorVisible
PropertyAnimation { to: false; duration: 600; }
PropertyAnimation { to: true; duration: 600; }
}
}
Keys.onPressed: {
if (event.matches(StandardKey.Paste)) {
event.accepted = true
const previousText = text;
const previousSelectedText = selectedText;
paste()
if (previousText === "" || previousSelectedText.length === previousText.length)
root.textPasted(text)
return;
}
if (suggestionsDialog.visible) {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
root.entryAccepted(suggestionsListView.itemAtIndex(suggestionsListView.currentIndex))
} else if (event.key === Qt.Key_Up) {
suggestionsListView.decrementCurrentIndex()
} else if (event.key === Qt.Key_Down) {
suggestionsListView.incrementCurrentIndex()
}
} else {
if (event.key === Qt.Key_Backspace && edit.text === "" && listView.count > 0) {
root.entryRemoved(listView.itemAtIndex(listView.count - 1))
} else if (event.key === Qt.Key_Return || event.key === Qt.Enter) {
root.enterKeyPressed()
} else if (event.key === Qt.Key_Escape) {
root.rejected()
} else if (event.key === Qt.Key_Up) {
root.upKeyPressed();
} else if (event.key === Qt.Key_Down) {
root.downKeyPressed();
}
}
}
}
// ensure edit cursor is visible
Item {
Layout.fillHeight: true
implicitWidth: 1
}
}
}
StatusBaseText {
id: warningLabel
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.rightMargin: Style.current.padding
visible: text !== ""
font.pixelSize: 10
color: Theme.palette.dangerColor1
}
}
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onPressed: {
edit.forceActiveFocus()
mouse.accepted = false
}
}
}
StatusButton {
objectName: "inlineSelectorConfirmButton"
Layout.alignment: Qt.AlignVCenter
enabled: root.confirmBtnEnabled
text: qsTr("Confirm")
onClicked: root.confirmed()
}
StatusButton {
Layout.alignment: Qt.AlignVCenter
text: qsTr("Cancel")
type: StatusBaseButton.Type.Danger
onClicked: root.rejected()
}
}
Popup {
id: suggestionsDialog
parent: edit
x: (parent.contentWidth - Style.current.halfPadding)
y: (parent.height + Style.current.halfPadding)
visible: edit.text !== ""
padding: Style.current.halfPadding
background: StatusDialogBackground {
id: bg
layer.enabled: true
layer.effect: DropShadow {
source: bg
horizontalOffset: 0
verticalOffset: 4
radius: 12
samples: 25
spread: 0.2
color: Theme.palette.dropShadow
}
}
ColumnLayout {
anchors.fill: parent
StatusBaseText {
visible: root.suggestionsModel.count === 0
text: qsTr("No results found")
color: Theme.palette.baseColor1
}
StatusListView {
id: suggestionsListView
visible: root.suggestionsModel.count
implicitWidth: contentItem.childrenRect.width
implicitHeight: contentItem.childrenRect.height
onVisibleChanged: currentIndex = 0
}
}
}
}