mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 21:32:15 +01:00
263 lines
8.4 KiB
Python
263 lines
8.4 KiB
Python
from qtpy import QtWidgets, QtCore, QtGui
|
|
from openpype import style, resources
|
|
from igniter.nice_progress_bar import NiceProgressBar
|
|
|
|
|
|
class SplashScreen(QtWidgets.QDialog):
|
|
"""Splash screen for executing a process on another thread. It is able
|
|
to inform about the progress of the process and log given information.
|
|
"""
|
|
|
|
splash_icon = None
|
|
top_label = None
|
|
show_log_btn: QtWidgets.QLabel = None
|
|
progress_bar = None
|
|
log_text: QtWidgets.QLabel = None
|
|
scroll_area: QtWidgets.QScrollArea = None
|
|
close_btn: QtWidgets.QPushButton = None
|
|
scroll_bar: QtWidgets.QScrollBar = None
|
|
|
|
is_log_visible = False
|
|
is_scroll_auto = True
|
|
|
|
thread_return_code = None
|
|
q_thread: QtCore.QThread = None
|
|
|
|
def __init__(self,
|
|
window_title: str,
|
|
splash_icon=None,
|
|
window_icon=None):
|
|
"""
|
|
Args:
|
|
window_title (str): String which sets the window title
|
|
splash_icon (str | bytes | None): A resource (pic) which is used
|
|
for the splash icon
|
|
window_icon (str | bytes | None: A resource (pic) which is used for
|
|
the window's icon
|
|
"""
|
|
super(SplashScreen, self).__init__()
|
|
|
|
if splash_icon is None:
|
|
splash_icon = resources.get_openpype_icon_filepath()
|
|
|
|
if window_icon is None:
|
|
window_icon = resources.get_openpype_icon_filepath()
|
|
|
|
self.splash_icon = splash_icon
|
|
self.setWindowIcon(QtGui.QIcon(window_icon))
|
|
self.setWindowTitle(window_title)
|
|
self.init_ui()
|
|
|
|
def was_proc_successful(self) -> bool:
|
|
return self.thread_return_code == 0
|
|
|
|
def start_thread(self, q_thread: QtCore.QThread):
|
|
"""Saves the reference to this thread and starts it.
|
|
|
|
Args:
|
|
q_thread (QtCore.QThread): A QThread containing a given worker
|
|
(QtCore.QObject)
|
|
|
|
Returns:
|
|
None
|
|
"""
|
|
if not q_thread:
|
|
raise RuntimeError("Failed to run a worker thread! "
|
|
"The thread is null!")
|
|
|
|
self.q_thread = q_thread
|
|
self.q_thread.start()
|
|
|
|
@QtCore.Slot()
|
|
def quit_and_close(self):
|
|
"""Quits the thread and closes the splash screen. Note that this means
|
|
the thread has exited with the return code 0!
|
|
|
|
Returns:
|
|
None
|
|
"""
|
|
self.thread_return_code = 0
|
|
self.q_thread.quit()
|
|
|
|
if not self.q_thread.wait(5000):
|
|
raise RuntimeError("Failed to quit the QThread! "
|
|
"The deadline has been reached! The thread "
|
|
"has not finished it's execution!.")
|
|
self.close()
|
|
|
|
|
|
@QtCore.Slot()
|
|
def toggle_log(self):
|
|
if self.is_log_visible:
|
|
self.scroll_area.hide()
|
|
width = self.width()
|
|
self.adjustSize()
|
|
self.resize(width, self.height())
|
|
else:
|
|
self.scroll_area.show()
|
|
self.scroll_bar.setValue(self.scroll_bar.maximum())
|
|
self.resize(self.width(), 300)
|
|
|
|
self.is_log_visible = not self.is_log_visible
|
|
|
|
def show_ui(self):
|
|
"""Shows the splash screen. BEWARE THAT THIS FUNCTION IS BLOCKING
|
|
(The execution of code can not proceed further beyond this function
|
|
until the splash screen is closed!)
|
|
|
|
Returns:
|
|
None
|
|
"""
|
|
self.show()
|
|
self.exec_()
|
|
|
|
def init_ui(self):
|
|
self.resize(450, 100)
|
|
self.setMinimumWidth(250)
|
|
self.setStyleSheet(style.load_stylesheet())
|
|
|
|
# Top Section
|
|
self.top_label = QtWidgets.QLabel(self)
|
|
self.top_label.setText("Starting process ...")
|
|
self.top_label.setWordWrap(True)
|
|
|
|
icon = QtWidgets.QLabel(self)
|
|
icon.setPixmap(QtGui.QPixmap(self.splash_icon))
|
|
icon.setFixedHeight(45)
|
|
icon.setFixedWidth(45)
|
|
icon.setScaledContents(True)
|
|
|
|
self.close_btn = QtWidgets.QPushButton(self)
|
|
self.close_btn.setText("Quit")
|
|
self.close_btn.clicked.connect(self.close)
|
|
self.close_btn.setFixedWidth(80)
|
|
self.close_btn.hide()
|
|
|
|
self.show_log_btn = QtWidgets.QPushButton(self)
|
|
self.show_log_btn.setText("Show log")
|
|
self.show_log_btn.setFixedWidth(80)
|
|
self.show_log_btn.clicked.connect(self.toggle_log)
|
|
|
|
button_layout = QtWidgets.QVBoxLayout()
|
|
button_layout.addWidget(self.show_log_btn)
|
|
button_layout.addWidget(self.close_btn)
|
|
|
|
# Progress Bar
|
|
self.progress_bar = NiceProgressBar()
|
|
self.progress_bar.setValue(0)
|
|
self.progress_bar.setAlignment(QtCore.Qt.AlignTop)
|
|
|
|
# Log Content
|
|
self.scroll_area = QtWidgets.QScrollArea(self)
|
|
self.scroll_area.hide()
|
|
log_widget = QtWidgets.QWidget(self.scroll_area)
|
|
self.scroll_area.setWidgetResizable(True)
|
|
self.scroll_area.setHorizontalScrollBarPolicy(
|
|
QtCore.Qt.ScrollBarAlwaysOn
|
|
)
|
|
self.scroll_area.setVerticalScrollBarPolicy(
|
|
QtCore.Qt.ScrollBarAlwaysOn
|
|
)
|
|
self.scroll_area.setWidget(log_widget)
|
|
|
|
self.scroll_bar = self.scroll_area.verticalScrollBar()
|
|
self.scroll_bar.sliderMoved.connect(self.on_scroll)
|
|
|
|
self.log_text = QtWidgets.QLabel(self)
|
|
self.log_text.setText('')
|
|
self.log_text.setAlignment(QtCore.Qt.AlignTop)
|
|
|
|
log_layout = QtWidgets.QVBoxLayout(log_widget)
|
|
log_layout.addWidget(self.log_text)
|
|
|
|
top_layout = QtWidgets.QHBoxLayout()
|
|
top_layout.setAlignment(QtCore.Qt.AlignTop)
|
|
top_layout.addWidget(icon)
|
|
top_layout.addSpacing(10)
|
|
top_layout.addWidget(self.top_label)
|
|
top_layout.addSpacing(10)
|
|
top_layout.addLayout(button_layout)
|
|
|
|
main_layout = QtWidgets.QVBoxLayout(self)
|
|
main_layout.addLayout(top_layout)
|
|
main_layout.addSpacing(10)
|
|
main_layout.addWidget(self.progress_bar)
|
|
main_layout.addSpacing(10)
|
|
main_layout.addWidget(self.scroll_area)
|
|
|
|
self.setWindowFlags(
|
|
QtCore.Qt.Window
|
|
| QtCore.Qt.CustomizeWindowHint
|
|
| QtCore.Qt.WindowTitleHint
|
|
| QtCore.Qt.WindowMinimizeButtonHint
|
|
)
|
|
|
|
desktop_rect = QtWidgets.QApplication.desktop().availableGeometry(self)
|
|
center = desktop_rect.center()
|
|
self.move(
|
|
center.x() - (self.width() * 0.5),
|
|
center.y() - (self.height() * 0.5)
|
|
)
|
|
|
|
@QtCore.Slot(int)
|
|
def update_progress(self, value: int):
|
|
self.progress_bar.setValue(value)
|
|
|
|
@QtCore.Slot(str)
|
|
def update_top_label_text(self, text: str):
|
|
self.top_label.setText(text)
|
|
|
|
@QtCore.Slot(str, str)
|
|
def append_log(self, text: str, end: str = ''):
|
|
"""A slot used for receiving log info and appending it to scroll area's
|
|
content.
|
|
Args:
|
|
text (str): A log text that will append to the current one in the
|
|
scroll area.
|
|
end (str): end string which can be appended to the end of the given
|
|
line (for ex. a line break).
|
|
|
|
Returns:
|
|
None
|
|
"""
|
|
self.log_text.setText(self.log_text.text() + text + end)
|
|
if self.is_scroll_auto:
|
|
self.scroll_bar.setValue(self.scroll_bar.maximum())
|
|
|
|
@QtCore.Slot(int)
|
|
def on_scroll(self, position: int):
|
|
"""
|
|
A slot for the vertical scroll bar's movement. This ensures the
|
|
auto-scrolling feature of the scroll area when the scroll bar is at its
|
|
maximum value.
|
|
|
|
Args:
|
|
position (int): Position value of the scroll bar.
|
|
|
|
Returns:
|
|
None
|
|
"""
|
|
if self.scroll_bar.maximum() == position:
|
|
self.is_scroll_auto = True
|
|
return
|
|
|
|
self.is_scroll_auto = False
|
|
|
|
@QtCore.Slot(str, int)
|
|
def fail(self, text: str, return_code: int = 1):
|
|
"""
|
|
A slot used for signals which can emit when a worker (process) has
|
|
failed. at this moment the splash screen doesn't close by itself.
|
|
it has to be closed by the user.
|
|
|
|
Args:
|
|
text (str): A text which can be set to the top label.
|
|
|
|
Returns:
|
|
return_code (int): Return code of the thread's code
|
|
"""
|
|
self.top_label.setText(text)
|
|
self.close_btn.show()
|
|
self.thread_return_code = return_code
|
|
self.q_thread.exit(return_code)
|
|
self.q_thread.wait()
|