From 263386e2f1622ff25cc1d92f6067216f52ccc836 Mon Sep 17 00:00:00 2001 From: 283375 Date: Mon, 16 Oct 2023 01:16:11 +0800 Subject: [PATCH] feat: `TabTools_ChartInfoEditor` --- .../tabs/tabDb/tabDb_ChartInfoEditor.ui | 263 ++++++++++++++++++ .../tabs/tabDb/tabDb_ChartInfoEditor_ui.py | 198 +++++++++++++ ui/designer/tabs/tabDbEntry.ui | 11 + ui/designer/tabs/tabDbEntry_ui.py | 7 +- .../tabs/tabDb/tabDb_ChartInfoEditor.py | 32 +++ .../tabs/tabDb/tabDb_ChartInfoEditor.py | 226 +++++++++++++++ ui/resources/lang/en_US.ts | 97 +++++-- ui/resources/lang/zh_CN.ts | 97 +++++-- 8 files changed, 886 insertions(+), 45 deletions(-) create mode 100644 ui/designer/tabs/tabDb/tabDb_ChartInfoEditor.ui create mode 100644 ui/designer/tabs/tabDb/tabDb_ChartInfoEditor_ui.py create mode 100644 ui/extends/tabs/tabDb/tabDb_ChartInfoEditor.py create mode 100644 ui/implements/tabs/tabDb/tabDb_ChartInfoEditor.py diff --git a/ui/designer/tabs/tabDb/tabDb_ChartInfoEditor.ui b/ui/designer/tabs/tabDb/tabDb_ChartInfoEditor.ui new file mode 100644 index 0000000..8290eb4 --- /dev/null +++ b/ui/designer/tabs/tabDb/tabDb_ChartInfoEditor.ui @@ -0,0 +1,263 @@ + + + TabDb_ChartInfoEditor + + + + 0 + 0 + 659 + 570 + + + + TabDb_ChartInfoEditor + + + + + + editor.title + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + editor.constant + + + + + + + editor.notes + + + + + + + + GeosansLight + 14 + true + + + + + + + + + 100 + 100 + + + + + 100 + 100 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + ... + + + + + + + ... + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + GeosansLight + 14 + true + + + + + + + + > ... + + + + + + + + + + + 0 + 0 + + + + editor.tip + + + + + + + editor.tip.content + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + editor.delete + + + + + + + editor.commit + + + + + + + + + + + + + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + + + + + + ChartSelector + QWidget +
ui.implements.components.chartSelector
+ 1 +
+
+ + +
diff --git a/ui/designer/tabs/tabDb/tabDb_ChartInfoEditor_ui.py b/ui/designer/tabs/tabDb/tabDb_ChartInfoEditor_ui.py new file mode 100644 index 0000000..3e086c8 --- /dev/null +++ b/ui/designer/tabs/tabDb/tabDb_ChartInfoEditor_ui.py @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'tabDb_ChartInfoEditor.ui' +## +## Created by: Qt User Interface Compiler version 6.5.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QAbstractItemView, QApplication, QFormLayout, QGridLayout, + QGroupBox, QHBoxLayout, QLabel, QLineEdit, + QListView, QPushButton, QSizePolicy, QSpacerItem, + QVBoxLayout, QWidget) + +from ui.implements.components.chartSelector import ChartSelector + +class Ui_TabDb_ChartInfoEditor(object): + def setupUi(self, TabDb_ChartInfoEditor): + if not TabDb_ChartInfoEditor.objectName(): + TabDb_ChartInfoEditor.setObjectName(u"TabDb_ChartInfoEditor") + TabDb_ChartInfoEditor.resize(659, 570) + TabDb_ChartInfoEditor.setWindowTitle(u"TabDb_ChartInfoEditor") + self.gridLayout = QGridLayout(TabDb_ChartInfoEditor) + self.gridLayout.setObjectName(u"gridLayout") + self.groupBox = QGroupBox(TabDb_ChartInfoEditor) + self.groupBox.setObjectName(u"groupBox") + self.verticalLayout_2 = QVBoxLayout(self.groupBox) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.widget = QWidget(self.groupBox) + self.widget.setObjectName(u"widget") + self.formLayout = QFormLayout(self.widget) + self.formLayout.setObjectName(u"formLayout") + self.formLayout.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + self.label = QLabel(self.widget) + self.label.setObjectName(u"label") + + self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label) + + self.label_2 = QLabel(self.widget) + self.label_2.setObjectName(u"label_2") + + self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_2) + + self.notesLineEdit = QLineEdit(self.widget) + self.notesLineEdit.setObjectName(u"notesLineEdit") + font = QFont() + font.setFamilies([u"GeosansLight"]) + font.setPointSize(14) + font.setBold(True) + self.notesLineEdit.setFont(font) + + self.formLayout.setWidget(2, QFormLayout.FieldRole, self.notesLineEdit) + + self.jacketLabel = QLabel(self.widget) + self.jacketLabel.setObjectName(u"jacketLabel") + self.jacketLabel.setMinimumSize(QSize(100, 100)) + self.jacketLabel.setMaximumSize(QSize(100, 100)) + self.jacketLabel.setText(u"") + + self.formLayout.setWidget(0, QFormLayout.LabelRole, self.jacketLabel) + + self.verticalLayout = QVBoxLayout() + self.verticalLayout.setObjectName(u"verticalLayout") + self.verticalSpacer = QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout.addItem(self.verticalSpacer) + + self.titleLabel = QLabel(self.widget) + self.titleLabel.setObjectName(u"titleLabel") + self.titleLabel.setText(u"...") + + self.verticalLayout.addWidget(self.titleLabel) + + self.ratingLabel = QLabel(self.widget) + self.ratingLabel.setObjectName(u"ratingLabel") + self.ratingLabel.setText(u"...") + + self.verticalLayout.addWidget(self.ratingLabel) + + self.verticalSpacer_2 = QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout.addItem(self.verticalSpacer_2) + + + self.formLayout.setLayout(0, QFormLayout.FieldRole, self.verticalLayout) + + self.horizontalWidget_2 = QWidget(self.widget) + self.horizontalWidget_2.setObjectName(u"horizontalWidget_2") + sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.horizontalWidget_2.sizePolicy().hasHeightForWidth()) + self.horizontalWidget_2.setSizePolicy(sizePolicy) + self.horizontalLayout_2 = QHBoxLayout(self.horizontalWidget_2) + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.constantLineEdit = QLineEdit(self.horizontalWidget_2) + self.constantLineEdit.setObjectName(u"constantLineEdit") + self.constantLineEdit.setFont(font) + + self.horizontalLayout_2.addWidget(self.constantLineEdit) + + self.constantPreviewLabel = QLabel(self.horizontalWidget_2) + self.constantPreviewLabel.setObjectName(u"constantPreviewLabel") + self.constantPreviewLabel.setText(u"> ...") + + self.horizontalLayout_2.addWidget(self.constantPreviewLabel) + + + self.formLayout.setWidget(1, QFormLayout.FieldRole, self.horizontalWidget_2) + + self.label_3 = QLabel(self.widget) + self.label_3.setObjectName(u"label_3") + sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy1) + + self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_3) + + self.label_4 = QLabel(self.widget) + self.label_4.setObjectName(u"label_4") + + self.formLayout.setWidget(3, QFormLayout.FieldRole, self.label_4) + + + self.verticalLayout_2.addWidget(self.widget) + + self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer_3) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout.addItem(self.horizontalSpacer) + + self.deleteButton = QPushButton(self.groupBox) + self.deleteButton.setObjectName(u"deleteButton") + + self.horizontalLayout.addWidget(self.deleteButton) + + self.commitButton = QPushButton(self.groupBox) + self.commitButton.setObjectName(u"commitButton") + + self.horizontalLayout.addWidget(self.commitButton) + + + self.verticalLayout_2.addLayout(self.horizontalLayout) + + + self.gridLayout.addWidget(self.groupBox, 1, 1, 1, 1) + + self.chartSelector = ChartSelector(TabDb_ChartInfoEditor) + self.chartSelector.setObjectName(u"chartSelector") + + self.gridLayout.addWidget(self.chartSelector, 0, 0, 1, 2) + + self.listView = QListView(TabDb_ChartInfoEditor) + self.listView.setObjectName(u"listView") + sizePolicy2 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + sizePolicy2.setHorizontalStretch(0) + sizePolicy2.setVerticalStretch(0) + sizePolicy2.setHeightForWidth(self.listView.sizePolicy().hasHeightForWidth()) + self.listView.setSizePolicy(sizePolicy2) + self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.listView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) + self.listView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) + + self.gridLayout.addWidget(self.listView, 1, 0, 1, 1) + + + self.retranslateUi(TabDb_ChartInfoEditor) + + QMetaObject.connectSlotsByName(TabDb_ChartInfoEditor) + # setupUi + + def retranslateUi(self, TabDb_ChartInfoEditor): + self.groupBox.setTitle(QCoreApplication.translate("TabDb_ChartInfoEditor", u"editor.title", None)) + self.label.setText(QCoreApplication.translate("TabDb_ChartInfoEditor", u"editor.constant", None)) + self.label_2.setText(QCoreApplication.translate("TabDb_ChartInfoEditor", u"editor.notes", None)) + self.label_3.setText(QCoreApplication.translate("TabDb_ChartInfoEditor", u"editor.tip", None)) + self.label_4.setText(QCoreApplication.translate("TabDb_ChartInfoEditor", u"editor.tip.content", None)) + self.deleteButton.setText(QCoreApplication.translate("TabDb_ChartInfoEditor", u"editor.delete", None)) + self.commitButton.setText(QCoreApplication.translate("TabDb_ChartInfoEditor", u"editor.commit", None)) + pass + # retranslateUi + diff --git a/ui/designer/tabs/tabDbEntry.ui b/ui/designer/tabs/tabDbEntry.ui index be1da1d..89befa5 100644 --- a/ui/designer/tabs/tabDbEntry.ui +++ b/ui/designer/tabs/tabDbEntry.ui @@ -24,6 +24,11 @@ tab.manage + + + tab.chartInfoEditor + + @@ -35,6 +40,12 @@
ui.implements.tabs.tabDb.tabDb_Manage
1 + + TabDb_ChartInfoEditor + QWidget +
ui.implements.tabs.tabDb.tabDb_ChartInfoEditor
+ 1 +
diff --git a/ui/designer/tabs/tabDbEntry_ui.py b/ui/designer/tabs/tabDbEntry_ui.py index 44c2e1d..423da36 100644 --- a/ui/designer/tabs/tabDbEntry_ui.py +++ b/ui/designer/tabs/tabDbEntry_ui.py @@ -3,7 +3,7 @@ ################################################################################ ## Form generated from reading UI file 'tabDbEntry.ui' ## -## Created by: Qt User Interface Compiler version 6.5.0 +## Created by: Qt User Interface Compiler version 6.5.2 ## ## WARNING! All changes made in this file will be lost when recompiling UI file! ################################################################################ @@ -18,6 +18,7 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, from PySide6.QtWidgets import (QApplication, QSizePolicy, QTabWidget, QVBoxLayout, QWidget) +from ui.implements.tabs.tabDb.tabDb_ChartInfoEditor import TabDb_ChartInfoEditor from ui.implements.tabs.tabDb.tabDb_Manage import TabDb_Manage class Ui_TabDbEntry(object): @@ -33,6 +34,9 @@ class Ui_TabDbEntry(object): self.tab_manage = TabDb_Manage() self.tab_manage.setObjectName(u"tab_manage") self.tabWidget.addTab(self.tab_manage, "") + self.tab_chartInfoEditor = TabDb_ChartInfoEditor() + self.tab_chartInfoEditor.setObjectName(u"tab_chartInfoEditor") + self.tabWidget.addTab(self.tab_chartInfoEditor, "") self.verticalLayout.addWidget(self.tabWidget) @@ -47,6 +51,7 @@ class Ui_TabDbEntry(object): def retranslateUi(self, TabDbEntry): self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_manage), QCoreApplication.translate("TabDbEntry", u"tab.manage", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_chartInfoEditor), QCoreApplication.translate("TabDbEntry", u"tab.chartInfoEditor", None)) pass # retranslateUi diff --git a/ui/extends/tabs/tabDb/tabDb_ChartInfoEditor.py b/ui/extends/tabs/tabDb/tabDb_ChartInfoEditor.py new file mode 100644 index 0000000..5241dd1 --- /dev/null +++ b/ui/extends/tabs/tabDb/tabDb_ChartInfoEditor.py @@ -0,0 +1,32 @@ +from arcaea_offline.models import Difficulty, Song +from PySide6.QtCore import QModelIndex, Qt +from PySide6.QtGui import QStandardItem, QStandardItemModel + +from ui.extends.shared.delegates.chartDelegate import ChartDelegate + + +class ChartInfoAbsentModel(QStandardItemModel): + SongRole = Qt.ItemDataRole.UserRole + DifficultyRole = Qt.ItemDataRole.UserRole + 1 + + def setCustomData(self, songs: list[Song], difficulties: list[Difficulty]): + self.clear() + + for song, difficulty in zip(songs, difficulties): + item = QStandardItem() + item.setData(song, self.SongRole) + item.setData(difficulty, self.DifficultyRole) + self.appendRow(item) + + def setLoading(self): + self.clear() + + self.appendRow(QStandardItem("Loading...")) + + +class ListViewDelegate(ChartDelegate): + def getSong(self, index: QModelIndex): + return index.data(ChartInfoAbsentModel.SongRole) + + def getDifficulty(self, index: QModelIndex): + return index.data(ChartInfoAbsentModel.DifficultyRole) diff --git a/ui/implements/tabs/tabDb/tabDb_ChartInfoEditor.py b/ui/implements/tabs/tabDb/tabDb_ChartInfoEditor.py new file mode 100644 index 0000000..d636ae6 --- /dev/null +++ b/ui/implements/tabs/tabDb/tabDb_ChartInfoEditor.py @@ -0,0 +1,226 @@ +import logging + +from arcaea_offline.database import Database +from arcaea_offline.models import Chart, ChartInfo, Difficulty, Song +from arcaea_offline.utils.rating import rating_class_to_text +from PySide6.QtCore import QCoreApplication, QModelIndex, Qt, Slot +from PySide6.QtGui import QPixmap, QRegularExpressionValidator, QStandardItem +from PySide6.QtWidgets import QApplication, QMessageBox, QStyledItemDelegate, QWidget +from sqlalchemy import select + +from ui.designer.tabs.tabDb.tabDb_ChartInfoEditor_ui import Ui_TabDb_ChartInfoEditor +from ui.extends.shared.data import Data +from ui.extends.shared.database import databaseUpdateSignals +from ui.extends.shared.language import LanguageChangeEventFilter +from ui.extends.tabs.tabDb.tabDb_ChartInfoEditor import ( + ChartInfoAbsentModel, + ListViewDelegate, +) +from ui.implements.components.songIdSelector import SongIdSelectorMode + +logger = logging.getLogger(__name__) + + +class TabDb_ChartInfoEditor(Ui_TabDb_ChartInfoEditor, QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.setupUi(self) + + self.languageChangeEventFilter = LanguageChangeEventFilter(self) + self.installEventFilter(self.languageChangeEventFilter) + + self.db = Database() + + self.numberRegexValidator = QRegularExpressionValidator(r"^\d+$", self) + self.constantLineEdit.setValidator(self.numberRegexValidator) + self.notesLineEdit.setValidator(self.numberRegexValidator) + + self.constantLineEdit.textChanged.connect(self.updateConstantPreviewLabel) + + self.chartInfoAbsentModel = ChartInfoAbsentModel(self) + self.listView.setModel(self.chartInfoAbsentModel) + self.listViewDelegate = ListViewDelegate(self) + + self.listView.selectionModel().currentChanged.connect( + self.listViewSelectionChanged + ) + + self.chartSelector.setSongIdSelectorMode(SongIdSelectorMode.SongId) + self.chartSelector.valueChanged.connect(self.chartSelectorValueChanged) + + databaseUpdateSignals.songDataUpdated.connect(self.updateChartInfoAbsentModel) + self.updateChartInfoAbsentModel() + + self.commitButton.clicked.connect(self.commitChartInfo) + self.deleteButton.clicked.connect(self.deleteChartInfo) + + def updateConstantPreviewLabel(self): + text = self.constantLineEdit.text() + if self.constantLineEdit.hasAcceptableInput(): + self.constantPreviewLabel.setText(f"> {int(text) / 10:.1f}") + else: + self.constantPreviewLabel.setText("> ...") + + def reset(self): + self.jacketLabel.clear() + self.titleLabel.setText("...") + self.ratingLabel.setText("...") + self.constantLineEdit.setText("") + self.notesLineEdit.setText("") + + def updateChartInfoAbsentModel(self): + self.listView.setItemDelegate(QStyledItemDelegate()) + self.chartInfoAbsentModel.clear() + self.chartInfoAbsentModel.appendRow(QStandardItem("Loading...")) + QApplication.processEvents() + + with self.db.sessionmaker() as session: + stmt = ( + select(Difficulty) + .join( + ChartInfo, + (Difficulty.song_id == ChartInfo.song_id) + & (Difficulty.rating_class == ChartInfo.rating_class), + isouter=True, + ) + .where(ChartInfo.notes.is_(None)) + ) + absentInfoDifficulties = sorted( + list(session.scalars(stmt)), + key=lambda d: f"{d.song_id},{d.rating_class}", + ) + songIds = sorted(list(set(d.song_id for d in absentInfoDifficulties))) + songsStmt = select(Song).where(Song.id.in_(songIds)) + songs = sorted(list(session.scalars(songsStmt)), key=lambda s: s.id) + + modelSongs = [] + for difficulty in absentInfoDifficulties: + songIndex = songIds.index(difficulty.song_id) + modelSongs.append(songs[songIndex]) + self.chartInfoAbsentModel.setCustomData(modelSongs, absentInfoDifficulties) + self.listView.setItemDelegate(self.listViewDelegate) + + @Slot(QModelIndex) + def listViewSelectionChanged(self, current: QModelIndex): + if current.row() < 0 or current.column() < 0: + return + + song: Song = current.data(ChartInfoAbsentModel.SongRole) + difficulty: Difficulty = current.data(ChartInfoAbsentModel.DifficultyRole) + self.chartSelector.selectChart( + Chart( + song_id=difficulty.song_id, + rating_class=difficulty.rating_class, + set=song.set, + ) + ) + + def chartSelectorValueChanged(self): + if chart := self.chartSelector.value(): + self.fillChartInfo(chart.song_id, chart.rating_class) + else: + self.reset() + + def fillChartInfo(self, songId: str, ratingClass: int): + song = self.db.get_song(songId) + difficulty = self.db.get_difficulty(songId, ratingClass) + + self.titleLabel.setText(difficulty.title or song.title) + self.ratingLabel.setText( + rating_class_to_text(difficulty.rating_class) + + " " + + str(difficulty.rating) + + ("+" if difficulty.rating_plus else "") + ) + + jacketPath = Data().getJacketPath(song, difficulty) + if not jacketPath: + pixmap = QPixmap(":/images/jacket-placeholder.png") + else: + pixmap = QPixmap(str(jacketPath.resolve())) + self.jacketLabel.setPixmap( + pixmap.scaled( + self.jacketLabel.size(), + Qt.AspectRatioMode.KeepAspectRatio, + Qt.TransformationMode.SmoothTransformation, + ) + ) + + chartInfo = self.db.get_chart_info(songId, ratingClass) + if chartInfo is not None: + if chartInfo.constant is not None: + self.constantLineEdit.setText(str(chartInfo.constant)) + if chartInfo.notes is not None: + self.notesLineEdit.setText(str(chartInfo.notes)) + else: + self.constantLineEdit.setText("") + self.notesLineEdit.setText("") + + def commitChartInfo(self): + chart = self.chartSelector.value() + + if not chart: + QMessageBox.critical( + self, + None, + # fmt: off + QCoreApplication.translate("TabDb_ChartInfoEditor", "commit.chartNotSelected"), + # fmt: on + ) + return + if not self.constantLineEdit.hasAcceptableInput(): + QMessageBox.critical( + self, + None, + # fmt: off + QCoreApplication.translate("TabDb_ChartInfoEditor", "commit.constantRequired"), + # fmt: on + ) + return + + constant = int(self.constantLineEdit.text()) + notes = ( + int(self.notesLineEdit.text()) + if self.notesLineEdit.hasAcceptableInput() + else None + ) + chartInfo = ChartInfo( + song_id=chart.song_id, + rating_class=chart.rating_class, + constant=constant, + notes=notes, + ) + with self.db.sessionmaker() as session: + session.merge(chartInfo) + session.commit() + databaseUpdateSignals.songDataUpdated.emit() + + def deleteChartInfo(self): + chart = self.chartSelector.value() + + if not chart: + QMessageBox.critical( + self, + None, + # fmt: off + QCoreApplication.translate("TabDb_ChartInfoEditor", "commit.chartNotSelected"), + # fmt: on + ) + return + + chartInfo = self.db.get_chart_info(chart.song_id, chart.rating_class) + if chartInfo: + result = QMessageBox.warning( + self, + None, + # fmt: off + QCoreApplication.translate("TabDb_ChartInfoEditor", "deleteConfirm"), + # fmt: on + QMessageBox.StandardButton.Yes, + QMessageBox.StandardButton.No, + ) + if result == QMessageBox.StandardButton.Yes: + with self.db.sessionmaker() as session: + session.delete(chartInfo) + session.commit() + databaseUpdateSignals.songDataUpdated.emit() diff --git a/ui/resources/lang/en_US.ts b/ui/resources/lang/en_US.ts index 973c9a2..291544a 100644 --- a/ui/resources/lang/en_US.ts +++ b/ui/resources/lang/en_US.ts @@ -17,12 +17,12 @@ ChartSelector - + songIdSelector.title Select a Song - + resetButton Reset @@ -542,14 +542,14 @@ validation Search... - - + + previous Previous - - + + next Next @@ -574,6 +574,11 @@ validation tab.manage Manage + + + tab.chartInfoEditor + Chart Info Editor + tab.scoreTableViewer @@ -585,6 +590,60 @@ validation Table [B30] + + TabDb_ChartInfoEditor + + + editor.title + Editor + + + + editor.constant + Constant + + + + editor.notes + Notes + + + + editor.tip + Tip + + + + editor.tip.content + Due to the special data structure,<br>please fill in 10 times of the constant value.<br>For example, Testify [BYD] is a 12.0,<br>then fill "120" instead of "12.0". + + + + editor.delete + Delete + + + + editor.commit + Commit + + + + + commit.chartNotSelected + Please select a chart first. + + + + commit.constantRequired + Constant field is required. + + + + deleteConfirm + Are you sure to delete this chart data? + + TabDb_Manage @@ -783,28 +842,28 @@ validation Rois - + options.masker Masker - - + + options.useCustom Use custom options - + dependencies.title OCR Dependencies - + dependencies.knnModel KNearest model - + dependencies.phashDatabase Image pHash database @@ -812,7 +871,7 @@ validation TabOverview - + databaseDescribeLabel {} {} {} {} {} {} There are {} packs, {} songs, {} difficulties, {} chart info ({} complete) and {} scores in database. @@ -911,23 +970,17 @@ validation TabTools_ChartRecommend - + constantRangeFromPlayRating Chart Constant Range from Play Rating - + chartsByConstant Charts by Constant - - - refreshButton - Roll - - - + chartsRecommendFromPlayRating Chart from Play Rating Based on Best Score diff --git a/ui/resources/lang/zh_CN.ts b/ui/resources/lang/zh_CN.ts index 0064c23..06b81c4 100644 --- a/ui/resources/lang/zh_CN.ts +++ b/ui/resources/lang/zh_CN.ts @@ -17,12 +17,12 @@ ChartSelector - + songIdSelector.title 选择一首歌曲 - + resetButton 重置 @@ -541,14 +541,14 @@ 搜索…… - - + + previous 上一个 - - + + next 下一个 @@ -573,6 +573,11 @@ tab.manage 管理 + + + tab.chartInfoEditor + 谱面信息编辑器 + tab.scoreTableViewer @@ -584,6 +589,60 @@ 表 [B30] + + TabDb_ChartInfoEditor + + + editor.title + 编辑器 + + + + editor.constant + 定数 + + + + editor.notes + note 数 + + + + editor.tip + 提示 + + + + editor.tip.content + 由于特殊的数据结构,请在编辑<br>定数时填入原数值的 10 倍。<br>举例:Testify [BYD] 的定数是 12.0,<br>则填入 120,而非 12.0。 + + + + editor.delete + 删除 + + + + editor.commit + 提交 + + + + + commit.chartNotSelected + 请先选择一个谱面 + + + + commit.constantRequired + 定数字段为必填项 + + + + deleteConfirm + 确定删除该谱面数据吗? + + TabDb_Manage @@ -782,28 +841,28 @@ 定位器 - + options.masker 遮罩器 - - + + options.useCustom 使用自定义设置 - + dependencies.title OCR 依赖 - + dependencies.knnModel KNearest 模型 - + dependencies.phashDatabase 图像 pHash 数据库 @@ -811,7 +870,7 @@ TabOverview - + databaseDescribeLabel {} {} {} {} {} {} 数据库中有 {} 个曲包,{} 首歌曲,{} 个难度,{} 个谱面信息({} 个完整),{} 个分数记录。 @@ -910,23 +969,17 @@ TabTools_ChartRecommend - + constantRangeFromPlayRating 由单曲 PTT 逆算谱面定数范围 - + chartsByConstant 按定数查谱 - - - refreshButton - 换一批 - - - + chartsRecommendFromPlayRating 由单曲 PTT 结合最好成绩推荐谱面