fuzbal/Sidebar.qml
Timotej Lazar cb76fedcbc
Implement event model in C++
Filtering events in JS is too slow with >20,000 events. This moves the
event data model into C++.
2021-09-16 20:33:05 +02:00

226 lines
7.1 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: Unlicense
import QtQuick 2.12
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.6
import Qt.labs.platform 1.1
import fuzbal 1
Page {
id: control
property bool modified: false
property Video video
EventList {
id: eventList
onDataChanged: modified = true
onRowsInserted: modified = true
onRowsRemoved: modified = true
}
FileDialog {
id: videoDialog
title: qsTr('Open video')
onAccepted: {
video.source = currentFile
const json = JSON.parse(io.read(currentFile+'.events') || '{}')
eventList.load(json)
description.text = json['description'] || ''
modified = false
}
}
FileDialog {
id: tagsDialog
title: qsTr('Load tags')
nameFilters: [qsTr('JSON files (*.json)'), qsTr('All files (*)')]
onAccepted: eventList.load({ 'tags': JSON.parse(io.read(currentFile)) })
}
Keys.forwardTo: [tags, video]
header: ToolBar {
horizontalPadding: 0
RowLayout {
anchors.fill: parent
ToolButton {
action: Action {
icon.name: 'document-open'
shortcut: StandardKey.Open
onTriggered: videoDialog.open()
}
focusPolicy: Qt.NoFocus
}
Label {
text: video.loaded ? video.source : ''
elide: Text.ElideLeft
Layout.fillWidth: true
}
ToolButton {
action: Action {
onTriggered: {
var json = eventList.save()
json['description'] = description.text
json['video'] = video.source
json['version'] = Qt.application.version
io.write(video.source+'.events', JSON.stringify(json))
modified = false
}
shortcut: StandardKey.Save
icon.name: 'document-save'
enabled: video.loaded && control.modified
}
visible: video.loaded
opacity: enabled ? 1 : 0.25
focusPolicy: Qt.NoFocus
}
}
}
ColumnLayout {
anchors.fill: parent
// Description box.
ColumnLayout {
spacing: 0
RowLayout {
Label {
text: qsTr('Description')
Layout.fillWidth: true
}
Label { text: description.enabled ? qsTr('') : qsTr('+') }
TapHandler { onTapped: description.enabled = !description.enabled }
}
ScrollView {
Layout.fillWidth: true
Layout.preferredHeight: 100
contentWidth: parent.availableWidth
padding: 1
visible: description.enabled
background: Frame { }
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
TextArea {
id: description
background: Rectangle { color: palette.base }
leftPadding: padding
selectByMouse: true
wrapMode: Text.Wrap
onTextChanged: modified = true
KeyNavigation.priority: KeyNavigation.BeforeItem
KeyNavigation.tab: events
}
}
}
// Events list.
ColumnLayout {
spacing: 0
Label { text: qsTr('Events') }
Frame {
padding: 1
Layout.fillWidth: true
Layout.fillHeight: true
Events {
id: events
anchors.fill: parent
focus: true
model: eventList
tags: eventList.tags
onEditingChanged: video.pause(editing)
onCurrentItemChanged: {
if (currentItem)
video.seek(currentItem.time)
}
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:
if (editing) {
currentItem.reset()
editing = false
}
break
case Qt.Key_Delete:
editing = false
eventList.removeRows(currentIndex)
break
case Qt.Key_Tab:
case Qt.Key_Backtab:
// swallow tabs so we dont lose focus when editing
break
default:
return
}
event.accepted = true
}
}
}
}
// Tag list.
Frame {
Layout.fillWidth: true
Layout.fillHeight: false
padding: 5
ColumnLayout {
width: parent.width
spacing: 0
RowLayout {
Label {
text: qsTr('Tags')
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
}
ToolButton {
icon.name: 'document-open'
Layout.alignment: Qt.AlignVCenter
onClicked: tagsDialog.open()
focusPolicy:Qt.NoFocus
}
}
Tags {
id: tags
model: eventList.tagsOrder.map(tag => eventList.tags[tag])
enabled: video.loaded && !events.editing
onClicked: {
events.currentIndex = eventList.insert(video.time)
const event = events.currentItem
event.model.tag = tag
if (event.fields.length > 0)
events.editing = true
}
Layout.fillWidth: true
}
}
}
}
}