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