feat(ui): style app menus and extract glossary dialog
- Add AppMenu and AppMenuItem so menu labels, mnemonics and shortcuts render consistently under org.kde.union - Move the translation glossary into GlossaryDialog with add, remove and clear-all actions - Regroup the translation preset and instructions settings layout
This commit was merged in pull request #3.
This commit is contained in:
1 parent
9e55dba687
commit
de9e6484ee
24 files changed
+533
-166
No files matched your search
@@ -0,0 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick.Controls
|
||||
|
||||
Menu {
|
||||
delegate: AppMenuItem {}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
MenuItem {
|
||||
id: root
|
||||
|
||||
// org.kde.desktop sets these on its MenuItem, but other Plasma styles such
|
||||
// as org.kde.union do not, which would leave the label below empty.
|
||||
Kirigami.MnemonicData.enabled: enabled && visible
|
||||
Kirigami.MnemonicData.controlType: Kirigami.MnemonicData.MenuItem
|
||||
Kirigami.MnemonicData.label: text
|
||||
|
||||
// The content includes the submenu arrow slot, so do not add it again as
|
||||
// the desktop style does. Keep the style's background and indicator sizing.
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
|
||||
contentItem: Item {
|
||||
implicitWidth: row.implicitWidth
|
||||
implicitHeight: row.implicitHeight
|
||||
baselineOffset: row.y + label.y + label.baselineOffset
|
||||
|
||||
RowLayout {
|
||||
id: row
|
||||
width: parent.width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
layoutDirection: root.mirrored ? Qt.RightToLeft : Qt.LeftToRight
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: (root.ListView.view && root.ListView.view.hasCheckables) || root.checkable
|
||||
? root.indicator.width : Kirigami.Units.smallSpacing
|
||||
}
|
||||
|
||||
// Reserve the icon column even for rows without an icon.
|
||||
Item {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Layout.preferredWidth
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.fill: parent
|
||||
visible: root.icon.name !== "" || root.icon.source.toString() !== ""
|
||||
source: root.icon.name !== "" ? root.icon.name : root.icon.source
|
||||
color: root.icon.color
|
||||
selected: root.pressed
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: label
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
text: root.Kirigami.MnemonicData.richTextLabel
|
||||
// StyledText keeps mnemonic underlines without RichText's
|
||||
// different line metrics relative to the shortcut label.
|
||||
textFormat: Text.StyledText
|
||||
font: root.font
|
||||
color: root.pressed ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: root.mirrored ? Text.AlignRight : Text.AlignLeft
|
||||
}
|
||||
|
||||
Label {
|
||||
id: shortcut
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
visible: !root.subMenu && root.action && root.action.shortcut !== undefined
|
||||
text: visible ? itemShortcut.nativeText : ""
|
||||
textFormat: Text.PlainText
|
||||
font: root.font
|
||||
color: label.color
|
||||
horizontalAlignment: Text.AlignRight
|
||||
|
||||
Shortcut {
|
||||
id: itemShortcut
|
||||
sequence: shortcut.visible && root.action ? root.action.shortcut : ""
|
||||
}
|
||||
}
|
||||
|
||||
// The inherited arrow sits over this slot. Without a submenu,
|
||||
// shortcut text reaches the very same trailing edge.
|
||||
Item {
|
||||
visible: root.subMenu !== null
|
||||
Layout.preferredWidth: root.arrow ? root.arrow.width : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
@@ -19,9 +19,9 @@ Menu {
|
||||
title: KI18n.i18nc("@title:menu", "&Track")
|
||||
}
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.mute }
|
||||
MenuItem { action: root.actions.volumeUp }
|
||||
MenuItem { action: root.actions.volumeDown }
|
||||
MenuItem { action: root.actions.audioCycleUp }
|
||||
MenuItem { action: root.actions.audioCycleDown }
|
||||
AppMenuItem { action: root.actions.mute }
|
||||
AppMenuItem { action: root.actions.volumeUp }
|
||||
AppMenuItem { action: root.actions.volumeDown }
|
||||
AppMenuItem { action: root.actions.audioCycleUp }
|
||||
AppMenuItem { action: root.actions.audioCycleDown }
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
// Checkable list of audio tracks.
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property MpvItem mpv
|
||||
@@ -25,7 +25,7 @@ Menu {
|
||||
|
||||
Instantiator {
|
||||
model: root.mpv.audioTracks
|
||||
delegate: MenuItem {
|
||||
delegate: AppMenuItem {
|
||||
required property var modelData
|
||||
text: root.trackLabel(modelData)
|
||||
checkable: true
|
||||
|
||||
@@ -6,16 +6,16 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
|
||||
title: KI18n.i18nc("@title:menu", "&File")
|
||||
|
||||
MenuItem { action: root.actions.openFile }
|
||||
MenuItem { action: root.actions.openUrl }
|
||||
AppMenuItem { action: root.actions.openFile }
|
||||
AppMenuItem { action: root.actions.openUrl }
|
||||
RecentFilesMenu { actions: root.actions }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.quit }
|
||||
AppMenuItem { action: root.actions.quit }
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import org.kde.ki18n
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigami.dialogs as KDialogs
|
||||
|
||||
Kirigami.Dialog {
|
||||
id: root
|
||||
|
||||
required property var translator
|
||||
|
||||
readonly property real removeButtonWidth: Kirigami.Units.iconSizes.smallMedium + Kirigami.Units.smallSpacing * 2
|
||||
// One inset for the header, content and footer so every edge lines up.
|
||||
readonly property real inset: Kirigami.Units.largeSpacing
|
||||
|
||||
title: KI18n.i18nc("@title:window", "Translation Glossary")
|
||||
standardButtons: Kirigami.Dialog.NoButton
|
||||
width: Math.min(parent.width * 0.9, Kirigami.Units.gridUnit * 38)
|
||||
height: Math.min(parent.height - Kirigami.Units.largeSpacing * 2, Kirigami.Units.gridUnit * 30)
|
||||
leftPadding: inset
|
||||
rightPadding: inset
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
|
||||
header: KDialogs.DialogHeader {
|
||||
dialog: root
|
||||
leftPadding: root.inset
|
||||
rightPadding: root.inset
|
||||
topPadding: root.inset
|
||||
contentItem: KDialogs.DialogHeaderTopContent {
|
||||
dialog: root
|
||||
}
|
||||
}
|
||||
|
||||
function addTerm() {
|
||||
glossaryModel.append({
|
||||
source: "",
|
||||
target: ""
|
||||
})
|
||||
glossaryList.currentIndex = glossaryModel.count - 1
|
||||
Qt.callLater(() => {
|
||||
glossaryList.forceLayout()
|
||||
glossaryList.positionViewAtIndex(glossaryList.currentIndex, ListView.Contain)
|
||||
glossaryList.forceLayout()
|
||||
const row = glossaryList.itemAtIndex(glossaryList.currentIndex)
|
||||
if (row) {
|
||||
row.focusOriginal()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
glossaryModel.clear()
|
||||
for (const entry of translator.glossaryEntries) {
|
||||
glossaryModel.append(entry)
|
||||
}
|
||||
glossaryList.positionViewAtBeginning()
|
||||
}
|
||||
onAccepted: {
|
||||
const entries = []
|
||||
for (let i = 0; i < glossaryModel.count; ++i) {
|
||||
const entry = glossaryModel.get(i)
|
||||
entries.push({
|
||||
source: entry.source,
|
||||
target: entry.target
|
||||
})
|
||||
}
|
||||
translator.saveGlossary(entries)
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: glossaryModel
|
||||
}
|
||||
|
||||
// Union's DialogButtonBox adds its own padding on top of the dialog's, so
|
||||
// lay the footer out ourselves with the same inset as the header and content.
|
||||
footer: Control {
|
||||
leftPadding: root.inset
|
||||
rightPadding: root.inset
|
||||
topPadding: Kirigami.Units.largeSpacing
|
||||
bottomPadding: root.inset
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Button {
|
||||
text: KI18n.i18nc("@action:button", "Save")
|
||||
icon.name: "document-save"
|
||||
onClicked: root.accept()
|
||||
}
|
||||
|
||||
Button {
|
||||
text: KI18n.i18nc("@action:button", "Cancel")
|
||||
icon.name: "dialog-cancel"
|
||||
onClicked: root.reject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: addTermAction
|
||||
text: KI18n.i18nc("@action:button", "Add Term")
|
||||
icon.name: "list-add"
|
||||
onTriggered: root.addTerm()
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: KI18n.i18ncp("@label glossary term count", "%1 term", "%1 terms", glossaryModel.count)
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
}
|
||||
|
||||
Button {
|
||||
action: addTermAction
|
||||
}
|
||||
|
||||
Button {
|
||||
text: KI18n.i18nc("@action:button", "Clear All")
|
||||
icon.name: "edit-clear-all"
|
||||
enabled: glossaryModel.count > 0
|
||||
onClicked: glossaryModel.clear()
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: glossaryModel.count > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: listScroll.rightPadding
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 1
|
||||
Layout.minimumWidth: 0
|
||||
text: KI18n.i18nc("@title:column glossary source term", "Original")
|
||||
font: Kirigami.Theme.smallFont
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 1
|
||||
Layout.minimumWidth: 0
|
||||
text: KI18n.i18nc("@title:column glossary translated term", "Translation")
|
||||
font: Kirigami.Theme.smallFont
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: root.removeButtonWidth
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
ScrollView {
|
||||
id: listScroll
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: availableWidth
|
||||
leftPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
// Room for the scrollbar plus a gap, so its right edge lines up
|
||||
// with the buttons above and below.
|
||||
rightPadding: ScrollBar.vertical.visible ? ScrollBar.vertical.width + Kirigami.Units.smallSpacing : 0
|
||||
// The style's frame and focus ring would stretch into the margin.
|
||||
background: null
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
// The style's scrollbar is wide and draws a separator line; a slim
|
||||
// one keeps the right side tidy.
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
parent: listScroll
|
||||
policy: ScrollBar.AsNeeded
|
||||
active: true
|
||||
// Union sets each side explicitly, so `padding: 0` alone is not enough.
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
leftInset: 0
|
||||
rightInset: 0
|
||||
topInset: 0
|
||||
bottomInset: 0
|
||||
background: null
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: Kirigami.Units.smallSpacing * 1.5
|
||||
radius: width / 2
|
||||
color: Kirigami.Theme.textColor
|
||||
opacity: parent.pressed ? 0.6 : parent.hovered ? 0.45 : 0.25
|
||||
}
|
||||
width: implicitWidth
|
||||
x: listScroll.width - width
|
||||
y: 0
|
||||
height: listScroll.height
|
||||
}
|
||||
|
||||
contentItem: ListView {
|
||||
id: glossaryList
|
||||
clip: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: glossaryModel
|
||||
|
||||
delegate: RowLayout {
|
||||
id: termRow
|
||||
required property int index
|
||||
required property string source
|
||||
required property string target
|
||||
|
||||
width: glossaryList.width
|
||||
height: implicitHeight
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
function focusOriginal() {
|
||||
originalField.forceActiveFocus(Qt.TabFocusReason)
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: originalField
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 1
|
||||
Layout.minimumWidth: 0
|
||||
text: termRow.source
|
||||
placeholderText: KI18n.i18nc("@info:placeholder glossary source term", "Original term")
|
||||
Accessible.name: KI18n.i18nc("@label:textbox glossary source term", "Original term")
|
||||
onTextEdited: glossaryModel.setProperty(termRow.index, "source", text)
|
||||
}
|
||||
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 1
|
||||
Layout.minimumWidth: 0
|
||||
text: termRow.target
|
||||
placeholderText: KI18n.i18nc("@info:placeholder glossary translated term", "Translation")
|
||||
Accessible.name: KI18n.i18nc("@label:textbox glossary translated term", "Translation")
|
||||
onTextEdited: glossaryModel.setProperty(termRow.index, "target", text)
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
Layout.preferredWidth: root.removeButtonWidth
|
||||
Layout.minimumWidth: root.removeButtonWidth
|
||||
Layout.maximumWidth: root.removeButtonWidth
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
flat: true
|
||||
icon.name: "edit-delete"
|
||||
icon.color: Kirigami.Theme.textColor
|
||||
display: AbstractButton.IconOnly
|
||||
text: KI18n.i18nc("@action:button remove glossary term", "Remove")
|
||||
ToolTip.text: text
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
onClicked: glossaryModel.remove(termRow.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - Kirigami.Units.largeSpacing * 2
|
||||
visible: glossaryModel.count === 0
|
||||
text: KI18n.i18nc("@info:placeholder", "No glossary terms yet")
|
||||
explanation: KI18n.i18nc("@info:placeholder", "Terms are extracted automatically before translation, or you can add them manually.")
|
||||
helpfulAction: addTermAction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -29,19 +29,19 @@ ToolButton {
|
||||
ToolTip.visible: hovered && !menu.visible
|
||||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: menu
|
||||
|
||||
y: root.inFooter ? -height - Kirigami.Units.largeSpacing : root.height + Kirigami.Units.largeSpacing
|
||||
modal: true
|
||||
dim: false
|
||||
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
action: root.actions.openFile
|
||||
visible: root.inFooter
|
||||
height: visible ? implicitHeight : 0
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
action: root.actions.openUrl
|
||||
visible: root.inFooter
|
||||
height: visible ? implicitHeight : 0
|
||||
@@ -62,20 +62,20 @@ ToolButton {
|
||||
title: KI18n.i18nc("@title:menu", "Audio Track")
|
||||
}
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.translateSubtitle }
|
||||
MenuItem { action: root.actions.toggleFullscreen }
|
||||
MenuItem { action: root.actions.togglePlaylist }
|
||||
MenuItem { action: root.actions.screenshot }
|
||||
AppMenuItem { action: root.actions.translateSubtitle }
|
||||
AppMenuItem { action: root.actions.toggleFullscreen }
|
||||
AppMenuItem { action: root.actions.togglePlaylist }
|
||||
AppMenuItem { action: root.actions.screenshot }
|
||||
MenuSeparator {}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
action: root.actions.configure
|
||||
visible: root.inFooter
|
||||
height: visible ? implicitHeight : 0
|
||||
}
|
||||
MenuItem { action: root.actions.toggleMenuBar }
|
||||
MenuItem { action: root.actions.about }
|
||||
AppMenuItem { action: root.actions.toggleMenuBar }
|
||||
AppMenuItem { action: root.actions.about }
|
||||
MenuSeparator {}
|
||||
Menu {
|
||||
AppMenu {
|
||||
title: KI18n.i18nc("@title:menu", "&More")
|
||||
FileMenu { actions: root.actions }
|
||||
ViewMenu { actions: root.actions }
|
||||
|
||||
+2
-2
@@ -79,8 +79,8 @@ ToolBar {
|
||||
enabled: true
|
||||
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.translateSubtitle }
|
||||
MenuItem { action: root.actions.addSubtitle }
|
||||
AppMenuItem { action: root.actions.translateSubtitle }
|
||||
AppMenuItem { action: root.actions.addSubtitle }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
|
||||
title: KI18n.i18nc("@title:menu", "&Help")
|
||||
|
||||
MenuItem { action: root.actions.about }
|
||||
MenuItem { action: root.actions.reportBug }
|
||||
AppMenuItem { action: root.actions.about }
|
||||
AppMenuItem { action: root.actions.reportBug }
|
||||
}
|
||||
+2
-33
@@ -318,39 +318,8 @@ ApplicationWindow {
|
||||
onAccepted: video.addSubtitleFile(selectedFile)
|
||||
}
|
||||
|
||||
Kirigami.Dialog {
|
||||
GlossaryDialog {
|
||||
id: glossaryDialog
|
||||
title: KI18n.i18nc("@title:window", "Translation Glossary")
|
||||
standardButtons: Kirigami.Dialog.Save | Kirigami.Dialog.Cancel
|
||||
width: Math.min(appWindow.width * 0.9, 650)
|
||||
contentItem: ColumnLayout {
|
||||
ListView {
|
||||
id: glossaryList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 15
|
||||
clip: true
|
||||
model: ListModel { id: glossaryModel }
|
||||
delegate: RowLayout {
|
||||
width: glossaryList.width
|
||||
TextField { text: source; Layout.fillWidth: true; onTextChanged: model.source = text }
|
||||
TextField { text: target; Layout.fillWidth: true; onTextChanged: model.target = text }
|
||||
ToolButton { icon.name: "edit-delete-remove"; onClicked: glossaryModel.remove(index) }
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Button { text: KI18n.i18nc("@action:button", "Add"); onClicked: glossaryModel.append({source: "", target: ""}) }
|
||||
Button { text: KI18n.i18nc("@action:button", "Clear"); onClicked: glossaryModel.clear() }
|
||||
}
|
||||
}
|
||||
onOpened: {
|
||||
glossaryModel.clear()
|
||||
for (const entry of translationService.glossaryEntries) glossaryModel.append(entry)
|
||||
}
|
||||
onAccepted: {
|
||||
const entries = []
|
||||
for (let i = 0; i < glossaryModel.count; ++i) entries.push(glossaryModel.get(i))
|
||||
translationService.saveGlossary(entries)
|
||||
}
|
||||
translator: translationService
|
||||
}
|
||||
}
|
||||
+16
-16
@@ -7,24 +7,24 @@ import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
// Right click menu of the video.
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
required property MpvItem mpv
|
||||
|
||||
MenuItem { action: root.actions.playPause }
|
||||
MenuItem { action: root.actions.playNextFile }
|
||||
MenuItem { action: root.actions.playPreviousFile }
|
||||
Menu {
|
||||
AppMenuItem { action: root.actions.playPause }
|
||||
AppMenuItem { action: root.actions.playNextFile }
|
||||
AppMenuItem { action: root.actions.playPreviousFile }
|
||||
AppMenu {
|
||||
title: KI18n.i18nc("@title:menu", "Playback Speed")
|
||||
MenuItem { action: root.actions.speedUp }
|
||||
MenuItem { action: root.actions.speedDown }
|
||||
MenuItem { action: root.actions.speedReset }
|
||||
AppMenuItem { action: root.actions.speedUp }
|
||||
AppMenuItem { action: root.actions.speedDown }
|
||||
AppMenuItem { action: root.actions.speedReset }
|
||||
}
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.openFile }
|
||||
MenuItem { action: root.actions.openUrl }
|
||||
AppMenuItem { action: root.actions.openFile }
|
||||
AppMenuItem { action: root.actions.openUrl }
|
||||
MenuSeparator {}
|
||||
SubtitleTracksMenu {
|
||||
mpv: root.mpv
|
||||
@@ -40,7 +40,7 @@ Menu {
|
||||
mpv: root.mpv
|
||||
title: KI18n.i18nc("@title:menu", "Audio Track")
|
||||
}
|
||||
MenuItem { action: root.actions.translateSubtitle }
|
||||
AppMenuItem { action: root.actions.translateSubtitle }
|
||||
MenuSeparator {}
|
||||
VideoMenu { actions: root.actions }
|
||||
SubtitlesMenu {
|
||||
@@ -52,10 +52,10 @@ Menu {
|
||||
mpv: root.mpv
|
||||
}
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.toggleFullscreen }
|
||||
MenuItem { action: root.actions.togglePlaylist }
|
||||
MenuItem { action: root.actions.toggleMenuBar }
|
||||
MenuItem { action: root.actions.toggleHeader }
|
||||
AppMenuItem { action: root.actions.toggleFullscreen }
|
||||
AppMenuItem { action: root.actions.togglePlaylist }
|
||||
AppMenuItem { action: root.actions.toggleMenuBar }
|
||||
AppMenuItem { action: root.actions.toggleHeader }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.configure }
|
||||
AppMenuItem { action: root.actions.configure }
|
||||
}
|
||||
+22
-22
@@ -6,41 +6,41 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
|
||||
title: KI18n.i18nc("@title:menu", "&Playback")
|
||||
|
||||
MenuItem { action: root.actions.playPause }
|
||||
MenuItem { action: root.actions.stop }
|
||||
MenuItem { action: root.actions.playNextFile }
|
||||
MenuItem { action: root.actions.playPreviousFile }
|
||||
MenuItem { action: root.actions.restart }
|
||||
AppMenuItem { action: root.actions.playPause }
|
||||
AppMenuItem { action: root.actions.stop }
|
||||
AppMenuItem { action: root.actions.playNextFile }
|
||||
AppMenuItem { action: root.actions.playPreviousFile }
|
||||
AppMenuItem { action: root.actions.restart }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.speedUp }
|
||||
MenuItem { action: root.actions.speedDown }
|
||||
MenuItem { action: root.actions.speedReset }
|
||||
AppMenuItem { action: root.actions.speedUp }
|
||||
AppMenuItem { action: root.actions.speedDown }
|
||||
AppMenuItem { action: root.actions.speedReset }
|
||||
MenuSeparator {}
|
||||
Menu {
|
||||
AppMenu {
|
||||
title: KI18n.i18nc("@title:menu", "Seek")
|
||||
MenuItem { action: root.actions.seekForwardSmall }
|
||||
MenuItem { action: root.actions.seekBackwardSmall }
|
||||
AppMenuItem { action: root.actions.seekForwardSmall }
|
||||
AppMenuItem { action: root.actions.seekBackwardSmall }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.seekForwardMedium }
|
||||
MenuItem { action: root.actions.seekBackwardMedium }
|
||||
AppMenuItem { action: root.actions.seekForwardMedium }
|
||||
AppMenuItem { action: root.actions.seekBackwardMedium }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.seekForwardBig }
|
||||
MenuItem { action: root.actions.seekBackwardBig }
|
||||
AppMenuItem { action: root.actions.seekForwardBig }
|
||||
AppMenuItem { action: root.actions.seekBackwardBig }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.seekNextSubtitle }
|
||||
MenuItem { action: root.actions.seekPreviousSubtitle }
|
||||
AppMenuItem { action: root.actions.seekNextSubtitle }
|
||||
AppMenuItem { action: root.actions.seekPreviousSubtitle }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.seekNextChapter }
|
||||
MenuItem { action: root.actions.seekPreviousChapter }
|
||||
AppMenuItem { action: root.actions.seekNextChapter }
|
||||
AppMenuItem { action: root.actions.seekPreviousChapter }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.frameStepForward }
|
||||
MenuItem { action: root.actions.frameStepBackward }
|
||||
AppMenuItem { action: root.actions.frameStepForward }
|
||||
AppMenuItem { action: root.actions.frameStepBackward }
|
||||
}
|
||||
}
|
||||
@@ -113,15 +113,15 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: contextMenu
|
||||
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Play")
|
||||
icon.name: "media-playback-start"
|
||||
onTriggered: root.playlist.play(root.index)
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Open Containing Folder")
|
||||
icon.name: "folder-open"
|
||||
enabled: root.url.toString().startsWith("file://")
|
||||
@@ -131,19 +131,19 @@ Item {
|
||||
}
|
||||
}
|
||||
MenuSeparator {}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Move Up")
|
||||
icon.name: "go-up"
|
||||
enabled: root.index > 0
|
||||
onTriggered: root.playlist.move(root.index, root.index - 1)
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Move Down")
|
||||
icon.name: "go-down"
|
||||
enabled: root.index < root.playlist.count - 1
|
||||
onTriggered: root.playlist.move(root.index, root.index + 1)
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Remove from Playlist")
|
||||
icon.name: "list-remove"
|
||||
onTriggered: root.playlist.remove(root.index)
|
||||
|
||||
@@ -8,7 +8,7 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
@@ -18,7 +18,7 @@ Menu {
|
||||
|
||||
Instantiator {
|
||||
model: RecentFilesModel
|
||||
delegate: MenuItem {
|
||||
delegate: AppMenuItem {
|
||||
required property url url
|
||||
required property string name
|
||||
required property string path
|
||||
@@ -35,7 +35,7 @@ Menu {
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Clear List")
|
||||
icon.name: "edit-clear-history"
|
||||
onTriggered: RecentFilesModel.clear()
|
||||
|
||||
@@ -6,34 +6,34 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
|
||||
title: KI18n.i18nc("@title:menu", "&Settings")
|
||||
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "General")
|
||||
onTriggered: root.actions.settingsRequested("general")
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Playback")
|
||||
onTriggered: root.actions.settingsRequested("playback")
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Subtitles")
|
||||
onTriggered: root.actions.settingsRequested("subtitles")
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Translation")
|
||||
onTriggered: root.actions.settingsRequested("translation")
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "Playlist")
|
||||
onTriggered: root.actions.settingsRequested("playlist")
|
||||
}
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@action:inmenu", "About")
|
||||
onTriggered: root.actions.settingsRequested("about")
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
// Checkable list of subtitle tracks, for the primary or the secondary subtitle.
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property MpvItem mpv
|
||||
@@ -36,7 +36,7 @@ Menu {
|
||||
|
||||
enabled: mpv.subtitleTracks.length > 0
|
||||
|
||||
MenuItem {
|
||||
AppMenuItem {
|
||||
text: KI18n.i18nc("@item:inmenu no subtitle", "None")
|
||||
checkable: true
|
||||
checked: root.selectedId === 0
|
||||
@@ -49,7 +49,7 @@ Menu {
|
||||
|
||||
Instantiator {
|
||||
model: root.mpv.subtitleTracks
|
||||
delegate: MenuItem {
|
||||
delegate: AppMenuItem {
|
||||
required property var modelData
|
||||
text: root.trackLabel(modelData)
|
||||
checkable: true
|
||||
|
||||
+13
-13
@@ -6,7 +6,7 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
@@ -25,21 +25,21 @@ Menu {
|
||||
title: KI18n.i18nc("@title:menu", "Secondary Subtitle")
|
||||
}
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.translateSubtitle }
|
||||
MenuItem { action: root.actions.editGlossary }
|
||||
MenuItem {
|
||||
AppMenuItem { action: root.actions.translateSubtitle }
|
||||
AppMenuItem { action: root.actions.editGlossary }
|
||||
AppMenuItem {
|
||||
action: root.actions.cancelTranslation
|
||||
visible: root.actions.cancelTranslation.enabled
|
||||
height: visible ? implicitHeight : 0
|
||||
}
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.addSubtitle }
|
||||
MenuItem { action: root.actions.subtitleBigger }
|
||||
MenuItem { action: root.actions.subtitleSmaller }
|
||||
MenuItem { action: root.actions.subtitleEarlier }
|
||||
MenuItem { action: root.actions.subtitleLater }
|
||||
MenuItem { action: root.actions.subtitleDelayReset }
|
||||
MenuItem { action: root.actions.subtitleToggle }
|
||||
MenuItem { action: root.actions.subtitleCycleUp }
|
||||
MenuItem { action: root.actions.subtitleCycleDown }
|
||||
AppMenuItem { action: root.actions.addSubtitle }
|
||||
AppMenuItem { action: root.actions.subtitleBigger }
|
||||
AppMenuItem { action: root.actions.subtitleSmaller }
|
||||
AppMenuItem { action: root.actions.subtitleEarlier }
|
||||
AppMenuItem { action: root.actions.subtitleLater }
|
||||
AppMenuItem { action: root.actions.subtitleDelayReset }
|
||||
AppMenuItem { action: root.actions.subtitleToggle }
|
||||
AppMenuItem { action: root.actions.subtitleCycleUp }
|
||||
AppMenuItem { action: root.actions.subtitleCycleDown }
|
||||
}
|
||||
@@ -147,36 +147,35 @@ SettingsBasePage {
|
||||
|
||||
Label {
|
||||
text: KI18n.i18nc("@label:listbox", "Preset")
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
ComboBox {
|
||||
id: presetCombo
|
||||
Layout.fillWidth: true
|
||||
|
||||
ComboBox {
|
||||
id: presetCombo
|
||||
Layout.fillWidth: true
|
||||
model: root.translator.translationPresets
|
||||
textRole: "name"
|
||||
valueRole: "id"
|
||||
Component.onCompleted: currentIndex = Math.max(0, indexOfValue(QtPotatoSettings.translationPreset))
|
||||
onActivated: {
|
||||
QtPotatoSettings.translationPreset = currentValue
|
||||
QtPotatoSettings.save()
|
||||
}
|
||||
model: root.translator.translationPresets
|
||||
textRole: "name"
|
||||
valueRole: "id"
|
||||
Component.onCompleted: currentIndex = Math.max(0, indexOfValue(QtPotatoSettings.translationPreset))
|
||||
onActivated: {
|
||||
QtPotatoSettings.translationPreset = currentValue
|
||||
QtPotatoSettings.save()
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: presetCombo.currentIndex >= 0 ? presetCombo.model[presetCombo.currentIndex].guidance : ""
|
||||
wrapMode: Text.WordWrap
|
||||
opacity: 0.7
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Item { Layout.preferredWidth: 1 }
|
||||
|
||||
Label {
|
||||
text: presetCombo.currentIndex >= 0 ? presetCombo.model[presetCombo.currentIndex].description : ""
|
||||
wrapMode: Text.WordWrap
|
||||
opacity: 0.7
|
||||
font: Kirigami.Theme.smallFont
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
text: KI18n.i18nc("@label:textbox", "Additional instructions")
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBaseline
|
||||
}
|
||||
|
||||
TextArea {
|
||||
@@ -184,6 +183,7 @@ SettingsBasePage {
|
||||
placeholderText: KI18n.i18nc("@info:placeholder", "e.g. Translate 'Young Master' as 'Thiếu gia'. Use 'ta/ngươi' between enemies.")
|
||||
wrapMode: TextArea.Wrap
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 4
|
||||
// TextArea has no textEdited before Qt 6.9.
|
||||
onTextChanged: QtPotatoSettings.customInstructions = text
|
||||
|
||||
@@ -6,18 +6,18 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
|
||||
title: KI18n.i18nc("@title:menu", "&Video")
|
||||
|
||||
MenuItem { action: root.actions.toggleDeinterlacing }
|
||||
MenuItem { action: root.actions.zoomIn }
|
||||
MenuItem { action: root.actions.zoomOut }
|
||||
MenuItem { action: root.actions.zoomReset }
|
||||
MenuItem { action: root.actions.screenshot }
|
||||
MenuItem { action: root.actions.rotateClockwise }
|
||||
MenuItem { action: root.actions.rotateCounterClockwise }
|
||||
AppMenuItem { action: root.actions.toggleDeinterlacing }
|
||||
AppMenuItem { action: root.actions.zoomIn }
|
||||
AppMenuItem { action: root.actions.zoomOut }
|
||||
AppMenuItem { action: root.actions.zoomReset }
|
||||
AppMenuItem { action: root.actions.screenshot }
|
||||
AppMenuItem { action: root.actions.rotateClockwise }
|
||||
AppMenuItem { action: root.actions.rotateCounterClockwise }
|
||||
}
|
||||
@@ -6,16 +6,16 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import org.kde.ki18n
|
||||
|
||||
Menu {
|
||||
AppMenu {
|
||||
id: root
|
||||
|
||||
required property Actions actions
|
||||
|
||||
title: KI18n.i18nc("@title:menu", "&View")
|
||||
|
||||
MenuItem { action: root.actions.toggleFullscreen }
|
||||
MenuItem { action: root.actions.togglePlaylist }
|
||||
AppMenuItem { action: root.actions.toggleFullscreen }
|
||||
AppMenuItem { action: root.actions.togglePlaylist }
|
||||
MenuSeparator {}
|
||||
MenuItem { action: root.actions.toggleMenuBar }
|
||||
MenuItem { action: root.actions.toggleHeader }
|
||||
AppMenuItem { action: root.actions.toggleMenuBar }
|
||||
AppMenuItem { action: root.actions.toggleHeader }
|
||||
}
|
||||
Reference in new issue
Block a user