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 is contained in:
1 parent
9e55dba687
commit
009dd94005
24 files changed
+519
-152
No files matched your search
@@ -62,11 +62,14 @@ ecm_add_qml_module(qtpotato
|
|||||||
|
|
||||||
ecm_target_qml_sources(qtpotato SOURCES
|
ecm_target_qml_sources(qtpotato SOURCES
|
||||||
qml/Actions.qml
|
qml/Actions.qml
|
||||||
|
qml/AppMenu.qml
|
||||||
|
qml/AppMenuItem.qml
|
||||||
qml/AudioMenu.qml
|
qml/AudioMenu.qml
|
||||||
qml/AudioTracksMenu.qml
|
qml/AudioTracksMenu.qml
|
||||||
qml/FileMenu.qml
|
qml/FileMenu.qml
|
||||||
qml/Footer.qml
|
qml/Footer.qml
|
||||||
qml/GeneralSettings.qml
|
qml/GeneralSettings.qml
|
||||||
|
qml/GlossaryDialog.qml
|
||||||
qml/HamburgerMenu.qml
|
qml/HamburgerMenu.qml
|
||||||
qml/Header.qml
|
qml/Header.qml
|
||||||
qml/HelpMenu.qml
|
qml/HelpMenu.qml
|
||||||
|
|||||||
@@ -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 QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
@@ -19,9 +19,9 @@ Menu {
|
|||||||
title: KI18n.i18nc("@title:menu", "&Track")
|
title: KI18n.i18nc("@title:menu", "&Track")
|
||||||
}
|
}
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.mute }
|
AppMenuItem { action: root.actions.mute }
|
||||||
MenuItem { action: root.actions.volumeUp }
|
AppMenuItem { action: root.actions.volumeUp }
|
||||||
MenuItem { action: root.actions.volumeDown }
|
AppMenuItem { action: root.actions.volumeDown }
|
||||||
MenuItem { action: root.actions.audioCycleUp }
|
AppMenuItem { action: root.actions.audioCycleUp }
|
||||||
MenuItem { action: root.actions.audioCycleDown }
|
AppMenuItem { action: root.actions.audioCycleDown }
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import QtQuick.Controls
|
|||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
// Checkable list of audio tracks.
|
// Checkable list of audio tracks.
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property MpvItem mpv
|
required property MpvItem mpv
|
||||||
@@ -25,7 +25,7 @@ Menu {
|
|||||||
|
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: root.mpv.audioTracks
|
model: root.mpv.audioTracks
|
||||||
delegate: MenuItem {
|
delegate: AppMenuItem {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
text: root.trackLabel(modelData)
|
text: root.trackLabel(modelData)
|
||||||
checkable: true
|
checkable: true
|
||||||
|
|||||||
@@ -6,16 +6,16 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
|
|
||||||
title: KI18n.i18nc("@title:menu", "&File")
|
title: KI18n.i18nc("@title:menu", "&File")
|
||||||
|
|
||||||
MenuItem { action: root.actions.openFile }
|
AppMenuItem { action: root.actions.openFile }
|
||||||
MenuItem { action: root.actions.openUrl }
|
AppMenuItem { action: root.actions.openUrl }
|
||||||
RecentFilesMenu { actions: root.actions }
|
RecentFilesMenu { actions: root.actions }
|
||||||
MenuSeparator {}
|
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.visible: hovered && !menu.visible
|
||||||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: menu
|
id: menu
|
||||||
|
|
||||||
y: root.inFooter ? -height - Kirigami.Units.largeSpacing : root.height + Kirigami.Units.largeSpacing
|
y: root.inFooter ? -height - Kirigami.Units.largeSpacing : root.height + Kirigami.Units.largeSpacing
|
||||||
modal: true
|
modal: true
|
||||||
dim: false
|
dim: false
|
||||||
|
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
action: root.actions.openFile
|
action: root.actions.openFile
|
||||||
visible: root.inFooter
|
visible: root.inFooter
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
action: root.actions.openUrl
|
action: root.actions.openUrl
|
||||||
visible: root.inFooter
|
visible: root.inFooter
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
@@ -62,20 +62,20 @@ ToolButton {
|
|||||||
title: KI18n.i18nc("@title:menu", "Audio Track")
|
title: KI18n.i18nc("@title:menu", "Audio Track")
|
||||||
}
|
}
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.translateSubtitle }
|
AppMenuItem { action: root.actions.translateSubtitle }
|
||||||
MenuItem { action: root.actions.toggleFullscreen }
|
AppMenuItem { action: root.actions.toggleFullscreen }
|
||||||
MenuItem { action: root.actions.togglePlaylist }
|
AppMenuItem { action: root.actions.togglePlaylist }
|
||||||
MenuItem { action: root.actions.screenshot }
|
AppMenuItem { action: root.actions.screenshot }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
action: root.actions.configure
|
action: root.actions.configure
|
||||||
visible: root.inFooter
|
visible: root.inFooter
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
}
|
}
|
||||||
MenuItem { action: root.actions.toggleMenuBar }
|
AppMenuItem { action: root.actions.toggleMenuBar }
|
||||||
MenuItem { action: root.actions.about }
|
AppMenuItem { action: root.actions.about }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
Menu {
|
AppMenu {
|
||||||
title: KI18n.i18nc("@title:menu", "&More")
|
title: KI18n.i18nc("@title:menu", "&More")
|
||||||
FileMenu { actions: root.actions }
|
FileMenu { actions: root.actions }
|
||||||
ViewMenu { actions: root.actions }
|
ViewMenu { actions: root.actions }
|
||||||
|
|||||||
+2
-2
@@ -79,8 +79,8 @@ ToolBar {
|
|||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.translateSubtitle }
|
AppMenuItem { action: root.actions.translateSubtitle }
|
||||||
MenuItem { action: root.actions.addSubtitle }
|
AppMenuItem { action: root.actions.addSubtitle }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
|
|
||||||
title: KI18n.i18nc("@title:menu", "&Help")
|
title: KI18n.i18nc("@title:menu", "&Help")
|
||||||
|
|
||||||
MenuItem { action: root.actions.about }
|
AppMenuItem { action: root.actions.about }
|
||||||
MenuItem { action: root.actions.reportBug }
|
AppMenuItem { action: root.actions.reportBug }
|
||||||
}
|
}
|
||||||
+2
-33
@@ -318,39 +318,8 @@ ApplicationWindow {
|
|||||||
onAccepted: video.addSubtitleFile(selectedFile)
|
onAccepted: video.addSubtitleFile(selectedFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Dialog {
|
GlossaryDialog {
|
||||||
id: glossaryDialog
|
id: glossaryDialog
|
||||||
title: KI18n.i18nc("@title:window", "Translation Glossary")
|
translator: translationService
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+16
-16
@@ -7,24 +7,24 @@ import QtQuick.Controls
|
|||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
// Right click menu of the video.
|
// Right click menu of the video.
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
required property MpvItem mpv
|
required property MpvItem mpv
|
||||||
|
|
||||||
MenuItem { action: root.actions.playPause }
|
AppMenuItem { action: root.actions.playPause }
|
||||||
MenuItem { action: root.actions.playNextFile }
|
AppMenuItem { action: root.actions.playNextFile }
|
||||||
MenuItem { action: root.actions.playPreviousFile }
|
AppMenuItem { action: root.actions.playPreviousFile }
|
||||||
Menu {
|
AppMenu {
|
||||||
title: KI18n.i18nc("@title:menu", "Playback Speed")
|
title: KI18n.i18nc("@title:menu", "Playback Speed")
|
||||||
MenuItem { action: root.actions.speedUp }
|
AppMenuItem { action: root.actions.speedUp }
|
||||||
MenuItem { action: root.actions.speedDown }
|
AppMenuItem { action: root.actions.speedDown }
|
||||||
MenuItem { action: root.actions.speedReset }
|
AppMenuItem { action: root.actions.speedReset }
|
||||||
}
|
}
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.openFile }
|
AppMenuItem { action: root.actions.openFile }
|
||||||
MenuItem { action: root.actions.openUrl }
|
AppMenuItem { action: root.actions.openUrl }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
SubtitleTracksMenu {
|
SubtitleTracksMenu {
|
||||||
mpv: root.mpv
|
mpv: root.mpv
|
||||||
@@ -40,7 +40,7 @@ Menu {
|
|||||||
mpv: root.mpv
|
mpv: root.mpv
|
||||||
title: KI18n.i18nc("@title:menu", "Audio Track")
|
title: KI18n.i18nc("@title:menu", "Audio Track")
|
||||||
}
|
}
|
||||||
MenuItem { action: root.actions.translateSubtitle }
|
AppMenuItem { action: root.actions.translateSubtitle }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
VideoMenu { actions: root.actions }
|
VideoMenu { actions: root.actions }
|
||||||
SubtitlesMenu {
|
SubtitlesMenu {
|
||||||
@@ -52,10 +52,10 @@ Menu {
|
|||||||
mpv: root.mpv
|
mpv: root.mpv
|
||||||
}
|
}
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.toggleFullscreen }
|
AppMenuItem { action: root.actions.toggleFullscreen }
|
||||||
MenuItem { action: root.actions.togglePlaylist }
|
AppMenuItem { action: root.actions.togglePlaylist }
|
||||||
MenuItem { action: root.actions.toggleMenuBar }
|
AppMenuItem { action: root.actions.toggleMenuBar }
|
||||||
MenuItem { action: root.actions.toggleHeader }
|
AppMenuItem { action: root.actions.toggleHeader }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.configure }
|
AppMenuItem { action: root.actions.configure }
|
||||||
}
|
}
|
||||||
+22
-22
@@ -6,41 +6,41 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
|
|
||||||
title: KI18n.i18nc("@title:menu", "&Playback")
|
title: KI18n.i18nc("@title:menu", "&Playback")
|
||||||
|
|
||||||
MenuItem { action: root.actions.playPause }
|
AppMenuItem { action: root.actions.playPause }
|
||||||
MenuItem { action: root.actions.stop }
|
AppMenuItem { action: root.actions.stop }
|
||||||
MenuItem { action: root.actions.playNextFile }
|
AppMenuItem { action: root.actions.playNextFile }
|
||||||
MenuItem { action: root.actions.playPreviousFile }
|
AppMenuItem { action: root.actions.playPreviousFile }
|
||||||
MenuItem { action: root.actions.restart }
|
AppMenuItem { action: root.actions.restart }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.speedUp }
|
AppMenuItem { action: root.actions.speedUp }
|
||||||
MenuItem { action: root.actions.speedDown }
|
AppMenuItem { action: root.actions.speedDown }
|
||||||
MenuItem { action: root.actions.speedReset }
|
AppMenuItem { action: root.actions.speedReset }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
Menu {
|
AppMenu {
|
||||||
title: KI18n.i18nc("@title:menu", "Seek")
|
title: KI18n.i18nc("@title:menu", "Seek")
|
||||||
MenuItem { action: root.actions.seekForwardSmall }
|
AppMenuItem { action: root.actions.seekForwardSmall }
|
||||||
MenuItem { action: root.actions.seekBackwardSmall }
|
AppMenuItem { action: root.actions.seekBackwardSmall }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.seekForwardMedium }
|
AppMenuItem { action: root.actions.seekForwardMedium }
|
||||||
MenuItem { action: root.actions.seekBackwardMedium }
|
AppMenuItem { action: root.actions.seekBackwardMedium }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.seekForwardBig }
|
AppMenuItem { action: root.actions.seekForwardBig }
|
||||||
MenuItem { action: root.actions.seekBackwardBig }
|
AppMenuItem { action: root.actions.seekBackwardBig }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.seekNextSubtitle }
|
AppMenuItem { action: root.actions.seekNextSubtitle }
|
||||||
MenuItem { action: root.actions.seekPreviousSubtitle }
|
AppMenuItem { action: root.actions.seekPreviousSubtitle }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.seekNextChapter }
|
AppMenuItem { action: root.actions.seekNextChapter }
|
||||||
MenuItem { action: root.actions.seekPreviousChapter }
|
AppMenuItem { action: root.actions.seekPreviousChapter }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.frameStepForward }
|
AppMenuItem { action: root.actions.frameStepForward }
|
||||||
MenuItem { action: root.actions.frameStepBackward }
|
AppMenuItem { action: root.actions.frameStepBackward }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,15 +113,15 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: contextMenu
|
id: contextMenu
|
||||||
|
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Play")
|
text: KI18n.i18nc("@action:inmenu", "Play")
|
||||||
icon.name: "media-playback-start"
|
icon.name: "media-playback-start"
|
||||||
onTriggered: root.playlist.play(root.index)
|
onTriggered: root.playlist.play(root.index)
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Open Containing Folder")
|
text: KI18n.i18nc("@action:inmenu", "Open Containing Folder")
|
||||||
icon.name: "folder-open"
|
icon.name: "folder-open"
|
||||||
enabled: root.url.toString().startsWith("file://")
|
enabled: root.url.toString().startsWith("file://")
|
||||||
@@ -131,19 +131,19 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Move Up")
|
text: KI18n.i18nc("@action:inmenu", "Move Up")
|
||||||
icon.name: "go-up"
|
icon.name: "go-up"
|
||||||
enabled: root.index > 0
|
enabled: root.index > 0
|
||||||
onTriggered: root.playlist.move(root.index, root.index - 1)
|
onTriggered: root.playlist.move(root.index, root.index - 1)
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Move Down")
|
text: KI18n.i18nc("@action:inmenu", "Move Down")
|
||||||
icon.name: "go-down"
|
icon.name: "go-down"
|
||||||
enabled: root.index < root.playlist.count - 1
|
enabled: root.index < root.playlist.count - 1
|
||||||
onTriggered: root.playlist.move(root.index, root.index + 1)
|
onTriggered: root.playlist.move(root.index, root.index + 1)
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Remove from Playlist")
|
text: KI18n.i18nc("@action:inmenu", "Remove from Playlist")
|
||||||
icon.name: "list-remove"
|
icon.name: "list-remove"
|
||||||
onTriggered: root.playlist.remove(root.index)
|
onTriggered: root.playlist.remove(root.index)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
@@ -18,7 +18,7 @@ Menu {
|
|||||||
|
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: RecentFilesModel
|
model: RecentFilesModel
|
||||||
delegate: MenuItem {
|
delegate: AppMenuItem {
|
||||||
required property url url
|
required property url url
|
||||||
required property string name
|
required property string name
|
||||||
required property string path
|
required property string path
|
||||||
@@ -35,7 +35,7 @@ Menu {
|
|||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Clear List")
|
text: KI18n.i18nc("@action:inmenu", "Clear List")
|
||||||
icon.name: "edit-clear-history"
|
icon.name: "edit-clear-history"
|
||||||
onTriggered: RecentFilesModel.clear()
|
onTriggered: RecentFilesModel.clear()
|
||||||
|
|||||||
@@ -6,34 +6,34 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
|
|
||||||
title: KI18n.i18nc("@title:menu", "&Settings")
|
title: KI18n.i18nc("@title:menu", "&Settings")
|
||||||
|
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "General")
|
text: KI18n.i18nc("@action:inmenu", "General")
|
||||||
onTriggered: root.actions.settingsRequested("general")
|
onTriggered: root.actions.settingsRequested("general")
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Playback")
|
text: KI18n.i18nc("@action:inmenu", "Playback")
|
||||||
onTriggered: root.actions.settingsRequested("playback")
|
onTriggered: root.actions.settingsRequested("playback")
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Subtitles")
|
text: KI18n.i18nc("@action:inmenu", "Subtitles")
|
||||||
onTriggered: root.actions.settingsRequested("subtitles")
|
onTriggered: root.actions.settingsRequested("subtitles")
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Translation")
|
text: KI18n.i18nc("@action:inmenu", "Translation")
|
||||||
onTriggered: root.actions.settingsRequested("translation")
|
onTriggered: root.actions.settingsRequested("translation")
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "Playlist")
|
text: KI18n.i18nc("@action:inmenu", "Playlist")
|
||||||
onTriggered: root.actions.settingsRequested("playlist")
|
onTriggered: root.actions.settingsRequested("playlist")
|
||||||
}
|
}
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@action:inmenu", "About")
|
text: KI18n.i18nc("@action:inmenu", "About")
|
||||||
onTriggered: root.actions.settingsRequested("about")
|
onTriggered: root.actions.settingsRequested("about")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import QtQuick.Controls
|
|||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
// Checkable list of subtitle tracks, for the primary or the secondary subtitle.
|
// Checkable list of subtitle tracks, for the primary or the secondary subtitle.
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property MpvItem mpv
|
required property MpvItem mpv
|
||||||
@@ -36,7 +36,7 @@ Menu {
|
|||||||
|
|
||||||
enabled: mpv.subtitleTracks.length > 0
|
enabled: mpv.subtitleTracks.length > 0
|
||||||
|
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
text: KI18n.i18nc("@item:inmenu no subtitle", "None")
|
text: KI18n.i18nc("@item:inmenu no subtitle", "None")
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: root.selectedId === 0
|
checked: root.selectedId === 0
|
||||||
@@ -49,7 +49,7 @@ Menu {
|
|||||||
|
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: root.mpv.subtitleTracks
|
model: root.mpv.subtitleTracks
|
||||||
delegate: MenuItem {
|
delegate: AppMenuItem {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
text: root.trackLabel(modelData)
|
text: root.trackLabel(modelData)
|
||||||
checkable: true
|
checkable: true
|
||||||
|
|||||||
+13
-13
@@ -6,7 +6,7 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
@@ -25,21 +25,21 @@ Menu {
|
|||||||
title: KI18n.i18nc("@title:menu", "Secondary Subtitle")
|
title: KI18n.i18nc("@title:menu", "Secondary Subtitle")
|
||||||
}
|
}
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.translateSubtitle }
|
AppMenuItem { action: root.actions.translateSubtitle }
|
||||||
MenuItem { action: root.actions.editGlossary }
|
AppMenuItem { action: root.actions.editGlossary }
|
||||||
MenuItem {
|
AppMenuItem {
|
||||||
action: root.actions.cancelTranslation
|
action: root.actions.cancelTranslation
|
||||||
visible: root.actions.cancelTranslation.enabled
|
visible: root.actions.cancelTranslation.enabled
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
}
|
}
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.addSubtitle }
|
AppMenuItem { action: root.actions.addSubtitle }
|
||||||
MenuItem { action: root.actions.subtitleBigger }
|
AppMenuItem { action: root.actions.subtitleBigger }
|
||||||
MenuItem { action: root.actions.subtitleSmaller }
|
AppMenuItem { action: root.actions.subtitleSmaller }
|
||||||
MenuItem { action: root.actions.subtitleEarlier }
|
AppMenuItem { action: root.actions.subtitleEarlier }
|
||||||
MenuItem { action: root.actions.subtitleLater }
|
AppMenuItem { action: root.actions.subtitleLater }
|
||||||
MenuItem { action: root.actions.subtitleDelayReset }
|
AppMenuItem { action: root.actions.subtitleDelayReset }
|
||||||
MenuItem { action: root.actions.subtitleToggle }
|
AppMenuItem { action: root.actions.subtitleToggle }
|
||||||
MenuItem { action: root.actions.subtitleCycleUp }
|
AppMenuItem { action: root.actions.subtitleCycleUp }
|
||||||
MenuItem { action: root.actions.subtitleCycleDown }
|
AppMenuItem { action: root.actions.subtitleCycleDown }
|
||||||
}
|
}
|
||||||
@@ -147,12 +147,9 @@ SettingsBasePage {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: KI18n.i18nc("@label:listbox", "Preset")
|
text: KI18n.i18nc("@label:listbox", "Preset")
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: presetCombo
|
id: presetCombo
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -166,17 +163,19 @@ SettingsBasePage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item { Layout.preferredWidth: 1 }
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: presetCombo.currentIndex >= 0 ? presetCombo.model[presetCombo.currentIndex].guidance : ""
|
text: presetCombo.currentIndex >= 0 ? presetCombo.model[presetCombo.currentIndex].description : ""
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
font: Kirigami.Theme.smallFont
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: KI18n.i18nc("@label:textbox", "Additional instructions")
|
text: KI18n.i18nc("@label:textbox", "Additional instructions")
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
Layout.alignment: Qt.AlignRight | Qt.AlignBaseline
|
||||||
}
|
}
|
||||||
|
|
||||||
TextArea {
|
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.")
|
placeholderText: KI18n.i18nc("@info:placeholder", "e.g. Translate 'Young Master' as 'Thiếu gia'. Use 'ta/ngươi' between enemies.")
|
||||||
wrapMode: TextArea.Wrap
|
wrapMode: TextArea.Wrap
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignBaseline
|
||||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 4
|
Layout.preferredHeight: Kirigami.Units.gridUnit * 4
|
||||||
// TextArea has no textEdited before Qt 6.9.
|
// TextArea has no textEdited before Qt 6.9.
|
||||||
onTextChanged: QtPotatoSettings.customInstructions = text
|
onTextChanged: QtPotatoSettings.customInstructions = text
|
||||||
|
|||||||
@@ -6,18 +6,18 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
|
|
||||||
title: KI18n.i18nc("@title:menu", "&Video")
|
title: KI18n.i18nc("@title:menu", "&Video")
|
||||||
|
|
||||||
MenuItem { action: root.actions.toggleDeinterlacing }
|
AppMenuItem { action: root.actions.toggleDeinterlacing }
|
||||||
MenuItem { action: root.actions.zoomIn }
|
AppMenuItem { action: root.actions.zoomIn }
|
||||||
MenuItem { action: root.actions.zoomOut }
|
AppMenuItem { action: root.actions.zoomOut }
|
||||||
MenuItem { action: root.actions.zoomReset }
|
AppMenuItem { action: root.actions.zoomReset }
|
||||||
MenuItem { action: root.actions.screenshot }
|
AppMenuItem { action: root.actions.screenshot }
|
||||||
MenuItem { action: root.actions.rotateClockwise }
|
AppMenuItem { action: root.actions.rotateClockwise }
|
||||||
MenuItem { action: root.actions.rotateCounterClockwise }
|
AppMenuItem { action: root.actions.rotateCounterClockwise }
|
||||||
}
|
}
|
||||||
@@ -6,16 +6,16 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import org.kde.ki18n
|
import org.kde.ki18n
|
||||||
|
|
||||||
Menu {
|
AppMenu {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Actions actions
|
required property Actions actions
|
||||||
|
|
||||||
title: KI18n.i18nc("@title:menu", "&View")
|
title: KI18n.i18nc("@title:menu", "&View")
|
||||||
|
|
||||||
MenuItem { action: root.actions.toggleFullscreen }
|
AppMenuItem { action: root.actions.toggleFullscreen }
|
||||||
MenuItem { action: root.actions.togglePlaylist }
|
AppMenuItem { action: root.actions.togglePlaylist }
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: root.actions.toggleMenuBar }
|
AppMenuItem { action: root.actions.toggleMenuBar }
|
||||||
MenuItem { action: root.actions.toggleHeader }
|
AppMenuItem { action: root.actions.toggleHeader }
|
||||||
}
|
}
|
||||||
@@ -15,31 +15,37 @@ const QList<Preset> &all()
|
|||||||
{
|
{
|
||||||
u"general"_s,
|
u"general"_s,
|
||||||
i18nc("@item:inlistbox translation preset", "General"),
|
i18nc("@item:inlistbox translation preset", "General"),
|
||||||
|
i18nc("@info translation preset description", "Natural dialogue with conventional names and a tone suited to the scene."),
|
||||||
u"Keep names as they are conventionally rendered and use a natural, conversational tone appropriate to the scene."_s,
|
u"Keep names as they are conventionally rendered and use a natural, conversational tone appropriate to the scene."_s,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
u"chinese-donghua"_s,
|
u"chinese-donghua"_s,
|
||||||
i18nc("@item:inlistbox translation preset", "Chinese animation / wuxia / xianxia"),
|
i18nc("@item:inlistbox translation preset", "Chinese animation / wuxia / xianxia"),
|
||||||
|
i18nc("@info translation preset description", "Traditional names, cultivation terms, and period-appropriate forms of address."),
|
||||||
u"For Chinese animation, wuxia, xianxia, and historical settings, the source is often an English subtitle with pinyin names. When translating into Vietnamese, convert Chinese personal names, place names, sect and clan names, techniques, and cultivation terms into their Sino-Vietnamese (Hán-Việt) forms (for example, Xiao Yan → Tiêu Viêm, Dou Qi → Đấu Khí, Sect Master → Tông chủ). For other target languages, use that language's conventional rendering. Be consistent and prefer well-known established renderings from famous works. When translating into Vietnamese, use period-appropriate forms of address such as ta/ngươi, huynh/đệ, sư phụ, and tiền bối."_s,
|
u"For Chinese animation, wuxia, xianxia, and historical settings, the source is often an English subtitle with pinyin names. When translating into Vietnamese, convert Chinese personal names, place names, sect and clan names, techniques, and cultivation terms into their Sino-Vietnamese (Hán-Việt) forms (for example, Xiao Yan → Tiêu Viêm, Dou Qi → Đấu Khí, Sect Master → Tông chủ). For other target languages, use that language's conventional rendering. Be consistent and prefer well-known established renderings from famous works. When translating into Vietnamese, use period-appropriate forms of address such as ta/ngươi, huynh/đệ, sư phụ, and tiền bối."_s,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
u"japanese-anime"_s,
|
u"japanese-anime"_s,
|
||||||
i18nc("@item:inlistbox translation preset", "Japanese anime"),
|
i18nc("@item:inlistbox translation preset", "Japanese anime"),
|
||||||
|
i18nc("@info translation preset description", "Casual dialogue with Japanese names and honorifics preserved."),
|
||||||
u"Keep Japanese names in romaji. Keep honorifics such as -san, -kun, and -senpai as-is. Use a natural, casual tone."_s,
|
u"Keep Japanese names in romaji. Keep honorifics such as -san, -kun, and -senpai as-is. Use a natural, casual tone."_s,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
u"korean-drama"_s,
|
u"korean-drama"_s,
|
||||||
i18nc("@item:inlistbox translation preset", "Korean drama"),
|
i18nc("@item:inlistbox translation preset", "Korean drama"),
|
||||||
|
i18nc("@info translation preset description", "Modern dialogue with Korean names and relationship-aware forms of address."),
|
||||||
u"Keep Korean names. Use modern forms of address that fit the relationships; when translating into Vietnamese, use forms such as anh/em, and oppa may be kept when appropriate."_s,
|
u"Keep Korean names. Use modern forms of address that fit the relationships; when translating into Vietnamese, use forms such as anh/em, and oppa may be kept when appropriate."_s,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
u"western"_s,
|
u"western"_s,
|
||||||
i18nc("@item:inlistbox translation preset", "Western"),
|
i18nc("@item:inlistbox translation preset", "Western"),
|
||||||
|
i18nc("@info translation preset description", "A neutral modern tone with naturally adapted idioms."),
|
||||||
u"Keep names. Use a neutral modern tone and adapt idioms naturally for the target language."_s,
|
u"Keep names. Use a neutral modern tone and adapt idioms naturally for the target language."_s,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
u"documentary"_s,
|
u"documentary"_s,
|
||||||
i18nc("@item:inlistbox translation preset", "Documentary"),
|
i18nc("@item:inlistbox translation preset", "Documentary"),
|
||||||
|
i18nc("@info translation preset description", "Formal, precise language with accurate terminology."),
|
||||||
u"Keep names. Use a formal, precise tone and translate terminology accurately."_s,
|
u"Keep names. Use a formal, precise tone and translate terminology accurately."_s,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace TranslationPresets
|
|||||||
struct Preset {
|
struct Preset {
|
||||||
QString id;
|
QString id;
|
||||||
QString name;
|
QString name;
|
||||||
|
QString description;
|
||||||
QString guidance;
|
QString guidance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ QVariantList TranslationService::translationPresets() const
|
|||||||
{
|
{
|
||||||
QVariantList result;
|
QVariantList result;
|
||||||
for (const auto &preset : TranslationPresets::all()) {
|
for (const auto &preset : TranslationPresets::all()) {
|
||||||
result.append(QVariantMap{{u"id"_s, preset.id}, {u"name"_s, preset.name}, {u"guidance"_s, preset.guidance}});
|
result.append(QVariantMap{{u"id"_s, preset.id}, {u"name"_s, preset.name}, {u"description"_s, preset.description}, {u"guidance"_s, preset.guidance}});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user