mirror of
https://github.com/283375/arcaea-offline-pyside-ui.git
synced 2025-07-01 12:26:26 +00:00
init
This commit is contained in:
0
ui/__init__.py
Normal file
0
ui/__init__.py
Normal file
251
ui/designer/components/chartSelector.ui
Normal file
251
ui/designer/components/chartSelector.ui
Normal file
@ -0,0 +1,251 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ChartSelector</class>
|
||||
<widget class="QWidget" name="ChartSelector">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>671</width>
|
||||
<height>295</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">ChartSelector</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainVerticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="songIdSelectorGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>songIdSelector.title</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="fuzzySearchLineEdit">
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>fuzzySearch.lineEdit.placeholder</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="packageComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="songIdComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="songIdSelectorQuickActionsGroupBox">
|
||||
<property name="title">
|
||||
<string>songIdSelector.quickActions</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="previousPackageButton">
|
||||
<property name="text">
|
||||
<string>songIdSelector.quickActions.previousPackageButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="previousSongIdButton">
|
||||
<property name="text">
|
||||
<string>songIdSelector.quickActions.previousSongIdButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="nextSongIdButton">
|
||||
<property name="text">
|
||||
<string>songIdSelector.quickActions.nextSongIdButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="nextPackageButton">
|
||||
<property name="text">
|
||||
<string>songIdSelector.quickActions.nextPackageButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="ratingClassGroupBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>ratingClassSelector.title</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="RatingClassRadioButton" name="pstButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PAST</string>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="RatingClassRadioButton" name="prsButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PRESENT</string>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="RatingClassRadioButton" name="ftrButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">FUTURE</string>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="RatingClassRadioButton" name="bydButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">BEYOND</string>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="resultsHorizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="resultLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="resetButton">
|
||||
<property name="text">
|
||||
<string>resetButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>RatingClassRadioButton</class>
|
||||
<extends>QRadioButton</extends>
|
||||
<header>ui.implements.components.ratingClassRadioButton</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>bydButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
190
ui/designer/components/chartSelector_ui.py
Normal file
190
ui/designer/components/chartSelector_ui.py
Normal file
@ -0,0 +1,190 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'chartSelector.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QComboBox, QGroupBox, QHBoxLayout,
|
||||
QLabel, QLineEdit, QPushButton, QSizePolicy,
|
||||
QSpacerItem, QVBoxLayout, QWidget)
|
||||
|
||||
from ui.implements.components.ratingClassRadioButton import RatingClassRadioButton
|
||||
|
||||
class Ui_ChartSelector(object):
|
||||
def setupUi(self, ChartSelector):
|
||||
if not ChartSelector.objectName():
|
||||
ChartSelector.setObjectName(u"ChartSelector")
|
||||
ChartSelector.resize(671, 295)
|
||||
ChartSelector.setWindowTitle(u"ChartSelector")
|
||||
self.mainVerticalLayout = QVBoxLayout(ChartSelector)
|
||||
self.mainVerticalLayout.setObjectName(u"mainVerticalLayout")
|
||||
self.songIdSelectorGroupBox = QGroupBox(ChartSelector)
|
||||
self.songIdSelectorGroupBox.setObjectName(u"songIdSelectorGroupBox")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.songIdSelectorGroupBox.sizePolicy().hasHeightForWidth())
|
||||
self.songIdSelectorGroupBox.setSizePolicy(sizePolicy)
|
||||
self.horizontalLayout = QHBoxLayout(self.songIdSelectorGroupBox)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.widget = QWidget(self.songIdSelectorGroupBox)
|
||||
self.widget.setObjectName(u"widget")
|
||||
self.widget.setMinimumSize(QSize(300, 0))
|
||||
self.verticalLayout = QVBoxLayout(self.widget)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.fuzzySearchLineEdit = QLineEdit(self.widget)
|
||||
self.fuzzySearchLineEdit.setObjectName(u"fuzzySearchLineEdit")
|
||||
self.fuzzySearchLineEdit.setFrame(True)
|
||||
self.fuzzySearchLineEdit.setClearButtonEnabled(True)
|
||||
|
||||
self.verticalLayout.addWidget(self.fuzzySearchLineEdit)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.verticalLayout.addItem(self.verticalSpacer)
|
||||
|
||||
self.packageComboBox = QComboBox(self.widget)
|
||||
self.packageComboBox.setObjectName(u"packageComboBox")
|
||||
|
||||
self.verticalLayout.addWidget(self.packageComboBox)
|
||||
|
||||
self.songIdComboBox = QComboBox(self.widget)
|
||||
self.songIdComboBox.setObjectName(u"songIdComboBox")
|
||||
|
||||
self.verticalLayout.addWidget(self.songIdComboBox)
|
||||
|
||||
|
||||
self.horizontalLayout.addWidget(self.widget)
|
||||
|
||||
self.songIdSelectorQuickActionsGroupBox = QGroupBox(self.songIdSelectorGroupBox)
|
||||
self.songIdSelectorQuickActionsGroupBox.setObjectName(u"songIdSelectorQuickActionsGroupBox")
|
||||
self.verticalLayout_2 = QVBoxLayout(self.songIdSelectorQuickActionsGroupBox)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.previousPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox)
|
||||
self.previousPackageButton.setObjectName(u"previousPackageButton")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.previousPackageButton)
|
||||
|
||||
self.previousSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox)
|
||||
self.previousSongIdButton.setObjectName(u"previousSongIdButton")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.previousSongIdButton)
|
||||
|
||||
self.nextSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox)
|
||||
self.nextSongIdButton.setObjectName(u"nextSongIdButton")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.nextSongIdButton)
|
||||
|
||||
self.nextPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox)
|
||||
self.nextPackageButton.setObjectName(u"nextPackageButton")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.nextPackageButton)
|
||||
|
||||
|
||||
self.horizontalLayout.addWidget(self.songIdSelectorQuickActionsGroupBox)
|
||||
|
||||
|
||||
self.mainVerticalLayout.addWidget(self.songIdSelectorGroupBox)
|
||||
|
||||
self.ratingClassGroupBox = QGroupBox(ChartSelector)
|
||||
self.ratingClassGroupBox.setObjectName(u"ratingClassGroupBox")
|
||||
self.ratingClassGroupBox.setMinimumSize(QSize(200, 0))
|
||||
self.horizontalLayout_2 = QHBoxLayout(self.ratingClassGroupBox)
|
||||
self.horizontalLayout_2.setSpacing(0)
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.pstButton = RatingClassRadioButton(self.ratingClassGroupBox)
|
||||
self.pstButton.setObjectName(u"pstButton")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.pstButton.sizePolicy().hasHeightForWidth())
|
||||
self.pstButton.setSizePolicy(sizePolicy1)
|
||||
self.pstButton.setText(u"PAST")
|
||||
self.pstButton.setAutoExclusive(False)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.pstButton)
|
||||
|
||||
self.prsButton = RatingClassRadioButton(self.ratingClassGroupBox)
|
||||
self.prsButton.setObjectName(u"prsButton")
|
||||
sizePolicy1.setHeightForWidth(self.prsButton.sizePolicy().hasHeightForWidth())
|
||||
self.prsButton.setSizePolicy(sizePolicy1)
|
||||
self.prsButton.setText(u"PRESENT")
|
||||
self.prsButton.setAutoExclusive(False)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.prsButton)
|
||||
|
||||
self.ftrButton = RatingClassRadioButton(self.ratingClassGroupBox)
|
||||
self.ftrButton.setObjectName(u"ftrButton")
|
||||
sizePolicy1.setHeightForWidth(self.ftrButton.sizePolicy().hasHeightForWidth())
|
||||
self.ftrButton.setSizePolicy(sizePolicy1)
|
||||
self.ftrButton.setText(u"FUTURE")
|
||||
self.ftrButton.setAutoExclusive(False)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.ftrButton)
|
||||
|
||||
self.bydButton = RatingClassRadioButton(self.ratingClassGroupBox)
|
||||
self.bydButton.setObjectName(u"bydButton")
|
||||
self.bydButton.setEnabled(False)
|
||||
sizePolicy1.setHeightForWidth(self.bydButton.sizePolicy().hasHeightForWidth())
|
||||
self.bydButton.setSizePolicy(sizePolicy1)
|
||||
self.bydButton.setText(u"BEYOND")
|
||||
self.bydButton.setAutoExclusive(False)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.bydButton)
|
||||
|
||||
|
||||
self.mainVerticalLayout.addWidget(self.ratingClassGroupBox)
|
||||
|
||||
self.resultsHorizontalLayout = QHBoxLayout()
|
||||
self.resultsHorizontalLayout.setObjectName(u"resultsHorizontalLayout")
|
||||
self.resultLabel = QLabel(ChartSelector)
|
||||
self.resultLabel.setObjectName(u"resultLabel")
|
||||
sizePolicy2 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
sizePolicy2.setHorizontalStretch(0)
|
||||
sizePolicy2.setVerticalStretch(0)
|
||||
sizePolicy2.setHeightForWidth(self.resultLabel.sizePolicy().hasHeightForWidth())
|
||||
self.resultLabel.setSizePolicy(sizePolicy2)
|
||||
self.resultLabel.setText(u"...")
|
||||
self.resultLabel.setTextFormat(Qt.RichText)
|
||||
|
||||
self.resultsHorizontalLayout.addWidget(self.resultLabel)
|
||||
|
||||
self.resetButton = QPushButton(ChartSelector)
|
||||
self.resetButton.setObjectName(u"resetButton")
|
||||
|
||||
self.resultsHorizontalLayout.addWidget(self.resetButton)
|
||||
|
||||
|
||||
self.mainVerticalLayout.addLayout(self.resultsHorizontalLayout)
|
||||
|
||||
|
||||
self.retranslateUi(ChartSelector)
|
||||
|
||||
QMetaObject.connectSlotsByName(ChartSelector)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, ChartSelector):
|
||||
self.songIdSelectorGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"songIdSelector.title", None))
|
||||
self.fuzzySearchLineEdit.setPlaceholderText(QCoreApplication.translate("ChartSelector", u"fuzzySearch.lineEdit.placeholder", None))
|
||||
self.songIdSelectorQuickActionsGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions", None))
|
||||
self.previousPackageButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousPackageButton", None))
|
||||
self.previousSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousSongIdButton", None))
|
||||
self.nextSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.nextSongIdButton", None))
|
||||
self.nextPackageButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.nextPackageButton", None))
|
||||
self.ratingClassGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"ratingClassSelector.title", None))
|
||||
self.resetButton.setText(QCoreApplication.translate("ChartSelector", u"resetButton", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
159
ui/designer/components/dbTableViewer.ui
Normal file
159
ui/designer/components/dbTableViewer.ui
Normal file
@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DbTableViewer</class>
|
||||
<widget class="QWidget" name="DbTableViewer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>681</width>
|
||||
<height>575</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">DbTableViewer</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>actions</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="action_removeSelectedButton">
|
||||
<property name="text">
|
||||
<string>actions.removeSelected</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="refreshButton">
|
||||
<property name="text">
|
||||
<string>actions.refresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTableView" name="tableView">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>view</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>view.sort.label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="sort_comboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="sort_descendingCheckBox">
|
||||
<property name="text">
|
||||
<string>view.sort.descendingCheckBox</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>view.filter.label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>view.filter.configureButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
134
ui/designer/components/dbTableViewer_ui.py
Normal file
134
ui/designer/components/dbTableViewer_ui.py
Normal file
@ -0,0 +1,134 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'dbTableViewer.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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, QCheckBox, QComboBox,
|
||||
QGridLayout, QGroupBox, QHBoxLayout, QHeaderView,
|
||||
QLabel, QPushButton, QSizePolicy, QSpacerItem,
|
||||
QTableView, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_DbTableViewer(object):
|
||||
def setupUi(self, DbTableViewer):
|
||||
if not DbTableViewer.objectName():
|
||||
DbTableViewer.setObjectName(u"DbTableViewer")
|
||||
DbTableViewer.resize(681, 575)
|
||||
DbTableViewer.setWindowTitle(u"DbTableViewer")
|
||||
self.gridLayout = QGridLayout(DbTableViewer)
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.groupBox = QGroupBox(DbTableViewer)
|
||||
self.groupBox.setObjectName(u"groupBox")
|
||||
self.verticalLayout = QVBoxLayout(self.groupBox)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.action_removeSelectedButton = QPushButton(self.groupBox)
|
||||
self.action_removeSelectedButton.setObjectName(u"action_removeSelectedButton")
|
||||
|
||||
self.verticalLayout.addWidget(self.action_removeSelectedButton)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.verticalLayout.addItem(self.verticalSpacer)
|
||||
|
||||
self.refreshButton = QPushButton(self.groupBox)
|
||||
self.refreshButton.setObjectName(u"refreshButton")
|
||||
|
||||
self.verticalLayout.addWidget(self.refreshButton)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.groupBox, 0, 1, 1, 1)
|
||||
|
||||
self.tableView = QTableView(DbTableViewer)
|
||||
self.tableView.setObjectName(u"tableView")
|
||||
self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed)
|
||||
self.tableView.setProperty("showDropIndicator", False)
|
||||
self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
||||
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.tableView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
self.tableView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
self.tableView.verticalHeader().setVisible(False)
|
||||
|
||||
self.gridLayout.addWidget(self.tableView, 0, 0, 1, 1)
|
||||
|
||||
self.groupBox_2 = QGroupBox(DbTableViewer)
|
||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||
self.verticalLayout_3 = QVBoxLayout(self.groupBox_2)
|
||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.label = QLabel(self.groupBox_2)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.label)
|
||||
|
||||
self.sort_comboBox = QComboBox(self.groupBox_2)
|
||||
self.sort_comboBox.setObjectName(u"sort_comboBox")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.sort_comboBox.sizePolicy().hasHeightForWidth())
|
||||
self.sort_comboBox.setSizePolicy(sizePolicy)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.sort_comboBox)
|
||||
|
||||
self.sort_descendingCheckBox = QCheckBox(self.groupBox_2)
|
||||
self.sort_descendingCheckBox.setObjectName(u"sort_descendingCheckBox")
|
||||
self.sort_descendingCheckBox.setChecked(True)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.sort_descendingCheckBox)
|
||||
|
||||
|
||||
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.horizontalLayout.setContentsMargins(-1, 9, -1, 9)
|
||||
self.label_2 = QLabel(self.groupBox_2)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
|
||||
self.horizontalLayout.addWidget(self.label_2)
|
||||
|
||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.horizontalLayout.addItem(self.horizontalSpacer)
|
||||
|
||||
self.pushButton = QPushButton(self.groupBox_2)
|
||||
self.pushButton.setObjectName(u"pushButton")
|
||||
|
||||
self.horizontalLayout.addWidget(self.pushButton)
|
||||
|
||||
|
||||
self.verticalLayout_3.addLayout(self.horizontalLayout)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.groupBox_2, 1, 0, 1, 1)
|
||||
|
||||
|
||||
self.retranslateUi(DbTableViewer)
|
||||
|
||||
QMetaObject.connectSlotsByName(DbTableViewer)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, DbTableViewer):
|
||||
self.groupBox.setTitle(QCoreApplication.translate("DbTableViewer", u"actions", None))
|
||||
self.action_removeSelectedButton.setText(QCoreApplication.translate("DbTableViewer", u"actions.removeSelected", None))
|
||||
self.refreshButton.setText(QCoreApplication.translate("DbTableViewer", u"actions.refresh", None))
|
||||
self.groupBox_2.setTitle(QCoreApplication.translate("DbTableViewer", u"view", None))
|
||||
self.label.setText(QCoreApplication.translate("DbTableViewer", u"view.sort.label", None))
|
||||
self.sort_descendingCheckBox.setText(QCoreApplication.translate("DbTableViewer", u"view.sort.descendingCheckBox", None))
|
||||
self.label_2.setText(QCoreApplication.translate("DbTableViewer", u"view.filter.label", None))
|
||||
self.pushButton.setText(QCoreApplication.translate("DbTableViewer", u"view.filter.configureButton", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
60
ui/designer/components/fileSelector.ui
Normal file
60
ui/designer/components/fileSelector.ui
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FileSelector</class>
|
||||
<widget class="QWidget" name="FileSelector">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<height>42</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">FileSelector</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ElidedLabel" name="elidedLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="selectButton">
|
||||
<property name="text">
|
||||
<string>selectButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ElidedLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>ui.implements.components.elidedLabel</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
58
ui/designer/components/fileSelector_ui.py
Normal file
58
ui/designer/components/fileSelector_ui.py
Normal file
@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'fileSelector.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QHBoxLayout, QPushButton, QSizePolicy,
|
||||
QWidget)
|
||||
|
||||
from ui.implements.components.elidedLabel import ElidedLabel
|
||||
|
||||
class Ui_FileSelector(object):
|
||||
def setupUi(self, FileSelector):
|
||||
if not FileSelector.objectName():
|
||||
FileSelector.setObjectName(u"FileSelector")
|
||||
FileSelector.resize(559, 42)
|
||||
FileSelector.setWindowTitle(u"FileSelector")
|
||||
self.horizontalLayout_2 = QHBoxLayout(FileSelector)
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.elidedLabel = ElidedLabel(FileSelector)
|
||||
self.elidedLabel.setObjectName(u"elidedLabel")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.elidedLabel.sizePolicy().hasHeightForWidth())
|
||||
self.elidedLabel.setSizePolicy(sizePolicy)
|
||||
self.elidedLabel.setText(u"...")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.elidedLabel)
|
||||
|
||||
self.selectButton = QPushButton(FileSelector)
|
||||
self.selectButton.setObjectName(u"selectButton")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.selectButton)
|
||||
|
||||
|
||||
self.retranslateUi(FileSelector)
|
||||
|
||||
QMetaObject.connectSlotsByName(FileSelector)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, FileSelector):
|
||||
self.selectButton.setText(QCoreApplication.translate("FileSelector", u"selectButton", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
228
ui/designer/components/scoreEditor.ui
Normal file
228
ui/designer/components/scoreEditor.ui
Normal file
@ -0,0 +1,228 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScoreEditor</class>
|
||||
<widget class="QWidget" name="ScoreEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>365</width>
|
||||
<height>253</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">ScoreEditor</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>formLabel.score</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="FocusSelectAllLineEdit" name="scoreLineEdit">
|
||||
<property name="inputMask">
|
||||
<string notr="true">B9'999'999;_</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string notr="true">PURE</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="pureSpinBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string notr="true">FAR</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="farSpinBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string notr="true">LOST</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="lostSpinBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>formLabel.time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDateTimeEdit" name="dateTimeEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="dateTime">
|
||||
<datetime>
|
||||
<hour>0</hour>
|
||||
<minute>0</minute>
|
||||
<second>0</second>
|
||||
<year>2017</year>
|
||||
<month>1</month>
|
||||
<day>22</day>
|
||||
</datetime>
|
||||
</property>
|
||||
<property name="minimumDate">
|
||||
<date>
|
||||
<year>2017</year>
|
||||
<month>1</month>
|
||||
<day>22</day>
|
||||
</date>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string notr="true">MAX RECALL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="maxRecallSpinBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="validateLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="commitButton">
|
||||
<property name="text">
|
||||
<string>commitButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>formLabel.clearType</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QComboBox" name="clearTypeComboBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FocusSelectAllLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>ui.implements.components.focusSelectAllLineEdit</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
167
ui/designer/components/scoreEditor_ui.py
Normal file
167
ui/designer/components/scoreEditor_ui.py
Normal file
@ -0,0 +1,167 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'scoreEditor.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QComboBox, QDateTimeEdit, QFormLayout,
|
||||
QHBoxLayout, QLabel, QPushButton, QSizePolicy,
|
||||
QSpacerItem, QSpinBox, QWidget)
|
||||
|
||||
from ui.implements.components.focusSelectAllLineEdit import FocusSelectAllLineEdit
|
||||
|
||||
class Ui_ScoreEditor(object):
|
||||
def setupUi(self, ScoreEditor):
|
||||
if not ScoreEditor.objectName():
|
||||
ScoreEditor.setObjectName(u"ScoreEditor")
|
||||
ScoreEditor.resize(365, 253)
|
||||
ScoreEditor.setWindowTitle(u"ScoreEditor")
|
||||
self.formLayout = QFormLayout(ScoreEditor)
|
||||
self.formLayout.setObjectName(u"formLayout")
|
||||
self.formLayout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
|
||||
self.formLayout.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
self.label = QLabel(ScoreEditor)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label)
|
||||
|
||||
self.scoreLineEdit = FocusSelectAllLineEdit(ScoreEditor)
|
||||
self.scoreLineEdit.setObjectName(u"scoreLineEdit")
|
||||
self.scoreLineEdit.setInputMask(u"B9'999'999;_")
|
||||
|
||||
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.scoreLineEdit)
|
||||
|
||||
self.label_2 = QLabel(ScoreEditor)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
self.label_2.setText(u"PURE")
|
||||
|
||||
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2)
|
||||
|
||||
self.pureSpinBox = QSpinBox(ScoreEditor)
|
||||
self.pureSpinBox.setObjectName(u"pureSpinBox")
|
||||
self.pureSpinBox.setMinimumSize(QSize(100, 0))
|
||||
self.pureSpinBox.setMaximum(0)
|
||||
|
||||
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.pureSpinBox)
|
||||
|
||||
self.label_3 = QLabel(ScoreEditor)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
self.label_3.setText(u"FAR")
|
||||
|
||||
self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3)
|
||||
|
||||
self.farSpinBox = QSpinBox(ScoreEditor)
|
||||
self.farSpinBox.setObjectName(u"farSpinBox")
|
||||
self.farSpinBox.setMinimumSize(QSize(100, 0))
|
||||
self.farSpinBox.setMaximum(0)
|
||||
|
||||
self.formLayout.setWidget(2, QFormLayout.FieldRole, self.farSpinBox)
|
||||
|
||||
self.label_4 = QLabel(ScoreEditor)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
self.label_4.setText(u"LOST")
|
||||
|
||||
self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_4)
|
||||
|
||||
self.lostSpinBox = QSpinBox(ScoreEditor)
|
||||
self.lostSpinBox.setObjectName(u"lostSpinBox")
|
||||
self.lostSpinBox.setMinimumSize(QSize(100, 0))
|
||||
self.lostSpinBox.setMaximum(0)
|
||||
|
||||
self.formLayout.setWidget(3, QFormLayout.FieldRole, self.lostSpinBox)
|
||||
|
||||
self.label_5 = QLabel(ScoreEditor)
|
||||
self.label_5.setObjectName(u"label_5")
|
||||
|
||||
self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label_5)
|
||||
|
||||
self.dateTimeEdit = QDateTimeEdit(ScoreEditor)
|
||||
self.dateTimeEdit.setObjectName(u"dateTimeEdit")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.dateTimeEdit.sizePolicy().hasHeightForWidth())
|
||||
self.dateTimeEdit.setSizePolicy(sizePolicy)
|
||||
self.dateTimeEdit.setDateTime(QDateTime(QDate(2017, 1, 22), QTime(0, 0, 0)))
|
||||
self.dateTimeEdit.setMinimumDate(QDate(2017, 1, 22))
|
||||
|
||||
self.formLayout.setWidget(4, QFormLayout.FieldRole, self.dateTimeEdit)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.formLayout.setItem(5, QFormLayout.LabelRole, self.verticalSpacer)
|
||||
|
||||
self.label_6 = QLabel(ScoreEditor)
|
||||
self.label_6.setObjectName(u"label_6")
|
||||
self.label_6.setText(u"MAX RECALL")
|
||||
|
||||
self.formLayout.setWidget(6, QFormLayout.LabelRole, self.label_6)
|
||||
|
||||
self.maxRecallSpinBox = QSpinBox(ScoreEditor)
|
||||
self.maxRecallSpinBox.setObjectName(u"maxRecallSpinBox")
|
||||
self.maxRecallSpinBox.setMinimumSize(QSize(100, 0))
|
||||
self.maxRecallSpinBox.setMinimum(-1)
|
||||
self.maxRecallSpinBox.setMaximum(0)
|
||||
self.maxRecallSpinBox.setValue(-1)
|
||||
|
||||
self.formLayout.setWidget(6, QFormLayout.FieldRole, self.maxRecallSpinBox)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.validateLabel = QLabel(ScoreEditor)
|
||||
self.validateLabel.setObjectName(u"validateLabel")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.validateLabel.sizePolicy().hasHeightForWidth())
|
||||
self.validateLabel.setSizePolicy(sizePolicy1)
|
||||
self.validateLabel.setText(u"...")
|
||||
self.validateLabel.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
|
||||
self.horizontalLayout.addWidget(self.validateLabel)
|
||||
|
||||
self.commitButton = QPushButton(ScoreEditor)
|
||||
self.commitButton.setObjectName(u"commitButton")
|
||||
|
||||
self.horizontalLayout.addWidget(self.commitButton)
|
||||
|
||||
|
||||
self.formLayout.setLayout(8, QFormLayout.SpanningRole, self.horizontalLayout)
|
||||
|
||||
self.label_8 = QLabel(ScoreEditor)
|
||||
self.label_8.setObjectName(u"label_8")
|
||||
|
||||
self.formLayout.setWidget(7, QFormLayout.LabelRole, self.label_8)
|
||||
|
||||
self.clearTypeComboBox = QComboBox(ScoreEditor)
|
||||
self.clearTypeComboBox.setObjectName(u"clearTypeComboBox")
|
||||
self.clearTypeComboBox.setEnabled(False)
|
||||
self.clearTypeComboBox.setMinimumSize(QSize(100, 0))
|
||||
|
||||
self.formLayout.setWidget(7, QFormLayout.FieldRole, self.clearTypeComboBox)
|
||||
|
||||
|
||||
self.retranslateUi(ScoreEditor)
|
||||
|
||||
QMetaObject.connectSlotsByName(ScoreEditor)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, ScoreEditor):
|
||||
self.label.setText(QCoreApplication.translate("ScoreEditor", u"formLabel.score", None))
|
||||
self.label_5.setText(QCoreApplication.translate("ScoreEditor", u"formLabel.time", None))
|
||||
self.commitButton.setText(QCoreApplication.translate("ScoreEditor", u"commitButton", None))
|
||||
self.label_8.setText(QCoreApplication.translate("ScoreEditor", u"formLabel.clearType", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
92
ui/designer/mainwindow.ui
Normal file
92
ui/designer/mainwindow.ui
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>601</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Arcaea Offline</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="TabOverview" name="tab_overview">
|
||||
<attribute name="title">
|
||||
<string>tab.overview</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="TabInputScore" name="tab_input">
|
||||
<attribute name="title">
|
||||
<string>tab.input</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="TabDbEntry" name="tab_db">
|
||||
<attribute name="title">
|
||||
<string>tab.db</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_ocr">
|
||||
<attribute name="title">
|
||||
<string>tab.ocr</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="TabSettings" name="tab_settings">
|
||||
<attribute name="title">
|
||||
<string>tab.settings</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="TabAbout" name="tab_about">
|
||||
<attribute name="title">
|
||||
<string>tab.about</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TabInputScore</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.tabs.tabInputScore</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TabOverview</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.tabs.tabOverview</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TabSettings</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.tabs.tabSettings</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TabAbout</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.tabs.tabAbout</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TabDbEntry</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.tabs.tabDbEntry</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
79
ui/designer/mainwindow_ui.py
Normal file
79
ui/designer/mainwindow_ui.py
Normal file
@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'mainwindow.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QMainWindow, QSizePolicy, QTabWidget,
|
||||
QVBoxLayout, QWidget)
|
||||
|
||||
from ui.implements.tabs.tabAbout import TabAbout
|
||||
from ui.implements.tabs.tabDbEntry import TabDbEntry
|
||||
from ui.implements.tabs.tabInputScore import TabInputScore
|
||||
from ui.implements.tabs.tabOverview import TabOverview
|
||||
from ui.implements.tabs.tabSettings import TabSettings
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
if not MainWindow.objectName():
|
||||
MainWindow.setObjectName(u"MainWindow")
|
||||
MainWindow.resize(800, 601)
|
||||
MainWindow.setWindowTitle(u"Arcaea Offline")
|
||||
self.centralwidget = QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName(u"centralwidget")
|
||||
self.verticalLayout = QVBoxLayout(self.centralwidget)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.tabWidget = QTabWidget(self.centralwidget)
|
||||
self.tabWidget.setObjectName(u"tabWidget")
|
||||
self.tab_overview = TabOverview()
|
||||
self.tab_overview.setObjectName(u"tab_overview")
|
||||
self.tabWidget.addTab(self.tab_overview, "")
|
||||
self.tab_input = TabInputScore()
|
||||
self.tab_input.setObjectName(u"tab_input")
|
||||
self.tabWidget.addTab(self.tab_input, "")
|
||||
self.tab_db = TabDbEntry()
|
||||
self.tab_db.setObjectName(u"tab_db")
|
||||
self.tabWidget.addTab(self.tab_db, "")
|
||||
self.tab_ocr = QWidget()
|
||||
self.tab_ocr.setObjectName(u"tab_ocr")
|
||||
self.tabWidget.addTab(self.tab_ocr, "")
|
||||
self.tab_settings = TabSettings()
|
||||
self.tab_settings.setObjectName(u"tab_settings")
|
||||
self.tabWidget.addTab(self.tab_settings, "")
|
||||
self.tab_about = TabAbout()
|
||||
self.tab_about.setObjectName(u"tab_about")
|
||||
self.tabWidget.addTab(self.tab_about, "")
|
||||
|
||||
self.verticalLayout.addWidget(self.tabWidget)
|
||||
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
|
||||
|
||||
QMetaObject.connectSlotsByName(MainWindow)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_overview), QCoreApplication.translate("MainWindow", u"tab.overview", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_input), QCoreApplication.translate("MainWindow", u"tab.input", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_db), QCoreApplication.translate("MainWindow", u"tab.db", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_ocr), QCoreApplication.translate("MainWindow", u"tab.ocr", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_settings), QCoreApplication.translate("MainWindow", u"tab.settings", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_about), QCoreApplication.translate("MainWindow", u"tab.about", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
168
ui/designer/settings/settingsDefault.ui
Normal file
168
ui/designer/settings/settingsDefault.ui
Normal file
@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SettingsDefault</class>
|
||||
<widget class="QWidget" name="SettingsDefault">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>682</width>
|
||||
<height>493</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">SettingsDefault</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="rowWrapPolicy">
|
||||
<enum>QFormLayout::DontWrapRows</enum>
|
||||
</property>
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>devicesJsonFile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="FileSelector" name="devicesJsonFileSelector" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="devicesJsonFileResetButton">
|
||||
<property name="text">
|
||||
<string>devicesJsonPath.resetButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>deviceUuid</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="DevicesComboBox" name="devicesComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deviceUuidResetButton">
|
||||
<property name="text">
|
||||
<string>defaultDevice.resetButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>tesseractFile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="FileSelector" name="tesseractFileSelector" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>500000</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FileSelector</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.components.fileSelector</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>DevicesComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>ui.implements.components</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
130
ui/designer/settings/settingsDefault_ui.py
Normal file
130
ui/designer/settings/settingsDefault_ui.py
Normal file
@ -0,0 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'settingsDefault.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QFormLayout, QHBoxLayout, QLabel,
|
||||
QPushButton, QSizePolicy, QSpacerItem, QWidget)
|
||||
|
||||
from ui.implements.components import DevicesComboBox
|
||||
from ui.implements.components.fileSelector import FileSelector
|
||||
|
||||
class Ui_SettingsDefault(object):
|
||||
def setupUi(self, SettingsDefault):
|
||||
if not SettingsDefault.objectName():
|
||||
SettingsDefault.setObjectName(u"SettingsDefault")
|
||||
SettingsDefault.resize(682, 493)
|
||||
SettingsDefault.setWindowTitle(u"SettingsDefault")
|
||||
self.formLayout = QFormLayout(SettingsDefault)
|
||||
self.formLayout.setObjectName(u"formLayout")
|
||||
self.formLayout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
|
||||
self.formLayout.setRowWrapPolicy(QFormLayout.DontWrapRows)
|
||||
self.formLayout.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
self.label_2 = QLabel(SettingsDefault)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
|
||||
self.label_2.setSizePolicy(sizePolicy)
|
||||
|
||||
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_2)
|
||||
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.devicesJsonFileSelector = FileSelector(SettingsDefault)
|
||||
self.devicesJsonFileSelector.setObjectName(u"devicesJsonFileSelector")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.devicesJsonFileSelector.sizePolicy().hasHeightForWidth())
|
||||
self.devicesJsonFileSelector.setSizePolicy(sizePolicy1)
|
||||
self.devicesJsonFileSelector.setMinimumSize(QSize(200, 0))
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.devicesJsonFileSelector)
|
||||
|
||||
self.devicesJsonFileResetButton = QPushButton(SettingsDefault)
|
||||
self.devicesJsonFileResetButton.setObjectName(u"devicesJsonFileResetButton")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.devicesJsonFileResetButton)
|
||||
|
||||
|
||||
self.formLayout.setLayout(0, QFormLayout.FieldRole, self.horizontalLayout_2)
|
||||
|
||||
self.label_3 = QLabel(SettingsDefault)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth())
|
||||
self.label_3.setSizePolicy(sizePolicy)
|
||||
|
||||
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_3)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.devicesComboBox = DevicesComboBox(SettingsDefault)
|
||||
self.devicesComboBox.setObjectName(u"devicesComboBox")
|
||||
sizePolicy2 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
sizePolicy2.setHorizontalStretch(0)
|
||||
sizePolicy2.setVerticalStretch(0)
|
||||
sizePolicy2.setHeightForWidth(self.devicesComboBox.sizePolicy().hasHeightForWidth())
|
||||
self.devicesComboBox.setSizePolicy(sizePolicy2)
|
||||
self.devicesComboBox.setMinimumSize(QSize(200, 0))
|
||||
|
||||
self.horizontalLayout.addWidget(self.devicesComboBox)
|
||||
|
||||
self.deviceUuidResetButton = QPushButton(SettingsDefault)
|
||||
self.deviceUuidResetButton.setObjectName(u"deviceUuidResetButton")
|
||||
|
||||
self.horizontalLayout.addWidget(self.deviceUuidResetButton)
|
||||
|
||||
|
||||
self.formLayout.setLayout(1, QFormLayout.FieldRole, self.horizontalLayout)
|
||||
|
||||
self.label_4 = QLabel(SettingsDefault)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth())
|
||||
self.label_4.setSizePolicy(sizePolicy)
|
||||
|
||||
self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_4)
|
||||
|
||||
self.tesseractFileSelector = FileSelector(SettingsDefault)
|
||||
self.tesseractFileSelector.setObjectName(u"tesseractFileSelector")
|
||||
sizePolicy3 = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
|
||||
sizePolicy3.setHorizontalStretch(0)
|
||||
sizePolicy3.setVerticalStretch(0)
|
||||
sizePolicy3.setHeightForWidth(self.tesseractFileSelector.sizePolicy().hasHeightForWidth())
|
||||
self.tesseractFileSelector.setSizePolicy(sizePolicy3)
|
||||
self.tesseractFileSelector.setMinimumSize(QSize(200, 0))
|
||||
|
||||
self.formLayout.setWidget(3, QFormLayout.FieldRole, self.tesseractFileSelector)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 500000, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.formLayout.setItem(5, QFormLayout.FieldRole, self.verticalSpacer)
|
||||
|
||||
|
||||
self.retranslateUi(SettingsDefault)
|
||||
|
||||
QMetaObject.connectSlotsByName(SettingsDefault)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, SettingsDefault):
|
||||
self.label_2.setText(QCoreApplication.translate("SettingsDefault", u"devicesJsonFile", None))
|
||||
self.devicesJsonFileResetButton.setText(QCoreApplication.translate("SettingsDefault", u"devicesJsonPath.resetButton", None))
|
||||
self.label_3.setText(QCoreApplication.translate("SettingsDefault", u"deviceUuid", None))
|
||||
self.deviceUuidResetButton.setText(QCoreApplication.translate("SettingsDefault", u"defaultDevice.resetButton", None))
|
||||
self.label_4.setText(QCoreApplication.translate("SettingsDefault", u"tesseractFile", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
102
ui/designer/tabs/tabAbout.ui
Normal file
102
ui/designer/tabs/tabAbout.ui
Normal file
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabAbout</class>
|
||||
<widget class="QWidget" name="TabAbout">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>587</width>
|
||||
<height>431</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabAbout</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="logoLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">arcaea-offline-pyside-ui</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignHCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string notr="true">A part of <a href="https://github.com/283375/arcaea-offline">arcaea-offline project</a></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="aboutQtButton">
|
||||
<property name="text">
|
||||
<string>About Qt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
87
ui/designer/tabs/tabAbout_ui.py
Normal file
87
ui/designer/tabs/tabAbout_ui.py
Normal file
@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabAbout.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QHBoxLayout, QLabel, QPushButton,
|
||||
QSizePolicy, QSpacerItem, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_TabAbout(object):
|
||||
def setupUi(self, TabAbout):
|
||||
if not TabAbout.objectName():
|
||||
TabAbout.setObjectName(u"TabAbout")
|
||||
TabAbout.resize(587, 431)
|
||||
TabAbout.setWindowTitle(u"TabAbout")
|
||||
self.verticalLayout = QVBoxLayout(TabAbout)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.logoLabel = QLabel(TabAbout)
|
||||
self.logoLabel.setObjectName(u"logoLabel")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.logoLabel.sizePolicy().hasHeightForWidth())
|
||||
self.logoLabel.setSizePolicy(sizePolicy)
|
||||
self.logoLabel.setText(u"")
|
||||
self.logoLabel.setAlignment(Qt.AlignCenter)
|
||||
|
||||
self.verticalLayout.addWidget(self.logoLabel)
|
||||
|
||||
self.label = QLabel(TabAbout)
|
||||
self.label.setObjectName(u"label")
|
||||
font = QFont()
|
||||
font.setPointSize(14)
|
||||
self.label.setFont(font)
|
||||
self.label.setText(u"arcaea-offline-pyside-ui")
|
||||
self.label.setAlignment(Qt.AlignBottom|Qt.AlignHCenter)
|
||||
|
||||
self.verticalLayout.addWidget(self.label)
|
||||
|
||||
self.label_2 = QLabel(TabAbout)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
self.label_2.setText(u"A part of <a href=\"https://github.com/283375/arcaea-offline\">arcaea-offline project</a>")
|
||||
self.label_2.setAlignment(Qt.AlignHCenter|Qt.AlignTop)
|
||||
self.label_2.setOpenExternalLinks(True)
|
||||
|
||||
self.verticalLayout.addWidget(self.label_2)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.horizontalLayout.addItem(self.horizontalSpacer)
|
||||
|
||||
self.aboutQtButton = QPushButton(TabAbout)
|
||||
self.aboutQtButton.setObjectName(u"aboutQtButton")
|
||||
|
||||
self.horizontalLayout.addWidget(self.aboutQtButton)
|
||||
|
||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.horizontalLayout.addItem(self.horizontalSpacer_2)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
|
||||
self.retranslateUi(TabAbout)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabAbout)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabAbout):
|
||||
self.aboutQtButton.setText(QCoreApplication.translate("TabAbout", u"About Qt", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
38
ui/designer/tabs/tabDb/tabDb_Manage.ui
Normal file
38
ui/designer/tabs/tabDb/tabDb_Manage.ui
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabDb_Manage</class>
|
||||
<widget class="QWidget" name="TabDb_Manage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>630</width>
|
||||
<height>528</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabDb_Manage</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="syncArcSongDbButton">
|
||||
<property name="text">
|
||||
<string>syncArcSongDbButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>syncArcSongDb.description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
51
ui/designer/tabs/tabDb/tabDb_Manage_ui.py
Normal file
51
ui/designer/tabs/tabDb/tabDb_Manage_ui.py
Normal file
@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabDb_Manage.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QFormLayout, QLabel, QPushButton,
|
||||
QSizePolicy, QWidget)
|
||||
|
||||
class Ui_TabDb_Manage(object):
|
||||
def setupUi(self, TabDb_Manage):
|
||||
if not TabDb_Manage.objectName():
|
||||
TabDb_Manage.setObjectName(u"TabDb_Manage")
|
||||
TabDb_Manage.resize(630, 528)
|
||||
TabDb_Manage.setWindowTitle(u"TabDb_Manage")
|
||||
self.formLayout = QFormLayout(TabDb_Manage)
|
||||
self.formLayout.setObjectName(u"formLayout")
|
||||
self.formLayout.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
self.syncArcSongDbButton = QPushButton(TabDb_Manage)
|
||||
self.syncArcSongDbButton.setObjectName(u"syncArcSongDbButton")
|
||||
|
||||
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.syncArcSongDbButton)
|
||||
|
||||
self.label = QLabel(TabDb_Manage)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.label)
|
||||
|
||||
|
||||
self.retranslateUi(TabDb_Manage)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabDb_Manage)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabDb_Manage):
|
||||
self.syncArcSongDbButton.setText(QCoreApplication.translate("TabDb_Manage", u"syncArcSongDbButton", None))
|
||||
self.label.setText(QCoreApplication.translate("TabDb_Manage", u"syncArcSongDb.description", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
41
ui/designer/tabs/tabDbEntry.ui
Normal file
41
ui/designer/tabs/tabDbEntry.ui
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabDbEntry</class>
|
||||
<widget class="QWidget" name="TabDbEntry">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>648</width>
|
||||
<height>579</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabDbEntry</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="TabDb_Manage" name="tab_manage">
|
||||
<attribute name="title">
|
||||
<string>tab.manage</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TabDb_Manage</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.tabs.tabDb.tabDb_Manage</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
52
ui/designer/tabs/tabDbEntry_ui.py
Normal file
52
ui/designer/tabs/tabDbEntry_ui.py
Normal file
@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabDbEntry.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QSizePolicy, QTabWidget, QVBoxLayout,
|
||||
QWidget)
|
||||
|
||||
from ui.implements.tabs.tabDb.tabDb_Manage import TabDb_Manage
|
||||
|
||||
class Ui_TabDbEntry(object):
|
||||
def setupUi(self, TabDbEntry):
|
||||
if not TabDbEntry.objectName():
|
||||
TabDbEntry.setObjectName(u"TabDbEntry")
|
||||
TabDbEntry.resize(648, 579)
|
||||
TabDbEntry.setWindowTitle(u"TabDbEntry")
|
||||
self.verticalLayout = QVBoxLayout(TabDbEntry)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.tabWidget = QTabWidget(TabDbEntry)
|
||||
self.tabWidget.setObjectName(u"tabWidget")
|
||||
self.tab_manage = TabDb_Manage()
|
||||
self.tab_manage.setObjectName(u"tab_manage")
|
||||
self.tabWidget.addTab(self.tab_manage, "")
|
||||
|
||||
self.verticalLayout.addWidget(self.tabWidget)
|
||||
|
||||
|
||||
self.retranslateUi(TabDbEntry)
|
||||
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
|
||||
|
||||
QMetaObject.connectSlotsByName(TabDbEntry)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabDbEntry):
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_manage), QCoreApplication.translate("TabDbEntry", u"tab.manage", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
89
ui/designer/tabs/tabInputScore.ui
Normal file
89
ui/designer/tabs/tabInputScore.ui
Normal file
@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabInputScore</class>
|
||||
<widget class="QWidget" name="TabInputScore">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>514</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabInputScore</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>tab.selectChart</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ChartSelector" name="chartSelector" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>tab.scoreEdit</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ScoreEditor" name="scoreEditor" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ChartSelector</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.components.chartSelector</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ScoreEditor</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.components.scoreEditor</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
74
ui/designer/tabs/tabInputScore_ui.py
Normal file
74
ui/designer/tabs/tabInputScore_ui.py
Normal file
@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabInputScore.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QGroupBox, QSizePolicy, QVBoxLayout,
|
||||
QWidget)
|
||||
|
||||
from ui.implements.components.chartSelector import ChartSelector
|
||||
from ui.implements.components.scoreEditor import ScoreEditor
|
||||
|
||||
class Ui_TabInputScore(object):
|
||||
def setupUi(self, TabInputScore):
|
||||
if not TabInputScore.objectName():
|
||||
TabInputScore.setObjectName(u"TabInputScore")
|
||||
TabInputScore.resize(514, 400)
|
||||
TabInputScore.setWindowTitle(u"TabInputScore")
|
||||
self.verticalLayout = QVBoxLayout(TabInputScore)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.groupBox = QGroupBox(TabInputScore)
|
||||
self.groupBox.setObjectName(u"groupBox")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
|
||||
self.groupBox.setSizePolicy(sizePolicy)
|
||||
self.verticalLayout_2 = QVBoxLayout(self.groupBox)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.chartSelector = ChartSelector(self.groupBox)
|
||||
self.chartSelector.setObjectName(u"chartSelector")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.chartSelector)
|
||||
|
||||
|
||||
self.verticalLayout.addWidget(self.groupBox)
|
||||
|
||||
self.groupBox_2 = QGroupBox(TabInputScore)
|
||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||
self.verticalLayout_3 = QVBoxLayout(self.groupBox_2)
|
||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||
self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
|
||||
self.scoreEditor = ScoreEditor(self.groupBox_2)
|
||||
self.scoreEditor.setObjectName(u"scoreEditor")
|
||||
|
||||
self.verticalLayout_3.addWidget(self.scoreEditor)
|
||||
|
||||
|
||||
self.verticalLayout.addWidget(self.groupBox_2)
|
||||
|
||||
|
||||
self.retranslateUi(TabInputScore)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabInputScore)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabInputScore):
|
||||
self.groupBox.setTitle(QCoreApplication.translate("TabInputScore", u"tab.selectChart", None))
|
||||
self.groupBox_2.setTitle(QCoreApplication.translate("TabInputScore", u"tab.scoreEdit", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
198
ui/designer/tabs/tabOcr.ui
Normal file
198
ui/designer/tabs/tabOcr.ui
Normal file
@ -0,0 +1,198 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabOcr</class>
|
||||
<widget class="QWidget" name="TabOcr">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>632</width>
|
||||
<height>527</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabOcr</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="openWizardButton">
|
||||
<property name="text">
|
||||
<string>openWizardButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>deviceSelector.title</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="FileSelector" name="deviceFileSelector" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="DevicesComboBox" name="deviceComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>tesseractSelector.title</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="FileSelector" name="tesseractFileSelector" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>ocr.title</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>ocr.queue.title</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="ocr_addImageButton">
|
||||
<property name="text">
|
||||
<string>ocr.queue.addImageButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ocr_removeSelectedButton">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ocr.queue.removeSelected</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ocr_removeAllButton">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ocr.queue.removeAll</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ocr_startButton">
|
||||
<property name="text">
|
||||
<string>ocr.queue.startOcrButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>ocr.results</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="ocr_acceptSelectedButton">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ocr.results.acceptSelectedButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ocr_acceptAllButton">
|
||||
<property name="text">
|
||||
<string>ocr.results.acceptAllButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ocr_ignoreValidateCheckBox">
|
||||
<property name="text">
|
||||
<string>ocr.results.ignoreValidate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FileSelector</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.components</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>DevicesComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>ui.implements.components</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
105
ui/designer/tabs/tabOcrDisabled.ui
Normal file
105
ui/designer/tabs/tabOcrDisabled.ui
Normal file
@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabOcrDisabled</class>
|
||||
<widget class="QWidget" name="TabOcrDisabled">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>468</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabOcrDisabled</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>ocrDisabled.title</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="contentLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
80
ui/designer/tabs/tabOcrDisabled_ui.py
Normal file
80
ui/designer/tabs/tabOcrDisabled_ui.py
Normal file
@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabOcrDisabled.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QGridLayout, QLabel, QSizePolicy,
|
||||
QSpacerItem, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_TabOcrDisabled(object):
|
||||
def setupUi(self, TabOcrDisabled):
|
||||
if not TabOcrDisabled.objectName():
|
||||
TabOcrDisabled.setObjectName(u"TabOcrDisabled")
|
||||
TabOcrDisabled.resize(564, 468)
|
||||
TabOcrDisabled.setWindowTitle(u"TabOcrDisabled")
|
||||
self.gridLayout = QGridLayout(TabOcrDisabled)
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.gridLayout.addItem(self.horizontalSpacer, 1, 0, 1, 1)
|
||||
|
||||
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.gridLayout.addItem(self.verticalSpacer_2, 2, 1, 1, 1)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.gridLayout.addItem(self.verticalSpacer, 0, 1, 1, 1)
|
||||
|
||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.gridLayout.addItem(self.horizontalSpacer_2, 1, 2, 1, 1)
|
||||
|
||||
self.widget = QWidget(TabOcrDisabled)
|
||||
self.widget.setObjectName(u"widget")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
|
||||
self.widget.setSizePolicy(sizePolicy)
|
||||
self.verticalLayout = QVBoxLayout(self.widget)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.label = QLabel(self.widget)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.verticalLayout.addWidget(self.label)
|
||||
|
||||
self.contentLabel = QLabel(self.widget)
|
||||
self.contentLabel.setObjectName(u"contentLabel")
|
||||
sizePolicy.setHeightForWidth(self.contentLabel.sizePolicy().hasHeightForWidth())
|
||||
self.contentLabel.setSizePolicy(sizePolicy)
|
||||
self.contentLabel.setText(u"...")
|
||||
|
||||
self.verticalLayout.addWidget(self.contentLabel)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.widget, 1, 1, 1, 1)
|
||||
|
||||
|
||||
self.retranslateUi(TabOcrDisabled)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabOcrDisabled)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabOcrDisabled):
|
||||
self.label.setText(QCoreApplication.translate("TabOcrDisabled", u"ocrDisabled.title", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
165
ui/designer/tabs/tabOcr_ui.py
Normal file
165
ui/designer/tabs/tabOcr_ui.py
Normal file
@ -0,0 +1,165 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabOcr.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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, QCheckBox, QGroupBox,
|
||||
QHBoxLayout, QHeaderView, QPushButton, QSizePolicy,
|
||||
QSpacerItem, QTableView, QVBoxLayout, QWidget)
|
||||
|
||||
from ui.implements.components import (DevicesComboBox, FileSelector)
|
||||
|
||||
class Ui_TabOcr(object):
|
||||
def setupUi(self, TabOcr):
|
||||
if not TabOcr.objectName():
|
||||
TabOcr.setObjectName(u"TabOcr")
|
||||
TabOcr.resize(632, 527)
|
||||
TabOcr.setWindowTitle(u"TabOcr")
|
||||
self.verticalLayout_3 = QVBoxLayout(TabOcr)
|
||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||
self.openWizardButton = QPushButton(TabOcr)
|
||||
self.openWizardButton.setObjectName(u"openWizardButton")
|
||||
|
||||
self.verticalLayout_3.addWidget(self.openWizardButton)
|
||||
|
||||
self.groupBox = QGroupBox(TabOcr)
|
||||
self.groupBox.setObjectName(u"groupBox")
|
||||
self.verticalLayout = QVBoxLayout(self.groupBox)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.deviceFileSelector = FileSelector(self.groupBox)
|
||||
self.deviceFileSelector.setObjectName(u"deviceFileSelector")
|
||||
|
||||
self.verticalLayout.addWidget(self.deviceFileSelector)
|
||||
|
||||
self.deviceComboBox = DevicesComboBox(self.groupBox)
|
||||
self.deviceComboBox.setObjectName(u"deviceComboBox")
|
||||
|
||||
self.verticalLayout.addWidget(self.deviceComboBox)
|
||||
|
||||
|
||||
self.verticalLayout_3.addWidget(self.groupBox)
|
||||
|
||||
self.groupBox_4 = QGroupBox(TabOcr)
|
||||
self.groupBox_4.setObjectName(u"groupBox_4")
|
||||
self.verticalLayout_5 = QVBoxLayout(self.groupBox_4)
|
||||
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
|
||||
self.tesseractFileSelector = FileSelector(self.groupBox_4)
|
||||
self.tesseractFileSelector.setObjectName(u"tesseractFileSelector")
|
||||
|
||||
self.verticalLayout_5.addWidget(self.tesseractFileSelector)
|
||||
|
||||
|
||||
self.verticalLayout_3.addWidget(self.groupBox_4)
|
||||
|
||||
self.groupBox_2 = QGroupBox(TabOcr)
|
||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||
self.horizontalLayout = QHBoxLayout(self.groupBox_2)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.groupBox_3 = QGroupBox(self.groupBox_2)
|
||||
self.groupBox_3.setObjectName(u"groupBox_3")
|
||||
self.verticalLayout_2 = QVBoxLayout(self.groupBox_3)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.ocr_addImageButton = QPushButton(self.groupBox_3)
|
||||
self.ocr_addImageButton.setObjectName(u"ocr_addImageButton")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.ocr_addImageButton)
|
||||
|
||||
self.ocr_removeSelectedButton = QPushButton(self.groupBox_3)
|
||||
self.ocr_removeSelectedButton.setObjectName(u"ocr_removeSelectedButton")
|
||||
self.ocr_removeSelectedButton.setEnabled(True)
|
||||
|
||||
self.verticalLayout_2.addWidget(self.ocr_removeSelectedButton)
|
||||
|
||||
self.ocr_removeAllButton = QPushButton(self.groupBox_3)
|
||||
self.ocr_removeAllButton.setObjectName(u"ocr_removeAllButton")
|
||||
self.ocr_removeAllButton.setEnabled(True)
|
||||
|
||||
self.verticalLayout_2.addWidget(self.ocr_removeAllButton)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.verticalLayout_2.addItem(self.verticalSpacer)
|
||||
|
||||
self.ocr_startButton = QPushButton(self.groupBox_3)
|
||||
self.ocr_startButton.setObjectName(u"ocr_startButton")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.ocr_startButton)
|
||||
|
||||
|
||||
self.horizontalLayout.addWidget(self.groupBox_3)
|
||||
|
||||
self.tableView = QTableView(self.groupBox_2)
|
||||
self.tableView.setObjectName(u"tableView")
|
||||
self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed)
|
||||
self.tableView.setSelectionMode(QAbstractItemView.MultiSelection)
|
||||
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.tableView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
self.tableView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
|
||||
self.horizontalLayout.addWidget(self.tableView)
|
||||
|
||||
self.groupBox_5 = QGroupBox(self.groupBox_2)
|
||||
self.groupBox_5.setObjectName(u"groupBox_5")
|
||||
self.verticalLayout_4 = QVBoxLayout(self.groupBox_5)
|
||||
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
||||
self.ocr_acceptSelectedButton = QPushButton(self.groupBox_5)
|
||||
self.ocr_acceptSelectedButton.setObjectName(u"ocr_acceptSelectedButton")
|
||||
self.ocr_acceptSelectedButton.setEnabled(True)
|
||||
|
||||
self.verticalLayout_4.addWidget(self.ocr_acceptSelectedButton)
|
||||
|
||||
self.ocr_acceptAllButton = QPushButton(self.groupBox_5)
|
||||
self.ocr_acceptAllButton.setObjectName(u"ocr_acceptAllButton")
|
||||
|
||||
self.verticalLayout_4.addWidget(self.ocr_acceptAllButton)
|
||||
|
||||
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.verticalLayout_4.addItem(self.verticalSpacer_2)
|
||||
|
||||
self.ocr_ignoreValidateCheckBox = QCheckBox(self.groupBox_5)
|
||||
self.ocr_ignoreValidateCheckBox.setObjectName(u"ocr_ignoreValidateCheckBox")
|
||||
|
||||
self.verticalLayout_4.addWidget(self.ocr_ignoreValidateCheckBox)
|
||||
|
||||
|
||||
self.horizontalLayout.addWidget(self.groupBox_5)
|
||||
|
||||
|
||||
self.verticalLayout_3.addWidget(self.groupBox_2)
|
||||
|
||||
|
||||
self.retranslateUi(TabOcr)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabOcr)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabOcr):
|
||||
self.openWizardButton.setText(QCoreApplication.translate("TabOcr", u"openWizardButton", None))
|
||||
self.groupBox.setTitle(QCoreApplication.translate("TabOcr", u"deviceSelector.title", None))
|
||||
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr", u"tesseractSelector.title", None))
|
||||
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr", u"ocr.title", None))
|
||||
self.groupBox_3.setTitle(QCoreApplication.translate("TabOcr", u"ocr.queue.title", None))
|
||||
self.ocr_addImageButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.addImageButton", None))
|
||||
self.ocr_removeSelectedButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.removeSelected", None))
|
||||
self.ocr_removeAllButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.removeAll", None))
|
||||
self.ocr_startButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.startOcrButton", None))
|
||||
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr", u"ocr.results", None))
|
||||
self.ocr_acceptSelectedButton.setText(QCoreApplication.translate("TabOcr", u"ocr.results.acceptSelectedButton", None))
|
||||
self.ocr_acceptAllButton.setText(QCoreApplication.translate("TabOcr", u"ocr.results.acceptAllButton", None))
|
||||
self.ocr_ignoreValidateCheckBox.setText(QCoreApplication.translate("TabOcr", u"ocr.results.ignoreValidate", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
117
ui/designer/tabs/tabOverview.ui
Normal file
117
ui/designer/tabs/tabOverview.ui
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabOverview</class>
|
||||
<widget class="QWidget" name="TabOverview">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>696</width>
|
||||
<height>509</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabOverview</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="b30Label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>30</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0.00</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignHCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>20</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">B30</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_4" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="r10Label">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>30</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">--</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignHCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>20</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">R10</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
108
ui/designer/tabs/tabOverview_ui.py
Normal file
108
ui/designer/tabs/tabOverview_ui.py
Normal file
@ -0,0 +1,108 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabOverview.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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 (QApplication, QHBoxLayout, QLabel, QSizePolicy,
|
||||
QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_TabOverview(object):
|
||||
def setupUi(self, TabOverview):
|
||||
if not TabOverview.objectName():
|
||||
TabOverview.setObjectName(u"TabOverview")
|
||||
TabOverview.resize(696, 509)
|
||||
TabOverview.setWindowTitle(u"TabOverview")
|
||||
self.verticalLayout = QVBoxLayout(TabOverview)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.widget = QWidget(TabOverview)
|
||||
self.widget.setObjectName(u"widget")
|
||||
|
||||
self.verticalLayout.addWidget(self.widget)
|
||||
|
||||
self.widget_2 = QWidget(TabOverview)
|
||||
self.widget_2.setObjectName(u"widget_2")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.widget_2.sizePolicy().hasHeightForWidth())
|
||||
self.widget_2.setSizePolicy(sizePolicy)
|
||||
self.horizontalLayout = QHBoxLayout(self.widget_2)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.widget_3 = QWidget(self.widget_2)
|
||||
self.widget_3.setObjectName(u"widget_3")
|
||||
self.verticalLayout_2 = QVBoxLayout(self.widget_3)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.b30Label = QLabel(self.widget_3)
|
||||
self.b30Label.setObjectName(u"b30Label")
|
||||
font = QFont()
|
||||
font.setPointSize(30)
|
||||
self.b30Label.setFont(font)
|
||||
self.b30Label.setText(u"0.00")
|
||||
self.b30Label.setAlignment(Qt.AlignBottom|Qt.AlignHCenter)
|
||||
|
||||
self.verticalLayout_2.addWidget(self.b30Label)
|
||||
|
||||
self.label_2 = QLabel(self.widget_3)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
font1 = QFont()
|
||||
font1.setPointSize(20)
|
||||
self.label_2.setFont(font1)
|
||||
self.label_2.setText(u"B30")
|
||||
self.label_2.setAlignment(Qt.AlignHCenter|Qt.AlignTop)
|
||||
|
||||
self.verticalLayout_2.addWidget(self.label_2)
|
||||
|
||||
|
||||
self.horizontalLayout.addWidget(self.widget_3)
|
||||
|
||||
self.widget_4 = QWidget(self.widget_2)
|
||||
self.widget_4.setObjectName(u"widget_4")
|
||||
self.widget_4.setEnabled(False)
|
||||
self.verticalLayout_3 = QVBoxLayout(self.widget_4)
|
||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||
self.r10Label = QLabel(self.widget_4)
|
||||
self.r10Label.setObjectName(u"r10Label")
|
||||
self.r10Label.setEnabled(False)
|
||||
self.r10Label.setFont(font)
|
||||
self.r10Label.setText(u"--")
|
||||
self.r10Label.setAlignment(Qt.AlignBottom|Qt.AlignHCenter)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.r10Label)
|
||||
|
||||
self.label_4 = QLabel(self.widget_4)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
self.label_4.setEnabled(False)
|
||||
self.label_4.setFont(font1)
|
||||
self.label_4.setText(u"R10")
|
||||
self.label_4.setAlignment(Qt.AlignHCenter|Qt.AlignTop)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.label_4)
|
||||
|
||||
|
||||
self.horizontalLayout.addWidget(self.widget_4)
|
||||
|
||||
|
||||
self.verticalLayout.addWidget(self.widget_2)
|
||||
|
||||
|
||||
self.retranslateUi(TabOverview)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabOverview)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabOverview):
|
||||
pass
|
||||
# retranslateUi
|
||||
|
74
ui/designer/tabs/tabSettings.ui
Normal file
74
ui/designer/tabs/tabSettings.ui
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabSettings</class>
|
||||
<widget class="QWidget" name="TabSettings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>499</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabSettings</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<widget class="SettingsDefault" name="page_default"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SettingsDefault</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.settings.settingsDefault</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
71
ui/designer/tabs/tabSettings_ui.py
Normal file
71
ui/designer/tabs/tabSettings_ui.py
Normal file
@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabSettings.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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, QAbstractScrollArea, QApplication, QHBoxLayout,
|
||||
QListWidget, QListWidgetItem, QSizePolicy, QStackedWidget,
|
||||
QWidget)
|
||||
|
||||
from ui.implements.settings.settingsDefault import SettingsDefault
|
||||
|
||||
class Ui_TabSettings(object):
|
||||
def setupUi(self, TabSettings):
|
||||
if not TabSettings.objectName():
|
||||
TabSettings.setObjectName(u"TabSettings")
|
||||
TabSettings.resize(562, 499)
|
||||
TabSettings.setWindowTitle(u"TabSettings")
|
||||
self.horizontalLayout = QHBoxLayout(TabSettings)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.listWidget = QListWidget(TabSettings)
|
||||
self.listWidget.setObjectName(u"listWidget")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
|
||||
self.listWidget.setSizePolicy(sizePolicy)
|
||||
self.listWidget.setMinimumSize(QSize(100, 0))
|
||||
self.listWidget.setBaseSize(QSize(100, 0))
|
||||
self.listWidget.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
|
||||
self.listWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
self.listWidget.setAlternatingRowColors(True)
|
||||
self.listWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
|
||||
self.horizontalLayout.addWidget(self.listWidget)
|
||||
|
||||
self.stackedWidget = QStackedWidget(TabSettings)
|
||||
self.stackedWidget.setObjectName(u"stackedWidget")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth())
|
||||
self.stackedWidget.setSizePolicy(sizePolicy1)
|
||||
self.page_default = SettingsDefault()
|
||||
self.page_default.setObjectName(u"page_default")
|
||||
self.stackedWidget.addWidget(self.page_default)
|
||||
|
||||
self.horizontalLayout.addWidget(self.stackedWidget)
|
||||
|
||||
self.horizontalLayout.setStretch(1, 1)
|
||||
|
||||
self.retranslateUi(TabSettings)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabSettings)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabSettings):
|
||||
pass
|
||||
# retranslateUi
|
||||
|
0
ui/extends/__init__.py
Normal file
0
ui/extends/__init__.py
Normal file
16
ui/extends/color.py
Normal file
16
ui/extends/color.py
Normal file
@ -0,0 +1,16 @@
|
||||
from PySide6.QtGui import QColor
|
||||
|
||||
|
||||
def mix_color(source_color: QColor, mix_color: QColor, mix_ratio: float = 0.5):
|
||||
r = round((mix_color.red() - source_color.red()) * mix_ratio + source_color.red())
|
||||
g = round(
|
||||
(mix_color.green() - source_color.green()) * mix_ratio + source_color.green()
|
||||
)
|
||||
b = round(
|
||||
(mix_color.blue() - source_color.blue()) * mix_ratio + source_color.blue()
|
||||
)
|
||||
a = round(
|
||||
(mix_color.alpha() - source_color.alpha()) * mix_ratio + source_color.alpha()
|
||||
)
|
||||
|
||||
return QColor(r, g, b, a)
|
33
ui/extends/components/chartSelector.py
Normal file
33
ui/extends/components/chartSelector.py
Normal file
@ -0,0 +1,33 @@
|
||||
from arcaea_offline.database import Database
|
||||
from arcaea_offline.models import Chart
|
||||
from arcaea_offline.utils import rating_class_to_short_text
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QStandardItem, QStandardItemModel
|
||||
|
||||
|
||||
class FuzzySearchCompleterModel(QStandardItemModel):
|
||||
def fillDbFuzzySearchResults(self, db: Database, kw: str):
|
||||
self.clear()
|
||||
|
||||
results = db.fuzzy_search_song_id(kw, limit=10)
|
||||
results = sorted(results, key=lambda r: r.confidence, reverse=True)
|
||||
songIds = [r.song_id for r in results]
|
||||
charts: list[Chart] = []
|
||||
for songId in songIds:
|
||||
dbChartRows = db.get_charts_by_song_id(songId)
|
||||
_charts = [Chart.from_db_row(dbRow) for dbRow in dbChartRows]
|
||||
_charts = sorted(_charts, key=lambda c: c.rating_class, reverse=True)
|
||||
charts += _charts
|
||||
|
||||
for chart in charts:
|
||||
displayText = (
|
||||
f"{chart.name_en} [{rating_class_to_short_text(chart.rating_class)}]"
|
||||
)
|
||||
item = QStandardItem(kw)
|
||||
item.setData(kw)
|
||||
item.setData(displayText, Qt.ItemDataRole.UserRole + 75)
|
||||
item.setData(
|
||||
f"{chart.song_id}, {chart.package_id}", Qt.ItemDataRole.UserRole + 76
|
||||
)
|
||||
item.setData(chart, Qt.ItemDataRole.UserRole + 10)
|
||||
self.appendRow(item)
|
5
ui/extends/components/dbTableViewer.py
Normal file
5
ui/extends/components/dbTableViewer.py
Normal file
@ -0,0 +1,5 @@
|
||||
from PySide6.QtCore import QAbstractTableModel
|
||||
|
||||
|
||||
class DbTableModel(QAbstractTableModel):
|
||||
pass
|
18
ui/extends/ocr.py
Normal file
18
ui/extends/ocr.py
Normal file
@ -0,0 +1,18 @@
|
||||
try:
|
||||
import json
|
||||
|
||||
from arcaea_offline_ocr.device import Device
|
||||
|
||||
def load_devices_json(filepath: str) -> list[Device]:
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
file_content = f.read()
|
||||
if len(file_content) == 0:
|
||||
return []
|
||||
content = json.loads(file_content)
|
||||
assert isinstance(content, list)
|
||||
return [Device.from_json_object(item) for item in content]
|
||||
|
||||
except Exception:
|
||||
|
||||
def load_devices_json(*args, **kwargs):
|
||||
pass
|
0
ui/extends/score.py
Normal file
0
ui/extends/score.py
Normal file
57
ui/extends/settings.py
Normal file
57
ui/extends/settings.py
Normal file
@ -0,0 +1,57 @@
|
||||
from PySide6.QtCore import QDir, QSettings
|
||||
|
||||
__all__ = [
|
||||
"DATABASE_PATH",
|
||||
"DEVICES_JSON_FILE",
|
||||
"DEVICE_UUID",
|
||||
"TESSERACT_FILE",
|
||||
"Settings",
|
||||
]
|
||||
|
||||
DATABASE_PATH = "General/DatabasePath"
|
||||
|
||||
DEVICES_JSON_FILE = "Ocr/DevicesJsonFile"
|
||||
DEVICE_UUID = "Ocr/DeviceUuid"
|
||||
TESSERACT_FILE = "Ocr/TesseractFile"
|
||||
|
||||
|
||||
class Settings(QSettings):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(
|
||||
QDir.current().absoluteFilePath("arcaea_offline.ini"),
|
||||
QSettings.Format.IniFormat,
|
||||
parent,
|
||||
)
|
||||
|
||||
def devicesJsonFile(self) -> str | None:
|
||||
return self.value(DEVICES_JSON_FILE, None, str)
|
||||
|
||||
def setDevicesJsonFile(self, path: str):
|
||||
self.setValue(DEVICES_JSON_FILE, path)
|
||||
self.sync()
|
||||
|
||||
def resetDevicesJsonFile(self):
|
||||
self.setValue(DEVICES_JSON_FILE, None)
|
||||
self.sync()
|
||||
|
||||
def deviceUuid(self) -> str | None:
|
||||
return self.value(DEVICE_UUID, None, str)
|
||||
|
||||
def setDeviceUuid(self, uuid: str):
|
||||
self.setValue(DEVICE_UUID, uuid)
|
||||
self.sync()
|
||||
|
||||
def resetDeviceUuid(self):
|
||||
self.setValue(DEVICE_UUID, None)
|
||||
self.sync()
|
||||
|
||||
def tesseractPath(self):
|
||||
return self.value(TESSERACT_FILE, None, str)
|
||||
|
||||
def setTesseractPath(self, path: str):
|
||||
self.setValue(TESSERACT_FILE, path)
|
||||
self.sync()
|
||||
|
||||
def resetTesseractPath(self):
|
||||
self.setValue(TESSERACT_FILE, None)
|
||||
self.sync()
|
0
ui/extends/shared/delegates/__init__.py
Normal file
0
ui/extends/shared/delegates/__init__.py
Normal file
152
ui/extends/shared/delegates/base.py
Normal file
152
ui/extends/shared/delegates/base.py
Normal file
@ -0,0 +1,152 @@
|
||||
from typing import Callable
|
||||
|
||||
from PySide6.QtCore import QEvent, QModelIndex, QObject, QPoint, QSize, Qt
|
||||
from PySide6.QtGui import QBrush, QColor, QFont, QFontMetrics, QLinearGradient, QPainter
|
||||
from PySide6.QtWidgets import QApplication, QStyledItemDelegate, QStyleOptionViewItem
|
||||
|
||||
|
||||
class TextSegmentDelegate(QStyledItemDelegate):
|
||||
VerticalPadding = 3
|
||||
HorizontalPadding = 5
|
||||
|
||||
TextRole = 3375
|
||||
ColorRole = TextRole + 1
|
||||
BrushRole = TextRole + 2
|
||||
GradientWrapperRole = TextRole + 3
|
||||
FontRole = TextRole + 20
|
||||
|
||||
def getTextSegments(
|
||||
self, index: QModelIndex, option
|
||||
) -> list[
|
||||
list[
|
||||
dict[
|
||||
int,
|
||||
str
|
||||
| QColor
|
||||
| QBrush
|
||||
| Callable[[float, float, float, float], QLinearGradient]
|
||||
| QFont,
|
||||
]
|
||||
]
|
||||
]:
|
||||
return []
|
||||
|
||||
def sizeHint(self, option, index) -> QSize:
|
||||
width = 0
|
||||
height = self.VerticalPadding
|
||||
fm: QFontMetrics = option.fontMetrics
|
||||
for line in self.getTextSegments(index, option):
|
||||
lineWidth = 4 * self.HorizontalPadding
|
||||
lineHeight = 0
|
||||
for textFrag in line:
|
||||
font = textFrag.get(self.FontRole)
|
||||
_fm = QFontMetrics(font) if font else fm
|
||||
text = textFrag[self.TextRole]
|
||||
textWidth = _fm.horizontalAdvance(text)
|
||||
textHeight = _fm.height()
|
||||
lineWidth += textWidth
|
||||
lineHeight = max(lineHeight, textHeight)
|
||||
width = max(lineWidth, width)
|
||||
height += lineHeight + self.VerticalPadding
|
||||
return QSize(width, height)
|
||||
|
||||
def paint(
|
||||
self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
|
||||
):
|
||||
self.initStyleOption(option, index)
|
||||
# draw text only
|
||||
baseX = option.rect.x() + self.HorizontalPadding
|
||||
baseY = option.rect.y() + self.VerticalPadding
|
||||
maxWidth = option.rect.width() - (2 * self.HorizontalPadding)
|
||||
fm: QFontMetrics = option.fontMetrics
|
||||
painter.save()
|
||||
for line in self.getTextSegments(index, option):
|
||||
lineBaseX = baseX
|
||||
lineBaseY = baseY
|
||||
lineHeight = 0
|
||||
for textFrag in line:
|
||||
painter.save()
|
||||
# elide text, get font values
|
||||
text = textFrag[self.TextRole]
|
||||
fragMaxWidth = maxWidth - (lineBaseX - baseX)
|
||||
font = textFrag.get(self.FontRole)
|
||||
if font:
|
||||
painter.setFont(font)
|
||||
_fm = QFontMetrics(font)
|
||||
else:
|
||||
_fm = fm
|
||||
lineHeight = max(lineHeight, _fm.height())
|
||||
elidedText = _fm.elidedText(
|
||||
text, Qt.TextElideMode.ElideRight, fragMaxWidth
|
||||
)
|
||||
|
||||
# confirm proper color
|
||||
brush = textFrag.get(self.BrushRole)
|
||||
gradientWrapper = textFrag.get(self.GradientWrapperRole)
|
||||
color = textFrag.get(self.ColorRole)
|
||||
pen = painter.pen()
|
||||
if brush:
|
||||
pen.setBrush(brush)
|
||||
elif gradientWrapper:
|
||||
gradient = gradientWrapper(
|
||||
lineBaseX,
|
||||
lineBaseY + lineHeight - _fm.height(),
|
||||
fragMaxWidth,
|
||||
_fm.height(),
|
||||
)
|
||||
pen.setBrush(gradient)
|
||||
elif color:
|
||||
pen.setColor(color)
|
||||
painter.setPen(pen)
|
||||
|
||||
painter.drawText(
|
||||
QPoint(lineBaseX, lineBaseY + lineHeight - _fm.descent()),
|
||||
elidedText,
|
||||
)
|
||||
painter.restore()
|
||||
|
||||
# if text elided, skip to next line
|
||||
# remember to add height before skipping
|
||||
if _fm.boundingRect(text).width() >= fragMaxWidth:
|
||||
break
|
||||
lineBaseX += _fm.horizontalAdvance(elidedText)
|
||||
|
||||
baseY += lineHeight + self.VerticalPadding
|
||||
painter.restore()
|
||||
|
||||
def super_styledItemDelegate_paint(self, painter, option, index):
|
||||
return super().paint(painter, option, index)
|
||||
|
||||
|
||||
class NoCommitWhenFocusOutEventFilter(QObject):
|
||||
"""
|
||||
--DEPRECATED--
|
||||
|
||||
The default QAbstractItemDelegate implementation has a private function
|
||||
`editorEventFilter()`, when editor sends focusOut/hide event, it emits the
|
||||
`commitData(editor)` signal. We don't want this since we need to validate
|
||||
the input, so we filter the event out and handle it by ourselves.
|
||||
|
||||
Reimplement `checkIsEditor(self, val) -> bool` to ensure this filter is
|
||||
working. The default implementation always return `False`.
|
||||
"""
|
||||
|
||||
def checkIsEditor(self, val) -> bool:
|
||||
return False
|
||||
|
||||
def eventFilter(self, object: QObject, event: QEvent) -> bool:
|
||||
if self.checkIsEditor(object) and event.type() in [
|
||||
QEvent.Type.FocusOut,
|
||||
QEvent.Type.Hide,
|
||||
]:
|
||||
widget = QApplication.focusWidget()
|
||||
while widget:
|
||||
# check if focus changed into editor's child
|
||||
if self.checkIsEditor(widget):
|
||||
return False
|
||||
widget = widget.parentWidget()
|
||||
|
||||
object.hide()
|
||||
object.deleteLater()
|
||||
return True
|
||||
return False
|
176
ui/extends/shared/delegates/chartDelegate.py
Normal file
176
ui/extends/shared/delegates/chartDelegate.py
Normal file
@ -0,0 +1,176 @@
|
||||
from typing import Union
|
||||
|
||||
from arcaea_offline.models import Chart
|
||||
from arcaea_offline.utils import rating_class_to_short_text, rating_class_to_text
|
||||
from PySide6.QtCore import QDateTime, QModelIndex, Qt, Signal
|
||||
from PySide6.QtGui import QBrush, QColor
|
||||
from PySide6.QtWidgets import (
|
||||
QFrame,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QMessageBox,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QStyleOptionViewItem,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from ui.implements.components.chartSelector import ChartSelector
|
||||
|
||||
from .base import TextSegmentDelegate
|
||||
|
||||
|
||||
def chartToRichText(chart: Chart):
|
||||
if isinstance(chart, Chart):
|
||||
text = f"{chart.name_en} [{rating_class_to_short_text(chart.rating_class)}]"
|
||||
text += "<br>"
|
||||
text += f'<font color="gray">({chart.song_id}, {chart.package_id})</font>'
|
||||
else:
|
||||
text = "(unknown chart)"
|
||||
return text
|
||||
|
||||
|
||||
class ChartSelectorDelegateWrapper(ChartSelector):
|
||||
accepted = Signal()
|
||||
rejected = Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.delegateHLine = QFrame(self)
|
||||
self.delegateHLine.setFrameShape(QFrame.Shape.HLine)
|
||||
self.delegateHLine.setFrameShadow(QFrame.Shadow.Plain)
|
||||
self.delegateHLine.setFixedHeight(5)
|
||||
self.mainVerticalLayout.insertWidget(0, self.delegateHLine)
|
||||
|
||||
self.delegateHeader = QWidget(self)
|
||||
self.delegateHeaderHBoxLayout = QHBoxLayout(self.delegateHeader)
|
||||
self.delegateHeaderHBoxLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.mainVerticalLayout.insertWidget(0, self.delegateHeader)
|
||||
|
||||
self.editorLabel = QLabel(self)
|
||||
self.editorLabel.setSizePolicy(
|
||||
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred
|
||||
)
|
||||
self.delegateHeaderHBoxLayout.addWidget(self.editorLabel)
|
||||
|
||||
self.editorCommitButton = QPushButton("Commit", self.delegateHeader)
|
||||
self.editorCommitButton.clicked.connect(self.accepted)
|
||||
self.delegateHeaderHBoxLayout.addWidget(self.editorCommitButton)
|
||||
|
||||
self.editorDiscardButton = QPushButton("Discard", self.delegateHeader)
|
||||
self.editorDiscardButton.clicked.connect(self.rejected)
|
||||
self.delegateHeaderHBoxLayout.addWidget(self.editorDiscardButton)
|
||||
|
||||
def setText(self, chart: Chart, _extra: str = None):
|
||||
text = "Editing "
|
||||
text += _extra or ""
|
||||
text += "<br>"
|
||||
text += (
|
||||
chartToRichText(chart) if isinstance(chart, Chart) else "(unknown chart)"
|
||||
)
|
||||
self.editorLabel.setText(text)
|
||||
|
||||
def validate(self):
|
||||
return isinstance(self.value(), Chart)
|
||||
|
||||
|
||||
class ChartDelegate(TextSegmentDelegate):
|
||||
RatingClassColors = [
|
||||
QColor("#399bb2"),
|
||||
QColor("#809955"),
|
||||
QColor("#702d60"),
|
||||
QColor("#710f25"),
|
||||
]
|
||||
ChartInvalidBackgroundColor = QColor("#e6a23c")
|
||||
|
||||
def getChart(self, index: QModelIndex) -> Chart | None:
|
||||
return None
|
||||
|
||||
def getTextSegments(self, index: QModelIndex, option):
|
||||
chart = self.getChart(index)
|
||||
if not isinstance(chart, Chart):
|
||||
return [
|
||||
[{self.TextRole: "Chart Invalid", self.ColorRole: QColor("#ff0000")}]
|
||||
]
|
||||
|
||||
return [
|
||||
[
|
||||
{self.TextRole: f"{chart.name_en}"},
|
||||
],
|
||||
[
|
||||
{
|
||||
self.TextRole: f"{rating_class_to_text(chart.rating_class)} {chart.rating / 10:.1f}",
|
||||
self.ColorRole: self.RatingClassColors[chart.rating_class],
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
self.TextRole: f"({chart.song_id}, {chart.package_id})",
|
||||
self.ColorRole: option.widget.palette().placeholderText().color(),
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||
return True
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
# draw chartInvalid warning background
|
||||
chart = self.getChart(index)
|
||||
if not isinstance(chart, Chart) and self.paintWarningBackground(index):
|
||||
painter.save()
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
bgColor = QColor(self.ChartInvalidBackgroundColor)
|
||||
bgColor.setAlpha(50)
|
||||
painter.setBrush(bgColor)
|
||||
painter.drawRect(option.rect)
|
||||
painter.restore()
|
||||
option.text = ""
|
||||
super().paint(painter, option, index)
|
||||
|
||||
def checkIsEditor(self, val):
|
||||
return isinstance(val, ChartSelectorDelegateWrapper)
|
||||
|
||||
def _closeEditor(self):
|
||||
editor = self.sender()
|
||||
self.closeEditor.emit(editor)
|
||||
|
||||
def _commitEditor(self):
|
||||
editor = self.sender()
|
||||
if editor.validate():
|
||||
confirm = QMessageBox.question(
|
||||
editor,
|
||||
"Confirm",
|
||||
f"Are you sure to change chart to<br><br>{chartToRichText(editor.value())}",
|
||||
)
|
||||
if confirm == QMessageBox.StandardButton.Yes:
|
||||
self.commitData.emit(editor)
|
||||
self.closeEditor.emit(editor)
|
||||
else:
|
||||
QMessageBox.critical(editor, "Invalid chart", "Cannot commit")
|
||||
|
||||
def createEditor(
|
||||
self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex
|
||||
) -> ChartSelectorDelegateWrapper:
|
||||
if isinstance(self.getChart(index), Chart):
|
||||
editor = ChartSelectorDelegateWrapper(parent)
|
||||
editor.setWindowFlag(Qt.WindowType.Sheet, True)
|
||||
editor.setWindowFlag(Qt.WindowType.FramelessWindowHint, True)
|
||||
editor.setText(self.getChart(index))
|
||||
editor.move(parent.mapToGlobal(parent.pos()))
|
||||
editor.accepted.connect(self._commitEditor)
|
||||
editor.rejected.connect(self._closeEditor)
|
||||
return editor
|
||||
|
||||
def updateEditorGeometry(self, editor: QWidget, option, index: QModelIndex) -> None:
|
||||
editor.move(editor.pos() + option.rect.topLeft())
|
||||
editor.setMaximumWidth(option.rect.width())
|
||||
|
||||
def setEditorData(self, editor: ChartSelectorDelegateWrapper, index: QModelIndex):
|
||||
if self.checkIsEditor(editor) and isinstance(self.getChart(index), Chart):
|
||||
editor.selectChart(self.getChart(index))
|
||||
return super().setEditorData(editor, index)
|
||||
|
||||
def setModelData(self, editor: ChartSelectorDelegateWrapper, model, index):
|
||||
...
|
35
ui/extends/shared/delegates/descriptionDelegate.py
Normal file
35
ui/extends/shared/delegates/descriptionDelegate.py
Normal file
@ -0,0 +1,35 @@
|
||||
from PySide6.QtCore import QModelIndex, Qt
|
||||
from PySide6.QtWidgets import QStyle, QStyleOptionViewItem
|
||||
|
||||
from .base import TextSegmentDelegate
|
||||
|
||||
|
||||
class DescriptionDelegate(TextSegmentDelegate):
|
||||
MainTextRole = Qt.ItemDataRole.UserRole + 75
|
||||
DescriptionTextRole = Qt.ItemDataRole.UserRole + 76
|
||||
|
||||
def getMainText(self, index: QModelIndex) -> str | None:
|
||||
return index.data(self.MainTextRole)
|
||||
|
||||
def getDescriptionText(self, index: QModelIndex) -> str | None:
|
||||
return index.data(self.DescriptionTextRole)
|
||||
|
||||
def getTextSegments(self, index: QModelIndex, option):
|
||||
return [
|
||||
[
|
||||
{self.TextRole: self.getMainText(index) or ""},
|
||||
{self.TextRole: " "},
|
||||
{
|
||||
self.TextRole: self.getDescriptionText(index) or "",
|
||||
self.ColorRole: option.widget.palette().placeholderText().color(),
|
||||
},
|
||||
]
|
||||
]
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
super().paint(painter, option, index)
|
||||
|
||||
optionNoText = QStyleOptionViewItem(option)
|
||||
optionNoText.text = ""
|
||||
style = option.widget.style() # type: QStyle
|
||||
style.drawControl(QStyle.ControlElement.CE_ItemViewItem, optionNoText, painter)
|
247
ui/extends/shared/delegates/scoreDelegate.py
Normal file
247
ui/extends/shared/delegates/scoreDelegate.py
Normal file
@ -0,0 +1,247 @@
|
||||
from typing import Union
|
||||
|
||||
from arcaea_offline.calculate import calculate_score_range
|
||||
from arcaea_offline.models import Chart, Score, ScoreInsert
|
||||
from arcaea_offline.utils import (
|
||||
rating_class_to_text,
|
||||
score_to_grade_text,
|
||||
zip_score_grade,
|
||||
)
|
||||
from PySide6.QtCore import QAbstractItemModel, QDateTime, QModelIndex, Qt, Signal
|
||||
from PySide6.QtGui import QColor, QFont, QLinearGradient
|
||||
from PySide6.QtWidgets import (
|
||||
QAbstractItemDelegate,
|
||||
QFrame,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from ui.implements.components.scoreEditor import ScoreEditor
|
||||
|
||||
from ..utils import keepWidgetInScreen
|
||||
from .base import TextSegmentDelegate
|
||||
|
||||
|
||||
class ScoreEditorDelegateWrapper(ScoreEditor):
|
||||
rejected = Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.hLine = QFrame(self)
|
||||
self.hLine.setFrameShape(QFrame.Shape.HLine)
|
||||
self.hLine.setFrameShadow(QFrame.Shadow.Plain)
|
||||
self.hLine.setFixedHeight(5)
|
||||
self.formLayout.insertRow(0, self.hLine)
|
||||
|
||||
self.delegateHeader = QWidget(self)
|
||||
self.delegateHeaderHBoxLayout = QHBoxLayout(self.delegateHeader)
|
||||
self.delegateHeaderHBoxLayout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.editorLabel = QLabel(self.delegateHeader)
|
||||
self.editorLabel.setSizePolicy(
|
||||
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred
|
||||
)
|
||||
self.delegateHeaderHBoxLayout.addWidget(self.editorLabel)
|
||||
|
||||
self.editorDiscardButton = QPushButton("Discard", self.delegateHeader)
|
||||
self.editorDiscardButton.clicked.connect(self.rejected)
|
||||
self.delegateHeaderHBoxLayout.addWidget(self.editorDiscardButton)
|
||||
|
||||
self.formLayout.insertRow(0, self.delegateHeader)
|
||||
|
||||
def setText(self, score: Score | ScoreInsert, _extra: str = None):
|
||||
text = "Editing "
|
||||
text += _extra or ""
|
||||
text += f"score {score.score}"
|
||||
text += f"<br>(P{score.pure} F{score.far} L{score.lost} | MR{score.max_recall})"
|
||||
self.editorLabel.setText(text)
|
||||
|
||||
|
||||
class ScoreDelegate(TextSegmentDelegate):
|
||||
@staticmethod
|
||||
def createGradeGradientWrapper(topColor: QColor, bottomColor: QColor):
|
||||
def wrapper(x, y, width, height):
|
||||
gradient = QLinearGradient(x + (width / 2), y, x + (width / 2), y + height)
|
||||
gradient.setColorAt(0.1, topColor)
|
||||
gradient.setColorAt(0.9, bottomColor)
|
||||
return gradient
|
||||
|
||||
return wrapper
|
||||
|
||||
ScoreMismatchBackgroundColor = QColor("#e6a23c")
|
||||
PureFarLostColors = [
|
||||
QColor("#f22ec6"),
|
||||
QColor("#ff9028"),
|
||||
QColor("#ff0c43"),
|
||||
]
|
||||
GradeGradientsWrappers = [ # EX+, EX, AA, A. B, C, D
|
||||
createGradeGradientWrapper(QColor("#83238c"), QColor("#2c72ae")),
|
||||
createGradeGradientWrapper(QColor("#721b6b"), QColor("#295b8d")),
|
||||
createGradeGradientWrapper(QColor("#5a3463"), QColor("#9b4b8d")),
|
||||
createGradeGradientWrapper(QColor("#46324d"), QColor("#92588a")),
|
||||
createGradeGradientWrapper(QColor("#43334a"), QColor("#755b7c")),
|
||||
createGradeGradientWrapper(QColor("#3b2b27"), QColor("#80566b")),
|
||||
createGradeGradientWrapper(QColor("#5d1d35"), QColor("#9f3c55")),
|
||||
]
|
||||
|
||||
def getScore(self, index: QModelIndex) -> Score | None:
|
||||
return None
|
||||
|
||||
def getScoreInsert(self, index: QModelIndex) -> ScoreInsert | None:
|
||||
return None
|
||||
|
||||
def _getScore(self, index: QModelIndex):
|
||||
score = self.getScore(index)
|
||||
scoreInsert = self.getScoreInsert(index)
|
||||
return scoreInsert if score is None else score
|
||||
|
||||
def getChart(self, index: QModelIndex) -> Chart | None:
|
||||
return None
|
||||
|
||||
def getScoreValidateOk(self, index: QModelIndex) -> bool | None:
|
||||
score = self._getScore(index)
|
||||
chart = self.getChart(index)
|
||||
|
||||
if isinstance(score, (Score, ScoreInsert)) and isinstance(chart, Chart):
|
||||
scoreRange = calculate_score_range(chart, score.pure, score.far)
|
||||
return scoreRange[0] <= score.score <= scoreRange[1]
|
||||
|
||||
def getScoreGradeGradientWrapper(self, score: int):
|
||||
return zip_score_grade(score, self.GradeGradientsWrappers)
|
||||
|
||||
def getTextSegments(self, index, option):
|
||||
score = self._getScore(index)
|
||||
chart = self.getChart(index)
|
||||
if not (isinstance(score, (Score, ScoreInsert)) and isinstance(chart, Chart)):
|
||||
return [
|
||||
[
|
||||
{
|
||||
self.TextRole: "Chart/Score Invalid",
|
||||
self.ColorRole: QColor("#ff0000"),
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
score_font = QFont(option.font)
|
||||
score_font.setPointSize(12)
|
||||
score_grade_font = QFont(score_font)
|
||||
score_grade_font.setBold(True)
|
||||
return [
|
||||
[
|
||||
{
|
||||
self.TextRole: score_to_grade_text(score.score),
|
||||
self.GradientWrapperRole: self.getScoreGradeGradientWrapper(
|
||||
score.score
|
||||
),
|
||||
self.FontRole: score_grade_font,
|
||||
},
|
||||
{self.TextRole: " | "},
|
||||
{self.TextRole: str(score.score), self.FontRole: score_font},
|
||||
],
|
||||
[
|
||||
{
|
||||
self.TextRole: f"PURE {score.pure}",
|
||||
self.ColorRole: self.PureFarLostColors[0],
|
||||
},
|
||||
{self.TextRole: " "},
|
||||
{
|
||||
self.TextRole: f"FAR {score.far}",
|
||||
self.ColorRole: self.PureFarLostColors[1],
|
||||
},
|
||||
{self.TextRole: " "},
|
||||
{
|
||||
self.TextRole: f"LOST {score.lost}",
|
||||
self.ColorRole: self.PureFarLostColors[2],
|
||||
},
|
||||
{self.TextRole: " | "},
|
||||
{self.TextRole: f"MAX RECALL {score.max_recall}"},
|
||||
],
|
||||
[
|
||||
{
|
||||
self.TextRole: QDateTime.fromSecsSinceEpoch(score.time).toString(
|
||||
"yyyy-MM-dd hh:mm:ss"
|
||||
)
|
||||
}
|
||||
],
|
||||
]
|
||||
|
||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||
return True
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
# draw scoreMismatch warning background
|
||||
score = self._getScore(index)
|
||||
chart = self.getChart(index)
|
||||
if (
|
||||
isinstance(score, (Score, ScoreInsert))
|
||||
and isinstance(chart, Chart)
|
||||
and self.paintWarningBackground(index)
|
||||
):
|
||||
scoreValidateOk = self.getScoreValidateOk(index)
|
||||
if not scoreValidateOk:
|
||||
painter.save()
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
bgColor = QColor(self.ScoreMismatchBackgroundColor)
|
||||
bgColor.setAlpha(50)
|
||||
painter.setBrush(bgColor)
|
||||
painter.drawRect(option.rect)
|
||||
painter.restore()
|
||||
|
||||
option.text = ""
|
||||
super().paint(painter, option, index)
|
||||
|
||||
def _closeEditor(self):
|
||||
editor = self.sender()
|
||||
self.closeEditor.emit(editor)
|
||||
|
||||
def _commitEditor(self):
|
||||
editor = self.sender()
|
||||
self.commitData.emit(editor)
|
||||
self.closeEditor.emit(editor)
|
||||
|
||||
def createEditor(self, parent, option, index) -> ScoreEditorDelegateWrapper:
|
||||
score = self._getScore(index)
|
||||
chart = self.getChart(index)
|
||||
if isinstance(score, (Score, ScoreInsert)) and isinstance(chart, Chart):
|
||||
editor = ScoreEditorDelegateWrapper(parent)
|
||||
editor.setWindowFlag(Qt.WindowType.Sheet, True)
|
||||
editor.setWindowFlag(Qt.WindowType.FramelessWindowHint, True)
|
||||
editor.setWindowTitle(
|
||||
f"{chart.name_en}({chart.song_id}) | {rating_class_to_text(chart.rating_class)} | {chart.package_id}"
|
||||
)
|
||||
editor.setText(self._getScore(index))
|
||||
editor.setValidateBeforeAccept(False)
|
||||
editor.move(parent.mapToGlobal(parent.pos()))
|
||||
editor.accepted.connect(self._commitEditor)
|
||||
editor.rejected.connect(self._closeEditor)
|
||||
editor.show()
|
||||
return editor
|
||||
return super().createEditor(parent, option, index)
|
||||
|
||||
def updateEditorGeometry(self, editor, option, index):
|
||||
editor.setMaximumWidth(option.rect.width())
|
||||
editor.move(editor.pos() + option.rect.topLeft())
|
||||
|
||||
keepWidgetInScreen(editor)
|
||||
|
||||
def setEditorData(self, editor: ScoreEditorDelegateWrapper, index) -> None:
|
||||
score = self._getScore(index)
|
||||
chart = self.getChart(index)
|
||||
if isinstance(score, (Score, ScoreInsert)) and isinstance(chart, Chart):
|
||||
editor.setChart(chart)
|
||||
editor.setValue(score)
|
||||
|
||||
def confirmSetModelData(self, editor: ScoreEditorDelegateWrapper):
|
||||
return editor.triggerValidateMessageBox()
|
||||
|
||||
def setModelData(
|
||||
self,
|
||||
editor: ScoreEditorDelegateWrapper,
|
||||
model: QAbstractItemModel,
|
||||
index: QModelIndex,
|
||||
):
|
||||
...
|
35
ui/extends/shared/models/tables/base.py
Normal file
35
ui/extends/shared/models/tables/base.py
Normal file
@ -0,0 +1,35 @@
|
||||
from typing import Union
|
||||
|
||||
from arcaea_offline.database import Database
|
||||
from PySide6.QtCore import QAbstractTableModel, Qt
|
||||
|
||||
|
||||
class DbTableModel(QAbstractTableModel):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self._horizontalHeaders = []
|
||||
self.retranslateHeaders()
|
||||
|
||||
self._db = Database()
|
||||
|
||||
def retranslateHeaders(self):
|
||||
...
|
||||
|
||||
def syncDb(self):
|
||||
...
|
||||
|
||||
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
|
||||
if (
|
||||
orientation == Qt.Orientation.Horizontal
|
||||
and self._horizontalHeaders
|
||||
and 0 <= section < len(self._horizontalHeaders)
|
||||
and role == Qt.ItemDataRole.DisplayRole
|
||||
):
|
||||
return self._horizontalHeaders[section]
|
||||
return super().headerData(section, orientation, role)
|
||||
|
||||
def columnCount(self, parent=None):
|
||||
if self._horizontalHeaders:
|
||||
return len(self._horizontalHeaders)
|
||||
return super().columnCount(parent)
|
197
ui/extends/shared/models/tables/score.py
Normal file
197
ui/extends/shared/models/tables/score.py
Normal file
@ -0,0 +1,197 @@
|
||||
from arcaea_offline.calculate import calculate_score
|
||||
from arcaea_offline.models import Chart, Score, ScoreInsert
|
||||
from PySide6.QtCore import QCoreApplication, QModelIndex, QSortFilterProxyModel, Qt
|
||||
|
||||
from .base import DbTableModel
|
||||
|
||||
|
||||
class DbScoreTableModel(DbTableModel):
|
||||
IdRole = Qt.ItemDataRole.UserRole + 10
|
||||
ChartRole = Qt.ItemDataRole.UserRole + 11
|
||||
ScoreRole = Qt.ItemDataRole.UserRole + 12
|
||||
PttRole = Qt.ItemDataRole.UserRole + 13
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.__items = []
|
||||
|
||||
def retranslateHeaders(self):
|
||||
self._horizontalHeaders = [
|
||||
# fmt: off
|
||||
QCoreApplication.translate("DbScoreTableModel", "horizontalHeader.id"),
|
||||
QCoreApplication.translate("DbScoreTableModel", "horizontalHeader.chart"),
|
||||
QCoreApplication.translate("DbScoreTableModel", "horizontalHeader.score"),
|
||||
QCoreApplication.translate("DbScoreTableModel", "horizontalHeader.potential"),
|
||||
# fmt: on
|
||||
]
|
||||
|
||||
def syncDb(self):
|
||||
newScores = [Score.from_db_row(dbRow) for dbRow in self._db.get_scores()]
|
||||
newScores = sorted(newScores, key=lambda x: x.id)
|
||||
newCharts = [
|
||||
Chart.from_db_row(dbRow)
|
||||
for dbRow in [
|
||||
self._db.get_chart(score.song_id, score.rating_class)
|
||||
for score in newScores
|
||||
]
|
||||
]
|
||||
newPtts = []
|
||||
for chart, score in zip(newCharts, newScores):
|
||||
if isinstance(chart, Chart) and isinstance(score, Score):
|
||||
newPtts.append(calculate_score(chart, score).potential)
|
||||
else:
|
||||
newPtts.append(None)
|
||||
|
||||
newScoreIds = [score.id for score in newScores]
|
||||
oldScoreIds = [item[self.ScoreRole].id for item in self.__items]
|
||||
|
||||
deleteIds = list(set(oldScoreIds) - set(newScoreIds))
|
||||
newIds = list(set(newScoreIds) - set(oldScoreIds))
|
||||
deleteRowIndexes = [oldScoreIds.index(deleteId) for deleteId in deleteIds]
|
||||
|
||||
# first delete rows
|
||||
for deleteRowIndex in sorted(deleteRowIndexes, reverse=True):
|
||||
self.beginRemoveRows(QModelIndex(), deleteRowIndex, deleteRowIndex)
|
||||
self.__items.pop(deleteRowIndex)
|
||||
self.endRemoveRows()
|
||||
|
||||
# now update existing datas
|
||||
for oldItem, newChart, newScore, newPtt in zip(
|
||||
self.__items, newCharts, newScores, newPtts
|
||||
):
|
||||
oldItem[self.IdRole] = newScore.id
|
||||
oldItem[self.ChartRole] = newChart
|
||||
oldItem[self.ScoreRole] = newScore
|
||||
oldItem[self.PttRole] = newPtt
|
||||
|
||||
# finally insert new rows
|
||||
for newId in newIds:
|
||||
insertRowIndex = self.rowCount()
|
||||
itemListIndex = newScoreIds.index(newId)
|
||||
score = newScores[itemListIndex]
|
||||
chart = newCharts[itemListIndex]
|
||||
ptt = newPtts[itemListIndex]
|
||||
self.beginInsertRows(QModelIndex(), insertRowIndex, insertRowIndex)
|
||||
self.__items.append(
|
||||
{
|
||||
self.IdRole: score.id,
|
||||
self.ChartRole: chart,
|
||||
self.ScoreRole: score,
|
||||
self.PttRole: ptt,
|
||||
}
|
||||
)
|
||||
self.endInsertRows()
|
||||
|
||||
# trigger view update
|
||||
topLeft = self.index(0, 0)
|
||||
bottomRight = self.index(self.rowCount() - 1, self.columnCount() - 1)
|
||||
self.dataChanged.emit(
|
||||
topLeft,
|
||||
bottomRight,
|
||||
[Qt.ItemDataRole.DisplayRole, self.IdRole, self.ChartRole, self.ScoreRole],
|
||||
)
|
||||
|
||||
def rowCount(self, *args):
|
||||
return len(self.__items)
|
||||
|
||||
def data(self, index, role):
|
||||
if index.isValid() and self.checkIndex(index):
|
||||
if index.column() == 0 and role in [
|
||||
Qt.ItemDataRole.DisplayRole,
|
||||
self.IdRole,
|
||||
]:
|
||||
return self.__items[index.row()][self.IdRole]
|
||||
elif index.column() == 1 and role == self.ChartRole:
|
||||
return self.__items[index.row()][self.ChartRole]
|
||||
elif index.column() == 2 and role in [self.ChartRole, self.ScoreRole]:
|
||||
return self.__items[index.row()][role]
|
||||
elif index.column() == 3:
|
||||
if role == Qt.ItemDataRole.DisplayRole:
|
||||
return f"{self.__items[index.row()][self.PttRole]:.3f}"
|
||||
elif role == self.PttRole:
|
||||
return self.__items[index.row()][self.PttRole]
|
||||
return None
|
||||
|
||||
def setData(self, index, value, role):
|
||||
if not (index.isValid() and self.checkIndex(index)):
|
||||
return False
|
||||
|
||||
if (
|
||||
index.column() == 2
|
||||
and isinstance(value, ScoreInsert)
|
||||
and role == self.ScoreRole
|
||||
):
|
||||
self._db.update_score(self.__items[index.row()][self.IdRole], value)
|
||||
self.syncDb()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def flags(self, index) -> Qt.ItemFlag:
|
||||
flags = super().flags(index)
|
||||
flags |= Qt.ItemFlag.ItemIsSelectable
|
||||
if index.column() in [1, 2]:
|
||||
flags |= Qt.ItemFlag.ItemIsEditable
|
||||
return flags
|
||||
|
||||
def _removeRow(self, row: int, syncDb: bool = True):
|
||||
if not 0 <= row < self.rowCount():
|
||||
return False
|
||||
|
||||
try:
|
||||
self._db.delete_score(self.__items[row][self.IdRole])
|
||||
if syncDb:
|
||||
self.syncDb()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def removeRow(self, row: int, parent=...):
|
||||
return self._removeRow(row)
|
||||
|
||||
def removeRows(self, row: int, count: int, parent=...):
|
||||
maxRow = min(self.rowCount() - 1, row + count - 1)
|
||||
if row > maxRow:
|
||||
return False
|
||||
|
||||
result = all(
|
||||
self._removeRow(row, syncDb=False) for row in range(row, row + count)
|
||||
)
|
||||
self.syncDb()
|
||||
return result
|
||||
|
||||
def removeRowList(self, rowList: list[int]):
|
||||
result = all(
|
||||
self._removeRow(row, syncDb=False) for row in sorted(rowList, reverse=True)
|
||||
)
|
||||
self.syncDb()
|
||||
return result
|
||||
|
||||
|
||||
class DbScoreTableSortFilterProxyModel(QSortFilterProxyModel):
|
||||
Sort_C2_ScoreRole = Qt.ItemDataRole.UserRole + 75
|
||||
Sort_C2_TimeRole = Qt.ItemDataRole.UserRole + 76
|
||||
|
||||
def lessThan(self, source_left, source_right) -> bool:
|
||||
if source_left.column() != source_right.column():
|
||||
return
|
||||
|
||||
column = source_left.column()
|
||||
if column == 0:
|
||||
return source_left.data(DbScoreTableModel.IdRole) < source_right.data(
|
||||
DbScoreTableModel.IdRole
|
||||
)
|
||||
elif column == 2:
|
||||
score_left = source_left.data(DbScoreTableModel.ScoreRole)
|
||||
score_right = source_right.data(DbScoreTableModel.ScoreRole)
|
||||
if isinstance(score_left, Score) and isinstance(score_right, Score):
|
||||
if self.sortRole() == self.Sort_C2_ScoreRole:
|
||||
return score_left.score < score_right.score
|
||||
elif self.sortRole() == self.Sort_C2_TimeRole:
|
||||
return score_left.time < score_right.time
|
||||
elif column == 3:
|
||||
return source_left.data(DbScoreTableModel.PttRole) < source_right.data(
|
||||
DbScoreTableModel.PttRole
|
||||
)
|
||||
return super().lessThan(source_left, source_right)
|
54
ui/extends/shared/utils.py
Normal file
54
ui/extends/shared/utils.py
Normal file
@ -0,0 +1,54 @@
|
||||
from PySide6.QtCore import QPoint
|
||||
from PySide6.QtGui import QGuiApplication, QScreen
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
|
||||
def keepWidgetInScreen(widget: QWidget, screen: QScreen = None):
|
||||
"""ensure your widget is visible"""
|
||||
|
||||
# see https://doc.qt.io/qt-6/application-windows.html
|
||||
# for why using frameGeometry.width() / frameGeometry.height()
|
||||
# instead of width() / height().
|
||||
|
||||
screen = screen or QGuiApplication.primaryScreen()
|
||||
screenAvailableGeometry = screen.availableGeometry()
|
||||
|
||||
# X boundary
|
||||
if widget.pos().x() < screenAvailableGeometry.x():
|
||||
pos = QPoint(widget.pos())
|
||||
pos.setX(screenAvailableGeometry.x())
|
||||
widget.move(pos)
|
||||
elif (
|
||||
widget.pos().x() + widget.frameGeometry().width()
|
||||
> screenAvailableGeometry.width()
|
||||
):
|
||||
pos = QPoint(widget.pos())
|
||||
pos.setX(
|
||||
pos.x()
|
||||
- (
|
||||
pos.x()
|
||||
+ widget.frameGeometry().width()
|
||||
- screenAvailableGeometry.width()
|
||||
)
|
||||
)
|
||||
widget.move(pos)
|
||||
|
||||
# Y boundary
|
||||
if widget.pos().y() < screenAvailableGeometry.y():
|
||||
pos = QPoint(widget.pos())
|
||||
pos.setY(screenAvailableGeometry.y())
|
||||
widget.move(pos)
|
||||
elif (
|
||||
widget.pos().y() + widget.frameGeometry().height()
|
||||
> screenAvailableGeometry.height()
|
||||
):
|
||||
pos = QPoint(widget.pos())
|
||||
pos.setY(
|
||||
pos.y()
|
||||
- (
|
||||
pos.y()
|
||||
+ widget.frameGeometry().height()
|
||||
- screenAvailableGeometry.height()
|
||||
)
|
||||
)
|
||||
widget.move(pos)
|
476
ui/extends/tabs/tabOcr.py
Normal file
476
ui/extends/tabs/tabOcr.py
Normal file
@ -0,0 +1,476 @@
|
||||
import contextlib
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
import exif
|
||||
from arcaea_offline.calculate import calculate_score_range
|
||||
from arcaea_offline.database import Database
|
||||
from arcaea_offline.models import Chart, ScoreInsert
|
||||
from arcaea_offline_ocr.device import Device
|
||||
from arcaea_offline_ocr.recognize import RecognizeResult, recognize
|
||||
from PySide6.QtCore import (
|
||||
QAbstractListModel,
|
||||
QAbstractTableModel,
|
||||
QCoreApplication,
|
||||
QDateTime,
|
||||
QFileInfo,
|
||||
QModelIndex,
|
||||
QObject,
|
||||
QRect,
|
||||
QRunnable,
|
||||
QSize,
|
||||
Qt,
|
||||
QThreadPool,
|
||||
Signal,
|
||||
Slot,
|
||||
)
|
||||
from PySide6.QtGui import QPixmap
|
||||
from PySide6.QtWidgets import QLabel, QStyledItemDelegate, QWidget
|
||||
|
||||
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
||||
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
||||
from ui.implements.components.scoreEditor import ScoreEditor
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OcrTaskSignals(QObject):
|
||||
resultReady = Signal(int, RecognizeResult)
|
||||
finished = Signal(int)
|
||||
|
||||
|
||||
class OcrTask(QRunnable):
|
||||
def __init__(self, index: int, device: Device, imagePath: str):
|
||||
super().__init__()
|
||||
self.index = index
|
||||
self.device = device
|
||||
self.imagePath = imagePath
|
||||
self.signals = OcrTaskSignals()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
result = recognize(self.imagePath, self.device)
|
||||
self.signals.resultReady.emit(self.index, result)
|
||||
logger.info(
|
||||
f"OcrTask {self.imagePath} with {repr(self.device)} got result {repr(result)}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"OcrTask {self.imagePath} with {repr(self.device)} failed"
|
||||
)
|
||||
finally:
|
||||
self.signals.finished.emit(self.index)
|
||||
|
||||
|
||||
class OcrQueueModel(QAbstractListModel):
|
||||
ImagePathRole = Qt.ItemDataRole.UserRole + 1
|
||||
ImagePixmapRole = Qt.ItemDataRole.UserRole + 2
|
||||
RecognizeResultRole = Qt.ItemDataRole.UserRole + 10
|
||||
ScoreInsertRole = Qt.ItemDataRole.UserRole + 11
|
||||
ChartRole = Qt.ItemDataRole.UserRole + 12
|
||||
ScoreValidateOkRole = Qt.ItemDataRole.UserRole + 13
|
||||
|
||||
started = Signal()
|
||||
finished = Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.__db = Database()
|
||||
self.__items: list[dict[int, Any]] = []
|
||||
|
||||
@property
|
||||
def imagePaths(self):
|
||||
return [item.get(self.ImagePathRole) for item in self.__items]
|
||||
|
||||
def clear(self):
|
||||
self.beginResetModel()
|
||||
self.beginRemoveRows(QModelIndex(), 0, self.rowCount() - 1)
|
||||
self.__items.clear()
|
||||
self.endRemoveRows()
|
||||
self.endResetModel()
|
||||
|
||||
def rowCount(self, *args):
|
||||
return len(self.__items)
|
||||
|
||||
def data(self, index, role):
|
||||
if (
|
||||
index.isValid()
|
||||
and 0 <= index.row() < self.rowCount()
|
||||
and index.column() == 0
|
||||
):
|
||||
return self.__items[index.row()].get(role)
|
||||
return None
|
||||
|
||||
def setData(self, *args):
|
||||
return False
|
||||
|
||||
def addItem(self, imagePath: str):
|
||||
if imagePath in self.imagePaths or not QFileInfo(imagePath).exists():
|
||||
return
|
||||
|
||||
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
|
||||
self.__items.append(
|
||||
{
|
||||
self.ImagePathRole: imagePath,
|
||||
self.ImagePixmapRole: QPixmap(imagePath),
|
||||
self.RecognizeResultRole: None,
|
||||
self.ScoreInsertRole: None,
|
||||
self.ChartRole: None,
|
||||
self.ScoreValidateOkRole: False,
|
||||
}
|
||||
)
|
||||
self.endInsertRows()
|
||||
|
||||
def updateOcrResult(self, row: int, result: RecognizeResult) -> bool:
|
||||
if not 0 <= row < self.rowCount() or not isinstance(result, RecognizeResult):
|
||||
return False
|
||||
|
||||
item = self.__items[row]
|
||||
|
||||
imagePath: str = item[self.ImagePathRole]
|
||||
datetime = None
|
||||
with contextlib.suppress(Exception):
|
||||
with open(imagePath, "rb") as imgf:
|
||||
exifImage = exif.Image(imgf.read())
|
||||
if exifImage.has_exif and exifImage.get("datetime_original"):
|
||||
datetimeStr = exifImage.get("datetime_original")
|
||||
datetime = QDateTime.fromString(datetimeStr, "yyyy:MM:dd hh:mm:ss")
|
||||
if not isinstance(datetime, QDateTime):
|
||||
datetime = QFileInfo(imagePath).birthTime()
|
||||
|
||||
score = ScoreInsert(
|
||||
song_id=self.__db.fuzzy_search_song_id(result.title)[0][0],
|
||||
rating_class=result.rating_class,
|
||||
score=result.score,
|
||||
pure=result.pure,
|
||||
far=result.far,
|
||||
lost=result.lost,
|
||||
time=datetime.toSecsSinceEpoch(),
|
||||
max_recall=result.max_recall,
|
||||
clear_type=None,
|
||||
)
|
||||
chart = Chart.from_db_row(
|
||||
self.__db.get_chart(score.song_id, score.rating_class)
|
||||
)
|
||||
|
||||
item[self.RecognizeResultRole] = result
|
||||
self.setItemChart(row, chart)
|
||||
self.setItemScore(row, score)
|
||||
modelIndex = self.index(row, 0)
|
||||
self.dataChanged.emit(
|
||||
modelIndex,
|
||||
modelIndex,
|
||||
[self.RecognizeResultRole, self.ScoreInsertRole, self.ChartRole],
|
||||
)
|
||||
return True
|
||||
|
||||
@Slot(int, RecognizeResult)
|
||||
def ocrTaskReady(self, row: int, result: RecognizeResult):
|
||||
self.updateOcrResult(row, result)
|
||||
|
||||
@Slot(int)
|
||||
def ocrTaskFinished(self, row: int):
|
||||
self.__taskFinishedNum += 1
|
||||
if self.__taskFinishedNum == self.__taskNum:
|
||||
self.finished.emit()
|
||||
|
||||
def startQueue(self, device: Device):
|
||||
self.__taskNum = self.rowCount()
|
||||
self.__taskFinishedNum = 0
|
||||
self.started.emit()
|
||||
for row in range(self.rowCount()):
|
||||
modelIndex = self.index(row, 0)
|
||||
imagePath: str = modelIndex.data(self.ImagePathRole)
|
||||
task = OcrTask(row, device, imagePath)
|
||||
task.signals.resultReady.connect(self.ocrTaskReady)
|
||||
task.signals.finished.connect(self.ocrTaskFinished)
|
||||
QThreadPool.globalInstance().start(task)
|
||||
|
||||
def updateScoreValidateOk(self, row: int):
|
||||
if not 0 <= row < self.rowCount():
|
||||
return
|
||||
|
||||
item = self.__items[row]
|
||||
chart = item[self.ChartRole]
|
||||
score = item[self.ScoreInsertRole]
|
||||
if isinstance(chart, Chart) and isinstance(score, ScoreInsert):
|
||||
scoreRange = calculate_score_range(chart, score.pure, score.far)
|
||||
scoreValidateOk = scoreRange[0] <= score.score <= scoreRange[1]
|
||||
item[self.ScoreValidateOkRole] = scoreValidateOk
|
||||
else:
|
||||
item[self.ScoreValidateOkRole] = False
|
||||
|
||||
modelIndex = self.index(row, 0)
|
||||
self.dataChanged.emit(modelIndex, modelIndex, [self.ScoreValidateOkRole])
|
||||
|
||||
def setItemChart(self, row: int, chart: Chart):
|
||||
if not 0 <= row < self.rowCount() or not isinstance(chart, Chart):
|
||||
return False
|
||||
|
||||
item = self.__items[row]
|
||||
item[self.ChartRole] = chart
|
||||
updatedRoles = [self.ChartRole]
|
||||
|
||||
self.updateScoreValidateOk(row)
|
||||
|
||||
modelIndex = self.index(row, 0)
|
||||
self.dataChanged.emit(modelIndex, modelIndex, updatedRoles)
|
||||
return True
|
||||
|
||||
def setItemScore(self, row: int, score: ScoreInsert) -> bool:
|
||||
if not 0 <= row < self.rowCount() or not isinstance(score, ScoreInsert):
|
||||
return False
|
||||
|
||||
item = self.__items[row]
|
||||
item[self.ScoreInsertRole] = score
|
||||
updatedRoles = [self.ScoreInsertRole]
|
||||
|
||||
self.updateScoreValidateOk(row)
|
||||
|
||||
modelIndex = self.index(row, 0)
|
||||
self.dataChanged.emit(modelIndex, modelIndex, updatedRoles)
|
||||
return True
|
||||
|
||||
def acceptItem(self, row: int, ignoreValidate: bool = False):
|
||||
if not 0 <= row < self.rowCount():
|
||||
return
|
||||
|
||||
item = self.__items[row]
|
||||
score = item[self.ScoreInsertRole]
|
||||
if not isinstance(score, ScoreInsert) or (
|
||||
not item[self.ScoreValidateOkRole] and not ignoreValidate
|
||||
):
|
||||
return
|
||||
|
||||
try:
|
||||
self.__db.insert_score(score)
|
||||
self.beginRemoveRows(QModelIndex(), row, row)
|
||||
self.__items.pop(row)
|
||||
self.endRemoveRows()
|
||||
return
|
||||
except Exception as e:
|
||||
logger.exception(f"Error accepting {repr(item)}")
|
||||
return
|
||||
|
||||
def acceptItems(self, __rows: list[int], ignoreValidate: bool = False):
|
||||
items = sorted(__rows, reverse=True)
|
||||
[self.acceptItem(item, ignoreValidate) for item in items]
|
||||
|
||||
def acceptAllItems(self, ignoreValidate: bool = False):
|
||||
self.acceptItems([*range(self.rowCount())], ignoreValidate)
|
||||
|
||||
def removeItem(self, row: int):
|
||||
if not 0 <= row < self.rowCount():
|
||||
return
|
||||
|
||||
self.beginRemoveRows(QModelIndex(), row, row)
|
||||
self.__items.pop(row)
|
||||
self.endRemoveRows()
|
||||
|
||||
def removeItems(self, __rows: list[int]):
|
||||
rows = sorted(__rows, reverse=True)
|
||||
[self.removeItem(row) for row in rows]
|
||||
|
||||
|
||||
class OcrQueueTableProxyModel(QAbstractTableModel):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.retranslateHeaders()
|
||||
self.__sourceModel = None
|
||||
self.__columnRoleMapping = [
|
||||
[Qt.ItemDataRole.CheckStateRole],
|
||||
[OcrQueueModel.ImagePathRole, OcrQueueModel.ImagePixmapRole],
|
||||
[
|
||||
OcrQueueModel.RecognizeResultRole,
|
||||
OcrQueueModel.ChartRole,
|
||||
],
|
||||
[
|
||||
OcrQueueModel.RecognizeResultRole,
|
||||
OcrQueueModel.ScoreInsertRole,
|
||||
OcrQueueModel.ChartRole,
|
||||
OcrQueueModel.ScoreValidateOkRole,
|
||||
],
|
||||
]
|
||||
|
||||
def retranslateHeaders(self):
|
||||
self.__horizontalHeaders = [
|
||||
# fmt: off
|
||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.select"),
|
||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.imagePreview"),
|
||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.chart"),
|
||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.score"),
|
||||
# fmt: on
|
||||
]
|
||||
|
||||
def sourceModel(self) -> OcrQueueModel:
|
||||
return self.__sourceModel
|
||||
|
||||
def setSourceModel(self, sourceModel):
|
||||
if not isinstance(sourceModel, OcrQueueModel):
|
||||
return False
|
||||
|
||||
# connect signals
|
||||
sourceModel.rowsAboutToBeInserted.connect(self.rowsAboutToBeInserted)
|
||||
sourceModel.rowsInserted.connect(self.rowsInserted)
|
||||
sourceModel.rowsAboutToBeRemoved.connect(self.rowsAboutToBeRemoved)
|
||||
sourceModel.rowsRemoved.connect(self.rowsRemoved)
|
||||
sourceModel.dataChanged.connect(self.dataChanged)
|
||||
sourceModel.layoutAboutToBeChanged.connect(self.layoutAboutToBeChanged)
|
||||
sourceModel.layoutChanged.connect(self.layoutChanged)
|
||||
|
||||
self.__sourceModel = sourceModel
|
||||
return True
|
||||
|
||||
def rowCount(self, *args):
|
||||
return self.sourceModel().rowCount()
|
||||
|
||||
def columnCount(self, *args):
|
||||
return len(self.__horizontalHeaders)
|
||||
|
||||
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
|
||||
if (
|
||||
orientation == Qt.Orientation.Horizontal
|
||||
and 0 <= section < len(self.__horizontalHeaders)
|
||||
and role == Qt.ItemDataRole.DisplayRole
|
||||
):
|
||||
return self.__horizontalHeaders[section]
|
||||
return None
|
||||
|
||||
def data(self, index, role):
|
||||
if (
|
||||
0 <= index.row() < self.rowCount()
|
||||
and 0 <= index.column() < self.columnCount()
|
||||
and role in self.__columnRoleMapping[index.column()]
|
||||
):
|
||||
srcIndex = self.sourceModel().index(index.row(), 0)
|
||||
return srcIndex.data(role)
|
||||
return None
|
||||
|
||||
def setData(self, index, value, role):
|
||||
if index.column() == 2 and role == OcrQueueModel.ChartRole:
|
||||
return self.sourceModel().setItemChart(index.row(), value)
|
||||
if index.column() == 3 and role == OcrQueueModel.ScoreInsertRole:
|
||||
return self.sourceModel().setItemScore(index.row(), value)
|
||||
return False
|
||||
|
||||
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
|
||||
flags = (
|
||||
self.sourceModel().flags(index)
|
||||
if isinstance(self.sourceModel(), OcrQueueModel)
|
||||
else super().flags(index)
|
||||
)
|
||||
flags = flags | Qt.ItemFlag.ItemIsEnabled
|
||||
flags = flags | Qt.ItemFlag.ItemIsEditable
|
||||
flags = flags | Qt.ItemFlag.ItemIsSelectable
|
||||
if index.column() == 0:
|
||||
flags = flags & ~Qt.ItemFlag.ItemIsEnabled & ~Qt.ItemFlag.ItemIsEditable
|
||||
return flags
|
||||
|
||||
|
||||
class ImageDelegate(QStyledItemDelegate):
|
||||
def getPixmap(self, index: QModelIndex):
|
||||
return index.data(OcrQueueModel.ImagePixmapRole)
|
||||
|
||||
def getImagePath(self, index: QModelIndex):
|
||||
return index.data(OcrQueueModel.ImagePathRole)
|
||||
|
||||
def scalePixmap(self, pixmap: QPixmap):
|
||||
return pixmap.scaled(
|
||||
100,
|
||||
100,
|
||||
Qt.AspectRatioMode.KeepAspectRatio,
|
||||
Qt.TransformationMode.SmoothTransformation,
|
||||
)
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
pixmap = self.getPixmap(index)
|
||||
if not isinstance(pixmap, QPixmap):
|
||||
imagePath = self.getImagePath(index)
|
||||
option.text = imagePath
|
||||
super().paint(painter, option, index)
|
||||
else:
|
||||
pixmap = self.scalePixmap(pixmap)
|
||||
# https://stackoverflow.com/a/32047499/16484891
|
||||
# CC BY-SA 3.0
|
||||
x = option.rect.center().x() - pixmap.rect().width() / 2
|
||||
y = option.rect.center().y() - pixmap.rect().height() / 2
|
||||
|
||||
painter.drawPixmap(
|
||||
QRect(x, y, pixmap.rect().width(), pixmap.rect().height()), pixmap
|
||||
)
|
||||
|
||||
def sizeHint(self, option, index) -> QSize:
|
||||
pixmap = self.getPixmap(index)
|
||||
if isinstance(pixmap, QPixmap):
|
||||
pixmap = self.scalePixmap(pixmap)
|
||||
return pixmap.size()
|
||||
else:
|
||||
return QSize(100, 75)
|
||||
|
||||
def createEditor(self, parent, option, index) -> QWidget:
|
||||
pixmap = self.getPixmap(index)
|
||||
if isinstance(pixmap, QPixmap):
|
||||
label = QLabel(parent)
|
||||
label.setWindowFlags(Qt.WindowType.Window)
|
||||
label.setWindowFlag(Qt.WindowType.WindowMinimizeButtonHint, False)
|
||||
label.setWindowFlag(Qt.WindowType.WindowMaximizeButtonHint, False)
|
||||
label.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, True)
|
||||
label.setWindowTitle(QFileInfo(self.getImagePath(index)).fileName())
|
||||
pixmap = pixmap.scaled(
|
||||
800,
|
||||
800,
|
||||
Qt.AspectRatioMode.KeepAspectRatio,
|
||||
Qt.TransformationMode.SmoothTransformation,
|
||||
)
|
||||
label.setMinimumSize(pixmap.size())
|
||||
label.setPixmap(pixmap)
|
||||
label.move(parent.mapToGlobal(parent.pos()))
|
||||
return label
|
||||
|
||||
def setModelData(self, *args):
|
||||
...
|
||||
|
||||
def updateEditorGeometry(self, *args):
|
||||
...
|
||||
|
||||
|
||||
class TableChartDelegate(ChartDelegate):
|
||||
def getChart(self, index: QModelIndex) -> Chart | None:
|
||||
return index.data(OcrQueueModel.ChartRole)
|
||||
|
||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||
return isinstance(
|
||||
index.data(OcrQueueModel.RecognizeResultRole), RecognizeResult
|
||||
)
|
||||
|
||||
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
|
||||
if editor.validate():
|
||||
model.setData(index, editor.value(), OcrQueueModel.ChartRole)
|
||||
|
||||
|
||||
class TableScoreDelegate(ScoreDelegate):
|
||||
def getScoreInsert(self, index: QModelIndex):
|
||||
return index.data(OcrQueueModel.ScoreInsertRole)
|
||||
|
||||
def getChart(self, index: QModelIndex):
|
||||
return index.data(OcrQueueModel.ChartRole)
|
||||
|
||||
def getScoreValidateOk(self, index: QModelIndex):
|
||||
return index.data(OcrQueueModel.ScoreValidateOkRole)
|
||||
|
||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||
return isinstance(
|
||||
index.data(OcrQueueModel.RecognizeResultRole), RecognizeResult
|
||||
)
|
||||
|
||||
# def createEditor(self, parent, option, index):
|
||||
# editor = super().createEditor(parent, option, index)
|
||||
# editor.setManualHandleCommit(True)
|
||||
# return editor
|
||||
|
||||
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
|
||||
# userAcceptMessageBox = editor.triggerValidateMessageBox()
|
||||
# if userAcceptMessageBox:
|
||||
# model.setData(index, editor.value(), OcrQueueModel.ScoreInsertRole)
|
||||
if super().confirmSetModelData(editor):
|
||||
model.setData(index, editor.value(), OcrQueueModel.ScoreInsertRole)
|
6
ui/implements/components/__init__.py
Normal file
6
ui/implements/components/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
from .chartSelector import ChartSelector
|
||||
from .devicesComboBox import DevicesComboBox
|
||||
from .elidedLabel import ElidedLabel
|
||||
from .fileSelector import FileSelector
|
||||
from .ratingClassRadioButton import RatingClassRadioButton
|
||||
from .scoreEditor import ScoreEditor
|
254
ui/implements/components/chartSelector.py
Normal file
254
ui/implements/components/chartSelector.py
Normal file
@ -0,0 +1,254 @@
|
||||
from typing import Literal
|
||||
|
||||
from arcaea_offline.database import Database
|
||||
from arcaea_offline.models import Chart, Package
|
||||
from arcaea_offline.utils import rating_class_to_text
|
||||
from PySide6.QtCore import QModelIndex, Qt, Signal, Slot
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QCompleter, QWidget
|
||||
|
||||
from ui.designer.components.chartSelector_ui import Ui_ChartSelector
|
||||
from ui.extends.components.chartSelector import FuzzySearchCompleterModel
|
||||
from ui.extends.shared.delegates.descriptionDelegate import DescriptionDelegate
|
||||
from ui.implements.components.ratingClassRadioButton import RatingClassRadioButton
|
||||
|
||||
|
||||
class ChartSelector(Ui_ChartSelector, QWidget):
|
||||
valueChanged = Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.db = Database()
|
||||
self.db.register_update_hook(self.fillPackageComboBox)
|
||||
self.setupUi(self)
|
||||
|
||||
self.pstButton.setColors(QColor("#399bb2"), QColor("#f0f8fa"))
|
||||
self.prsButton.setColors(QColor("#809955"), QColor("#f7f9f4"))
|
||||
self.ftrButton.setColors(QColor("#702d60"), QColor("#f7ebf4"))
|
||||
self.bydButton.setColors(QColor("#710f25"), QColor("#f9ced8"))
|
||||
self.__RATING_CLASS_BUTTONS = [
|
||||
self.pstButton,
|
||||
self.prsButton,
|
||||
self.ftrButton,
|
||||
self.bydButton,
|
||||
]
|
||||
self.pstButton.clicked.connect(self.selectRatingClass)
|
||||
self.prsButton.clicked.connect(self.selectRatingClass)
|
||||
self.ftrButton.clicked.connect(self.selectRatingClass)
|
||||
self.bydButton.clicked.connect(self.selectRatingClass)
|
||||
self.deselectAllRatingClassButtons()
|
||||
self.updateRatingClassButtonsEnabled([])
|
||||
|
||||
self.previousPackageButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("previous", "package")
|
||||
)
|
||||
self.previousSongIdButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("previous", "songId")
|
||||
)
|
||||
self.nextSongIdButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("next", "songId")
|
||||
)
|
||||
self.nextPackageButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("next", "package")
|
||||
)
|
||||
|
||||
self.valueChanged.connect(self.updateResultLabel)
|
||||
|
||||
self.fillPackageComboBox()
|
||||
self.packageComboBox.setCurrentIndex(-1)
|
||||
self.songIdComboBox.setCurrentIndex(-1)
|
||||
|
||||
self.fuzzySearchCompleterModel = FuzzySearchCompleterModel()
|
||||
self.fuzzySearchCompleter = QCompleter(self.fuzzySearchCompleterModel)
|
||||
self.fuzzySearchCompleter.popup().setItemDelegate(
|
||||
DescriptionDelegate(self.fuzzySearchCompleter.popup())
|
||||
)
|
||||
self.fuzzySearchCompleter.activated[QModelIndex].connect(
|
||||
self.fuzzySearchCompleterSetSelection
|
||||
)
|
||||
self.fuzzySearchLineEdit.setCompleter(self.fuzzySearchCompleter)
|
||||
|
||||
self.packageComboBox.setItemDelegate(DescriptionDelegate(self.packageComboBox))
|
||||
self.songIdComboBox.setItemDelegate(DescriptionDelegate(self.songIdComboBox))
|
||||
|
||||
self.pstButton.toggled.connect(self.valueChanged)
|
||||
self.prsButton.toggled.connect(self.valueChanged)
|
||||
self.ftrButton.toggled.connect(self.valueChanged)
|
||||
self.bydButton.toggled.connect(self.valueChanged)
|
||||
self.packageComboBox.currentIndexChanged.connect(self.valueChanged)
|
||||
self.songIdComboBox.currentIndexChanged.connect(self.valueChanged)
|
||||
|
||||
def quickSwitchSelection(
|
||||
self,
|
||||
direction: Literal["previous", "next"],
|
||||
model: Literal["package", "songId"],
|
||||
):
|
||||
minIndex = 0
|
||||
if model == "package":
|
||||
maxIndex = self.packageComboBox.count() - 1
|
||||
currentIndex = self.packageComboBox.currentIndex() + (
|
||||
1 if direction == "next" else -1
|
||||
)
|
||||
currentIndex = max(min(maxIndex, currentIndex), minIndex)
|
||||
self.packageComboBox.setCurrentIndex(currentIndex)
|
||||
elif model == "songId":
|
||||
maxIndex = self.songIdComboBox.count() - 1
|
||||
currentIndex = self.songIdComboBox.currentIndex() + (
|
||||
1 if direction == "next" else -1
|
||||
)
|
||||
currentIndex = max(min(maxIndex, currentIndex), minIndex)
|
||||
self.songIdComboBox.setCurrentIndex(currentIndex)
|
||||
else:
|
||||
return
|
||||
|
||||
def value(self):
|
||||
packageId = self.packageComboBox.currentData()
|
||||
songId = self.songIdComboBox.currentData()
|
||||
ratingClass = self.selectedRatingClass()
|
||||
|
||||
if packageId and songId and isinstance(ratingClass, int):
|
||||
return Chart.from_db_row(self.db.get_chart(songId, ratingClass))
|
||||
return None
|
||||
|
||||
@Slot()
|
||||
def updateResultLabel(self):
|
||||
chart = self.value()
|
||||
if isinstance(chart, Chart):
|
||||
package = Package.from_db_row(
|
||||
self.db.get_package_by_package_id(chart.package_id)
|
||||
)
|
||||
texts = [
|
||||
[package.name, chart.name_en, rating_class_to_text(chart.rating_class)],
|
||||
[package.id, chart.song_id, str(chart.rating_class)],
|
||||
]
|
||||
texts = [" | ".join(t) for t in texts]
|
||||
text = f'{texts[0]}<br><font color="gray">{texts[1]}</font>'
|
||||
self.resultLabel.setText(text)
|
||||
else:
|
||||
self.resultLabel.setText("...")
|
||||
|
||||
def fillPackageComboBox(self):
|
||||
self.packageComboBox.clear()
|
||||
packages = [Package.from_db_row(dbRow) for dbRow in self.db.get_packages()]
|
||||
for package in packages:
|
||||
self.packageComboBox.addItem(f"{package.name} ({package.id})", package.id)
|
||||
row = self.packageComboBox.count() - 1
|
||||
self.packageComboBox.setItemData(
|
||||
row, package.name, DescriptionDelegate.MainTextRole
|
||||
)
|
||||
self.packageComboBox.setItemData(
|
||||
row, package.id, DescriptionDelegate.DescriptionTextRole
|
||||
)
|
||||
|
||||
self.packageComboBox.setCurrentIndex(-1)
|
||||
|
||||
def fillSongIdComboBox(self):
|
||||
self.songIdComboBox.clear()
|
||||
packageId = self.packageComboBox.currentData()
|
||||
if packageId:
|
||||
charts = [
|
||||
Chart.from_db_row(dbRow)
|
||||
for dbRow in self.db.get_charts_by_package_id(packageId)
|
||||
]
|
||||
inserted_song_ids = []
|
||||
for chart in charts:
|
||||
if chart.song_id not in inserted_song_ids:
|
||||
self.songIdComboBox.addItem(
|
||||
f"{chart.name_en} ({chart.song_id})", chart.song_id
|
||||
)
|
||||
inserted_song_ids.append(chart.song_id)
|
||||
row = self.songIdComboBox.count() - 1
|
||||
self.songIdComboBox.setItemData(
|
||||
row, chart.name_en, DescriptionDelegate.MainTextRole
|
||||
)
|
||||
self.songIdComboBox.setItemData(
|
||||
row, chart.song_id, DescriptionDelegate.DescriptionTextRole
|
||||
)
|
||||
self.songIdComboBox.setCurrentIndex(-1)
|
||||
|
||||
@Slot()
|
||||
def on_packageComboBox_activated(self):
|
||||
self.fillSongIdComboBox()
|
||||
|
||||
@Slot(int)
|
||||
def on_songIdComboBox_currentIndexChanged(self, index: int):
|
||||
rating_classes = []
|
||||
if index > -1:
|
||||
charts = [
|
||||
Chart.from_db_row(dbRow)
|
||||
for dbRow in self.db.get_charts_by_song_id(
|
||||
self.songIdComboBox.currentData()
|
||||
)
|
||||
]
|
||||
rating_classes = [chart.rating_class for chart in charts]
|
||||
self.updateRatingClassButtonsEnabled(rating_classes)
|
||||
|
||||
@Slot()
|
||||
def on_resetButton_clicked(self):
|
||||
self.packageComboBox.setCurrentIndex(-1)
|
||||
self.songIdComboBox.setCurrentIndex(-1)
|
||||
|
||||
@Slot(str)
|
||||
def on_fuzzySearchLineEdit_textChanged(self, text: str):
|
||||
if text:
|
||||
self.fuzzySearchCompleterModel.fillDbFuzzySearchResults(self.db, text)
|
||||
else:
|
||||
self.fuzzySearchCompleterModel.clear()
|
||||
|
||||
def selectChart(self, chart: Chart):
|
||||
packageIdIndex = self.packageComboBox.findData(chart.package_id)
|
||||
if packageIdIndex > -1:
|
||||
self.packageComboBox.setCurrentIndex(packageIdIndex)
|
||||
else:
|
||||
# QMessageBox
|
||||
return
|
||||
|
||||
self.fillSongIdComboBox()
|
||||
songIdIndex = self.songIdComboBox.findData(chart.song_id)
|
||||
if songIdIndex > -1:
|
||||
self.songIdComboBox.setCurrentIndex(songIdIndex)
|
||||
else:
|
||||
# QMessageBox
|
||||
return
|
||||
|
||||
self.selectRatingClass(chart.rating_class)
|
||||
|
||||
@Slot(QModelIndex)
|
||||
def fuzzySearchCompleterSetSelection(self, index: QModelIndex):
|
||||
chart = index.data(Qt.ItemDataRole.UserRole + 10) # type: Chart
|
||||
self.selectChart(chart)
|
||||
|
||||
self.fuzzySearchLineEdit.clear()
|
||||
self.fuzzySearchLineEdit.clearFocus()
|
||||
|
||||
def ratingClassButtons(self):
|
||||
return self.__RATING_CLASS_BUTTONS
|
||||
|
||||
def selectedRatingClass(self):
|
||||
for i, button in enumerate(self.__RATING_CLASS_BUTTONS):
|
||||
if button.isChecked():
|
||||
return i
|
||||
|
||||
def updateRatingClassButtonsEnabled(self, rating_classes: list[int]):
|
||||
for i, button in enumerate(self.__RATING_CLASS_BUTTONS):
|
||||
if i in rating_classes:
|
||||
button.setEnabled(True)
|
||||
else:
|
||||
button.setChecked(False)
|
||||
button.setEnabled(False)
|
||||
|
||||
def deselectAllRatingClassButtons(self):
|
||||
[button.setChecked(False) for button in self.__RATING_CLASS_BUTTONS]
|
||||
|
||||
@Slot()
|
||||
def selectRatingClass(self, rating_class: int | None = None):
|
||||
if type(rating_class) == int and rating_class in range(4):
|
||||
self.deselectAllRatingClassButtons()
|
||||
button = self.__RATING_CLASS_BUTTONS[rating_class]
|
||||
if button.isEnabled():
|
||||
button.setChecked(True)
|
||||
else:
|
||||
button = self.sender()
|
||||
if isinstance(button, RatingClassRadioButton) and button.isEnabled():
|
||||
self.deselectAllRatingClassButtons()
|
||||
button.setChecked(True)
|
9
ui/implements/components/dbTableViewer.py
Normal file
9
ui/implements/components/dbTableViewer.py
Normal file
@ -0,0 +1,9 @@
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from ui.designer.components.dbTableViewer_ui import Ui_DbTableViewer
|
||||
|
||||
|
||||
class DbTableViewer(Ui_DbTableViewer, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
32
ui/implements/components/devicesComboBox.py
Normal file
32
ui/implements/components/devicesComboBox.py
Normal file
@ -0,0 +1,32 @@
|
||||
from arcaea_offline_ocr.device import Device
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QComboBox
|
||||
|
||||
from ui.extends.ocr import load_devices_json
|
||||
from ui.extends.shared.delegates.descriptionDelegate import DescriptionDelegate
|
||||
|
||||
|
||||
class DevicesComboBox(QComboBox):
|
||||
DeviceUuidRole = Qt.ItemDataRole.UserRole + 10
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setItemDelegate(DescriptionDelegate(self))
|
||||
|
||||
def setDevices(self, devices: list[Device]):
|
||||
self.clear()
|
||||
for device in devices:
|
||||
self.addItem(f"{device.name} ({device.uuid})", device)
|
||||
row = self.count() - 1
|
||||
self.setItemData(row, device.uuid, self.DeviceUuidRole)
|
||||
self.setItemData(row, device.name, DescriptionDelegate.MainTextRole)
|
||||
self.setItemData(row, device.uuid, DescriptionDelegate.DescriptionTextRole)
|
||||
self.setCurrentIndex(-1)
|
||||
|
||||
def loadDevicesJson(self, path: str):
|
||||
devices = load_devices_json(path)
|
||||
self.setDevices(devices)
|
||||
|
||||
def selectDevice(self, deviceUuid: str):
|
||||
index = self.findData(deviceUuid, self.DeviceUuidRole)
|
||||
self.setCurrentIndex(index)
|
50
ui/implements/components/elidedLabel.py
Normal file
50
ui/implements/components/elidedLabel.py
Normal file
@ -0,0 +1,50 @@
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QLabel
|
||||
|
||||
|
||||
class ElidedLabel(QLabel):
|
||||
"""
|
||||
Adapted from https://wiki.qt.io/Elided_Label
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.__elideMode: Qt.TextElideMode = Qt.TextElideMode.ElideNone
|
||||
self.__cachedElidedText = ""
|
||||
self.__cachedText = ""
|
||||
|
||||
def elideMode(self):
|
||||
return self.__elideMode
|
||||
|
||||
def setElideMode(self, mode):
|
||||
self.__elideMode = mode
|
||||
self.__cachedText = ""
|
||||
self.update()
|
||||
|
||||
def resizeEvent(self, event):
|
||||
super().resizeEvent(event)
|
||||
self.__cachedText = ""
|
||||
|
||||
def paintEvent(self, event) -> None:
|
||||
if self.__elideMode == Qt.TextElideMode.ElideNone:
|
||||
return super().paintEvent(event)
|
||||
|
||||
self.updateCachedTexts()
|
||||
super().setText(self.__cachedElidedText)
|
||||
super().paintEvent(event)
|
||||
super().setText(self.__cachedText)
|
||||
|
||||
def updateCachedTexts(self):
|
||||
text = self.text()
|
||||
if self.__cachedText == text:
|
||||
return
|
||||
self.__cachedText = text
|
||||
fontMetrics = self.fontMetrics()
|
||||
self.__cachedElidedText = fontMetrics.elidedText(
|
||||
self.text(), self.__elideMode, self.width(), Qt.TextFlag.TextShowMnemonic
|
||||
)
|
||||
# make sure to show at least the first character
|
||||
if self.__cachedText:
|
||||
firstChar = f"{self.__cachedText[0]}..."
|
||||
self.setMinimumWidth(fontMetrics.horizontalAdvance(firstChar) + 1)
|
91
ui/implements/components/fileSelector.py
Normal file
91
ui/implements/components/fileSelector.py
Normal file
@ -0,0 +1,91 @@
|
||||
from PySide6.QtCore import QDir, QFileInfo, QMetaObject, Qt, Signal, Slot
|
||||
from PySide6.QtWidgets import QFileDialog, QWidget
|
||||
|
||||
from ui.designer.components.fileSelector_ui import Ui_FileSelector
|
||||
|
||||
|
||||
class FileSelector(Ui_FileSelector, QWidget):
|
||||
accepted = Signal()
|
||||
filesSelected = Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.reset()
|
||||
|
||||
self.elidedLabel.setElideMode(Qt.TextElideMode.ElideMiddle)
|
||||
|
||||
self.accepted.connect(self.filesSelected)
|
||||
self.accepted.connect(self.updateLabel)
|
||||
self.filesSelected.connect(self.updateLabel)
|
||||
|
||||
self.__mode = self.getOpenFileNames
|
||||
|
||||
def getOpenFileNames(self):
|
||||
selectedFiles, filter = QFileDialog.getOpenFileNames(
|
||||
self,
|
||||
self.__caption,
|
||||
self.__startDirectory,
|
||||
self.__filter,
|
||||
"",
|
||||
options=self.__options,
|
||||
)
|
||||
if selectedFiles:
|
||||
self.__selectedFiles = selectedFiles
|
||||
self.accepted.emit()
|
||||
|
||||
def getExistingDirectory(self):
|
||||
selectedDir = QFileDialog.getExistingDirectory(
|
||||
self,
|
||||
self.__caption,
|
||||
self.__startDirectory,
|
||||
QFileDialog.Option.ShowDirsOnly | self.__options,
|
||||
)
|
||||
if selectedDir:
|
||||
self.__selectedFiles = [selectedDir]
|
||||
self.accepted.emit()
|
||||
|
||||
def selectFile(self, filename: str):
|
||||
fileInfo = QFileInfo(filename)
|
||||
if not fileInfo.exists():
|
||||
return
|
||||
|
||||
self.__selectedFiles = [fileInfo.absoluteFilePath()]
|
||||
self.__startDirectory = fileInfo.dir().absolutePath()
|
||||
self.filesSelected.emit()
|
||||
|
||||
def selectedFiles(self):
|
||||
return self.__selectedFiles
|
||||
|
||||
def setNameFilters(self, filters: list[str]):
|
||||
self.__filter = ";;".join(filters) if filters else ""
|
||||
|
||||
def setOptions(self, options: QFileDialog.Option):
|
||||
self.__options = options
|
||||
|
||||
def setMode(self, mode):
|
||||
if mode in [self.getOpenFileNames, self.getExistingDirectory]:
|
||||
self.__mode = mode
|
||||
else:
|
||||
raise ValueError("Invalid mode")
|
||||
|
||||
def reset(self):
|
||||
self.__selectedFiles = []
|
||||
self.__caption = None
|
||||
self.__startDirectory = QDir.currentPath()
|
||||
self.__filter = ""
|
||||
self.__options = QFileDialog.Option(0)
|
||||
|
||||
self.updateLabel()
|
||||
|
||||
def updateLabel(self):
|
||||
selectedFiles = self.selectedFiles()
|
||||
|
||||
if not selectedFiles:
|
||||
self.elidedLabel.setText("...")
|
||||
else:
|
||||
self.elidedLabel.setText("<br>".join(selectedFiles))
|
||||
|
||||
@Slot()
|
||||
def on_selectButton_clicked(self):
|
||||
self.__mode()
|
15
ui/implements/components/focusSelectAllLineEdit.py
Normal file
15
ui/implements/components/focusSelectAllLineEdit.py
Normal file
@ -0,0 +1,15 @@
|
||||
from PySide6.QtWidgets import QLineEdit
|
||||
|
||||
|
||||
class FocusSelectAllLineEdit(QLineEdit):
|
||||
def mousePressEvent(self, event):
|
||||
super().mousePressEvent(event)
|
||||
self.selectAll()
|
||||
|
||||
def focusInEvent(self, event):
|
||||
super().focusInEvent(event)
|
||||
self.selectAll()
|
||||
|
||||
def focusOutEvent(self, event):
|
||||
super().focusOutEvent(event)
|
||||
self.deselect()
|
100
ui/implements/components/ratingClassRadioButton.py
Normal file
100
ui/implements/components/ratingClassRadioButton.py
Normal file
@ -0,0 +1,100 @@
|
||||
from PySide6.QtCore import Slot
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QGraphicsColorizeEffect, QRadioButton
|
||||
|
||||
from ui.extends.color import mix_color
|
||||
|
||||
STYLESHEET = """
|
||||
QRadioButton {{
|
||||
padding: 10px;
|
||||
background-color: qlineargradient(spread:pad, x1:0.7, y1:0.5, x2:1, y2:0.525, stop:0 {dark_color}, stop:1 {mid_color});
|
||||
color: {text_color};
|
||||
}}
|
||||
|
||||
QRadioButton::indicator {{
|
||||
border: 2px solid palette(Window);
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 0px;
|
||||
}}
|
||||
|
||||
QRadioButton::indicator:unchecked {{
|
||||
background-color: palette(Window);
|
||||
}}
|
||||
|
||||
QPushButton::indicator:checked {{
|
||||
background-color: {mid_color};
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
class RatingClassRadioButton(QRadioButton):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
|
||||
self.toggled.connect(self.updateCheckedEffect)
|
||||
|
||||
self.grayscaleEffect = QGraphicsColorizeEffect(self)
|
||||
self.grayscaleEffect.setColor("#000000")
|
||||
|
||||
def setColors(self, dark_color: QColor, text_color: QColor):
|
||||
self._dark_color = dark_color
|
||||
self._text_color = text_color
|
||||
self._mid_color = mix_color(dark_color, text_color, 0.616)
|
||||
self.updateEffects()
|
||||
|
||||
def isColorsSet(self) -> bool:
|
||||
return (
|
||||
hasattr(self, "_dark_color")
|
||||
and hasattr(self, "_text_color")
|
||||
and hasattr(self, "_mid_color")
|
||||
and isinstance(self._dark_color, QColor)
|
||||
and isinstance(self._text_color, QColor)
|
||||
and isinstance(self._mid_color, QColor)
|
||||
)
|
||||
|
||||
def setNormalStyleSheet(self):
|
||||
self.setStyleSheet(
|
||||
STYLESHEET.format(
|
||||
dark_color=self._dark_color.name(QColor.NameFormat.HexArgb),
|
||||
mid_color=self._mid_color.name(QColor.NameFormat.HexArgb),
|
||||
text_color=self._text_color.name(QColor.NameFormat.HexArgb),
|
||||
)
|
||||
)
|
||||
|
||||
def setDisabledStyleSheet(self):
|
||||
self.setStyleSheet(
|
||||
STYLESHEET.format(
|
||||
dark_color="#282828",
|
||||
mid_color="#282828",
|
||||
text_color="#9e9e9e",
|
||||
).replace("palette(Window)", "#333333")
|
||||
)
|
||||
|
||||
@Slot()
|
||||
def updateEnabledEffect(self):
|
||||
if self.isColorsSet():
|
||||
if self.isEnabled():
|
||||
self.setNormalStyleSheet()
|
||||
else:
|
||||
self.setDisabledStyleSheet()
|
||||
|
||||
@Slot()
|
||||
def updateCheckedEffect(self):
|
||||
if self.isColorsSet():
|
||||
if self.isEnabled():
|
||||
self.grayscaleEffect.setStrength(0.0 if self.isChecked() else 1.0)
|
||||
self.setGraphicsEffect(self.grayscaleEffect)
|
||||
|
||||
@Slot()
|
||||
def updateEffects(self):
|
||||
self.updateCheckedEffect()
|
||||
self.updateEnabledEffect()
|
||||
|
||||
def setChecked(self, arg__1: bool):
|
||||
super().setChecked(arg__1)
|
||||
self.updateEffects()
|
||||
|
||||
def setEnabled(self, arg__1: bool):
|
||||
super().setEnabled(arg__1)
|
||||
self.updateEffects()
|
197
ui/implements/components/scoreEditor.py
Normal file
197
ui/implements/components/scoreEditor.py
Normal file
@ -0,0 +1,197 @@
|
||||
from enum import IntEnum
|
||||
from typing import Optional
|
||||
|
||||
from arcaea_offline.calculate import calculate_score_range
|
||||
from arcaea_offline.models import Chart, Score, ScoreInsert
|
||||
from PySide6.QtCore import QCoreApplication, QDateTime, Signal, Slot
|
||||
from PySide6.QtWidgets import QMessageBox, QWidget
|
||||
|
||||
from ui.designer.components.scoreEditor_ui import Ui_ScoreEditor
|
||||
|
||||
|
||||
class ScoreValidateResult(IntEnum):
|
||||
Ok = 0
|
||||
ScoreMismatch = 1
|
||||
ScoreEmpty = 2
|
||||
ChartInvalid = 50
|
||||
|
||||
|
||||
class ScoreEditor(Ui_ScoreEditor, QWidget):
|
||||
valueChanged = Signal()
|
||||
accepted = Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.__validateBeforeAccept = True
|
||||
self.__chart = None
|
||||
|
||||
self.scoreLineEdit.textChanged.connect(self.valueChanged)
|
||||
self.pureSpinBox.valueChanged.connect(self.valueChanged)
|
||||
self.farSpinBox.valueChanged.connect(self.valueChanged)
|
||||
self.lostSpinBox.valueChanged.connect(self.valueChanged)
|
||||
self.dateTimeEdit.dateTimeChanged.connect(self.valueChanged)
|
||||
self.maxRecallSpinBox.valueChanged.connect(self.valueChanged)
|
||||
self.clearTypeComboBox.currentIndexChanged.connect(self.valueChanged)
|
||||
self.valueChanged.connect(self.validateScore)
|
||||
self.valueChanged.connect(self.updateValidateLabel)
|
||||
|
||||
self.clearTypeComboBox.addItem("HARD LOST", -1)
|
||||
self.clearTypeComboBox.addItem("TRACK LOST", 0)
|
||||
self.clearTypeComboBox.addItem("TRACK COMPLETE", 1)
|
||||
self.clearTypeComboBox.setCurrentIndex(-1)
|
||||
|
||||
def setValidateBeforeAccept(self, __bool: bool):
|
||||
self.__validateBeforeAccept = __bool
|
||||
|
||||
def triggerValidateMessageBox(self):
|
||||
validate = self.validateScore()
|
||||
|
||||
if validate == ScoreValidateResult.Ok:
|
||||
return True
|
||||
if validate == ScoreValidateResult.ChartInvalid:
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
# fmt: off
|
||||
QCoreApplication.translate("ScoreEditor", "chartInvalidDialog.title"),
|
||||
QCoreApplication.translate("ScoreEditor", "chartInvalidDialog.title"),
|
||||
# fmt: on
|
||||
)
|
||||
return False
|
||||
if validate == ScoreValidateResult.ScoreMismatch:
|
||||
result = QMessageBox.warning(
|
||||
self,
|
||||
# fmt: off
|
||||
QCoreApplication.translate("ScoreEditor", "scoreMismatchDialog.title"),
|
||||
QCoreApplication.translate("ScoreEditor", "scoreMismatchDialog.content"),
|
||||
# fmt: on
|
||||
QMessageBox.StandardButton.Yes,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
return result == QMessageBox.StandardButton.Yes
|
||||
elif validate == ScoreValidateResult.ScoreEmpty:
|
||||
result = QMessageBox.warning(
|
||||
self,
|
||||
# fmt: off
|
||||
QCoreApplication.translate("ScoreEditor", "emptyScoreDialog.title"),
|
||||
QCoreApplication.translate("ScoreEditor", "emptyScoreDialog.content"),
|
||||
# fmt: on
|
||||
QMessageBox.StandardButton.Yes,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
return result == QMessageBox.StandardButton.Yes
|
||||
else:
|
||||
return False
|
||||
|
||||
@Slot()
|
||||
def on_commitButton_clicked(self):
|
||||
userAccept = (
|
||||
self.triggerValidateMessageBox() if self.__validateBeforeAccept else True
|
||||
)
|
||||
|
||||
if userAccept:
|
||||
self.accepted.emit()
|
||||
|
||||
def score(self):
|
||||
score_text = self.scoreLineEdit.text().replace("'", "")
|
||||
return int(score_text) if score_text else 0
|
||||
|
||||
def setMinimums(self):
|
||||
self.pureSpinBox.setMinimum(0)
|
||||
self.farSpinBox.setMinimum(0)
|
||||
self.lostSpinBox.setMinimum(0)
|
||||
self.maxRecallSpinBox.setMinimum(-1)
|
||||
|
||||
def setLimits(self, chart: Chart):
|
||||
self.setMinimums()
|
||||
self.pureSpinBox.setMaximum(chart.note)
|
||||
self.farSpinBox.setMaximum(chart.note)
|
||||
self.lostSpinBox.setMaximum(chart.note)
|
||||
self.maxRecallSpinBox.setMaximum(chart.note)
|
||||
|
||||
def resetLimits(self):
|
||||
self.setMinimums()
|
||||
self.pureSpinBox.setMaximum(0)
|
||||
self.farSpinBox.setMaximum(0)
|
||||
self.lostSpinBox.setMaximum(0)
|
||||
self.maxRecallSpinBox.setMaximum(0)
|
||||
|
||||
def setChart(self, chart: Optional[Chart]):
|
||||
if isinstance(chart, Chart):
|
||||
self.__chart = chart
|
||||
self.setLimits(chart)
|
||||
else:
|
||||
self.__chart = None
|
||||
self.resetLimits()
|
||||
self.updateValidateLabel()
|
||||
|
||||
def validateScore(self) -> ScoreValidateResult:
|
||||
if not isinstance(self.__chart, Chart):
|
||||
return ScoreValidateResult.ChartInvalid
|
||||
|
||||
score = self.value()
|
||||
|
||||
score_range = calculate_score_range(self.__chart, score.pure, score.far)
|
||||
score_in_range = score_range[0] <= score.score <= score_range[1]
|
||||
note_in_range = score.pure + score.far + score.lost <= self.__chart.note
|
||||
if not score_in_range or not note_in_range:
|
||||
return ScoreValidateResult.ScoreMismatch
|
||||
if score.score == 0:
|
||||
return ScoreValidateResult.ScoreEmpty
|
||||
return ScoreValidateResult.Ok
|
||||
|
||||
def updateValidateLabel(self):
|
||||
validate = self.validateScore()
|
||||
|
||||
if validate == ScoreValidateResult.Ok:
|
||||
text = QCoreApplication.translate("ScoreEditor", "validate.ok")
|
||||
elif validate == ScoreValidateResult.ChartInvalid:
|
||||
text = QCoreApplication.translate("ScoreEditor", "validate.chartInvalid")
|
||||
elif validate == ScoreValidateResult.ScoreMismatch:
|
||||
text = QCoreApplication.translate("ScoreEditor", "validate.scoreMismatch")
|
||||
elif validate == ScoreValidateResult.ScoreEmpty:
|
||||
text = QCoreApplication.translate("ScoreEditor", "validate.scoreEmpty")
|
||||
else:
|
||||
text = QCoreApplication.translate("ScoreEditor", "validate.unknownState")
|
||||
|
||||
self.validateLabel.setText(text)
|
||||
|
||||
def value(self):
|
||||
if isinstance(self.__chart, Chart):
|
||||
return ScoreInsert(
|
||||
song_id=self.__chart.song_id,
|
||||
rating_class=self.__chart.rating_class,
|
||||
score=self.score(),
|
||||
pure=self.pureSpinBox.value(),
|
||||
far=self.farSpinBox.value(),
|
||||
lost=self.lostSpinBox.value(),
|
||||
time=self.dateTimeEdit.dateTime().toSecsSinceEpoch(),
|
||||
max_recall=self.maxRecallSpinBox.value()
|
||||
if self.maxRecallSpinBox.value() > -1
|
||||
else None,
|
||||
clear_type=None,
|
||||
)
|
||||
|
||||
def setValue(self, score: Score | ScoreInsert):
|
||||
if isinstance(score, (Score, ScoreInsert)):
|
||||
scoreText = str(score.score)
|
||||
scoreText = scoreText.rjust(8, "0")
|
||||
self.scoreLineEdit.setText(scoreText)
|
||||
self.pureSpinBox.setValue(score.pure)
|
||||
self.farSpinBox.setValue(score.far)
|
||||
self.lostSpinBox.setValue(score.lost)
|
||||
self.dateTimeEdit.setDateTime(QDateTime.fromSecsSinceEpoch(score.time))
|
||||
if score.max_recall is not None:
|
||||
self.maxRecallSpinBox.setValue(score.max_recall)
|
||||
if score.clear_type is not None:
|
||||
self.clearTypeComboBox.setCurrentIndex(score.clear_type)
|
||||
|
||||
def reset(self):
|
||||
self.setChart(None)
|
||||
self.scoreLineEdit.setText("''")
|
||||
self.pureSpinBox.setValue(0)
|
||||
self.farSpinBox.setValue(0)
|
||||
self.lostSpinBox.setValue(0)
|
||||
self.maxRecallSpinBox.setValue(-1)
|
||||
self.clearTypeComboBox.setCurrentIndex(-1)
|
38
ui/implements/mainwindow.py
Normal file
38
ui/implements/mainwindow.py
Normal file
@ -0,0 +1,38 @@
|
||||
from traceback import format_exception
|
||||
|
||||
from PySide6.QtWidgets import QMainWindow
|
||||
|
||||
from ui.designer.mainwindow_ui import Ui_MainWindow
|
||||
from ui.implements.tabs.tabOcr import TabOcr
|
||||
|
||||
# try:
|
||||
# import arcaea_offline_ocr
|
||||
|
||||
# from ui.implements.tabs.tabOcr import TabOcr
|
||||
|
||||
# OCR_ENABLED_FLAG = True
|
||||
# except Exception as e:
|
||||
# from ui.implements.tabs.tabOcrDisabled import TabOcrDisabled
|
||||
|
||||
# OCR_ENABLED_FLAG = False
|
||||
# OCR_ERROR_TEXT = "\n".join(format_exception(e))
|
||||
|
||||
|
||||
class MainWindow(Ui_MainWindow, QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
currentIndex = self.tabWidget.currentIndex()
|
||||
ocrTabIndex = self.tabWidget.indexOf(self.tab_ocr)
|
||||
self.tabWidget.removeTab(ocrTabIndex)
|
||||
self.tab_ocr.deleteLater()
|
||||
# if OCR_ENABLED_FLAG:
|
||||
# self.tab_ocr = TabOcr(self.tabWidget)
|
||||
# else:
|
||||
# self.tab_ocr = TabOcrDisabled(self.tabWidget)
|
||||
# self.tab_ocr.contentLabel.setText(OCR_ERROR_TEXT)
|
||||
self.tab_ocr = TabOcr(self.tabWidget)
|
||||
self.tabWidget.insertTab(ocrTabIndex, self.tab_ocr, "")
|
||||
self.tabWidget.setCurrentIndex(currentIndex)
|
||||
self.retranslateUi(self)
|
73
ui/implements/settings/settingsDefault.py
Normal file
73
ui/implements/settings/settingsDefault.py
Normal file
@ -0,0 +1,73 @@
|
||||
from arcaea_offline.database import Database
|
||||
from PySide6.QtCore import Slot
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from ui.designer.settings.settingsDefault_ui import Ui_SettingsDefault
|
||||
from ui.extends.ocr import load_devices_json
|
||||
from ui.extends.settings import *
|
||||
|
||||
|
||||
class SettingsDefault(Ui_SettingsDefault, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.settings = Settings(self)
|
||||
|
||||
self.devicesJsonFileSelector.filesSelected.connect(self.fillDevicesComboBox)
|
||||
self.devicesJsonFileResetButton.clicked.connect(self.resetDevicesJsonFile)
|
||||
self.deviceUuidResetButton.clicked.connect(self.resetDeviceUuid)
|
||||
|
||||
devicesJsonPath = self.settings.devicesJsonFile()
|
||||
self.devicesJsonFileSelector.selectFile(devicesJsonPath)
|
||||
tesseractPath = self.settings.tesseractPath()
|
||||
self.tesseractFileSelector.selectFile(tesseractPath)
|
||||
|
||||
self.devicesJsonFileSelector.accepted.connect(
|
||||
self.on_devicesJsonFileSelector_accepted
|
||||
)
|
||||
self.tesseractFileSelector.accepted.connect(
|
||||
self.on_tesseractFileSelector_accepted
|
||||
)
|
||||
|
||||
def setDevicesJsonFile(self):
|
||||
try:
|
||||
filename = self.devicesJsonFileSelector.selectedFiles()[0]
|
||||
devices = load_devices_json(filename)
|
||||
assert isinstance(devices, list)
|
||||
self.settings.setDevicesJsonFile(filename)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# QMessageBox
|
||||
return
|
||||
|
||||
def resetDevicesJsonFile(self):
|
||||
self.devicesJsonFileSelector.reset()
|
||||
self.settings.resetDevicesJsonFile()
|
||||
|
||||
def on_devicesJsonFileSelector_accepted(self):
|
||||
self.setDevicesJsonFile()
|
||||
|
||||
def fillDevicesComboBox(self):
|
||||
devicesJsonPath = self.devicesJsonFileSelector.selectedFiles()[0]
|
||||
self.devicesComboBox.loadDevicesJson(devicesJsonPath)
|
||||
|
||||
storedDeviceUuid = self.settings.deviceUuid()
|
||||
self.devicesComboBox.selectDevice(storedDeviceUuid)
|
||||
|
||||
@Slot()
|
||||
def on_devicesComboBox_activated(self):
|
||||
device = self.devicesComboBox.currentData()
|
||||
if device:
|
||||
self.settings.setDeviceUuid(device.uuid)
|
||||
|
||||
def resetDeviceUuid(self):
|
||||
self.devicesComboBox.setCurrentIndex(-1)
|
||||
self.settings.resetDeviceUuid()
|
||||
|
||||
def setTesseractFile(self):
|
||||
file = self.tesseractFileSelector.selectedFiles()[0]
|
||||
self.settings.setTesseractPath(file)
|
||||
|
||||
def on_tesseractFileSelector_accepted(self):
|
||||
self.setTesseractFile()
|
23
ui/implements/tabs/tabAbout.py
Normal file
23
ui/implements/tabs/tabAbout.py
Normal file
@ -0,0 +1,23 @@
|
||||
from PySide6.QtCore import Qt, Slot
|
||||
from PySide6.QtGui import QPixmap
|
||||
from PySide6.QtWidgets import QMessageBox, QWidget
|
||||
|
||||
from ui.designer.tabs.tabAbout_ui import Ui_TabAbout
|
||||
|
||||
|
||||
class TabAbout(Ui_TabAbout, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
logoPixmap = QPixmap(":/images/logo.png").scaled(
|
||||
300,
|
||||
300,
|
||||
Qt.AspectRatioMode.KeepAspectRatio,
|
||||
Qt.TransformationMode.SmoothTransformation,
|
||||
)
|
||||
self.logoLabel.setPixmap(logoPixmap)
|
||||
|
||||
@Slot()
|
||||
def on_aboutQtButton_clicked(self):
|
||||
QMessageBox.aboutQt(self)
|
30
ui/implements/tabs/tabDb/tabDb_Manage.py
Normal file
30
ui/implements/tabs/tabDb/tabDb_Manage.py
Normal file
@ -0,0 +1,30 @@
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from arcaea_offline.database import Database
|
||||
from PySide6.QtCore import Slot
|
||||
from PySide6.QtWidgets import QFileDialog, QMessageBox, QWidget
|
||||
|
||||
from ui.designer.tabs.tabDb.tabDb_Manage_ui import Ui_TabDb_Manage
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TabDb_Manage(Ui_TabDb_Manage, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
@Slot()
|
||||
def on_syncArcSongDbButton_clicked(self):
|
||||
dbFile, filter = QFileDialog.getOpenFileName(
|
||||
self, None, "", "DB File (*.db);;*"
|
||||
)
|
||||
try:
|
||||
Database().update_arcsong_db(dbFile)
|
||||
QMessageBox.information(self, "OK", "OK")
|
||||
except Exception as e:
|
||||
logging.exception("Sync arcsong.db error")
|
||||
QMessageBox.critical(
|
||||
self, "Sync Error", "\n".join(traceback.format_exception(e))
|
||||
)
|
114
ui/implements/tabs/tabDb/tabDb_ScoreTableViewer.py
Normal file
114
ui/implements/tabs/tabDb/tabDb_ScoreTableViewer.py
Normal file
@ -0,0 +1,114 @@
|
||||
from arcaea_offline.models import ScoreInsert
|
||||
from PySide6.QtCore import QModelIndex, Qt, Slot
|
||||
from PySide6.QtGui import QColor, QPalette
|
||||
from PySide6.QtWidgets import QMessageBox
|
||||
|
||||
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
||||
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
||||
from ui.extends.shared.models.tables.score import (
|
||||
DbScoreTableModel,
|
||||
DbScoreTableSortFilterProxyModel,
|
||||
)
|
||||
from ui.implements.components.dbTableViewer import DbTableViewer
|
||||
|
||||
|
||||
class TableChartDelegate(ChartDelegate):
|
||||
def getChart(self, index):
|
||||
return index.data(DbScoreTableModel.ChartRole)
|
||||
|
||||
|
||||
class TableScoreDelegate(ScoreDelegate):
|
||||
def getChart(self, index):
|
||||
return index.data(DbScoreTableModel.ChartRole)
|
||||
|
||||
def getScoreInsert(self, index: QModelIndex) -> ScoreInsert | None:
|
||||
return super().getScoreInsert(index)
|
||||
|
||||
def getScore(self, index):
|
||||
return index.data(DbScoreTableModel.ScoreRole)
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
if super().confirmSetModelData(editor):
|
||||
model.setData(index, editor.value(), DbScoreTableModel.ScoreRole)
|
||||
|
||||
|
||||
class DbScoreTableViewer(DbTableViewer):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.tableModel = DbScoreTableModel(self)
|
||||
self.tableProxyModel = DbScoreTableSortFilterProxyModel(self)
|
||||
self.tableProxyModel.setSourceModel(self.tableModel)
|
||||
self.tableView.setModel(self.tableProxyModel)
|
||||
self.tableView.setItemDelegateForColumn(1, TableChartDelegate(self.tableView))
|
||||
self.tableView.setItemDelegateForColumn(2, TableScoreDelegate(self.tableView))
|
||||
|
||||
tableViewPalette = QPalette(self.tableView.palette())
|
||||
highlightColor = QColor(tableViewPalette.color(QPalette.ColorRole.Highlight))
|
||||
highlightColor.setAlpha(25)
|
||||
tableViewPalette.setColor(QPalette.ColorRole.Highlight, highlightColor)
|
||||
self.tableView.setPalette(tableViewPalette)
|
||||
self.tableModel.dataChanged.connect(self.resizeTableView)
|
||||
|
||||
self.fillSortComboBox()
|
||||
|
||||
def fillSortComboBox(self):
|
||||
self.sort_comboBox.addItem("ID", [0, 1])
|
||||
self.sort_comboBox.addItem(
|
||||
"Score", [2, DbScoreTableSortFilterProxyModel.Sort_C2_ScoreRole]
|
||||
)
|
||||
self.sort_comboBox.addItem(
|
||||
"Time", [2, DbScoreTableSortFilterProxyModel.Sort_C2_TimeRole]
|
||||
)
|
||||
self.sort_comboBox.addItem("Potential", [3, 1])
|
||||
self.sort_comboBox.setCurrentIndex(0)
|
||||
self.on_sort_comboBox_activated()
|
||||
|
||||
@Slot()
|
||||
def resizeTableView(self):
|
||||
self.tableView.resizeRowsToContents()
|
||||
self.tableView.resizeColumnsToContents()
|
||||
|
||||
@Slot()
|
||||
def on_sort_comboBox_activated(self):
|
||||
self.sortProxyModel()
|
||||
|
||||
@Slot()
|
||||
def on_sort_descendingCheckBox_toggled(self):
|
||||
self.sortProxyModel()
|
||||
|
||||
@Slot()
|
||||
def sortProxyModel(self):
|
||||
if self.sort_comboBox.currentIndex() > -1:
|
||||
column, role = self.sort_comboBox.currentData()
|
||||
self.tableProxyModel.setSortRole(role)
|
||||
self.tableProxyModel.sort(
|
||||
column,
|
||||
Qt.SortOrder.DescendingOrder
|
||||
if self.sort_descendingCheckBox.isChecked()
|
||||
else Qt.SortOrder.AscendingOrder,
|
||||
)
|
||||
|
||||
@Slot()
|
||||
def on_action_removeSelectedButton_clicked(self):
|
||||
rows = [
|
||||
srcIndex.row()
|
||||
for srcIndex in [
|
||||
self.tableProxyModel.mapToSource(proxyIndex)
|
||||
for proxyIndex in self.tableView.selectionModel().selectedRows()
|
||||
]
|
||||
]
|
||||
result = QMessageBox.warning(
|
||||
self,
|
||||
"Warning",
|
||||
f"Removing {len(rows)} row(s). Are you sure?",
|
||||
QMessageBox.StandardButton.Yes,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if result == QMessageBox.StandardButton.Yes:
|
||||
self.tableModel.removeRowList(rows)
|
||||
|
||||
@Slot()
|
||||
def on_refreshButton_clicked(self):
|
||||
self.tableModel.syncDb()
|
||||
self.resizeTableView()
|
16
ui/implements/tabs/tabDbEntry.py
Normal file
16
ui/implements/tabs/tabDbEntry.py
Normal file
@ -0,0 +1,16 @@
|
||||
from PySide6.QtCore import QCoreApplication
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from ui.designer.tabs.tabDbEntry_ui import Ui_TabDbEntry
|
||||
from ui.implements.tabs.tabDb.tabDb_ScoreTableViewer import DbScoreTableViewer
|
||||
|
||||
|
||||
class TabDbEntry(Ui_TabDbEntry, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.tabWidget.addTab(
|
||||
DbScoreTableViewer(self),
|
||||
QCoreApplication.translate("TabDbEntry", "tab.scoreTableViewer"),
|
||||
)
|
33
ui/implements/tabs/tabInputScore.py
Normal file
33
ui/implements/tabs/tabInputScore.py
Normal file
@ -0,0 +1,33 @@
|
||||
import traceback
|
||||
|
||||
from arcaea_offline.database import Database
|
||||
from PySide6.QtCore import QCoreApplication, QModelIndex
|
||||
from PySide6.QtWidgets import QMessageBox, QWidget
|
||||
|
||||
from ui.designer.tabs.tabInputScore_ui import Ui_TabInputScore
|
||||
|
||||
|
||||
class TabInputScore(Ui_TabInputScore, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.chartSelector.valueChanged.connect(self.updateScoreEditorChart)
|
||||
self.scoreEditor.accepted.connect(self.commit)
|
||||
|
||||
def updateScoreEditorChart(self):
|
||||
chart = self.chartSelector.value()
|
||||
self.scoreEditor.setChart(chart)
|
||||
|
||||
def commit(self):
|
||||
try:
|
||||
Database().insert_score(self.scoreEditor.value())
|
||||
self.scoreEditor.reset()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
# fmt: off
|
||||
QCoreApplication.translate("General", "tracebackFormatExceptionOnly.title"),
|
||||
QCoreApplication.translate("General", "tracebackFormatExceptionOnly.content").format(traceback.format_exception_only(e))
|
||||
# fmt: on
|
||||
)
|
133
ui/implements/tabs/tabOcr.py
Normal file
133
ui/implements/tabs/tabOcr.py
Normal file
@ -0,0 +1,133 @@
|
||||
import pytesseract
|
||||
from arcaea_offline_ocr_device_creation_wizard.implements.wizard import Wizard
|
||||
from PySide6.QtCore import QModelIndex, Qt, Slot
|
||||
from PySide6.QtGui import QColor, QPalette
|
||||
from PySide6.QtWidgets import QFileDialog, QWidget
|
||||
|
||||
from ui.designer.tabs.tabOcr_ui import Ui_TabOcr
|
||||
from ui.extends.settings import Settings
|
||||
from ui.extends.tabs.tabOcr import (
|
||||
ImageDelegate,
|
||||
OcrQueueModel,
|
||||
OcrQueueTableProxyModel,
|
||||
TableChartDelegate,
|
||||
TableScoreDelegate,
|
||||
)
|
||||
|
||||
|
||||
class TabOcr(Ui_TabOcr, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.deviceFileSelector.filesSelected.connect(self.deviceFileSelected)
|
||||
self.tesseractFileSelector.filesSelected.connect(
|
||||
self.tesseractFileSelectorFilesSelected
|
||||
)
|
||||
|
||||
settings = Settings()
|
||||
self.deviceFileSelector.selectFile(settings.devicesJsonFile())
|
||||
self.tesseractFileSelector.selectFile(settings.tesseractPath())
|
||||
self.deviceComboBox.selectDevice(settings.deviceUuid())
|
||||
|
||||
self.ocrQueueModel = OcrQueueModel(self)
|
||||
self.ocrQueueModel.dataChanged.connect(self.resizeViewWhenScoreChanged)
|
||||
self.ocrQueueModel.started.connect(self.ocrStarted)
|
||||
self.ocrQueueModel.finished.connect(self.ocrFinished)
|
||||
self.ocrQueueProxyModel = OcrQueueTableProxyModel(self)
|
||||
self.ocrQueueProxyModel.setSourceModel(self.ocrQueueModel)
|
||||
|
||||
self.tableView.setModel(self.ocrQueueProxyModel)
|
||||
self.tableView.setItemDelegateForColumn(1, ImageDelegate(self.tableView))
|
||||
self.tableView.setItemDelegateForColumn(2, TableChartDelegate(self.tableView))
|
||||
self.tableView.setItemDelegateForColumn(3, TableScoreDelegate(self.tableView))
|
||||
|
||||
tableViewPalette = QPalette(self.tableView.palette())
|
||||
highlightColor = QColor(tableViewPalette.color(QPalette.ColorRole.Highlight))
|
||||
highlightColor.setAlpha(25)
|
||||
tableViewPalette.setColor(QPalette.ColorRole.Highlight, highlightColor)
|
||||
self.tableView.setPalette(tableViewPalette)
|
||||
|
||||
@Slot(QModelIndex, QModelIndex, list)
|
||||
def resizeViewWhenScoreChanged(
|
||||
self, topleft: QModelIndex, bottomRight: QModelIndex, roles: list[int]
|
||||
):
|
||||
if OcrQueueModel.ScoreInsertRole in roles:
|
||||
rows = [*range(topleft.row(), bottomRight.row() + 1)]
|
||||
[self.tableView.resizeRowToContents(row) for row in rows]
|
||||
self.tableView.resizeColumnsToContents()
|
||||
|
||||
@Slot()
|
||||
def on_openWizardButton_clicked(self):
|
||||
wizard = Wizard(self)
|
||||
wizard.open()
|
||||
|
||||
def deviceFileSelected(self):
|
||||
selectedFiles = self.deviceFileSelector.selectedFiles()
|
||||
if selectedFiles:
|
||||
file = selectedFiles[0]
|
||||
self.deviceComboBox.loadDevicesJson(file)
|
||||
|
||||
def tesseractFileSelectorFilesSelected(self):
|
||||
selectedFiles = self.tesseractFileSelector.selectedFiles()
|
||||
if selectedFiles:
|
||||
pytesseract.pytesseract.tesseract_cmd = selectedFiles[0]
|
||||
|
||||
def setOcrButtonsEnabled(self, __bool: bool):
|
||||
self.ocr_addImageButton.setEnabled(__bool)
|
||||
self.ocr_removeSelectedButton.setEnabled(__bool)
|
||||
self.ocr_removeAllButton.setEnabled(__bool)
|
||||
self.ocr_startButton.setEnabled(__bool)
|
||||
self.ocr_acceptSelectedButton.setEnabled(__bool)
|
||||
self.ocr_acceptAllButton.setEnabled(__bool)
|
||||
self.ocr_ignoreValidateCheckBox.setEnabled(__bool)
|
||||
|
||||
@Slot()
|
||||
def on_ocr_addImageButton_clicked(self):
|
||||
files, _filter = QFileDialog.getOpenFileNames(
|
||||
self, None, "", "Image Files (*.png *.jpg *.jpeg *.bmp *.webp);;*"
|
||||
)
|
||||
for file in files:
|
||||
self.ocrQueueModel.addItem(file)
|
||||
self.tableView.resizeRowsToContents()
|
||||
self.tableView.resizeColumnsToContents()
|
||||
|
||||
@Slot()
|
||||
def on_ocr_startButton_clicked(self):
|
||||
self.ocrQueueModel.startQueue(self.deviceComboBox.currentData())
|
||||
|
||||
def ocrStarted(self):
|
||||
self.setOcrButtonsEnabled(False)
|
||||
|
||||
def ocrFinished(self):
|
||||
self.setOcrButtonsEnabled(True)
|
||||
|
||||
@Slot()
|
||||
def on_ocr_removeSelectedButton_clicked(self):
|
||||
rows = [
|
||||
modelIndex.row()
|
||||
for modelIndex in self.tableView.selectionModel().selectedRows(0)
|
||||
]
|
||||
self.ocrQueueModel.removeItems(rows)
|
||||
|
||||
@Slot()
|
||||
def on_ocr_removeAllButton_clicked(self):
|
||||
self.ocrQueueModel.clear()
|
||||
|
||||
@Slot()
|
||||
def on_ocr_acceptSelectedButton_clicked(self):
|
||||
ignoreValidate = (
|
||||
self.ocr_ignoreValidateCheckBox.checkState() == Qt.CheckState.Checked
|
||||
)
|
||||
rows = [
|
||||
modelIndex.row()
|
||||
for modelIndex in self.tableView.selectionModel().selectedRows(0)
|
||||
]
|
||||
self.ocrQueueModel.acceptItems(rows, ignoreValidate)
|
||||
|
||||
@Slot()
|
||||
def on_ocr_acceptAllButton_clicked(self):
|
||||
ignoreValidate = (
|
||||
self.ocr_ignoreValidateCheckBox.checkState() == Qt.CheckState.Checked
|
||||
)
|
||||
self.ocrQueueModel.acceptAllItems(ignoreValidate)
|
9
ui/implements/tabs/tabOcrDisabled.py
Normal file
9
ui/implements/tabs/tabOcrDisabled.py
Normal file
@ -0,0 +1,9 @@
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from ui.designer.tabs.tabOcrDisabled_ui import Ui_TabOcrDisabled
|
||||
|
||||
|
||||
class TabOcrDisabled(Ui_TabOcrDisabled, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
18
ui/implements/tabs/tabOverview.py
Normal file
18
ui/implements/tabs/tabOverview.py
Normal file
@ -0,0 +1,18 @@
|
||||
from arcaea_offline.database import Database
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from ui.designer.tabs.tabOverview_ui import Ui_TabOverview
|
||||
|
||||
|
||||
class TabOverview(Ui_TabOverview, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.db = Database()
|
||||
self.db.register_update_hook(self.updateOverview)
|
||||
self.updateOverview()
|
||||
|
||||
def updateOverview(self):
|
||||
b30 = self.db.get_b30() or 0.00
|
||||
self.b30Label.setText(str(f"{b30:.3f}"))
|
23
ui/implements/tabs/tabSettings.py
Normal file
23
ui/implements/tabs/tabSettings.py
Normal file
@ -0,0 +1,23 @@
|
||||
from PySide6.QtCore import QModelIndex, Slot
|
||||
from PySide6.QtWidgets import QListWidgetItem, QWidget
|
||||
|
||||
from ui.designer.tabs.tabSettings_ui import Ui_TabSettings
|
||||
|
||||
|
||||
class SettingsEntryItem(QListWidgetItem):
|
||||
pass
|
||||
|
||||
|
||||
class TabSettings(Ui_TabSettings, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.listWidget.addItem("Default")
|
||||
self.listWidget.activated.connect(self.switchPage)
|
||||
|
||||
self.listWidget.setCurrentRow(self.stackedWidget.currentIndex())
|
||||
|
||||
@Slot(QModelIndex)
|
||||
def switchPage(self, index: QModelIndex):
|
||||
self.stackedWidget.setCurrentIndex(index.row())
|
0
ui/resources/images/__init__.py
Normal file
0
ui/resources/images/__init__.py
Normal file
BIN
ui/resources/images/icon.ico
Normal file
BIN
ui/resources/images/icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 162 KiB |
BIN
ui/resources/images/icon.png
Normal file
BIN
ui/resources/images/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
7
ui/resources/images/images.qrc
Normal file
7
ui/resources/images/images.qrc
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE RCC>
|
||||
<RCC version="1.0">
|
||||
<qresource prefix="/images">
|
||||
<file>icon.png</file>
|
||||
<file>logo.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
ui/resources/images/logo.png
Normal file
BIN
ui/resources/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
0
ui/resources/translations/__init__.py
Normal file
0
ui/resources/translations/__init__.py
Normal file
460
ui/resources/translations/en_US.ts
Normal file
460
ui/resources/translations/en_US.ts
Normal file
@ -0,0 +1,460 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>ChartSelector</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="56"/>
|
||||
<source>fuzzySearch.lineEdit.placeholder</source>
|
||||
<translation>Input here...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="26"/>
|
||||
<source>songIdSelector.title</source>
|
||||
<translation>Select Song</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="88"/>
|
||||
<source>songIdSelector.quickActions</source>
|
||||
<translation>Quick Actions</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="94"/>
|
||||
<source>songIdSelector.quickActions.previousPackageButton</source>
|
||||
<translation>Previous Package</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="101"/>
|
||||
<source>songIdSelector.quickActions.previousSongIdButton</source>
|
||||
<translation>Previous Song</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="108"/>
|
||||
<source>songIdSelector.quickActions.nextSongIdButton</source>
|
||||
<translation>Next Song</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="115"/>
|
||||
<source>songIdSelector.quickActions.nextPackageButton</source>
|
||||
<translation>Next Package</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="134"/>
|
||||
<source>ratingClassSelector.title</source>
|
||||
<translation>Rating Select</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="231"/>
|
||||
<source>resetButton</source>
|
||||
<translation>Reset</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DatabaseChecker</name>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="23"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="130"/>
|
||||
<source>dbPathLabel</source>
|
||||
<translation>Database Path</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="33"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="133"/>
|
||||
<source>dbVersionLabel</source>
|
||||
<translation>Database Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="47"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="136"/>
|
||||
<source>dbInitLabel</source>
|
||||
<translation>Initialize</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="54"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="139"/>
|
||||
<source>dbCheckConnLabel</source>
|
||||
<translation>Database Connection</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="61"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="142"/>
|
||||
<source>dbInitButton</source>
|
||||
<translation>Initialize Database</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="91"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="145"/>
|
||||
<source>continueButton</source>
|
||||
<translation>Continue</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DbScoreTableModel</name>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="22"/>
|
||||
<source>horizontalHeader.id</source>
|
||||
<translation>ID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="23"/>
|
||||
<source>horizontalHeader.chart</source>
|
||||
<translation>Chart</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="24"/>
|
||||
<source>horizontalHeader.score</source>
|
||||
<translation>Score</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="25"/>
|
||||
<source>horizontalHeader.potential</source>
|
||||
<translation>Potential</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DbTableViewer</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="20"/>
|
||||
<source>actions</source>
|
||||
<translation>Actions</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="26"/>
|
||||
<source>actions.removeSelected</source>
|
||||
<translation>Remove Selected</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="46"/>
|
||||
<source>actions.refresh</source>
|
||||
<translation>Refresh</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="81"/>
|
||||
<source>view</source>
|
||||
<translation>View</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="89"/>
|
||||
<source>view.sort.label</source>
|
||||
<translation>Sort By</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="106"/>
|
||||
<source>view.sort.descendingCheckBox</source>
|
||||
<translation>Descending</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="126"/>
|
||||
<source>view.filter.label</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="146"/>
|
||||
<source>view.filter.configureButton</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FileSelector</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/fileSelector.ui" line="45"/>
|
||||
<source>selectButton</source>
|
||||
<translation>Select...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>General</name>
|
||||
<message>
|
||||
<location filename="../../implements/tabs/tabInputScore.py" line="30"/>
|
||||
<source>tracebackFormatExceptionOnly.title</source>
|
||||
<translation>Error</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/tabs/tabInputScore.py" line="31"/>
|
||||
<source>tracebackFormatExceptionOnly.content</source>
|
||||
<translation>Unexpected Error<br>{0}</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="25"/>
|
||||
<source>tab.overview</source>
|
||||
<translation>Overview</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="30"/>
|
||||
<source>tab.input</source>
|
||||
<translation>Input</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="35"/>
|
||||
<source>tab.db</source>
|
||||
<translation>Database</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="40"/>
|
||||
<source>tab.ocr</source>
|
||||
<translation>OCR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="45"/>
|
||||
<source>tab.settings</source>
|
||||
<translation>Settings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="50"/>
|
||||
<source>tab.about</source>
|
||||
<translation>About</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OcrTableModel</name>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="298"/>
|
||||
<source>horizontalHeader.title.select</source>
|
||||
<translation>Select</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="299"/>
|
||||
<source>horizontalHeader.title.imagePreview</source>
|
||||
<translation>Image Preview</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="300"/>
|
||||
<source>horizontalHeader.title.chart</source>
|
||||
<translation>Chart</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="301"/>
|
||||
<source>horizontalHeader.title.score</source>
|
||||
<translation>Score</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ScoreEditor</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="26"/>
|
||||
<source>formLabel.score</source>
|
||||
<translation>Score</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="100"/>
|
||||
<source>formLabel.time</source>
|
||||
<translation>Time</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="191"/>
|
||||
<source>commitButton</source>
|
||||
<translation>Commit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="200"/>
|
||||
<source>formLabel.clearType</source>
|
||||
<translation>Clear Type</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="77"/>
|
||||
<source>emptyScoreDialog.title</source>
|
||||
<translation>Empty Score</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="78"/>
|
||||
<source>emptyScoreDialog.content</source>
|
||||
<translation>Are you sure to commit an empty score?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="57"/>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="58"/>
|
||||
<source>chartInvalidDialog.title</source>
|
||||
<translation>Chart Invalid</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="66"/>
|
||||
<source>scoreMismatchDialog.title</source>
|
||||
<translation>Possible Invalid Score</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="67"/>
|
||||
<source>scoreMismatchDialog.content</source>
|
||||
<translation>The entered score may not match the selected chart. Commit this score anyway?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="149"/>
|
||||
<source>validate.ok</source>
|
||||
<translation>OK</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="151"/>
|
||||
<source>validate.chartInvalid</source>
|
||||
<translation>Chart invalid</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="153"/>
|
||||
<source>validate.scoreMismatch</source>
|
||||
<translation>Possible invalid score</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="155"/>
|
||||
<source>validate.scoreEmpty</source>
|
||||
<translation>Empty score</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="158"/>
|
||||
<source>validate.unknownState</source>
|
||||
<translation>Unknown</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsDefault</name>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="35"/>
|
||||
<source>devicesJsonFile</source>
|
||||
<translation>Default devices.json</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="75"/>
|
||||
<source>deviceUuid</source>
|
||||
<translation>Default Device</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="115"/>
|
||||
<source>tesseractFile</source>
|
||||
<translation>tesseract Path</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="100"/>
|
||||
<source>defaultDevice.resetButton</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="60"/>
|
||||
<source>devicesJsonPath.resetButton</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabAbout</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabAbout.ui" line="79"/>
|
||||
<source>About Qt</source>
|
||||
<translation>About Qt</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabDbEntry</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabDbEntry.ui" line="24"/>
|
||||
<source>tab.manage</source>
|
||||
<translation>Manage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/tabs/tabDbEntry.py" line="15"/>
|
||||
<source>tab.scoreTableViewer</source>
|
||||
<translation>TABLE [Score]</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabDb_Manage</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="23"/>
|
||||
<source>syncArcSongDbButton</source>
|
||||
<translation>Sync arcsong.db</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="30"/>
|
||||
<source>syncArcSongDb.description</source>
|
||||
<translation>Write chart info to database</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabInputScore</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabInputScore.ui" line="26"/>
|
||||
<source>tab.selectChart</source>
|
||||
<translation>Chart Selector</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabInputScore.ui" line="50"/>
|
||||
<source>tab.scoreEdit</source>
|
||||
<translation>Score Edit</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="20"/>
|
||||
<source>openWizardButton</source>
|
||||
<translation>Open Device Creation Wizard</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="27"/>
|
||||
<source>deviceSelector.title</source>
|
||||
<translation>Select Device</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="42"/>
|
||||
<source>tesseractSelector.title</source>
|
||||
<translation>Select tesseract Path</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="54"/>
|
||||
<source>ocr.title</source>
|
||||
<translation>OCR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="60"/>
|
||||
<source>ocr.queue.title</source>
|
||||
<translation>Queue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="66"/>
|
||||
<source>ocr.queue.addImageButton</source>
|
||||
<translation>Add Image</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="76"/>
|
||||
<source>ocr.queue.removeSelected</source>
|
||||
<translation>Remove Selected</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="86"/>
|
||||
<source>ocr.queue.removeAll</source>
|
||||
<translation>Remove All</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="106"/>
|
||||
<source>ocr.queue.startOcrButton</source>
|
||||
<translation>Start OCR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="135"/>
|
||||
<source>ocr.results</source>
|
||||
<translation>Results</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="144"/>
|
||||
<source>ocr.results.acceptSelectedButton</source>
|
||||
<translation>Accept Selected</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="151"/>
|
||||
<source>ocr.results.acceptAllButton</source>
|
||||
<translation>Accept All</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="171"/>
|
||||
<source>ocr.results.ignoreValidate</source>
|
||||
<translation>Ignore
|
||||
validation</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcrDisabled</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcrDisabled.ui" line="81"/>
|
||||
<source>ocrDisabled.title</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
54
ui/resources/translations/extract_translations.py
Normal file
54
ui/resources/translations/extract_translations.py
Normal file
@ -0,0 +1,54 @@
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument(
|
||||
"-no-obsolete",
|
||||
action="store_true",
|
||||
default=False,
|
||||
required=False,
|
||||
dest="no_obsolete",
|
||||
)
|
||||
args = ap.parse_args(sys.argv[1:])
|
||||
|
||||
|
||||
script_file_path = Path(__file__)
|
||||
|
||||
root_dir_path = Path(script_file_path.parent.parent.parent)
|
||||
output_dir_path = Path(script_file_path.parent)
|
||||
|
||||
designer = root_dir_path / "designer"
|
||||
extends = root_dir_path / "extends"
|
||||
implements = root_dir_path / "implements"
|
||||
startup = root_dir_path / "startup"
|
||||
|
||||
assert designer.exists()
|
||||
assert extends.exists()
|
||||
assert implements.exists()
|
||||
assert startup.exists()
|
||||
|
||||
no_obsolete = args.no_obsolete
|
||||
|
||||
commands = [
|
||||
(
|
||||
"pyside6-lupdate"
|
||||
" -extensions py,ui"
|
||||
f" {designer.absolute()} {extends.absolute()} {implements.absolute()} {startup.absolute()}"
|
||||
f" -ts {str((output_dir_path / 'zh_CN.ts').absolute())}"
|
||||
), # zh_CN
|
||||
(
|
||||
"pyside6-lupdate"
|
||||
" -extensions py,ui"
|
||||
f" {designer.absolute()} {extends.absolute()} {implements.absolute()} {startup.absolute()}"
|
||||
f" -ts {str((output_dir_path / 'en_US.ts').absolute())}"
|
||||
), # en_US
|
||||
]
|
||||
if no_obsolete:
|
||||
commands = [f"{command} -no-obsolete" for command in commands]
|
||||
|
||||
for command in commands:
|
||||
print(f"Executing '{command}'")
|
||||
output = os.popen(command).read()
|
||||
print(output)
|
7
ui/resources/translations/translations.qrc
Normal file
7
ui/resources/translations/translations.qrc
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE RCC>
|
||||
<RCC version="1.0">
|
||||
<qresource prefix="/lang">
|
||||
<file>zh_CN.qm</file>
|
||||
<file>en_US.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
459
ui/resources/translations/zh_CN.ts
Normal file
459
ui/resources/translations/zh_CN.ts
Normal file
@ -0,0 +1,459 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="zh_CN">
|
||||
<context>
|
||||
<name>ChartSelector</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="56"/>
|
||||
<source>fuzzySearch.lineEdit.placeholder</source>
|
||||
<translation>在此输入……</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="26"/>
|
||||
<source>songIdSelector.title</source>
|
||||
<translation>选择曲目</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="88"/>
|
||||
<source>songIdSelector.quickActions</source>
|
||||
<translation>快速操作</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="94"/>
|
||||
<source>songIdSelector.quickActions.previousPackageButton</source>
|
||||
<translation>上一曲包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="101"/>
|
||||
<source>songIdSelector.quickActions.previousSongIdButton</source>
|
||||
<translation>上一曲目</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="108"/>
|
||||
<source>songIdSelector.quickActions.nextSongIdButton</source>
|
||||
<translation>下一曲目</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="115"/>
|
||||
<source>songIdSelector.quickActions.nextPackageButton</source>
|
||||
<translation>下一曲包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="134"/>
|
||||
<source>ratingClassSelector.title</source>
|
||||
<translation>难度选择</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/chartSelector.ui" line="231"/>
|
||||
<source>resetButton</source>
|
||||
<translation>重置</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DatabaseChecker</name>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="23"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="130"/>
|
||||
<source>dbPathLabel</source>
|
||||
<translation>数据库路径</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="33"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="133"/>
|
||||
<source>dbVersionLabel</source>
|
||||
<translation>数据库版本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="47"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="136"/>
|
||||
<source>dbInitLabel</source>
|
||||
<translation>初始化</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="54"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="139"/>
|
||||
<source>dbCheckConnLabel</source>
|
||||
<translation>数据库连接</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="61"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="142"/>
|
||||
<source>dbInitButton</source>
|
||||
<translation>初始化数据库</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.ui" line="91"/>
|
||||
<location filename="../../startup/databaseChecker_ui.py" line="145"/>
|
||||
<source>continueButton</source>
|
||||
<translation>继续</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DbScoreTableModel</name>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="22"/>
|
||||
<source>horizontalHeader.id</source>
|
||||
<translation>ID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="23"/>
|
||||
<source>horizontalHeader.chart</source>
|
||||
<translation>谱面</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="24"/>
|
||||
<source>horizontalHeader.score</source>
|
||||
<translation>分数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/shared/models/tables/score.py" line="25"/>
|
||||
<source>horizontalHeader.potential</source>
|
||||
<translation>单曲 PTT</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DbTableViewer</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="20"/>
|
||||
<source>actions</source>
|
||||
<translation>操作</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="26"/>
|
||||
<source>actions.removeSelected</source>
|
||||
<translation>移除选中</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="46"/>
|
||||
<source>actions.refresh</source>
|
||||
<translation>刷新</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="81"/>
|
||||
<source>view</source>
|
||||
<translation>视图</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="89"/>
|
||||
<source>view.sort.label</source>
|
||||
<translation>排序</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="106"/>
|
||||
<source>view.sort.descendingCheckBox</source>
|
||||
<translation>降序</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="126"/>
|
||||
<source>view.filter.label</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/dbTableViewer.ui" line="146"/>
|
||||
<source>view.filter.configureButton</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FileSelector</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/fileSelector.ui" line="45"/>
|
||||
<source>selectButton</source>
|
||||
<translation>选择</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>General</name>
|
||||
<message>
|
||||
<location filename="../../implements/tabs/tabInputScore.py" line="30"/>
|
||||
<source>tracebackFormatExceptionOnly.title</source>
|
||||
<translation>错误</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/tabs/tabInputScore.py" line="31"/>
|
||||
<source>tracebackFormatExceptionOnly.content</source>
|
||||
<translation>错误:{0}</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="25"/>
|
||||
<source>tab.overview</source>
|
||||
<translation>概览</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="30"/>
|
||||
<source>tab.input</source>
|
||||
<translation>录入</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="35"/>
|
||||
<source>tab.db</source>
|
||||
<translation>数据库</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="40"/>
|
||||
<source>tab.ocr</source>
|
||||
<translation>OCR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="45"/>
|
||||
<source>tab.settings</source>
|
||||
<translation>设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/mainwindow.ui" line="50"/>
|
||||
<source>tab.about</source>
|
||||
<translation>关于</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OcrTableModel</name>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="298"/>
|
||||
<source>horizontalHeader.title.select</source>
|
||||
<translation>选择</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="299"/>
|
||||
<source>horizontalHeader.title.imagePreview</source>
|
||||
<translation>图像预览</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="300"/>
|
||||
<source>horizontalHeader.title.chart</source>
|
||||
<translation>谱面</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../extends/tabs/tabOcr.py" line="301"/>
|
||||
<source>horizontalHeader.title.score</source>
|
||||
<translation>分数</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ScoreEditor</name>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="26"/>
|
||||
<source>formLabel.score</source>
|
||||
<translation>分数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="100"/>
|
||||
<source>formLabel.time</source>
|
||||
<translation>时间</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="191"/>
|
||||
<source>commitButton</source>
|
||||
<translation>提交</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/components/scoreEditor.ui" line="200"/>
|
||||
<source>formLabel.clearType</source>
|
||||
<translation>通关状态</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="77"/>
|
||||
<source>emptyScoreDialog.title</source>
|
||||
<translation>分数为空</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="78"/>
|
||||
<source>emptyScoreDialog.content</source>
|
||||
<translation>确定提交空分数吗?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="57"/>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="58"/>
|
||||
<source>chartInvalidDialog.title</source>
|
||||
<translation>谱面无效</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="66"/>
|
||||
<source>scoreMismatchDialog.title</source>
|
||||
<translation>分数可能有误</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="67"/>
|
||||
<source>scoreMismatchDialog.content</source>
|
||||
<translation>输入的分数不在理论计算范围内。是否确认提交?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="149"/>
|
||||
<source>validate.ok</source>
|
||||
<translation>OK</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="151"/>
|
||||
<source>validate.chartInvalid</source>
|
||||
<translation>谱面无效</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="153"/>
|
||||
<source>validate.scoreMismatch</source>
|
||||
<translation>分数可能有误</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="155"/>
|
||||
<source>validate.scoreEmpty</source>
|
||||
<translation>分数为空</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/components/scoreEditor.py" line="158"/>
|
||||
<source>validate.unknownState</source>
|
||||
<translation>未知</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsDefault</name>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="35"/>
|
||||
<source>devicesJsonFile</source>
|
||||
<translation>默认设备文件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="75"/>
|
||||
<source>deviceUuid</source>
|
||||
<translation>默认设备</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="115"/>
|
||||
<source>tesseractFile</source>
|
||||
<translation>tesseract 路径</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="100"/>
|
||||
<source>defaultDevice.resetButton</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/settings/settingsDefault.ui" line="60"/>
|
||||
<source>devicesJsonPath.resetButton</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabAbout</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabAbout.ui" line="79"/>
|
||||
<source>About Qt</source>
|
||||
<translation>关于 Qt</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabDbEntry</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabDbEntry.ui" line="24"/>
|
||||
<source>tab.manage</source>
|
||||
<translation>管理</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../implements/tabs/tabDbEntry.py" line="15"/>
|
||||
<source>tab.scoreTableViewer</source>
|
||||
<translation>表 [分数]</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabDb_Manage</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="23"/>
|
||||
<source>syncArcSongDbButton</source>
|
||||
<translation>同步 arcsong.db</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="30"/>
|
||||
<source>syncArcSongDb.description</source>
|
||||
<translation>将谱面信息写入数据库</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabInputScore</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabInputScore.ui" line="26"/>
|
||||
<source>tab.selectChart</source>
|
||||
<translation>谱面选择</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabInputScore.ui" line="50"/>
|
||||
<source>tab.scoreEdit</source>
|
||||
<translation>分数编辑</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="20"/>
|
||||
<source>openWizardButton</source>
|
||||
<translation>打开设备创建向导</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="27"/>
|
||||
<source>deviceSelector.title</source>
|
||||
<translation>选择设备</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="42"/>
|
||||
<source>tesseractSelector.title</source>
|
||||
<translation>选择 tesseract 路径</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="54"/>
|
||||
<source>ocr.title</source>
|
||||
<translation>OCR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="60"/>
|
||||
<source>ocr.queue.title</source>
|
||||
<translation>队列</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="66"/>
|
||||
<source>ocr.queue.addImageButton</source>
|
||||
<translation>添加图像文件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="76"/>
|
||||
<source>ocr.queue.removeSelected</source>
|
||||
<translation>移除选中</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="86"/>
|
||||
<source>ocr.queue.removeAll</source>
|
||||
<translation>移除所有</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="106"/>
|
||||
<source>ocr.queue.startOcrButton</source>
|
||||
<translation>开始 OCR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="135"/>
|
||||
<source>ocr.results</source>
|
||||
<translation>结果</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="144"/>
|
||||
<source>ocr.results.acceptSelectedButton</source>
|
||||
<translation>提交选中</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="151"/>
|
||||
<source>ocr.results.acceptAllButton</source>
|
||||
<translation>提交所有</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr.ui" line="171"/>
|
||||
<source>ocr.results.ignoreValidate</source>
|
||||
<translation>忽略验证</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcrDisabled</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcrDisabled.ui" line="81"/>
|
||||
<source>ocrDisabled.title</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
0
ui/startup/__init__.py
Normal file
0
ui/startup/__init__.py
Normal file
83
ui/startup/databaseChecker.py
Normal file
83
ui/startup/databaseChecker.py
Normal file
@ -0,0 +1,83 @@
|
||||
import traceback
|
||||
|
||||
from arcaea_offline.database import Database
|
||||
from PySide6.QtCore import QDir, QFile, Qt, QTimer, Slot
|
||||
from PySide6.QtWidgets import QDialog, QMessageBox
|
||||
|
||||
from ui.extends.settings import Settings
|
||||
|
||||
from .databaseChecker_ui import Ui_DatabaseChecker
|
||||
|
||||
|
||||
class DatabaseChecker(Ui_DatabaseChecker, QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.setWindowFlag(Qt.WindowType.WindowMinimizeButtonHint, False)
|
||||
self.setWindowFlag(Qt.WindowType.WindowMaximizeButtonHint, False)
|
||||
self.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, True)
|
||||
self.dbFileSelector.setMode(self.dbFileSelector.getExistingDirectory)
|
||||
self.dbFileSelector.filesSelected.connect(self.fileSelected)
|
||||
|
||||
self.settings = Settings(self)
|
||||
dbDir = self.settings.value("Default/DbDir", None, str)
|
||||
if dbDir and QFile(QDir(dbDir).filePath(Database.dbFilename)).exists():
|
||||
self.dbFileSelector.selectFile(dbDir)
|
||||
result = self.checkDbVersion()
|
||||
if result:
|
||||
QTimer.singleShot(50, self.accept)
|
||||
else:
|
||||
self.dbFileSelector.selectFile(QDir.currentPath())
|
||||
|
||||
def fileSelected(self):
|
||||
self.checkDbVersion()
|
||||
|
||||
def checkDbVersion(self) -> str | None:
|
||||
dbQDir = QDir(self.dbFileSelector.selectedFiles()[0])
|
||||
dbDir = dbQDir.absolutePath()
|
||||
|
||||
dbDir = self.dbFileSelector.selectedFiles()[0]
|
||||
dbQFile = QFile(QDir(dbDir).filePath(Database.dbFilename))
|
||||
if not dbQFile.exists():
|
||||
result = QMessageBox.question(self, "Database", "Create database file now?")
|
||||
if result != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
dbQFile.open(QFile.OpenModeFlag.WriteOnly)
|
||||
dbQFile.close()
|
||||
|
||||
Database.dbDir = dbDir
|
||||
|
||||
try:
|
||||
with Database().conn as conn:
|
||||
version = conn.execute(
|
||||
"SELECT value FROM properties WHERE key = 'db_version'"
|
||||
).fetchone()[0]
|
||||
self.dbVersionLabel.setText(version)
|
||||
self.continueButton.setEnabled(True)
|
||||
|
||||
self.dbCheckConnLabel.setText('<font color="green">OK</font>')
|
||||
self.settings.setValue("Default/DbDir", dbDir)
|
||||
return version
|
||||
except Exception as e:
|
||||
QMessageBox.critical(
|
||||
self, "Database Error", "\n".join(traceback.format_exception(e))
|
||||
)
|
||||
self.dbInitButton.setEnabled(True)
|
||||
self.continueButton.setEnabled(False)
|
||||
self.dbCheckConnLabel.setText('<font color="red">Error</font>')
|
||||
return False
|
||||
|
||||
@Slot()
|
||||
def on_dbInitButton_clicked(self):
|
||||
try:
|
||||
Database().init()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(
|
||||
self, "Database Error", "\n".join(traceback.format_exception(e))
|
||||
)
|
||||
finally:
|
||||
self.checkDbVersion()
|
||||
|
||||
@Slot()
|
||||
def on_continueButton_clicked(self):
|
||||
self.accept()
|
107
ui/startup/databaseChecker.ui
Normal file
107
ui/startup/databaseChecker.ui
Normal file
@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DatabaseChecker</class>
|
||||
<widget class="QWidget" name="DatabaseChecker">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>250</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">DatabaseChecker</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>dbPathLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="FileSelector" name="dbFileSelector" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>dbVersionLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="dbVersionLabel">
|
||||
<property name="text">
|
||||
<string notr="true">-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>dbInitLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>dbCheckConnLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="dbInitButton">
|
||||
<property name="text">
|
||||
<string>dbInitButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="dbCheckConnLabel">
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="continueButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>continueButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FileSelector</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.components.fileSelector</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
148
ui/startup/databaseChecker_ui.py
Normal file
148
ui/startup/databaseChecker_ui.py
Normal file
@ -0,0 +1,148 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'databaseChecker.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.0
|
||||
##
|
||||
## 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,
|
||||
Qt,
|
||||
QTime,
|
||||
QUrl,
|
||||
)
|
||||
from PySide6.QtGui import (
|
||||
QBrush,
|
||||
QColor,
|
||||
QConicalGradient,
|
||||
QCursor,
|
||||
QFont,
|
||||
QFontDatabase,
|
||||
QGradient,
|
||||
QIcon,
|
||||
QImage,
|
||||
QKeySequence,
|
||||
QLinearGradient,
|
||||
QPainter,
|
||||
QPalette,
|
||||
QPixmap,
|
||||
QRadialGradient,
|
||||
QTransform,
|
||||
)
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QFormLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QSpacerItem,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from ui.implements.components.fileSelector import FileSelector
|
||||
|
||||
|
||||
class Ui_DatabaseChecker(object):
|
||||
def setupUi(self, DatabaseChecker):
|
||||
if not DatabaseChecker.objectName():
|
||||
DatabaseChecker.setObjectName("DatabaseChecker")
|
||||
DatabaseChecker.resize(350, 250)
|
||||
DatabaseChecker.setWindowTitle("DatabaseChecker")
|
||||
self.formLayout = QFormLayout(DatabaseChecker)
|
||||
self.formLayout.setObjectName("formLayout")
|
||||
self.formLayout.setLabelAlignment(
|
||||
Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter
|
||||
)
|
||||
self.label = QLabel(DatabaseChecker)
|
||||
self.label.setObjectName("label")
|
||||
|
||||
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label)
|
||||
|
||||
self.dbFileSelector = FileSelector(DatabaseChecker)
|
||||
self.dbFileSelector.setObjectName("dbFileSelector")
|
||||
|
||||
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.dbFileSelector)
|
||||
|
||||
self.label_2 = QLabel(DatabaseChecker)
|
||||
self.label_2.setObjectName("label_2")
|
||||
|
||||
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2)
|
||||
|
||||
self.dbVersionLabel = QLabel(DatabaseChecker)
|
||||
self.dbVersionLabel.setObjectName("dbVersionLabel")
|
||||
self.dbVersionLabel.setText("-")
|
||||
|
||||
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.dbVersionLabel)
|
||||
|
||||
self.label_4 = QLabel(DatabaseChecker)
|
||||
self.label_4.setObjectName("label_4")
|
||||
|
||||
self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_4)
|
||||
|
||||
self.label_5 = QLabel(DatabaseChecker)
|
||||
self.label_5.setObjectName("label_5")
|
||||
|
||||
self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label_5)
|
||||
|
||||
self.dbInitButton = QPushButton(DatabaseChecker)
|
||||
self.dbInitButton.setObjectName("dbInitButton")
|
||||
|
||||
self.formLayout.setWidget(2, QFormLayout.FieldRole, self.dbInitButton)
|
||||
|
||||
self.dbCheckConnLabel = QLabel(DatabaseChecker)
|
||||
self.dbCheckConnLabel.setObjectName("dbCheckConnLabel")
|
||||
self.dbCheckConnLabel.setText("...")
|
||||
|
||||
self.formLayout.setWidget(4, QFormLayout.FieldRole, self.dbCheckConnLabel)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(
|
||||
20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding
|
||||
)
|
||||
|
||||
self.formLayout.setItem(3, QFormLayout.FieldRole, self.verticalSpacer)
|
||||
|
||||
self.continueButton = QPushButton(DatabaseChecker)
|
||||
self.continueButton.setObjectName("continueButton")
|
||||
self.continueButton.setEnabled(False)
|
||||
|
||||
self.formLayout.setWidget(5, QFormLayout.SpanningRole, self.continueButton)
|
||||
|
||||
self.retranslateUi(DatabaseChecker)
|
||||
|
||||
QMetaObject.connectSlotsByName(DatabaseChecker)
|
||||
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, DatabaseChecker):
|
||||
self.label.setText(
|
||||
QCoreApplication.translate("DatabaseChecker", "dbPathLabel", None)
|
||||
)
|
||||
self.label_2.setText(
|
||||
QCoreApplication.translate("DatabaseChecker", "dbVersionLabel", None)
|
||||
)
|
||||
self.label_4.setText(
|
||||
QCoreApplication.translate("DatabaseChecker", "dbInitLabel", None)
|
||||
)
|
||||
self.label_5.setText(
|
||||
QCoreApplication.translate("DatabaseChecker", "dbCheckConnLabel", None)
|
||||
)
|
||||
self.dbInitButton.setText(
|
||||
QCoreApplication.translate("DatabaseChecker", "dbInitButton", None)
|
||||
)
|
||||
self.continueButton.setText(
|
||||
QCoreApplication.translate("DatabaseChecker", "continueButton", None)
|
||||
)
|
||||
pass
|
||||
|
||||
# retranslateUi
|
Reference in New Issue
Block a user