diff --git a/Hotkey.qml b/Hotkey.qml
new file mode 100644
index 0000000..2dd333f
--- /dev/null
+++ b/Hotkey.qml
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: Unlicense
+
+import QtQuick 2.12
+import QtQuick.Controls 2.13
+
+// Define and display a shortcut to focus the given control.
+Label {
+ required property Item control
+ property alias sequence: shortcut.sequence
+
+ text: shortcut.nativeText
+ visible: !control.activeFocus
+
+ color: 'gray'
+ padding: 1
+ leftPadding: 2*padding
+ rightPadding: 2*padding
+
+ background: Rectangle {
+ color: palette.base
+ border { color: Qt.lighter(parent.color); width: 1 }
+ opacity: 0.9
+ radius: 2
+ }
+
+ Shortcut {
+ id: shortcut
+ onActivated: control.forceActiveFocus()
+ }
+}
diff --git a/Sidebar.qml b/Sidebar.qml
index 7f391c7..31eeaac 100644
--- a/Sidebar.qml
+++ b/Sidebar.qml
@@ -97,67 +97,63 @@ Page {
anchors.fill: parent
// Description box.
- ScrollView {
+ Rectangle {
Layout.fillWidth: true
Layout.maximumHeight: 100
- ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ Layout.preferredHeight: description.implicitHeight
- padding: 0
+ border.color: description.activeFocus ? palette.highlight : palette.dark
+ color: palette.base
+ radius: 2
- visible: description.enabled
- background: Rectangle {
- color: palette.base
- border.color: description.activeFocus ? palette.highlight : palette.dark
- radius: 2
+ ScrollView {
+ anchors.fill: parent
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ padding: 0
+
+ TextArea {
+ id: description
+
+ placeholderText: qsTr('Description')
+ padding: filter.padding
+ leftPadding: filter.leftPadding
+ selectByMouse: true
+ wrapMode: Text.Wrap
+
+ onTextChanged: modified = true
+ KeyNavigation.priority: KeyNavigation.BeforeItem
+ KeyNavigation.tab: nextItemInFocusChain()
+ }
}
- TextArea {
- id: description
-
- placeholderText: qsTr('Description')
- padding: filter.padding
- leftPadding: filter.leftPadding
- selectByMouse: true
- wrapMode: Text.Wrap
-
- onTextChanged: modified = true
- KeyNavigation.priority: KeyNavigation.BeforeItem
- KeyNavigation.tab: nextItemInFocusChain()
-
- Shortcut {
- id: shortcutDescription
- sequence: 'Ctrl+D'
- onActivated: description.forceActiveFocus()
- }
- Label {
- anchors { right: parent.right; bottom: parent.bottom; margins: 4 }
- visible: !parent.activeFocus
- text: shortcutDescription.nativeText
- font.pixelSize: parent.font.pixelSize * 0.75
- color: 'gray'
- }
+ Hotkey {
+ control: description
+ sequence: 'Ctrl+D'
+ anchors { right: parent.right; bottom: parent.bottom; margins: 4 }
+ font.pixelSize: description.font.pixelSize * 0.75
}
}
// Filter box.
TextField {
id: filter
+
Layout.fillWidth: true
placeholderText: qsTr('Filter')
+ background: Rectangle {
+ border.color: parent.activeFocus ? palette.highlight : palette.dark
+ color: palette.base
+ radius: 2
+ }
+
onTextChanged: eventFilter.setFilter(text)
Keys.onEscapePressed: text = ''
- Shortcut {
- id: shortcutFilter
- sequence: 'Ctrl+F'
- onActivated: filter.forceActiveFocus()
- }
- Label {
+ Hotkey {
+ control: filter
+ sequence: StandardKey.Find
anchors { right: parent.right; bottom: parent.bottom; margins: 4 }
- visible: !parent.activeFocus
- text: shortcutFilter.nativeText
font.pixelSize: filter.font.pixelSize * 0.75
- color: 'gray'
}
}
@@ -165,15 +161,15 @@ Page {
Frame {
Layout.fillWidth: true
Layout.fillHeight: true
- Layout.rightMargin: -control.padding
+ Layout.rightMargin: -control.padding // fill to window edge for easier scrolling
focusPolicy: Qt.StrongFocus
+
padding: 1
rightPadding: 0
-
background: Rectangle {
+ border.color: parent.activeFocus ? palette.highlight : palette.dark
color: 'transparent'
- border.color: events.activeFocus ? palette.highlight : palette.dark
radius: 2
}
@@ -192,19 +188,18 @@ Page {
video.seek(event.time)
}
Keys.forwardTo: control
+ }
- Shortcut {
- id: shortcutEvents
- sequence: 'Ctrl+E'
- onActivated: events.forceActiveFocus()
- }
- Label {
- anchors { right: parent.right; bottom: parent.bottom; margins: 4 }
- visible: !parent.activeFocus
- text: shortcutEvents.nativeText
- font.pixelSize: filter.font.pixelSize * 0.75
- color: 'gray'
+ Hotkey {
+ control: events
+ sequence: 'Ctrl+E'
+ anchors {
+ right: parent.right
+ top: parent.top
+ margins: 4
+ rightMargin: control.padding + anchors.margins
}
+ font.pixelSize: filter.font.pixelSize * 0.75
}
}
@@ -215,9 +210,9 @@ Page {
Layout.fillWidth: true
enabled: video.loaded && !events.editing
- // Try passing key to each field input in order.
- Keys.enabled: enabled
+ // Try passing key to each tag button in order.
Keys.forwardTo: Array.from({ length: buttons.count }, (_, i) => buttons.itemAt(i))
+ Keys.enabled: enabled
spacing: 5
@@ -237,6 +232,7 @@ Page {
implicitWidth: implicitContentWidth + 2*padding
onClicked: {
+ // Create a new event with this tag and current time.
const index = eventList.insert(name, video.time)
// Reset filter if new event doesn’t match.
var row = eventFilter.mapFromSource(eventList.index(index, 0)).row
diff --git a/main.qrc b/main.qrc
index 2eaccc8..2a064e6 100644
--- a/main.qrc
+++ b/main.qrc
@@ -10,6 +10,7 @@
Fields/Enum.qml
Fields/Text.qml
Fields/TextArea.qml
+ Hotkey.qml
Sidebar.qml
Video.qml
Volume.qml