summaryrefslogtreecommitdiff
path: root/Events.qml
diff options
context:
space:
mode:
authorTimotej Lazar <timotej.lazar@araneo.si>2021-09-12 19:34:10 +0200
committerTimotej Lazar <timotej.lazar@araneo.si>2021-09-16 20:33:53 +0200
commit09a1c7d57f349eaaf3779e0d45f844850164d30a (patch)
tree82828c904ddd2f0308e4c7be172df953ac0c0c1e /Events.qml
parent4ef0c49825c044edd972d1ffc59455db34bd20f4 (diff)
Events: inline event delegate
Also key handling. Again allow space to pause/resume video while editing an event.
Diffstat (limited to 'Events.qml')
-rw-r--r--Events.qml173
1 files changed, 157 insertions, 16 deletions
diff --git a/Events.qml b/Events.qml
index 218884a..bce1aac 100644
--- a/Events.qml
+++ b/Events.qml
@@ -4,6 +4,8 @@ import QtQuick 2.12
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.6
+import 'util.js' as Util
+
ListView {
id: control
@@ -12,37 +14,176 @@ ListView {
clip: true
focus: true
- keyNavigationEnabled: true
highlightMoveDuration: 0
highlightResizeDuration: 0
onCurrentIndexChanged: editing = false
+ Keys.onPressed: {
+ switch (event.key) {
+ case Qt.Key_Home:
+ currentIndex = 0
+ break
+ case Qt.Key_End:
+ currentIndex = count - 1
+ break
+ case Qt.Key_Enter:
+ case Qt.Key_Return:
+ if (editing) {
+ currentItem.store()
+ editing = false
+ } else {
+ if (currentItem.fields.length > 0)
+ editing = true
+ }
+ break
+ case Qt.Key_Escape:
+ editing = false
+ break
+ case Qt.Key_Delete:
+ editing = false
+ model.remove(currentIndex)
+ break
+ case Qt.Key_Tab:
+ case Qt.Key_Backtab:
+ // swallow tabs so we don’t lose focus when editing
+ break
+ default:
+ return
+ }
+ event.accepted = true
+ }
+
ScrollBar.vertical: ScrollBar { anchors.right: parent.right }
- delegate: Event {
- // If field definitions are missing for this event’s tag, use
- // Text for all field types unless where the value is bool.
- fields: tags[model.tag] ? tags[model.tag].fields :
- Object.entries(model.values).map(value => ({
- 'name': value[0],
- 'type': typeof(value[1]) === 'boolean' ? 'Bool' : 'Text',
- }))
+ delegate: ItemDelegate {
+ id: event
+
+ required property var model
+ required property int index
+ required property int time
+ required property string tag
+
+ property alias fields: inputs.model // field definitions
+ property bool editing: control.editing && ListView.isCurrentItem
width: control.width
- editing: control.editing && ListView.isCurrentItem
highlighted: ListView.isCurrentItem
- Connections {
- enabled: ListView.currentIndex === index
- function onHeightChanged() {
- control.positionViewAtIndex(index, ListView.Contain)
+ clip: true
+ padding: 2
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: highlighted ? Util.alphize(border.color, 0.1) :
+ (index % 2 === 0 ? palette.base : palette.alternateBase)
+ border {
+ color: editing ? palette.highlight : palette.dark
+ width: highlighted ? 1 : 0
}
+ radius: border.width
+ }
+
+ // Store current inputs in model.
+ function store() {
+ var values = {}
+ for (var i = 0; i < inputs.model.length; i++)
+ values[inputs.model[i].name] = inputs.items[i].value
+ model.values = values
}
+ // Try passing key to each field input in order. If none can
+ // handle it, pass it to control.
+ Keys.forwardTo: Array.prototype.concat(control, editing ? inputs.items : [])
+
onClicked: {
- control.currentIndex = index
- control.forceActiveFocus()
+ control.currentIndex = index
+ control.forceActiveFocus()
+ }
+
+ contentItem: ColumnLayout {
+ anchors { left: parent.left; right: parent.right; margins: 5 }
+
+ // Event time, tag and summary.
+ RowLayout {
+ Label {
+ text: new Date(model.time).toISOString().substr(12, 9)
+ font.pixelSize: 10
+ Layout.alignment: Qt.AlignBaseline
+ }
+ Label {
+ text: tag
+ font.weight: Font.DemiBold
+ Layout.alignment: Qt.AlignBaseline
+ }
+ Label {
+ text: {
+ var str = ''
+ for (var i = 0; i < inputs.count; i++) {
+ const field = inputs.model[i]
+ const value = model.values[field.name]
+ if (value && field.type !== 'TextArea')
+ str += (field.type === 'Bool' ? field.name : value) + ' '
+ }
+ return str
+ }
+ elide: Text.ElideRight
+ textFormat: Text.PlainText
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignBaseline
+ }
+ }
+
+ // Inputs for event‐specific fields.
+ GridLayout {
+ flow: GridLayout.TopToBottom
+ rows: inputs.count
+
+ columnSpacing: 10
+ visible: editing
+
+ // Labels.
+ Repeater {
+ model: inputs.model
+ delegate: Label {
+ text: Util.addShortcut(modelData.name, modelData.key)
+ Layout.alignment: Qt.AlignRight
+ }
+ }
+
+ // Inputs.
+ Repeater {
+ id: inputs
+
+ readonly property var items: Array.from({ length: count }, (_, i) => itemAt(i).item)
+
+ // If field definitions are missing for this event’s tag, use
+ // Text for all field types unless where the value is bool.
+ model: tags[tag] ? tags[tag].fields :
+ Object.entries(event.model.values).map(value => ({
+ 'name': value[0],
+ 'type': typeof(value[1]) === 'boolean' ? 'Bool' : 'Text',
+ }))
+
+ delegate: Loader {
+ source: 'qrc:/Fields/' + modelData.type + '.qml'
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ // Set input value to what is in the model each time the control is expanded.
+ onVisibleChanged: {
+ if (item && visible)
+ item.set(event.model.values[modelData.name])
+ }
+
+ Binding {
+ target: item; property: 'model'
+ value: modelData
+ }
+ }
+ }
+ }
}
}
}