Merge pull request #4058 from pypeclub/feature/publisher_create_next_animation

Publisher: Easy access to publish page from create page
This commit is contained in:
Jakub Trllo 2022-11-21 18:59:58 +01:00 committed by GitHub
commit 0f4f8884f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 280 additions and 19 deletions

View file

@ -1126,6 +1126,10 @@ ValidationArtistMessage QLabel {
background: transparent;
}
CreateNextPageOverlay {
font-size: 32pt;
}
/* Settings - NOT USED YET
- we need to define font family for settings UI */

View file

@ -8,6 +8,7 @@ from .widgets import (
ResetBtn,
ValidateBtn,
PublishBtn,
CreateNextPageOverlay,
)
from .help_widget import (
HelpButton,
@ -28,6 +29,7 @@ __all__ = (
"ResetBtn",
"ValidateBtn",
"PublishBtn",
"CreateNextPageOverlay",
"HelpButton",
"HelpDialog",

View file

@ -195,6 +195,16 @@ class OverviewWidget(QtWidgets.QFrame):
self._subset_views_widget.setMaximumWidth(view_width)
self._change_anim.start()
def get_subset_views_geo(self):
parent = self._subset_views_widget.parent()
global_pos = parent.mapToGlobal(self._subset_views_widget.pos())
return QtCore.QRect(
global_pos.x(),
global_pos.y(),
self._subset_views_widget.width(),
self._subset_views_widget.height()
)
def _on_create_clicked(self):
"""Pass signal to parent widget which should care about changing state.

View file

@ -511,7 +511,7 @@ class ValidationsWidget(QtWidgets.QFrame):
)
# After success publishing
publish_started_widget = ValidationArtistMessage(
"Publishing went smoothly", self
"So far so good", self
)
# After success publishing
publish_stop_ok_widget = ValidationArtistMessage(

View file

@ -1708,3 +1708,159 @@ class SubsetAttributesWidget(QtWidgets.QWidget):
self._thumbnail_widget.setVisible(True)
self._thumbnail_widget.set_current_thumbnails(thumbnail_paths)
class CreateNextPageOverlay(QtWidgets.QWidget):
clicked = QtCore.Signal()
def __init__(self, parent):
super(CreateNextPageOverlay, self).__init__(parent)
self.setCursor(QtCore.Qt.PointingHandCursor)
self._arrow_color = (
get_objected_colors("font").get_qcolor()
)
self._bg_color = (
get_objected_colors("bg-buttons").get_qcolor()
)
change_anim = QtCore.QVariantAnimation()
change_anim.setStartValue(0.0)
change_anim.setEndValue(1.0)
change_anim.setDuration(200)
change_anim.setEasingCurve(QtCore.QEasingCurve.OutCubic)
change_anim.valueChanged.connect(self._on_anim)
self._change_anim = change_anim
self._is_visible = None
self._anim_value = 0.0
self._increasing = False
self._under_mouse = None
self._handle_show_on_own = True
self._mouse_pressed = False
self.set_visible(True)
def set_increasing(self, increasing):
if self._increasing is increasing:
return
self._increasing = increasing
if increasing:
self._change_anim.setDirection(self._change_anim.Forward)
else:
self._change_anim.setDirection(self._change_anim.Backward)
if self._change_anim.state() != self._change_anim.Running:
self._change_anim.start()
def set_visible(self, visible):
if self._is_visible is visible:
return
self._is_visible = visible
if not visible:
self.set_increasing(False)
if not self._is_anim_finished():
return
self.setVisible(visible)
self._check_anim_timer()
def _is_anim_finished(self):
if self._increasing:
return self._anim_value == 1.0
return self._anim_value == 0.0
def _on_anim(self, value):
self._check_anim_timer()
self._anim_value = value
self.update()
if not self._is_anim_finished():
return
if not self._is_visible:
self.setVisible(False)
def set_under_mouse(self, under_mouse):
if self._under_mouse is under_mouse:
return
self._under_mouse = under_mouse
self.set_increasing(under_mouse)
def _is_under_mouse(self):
mouse_pos = self.mapFromGlobal(QtGui.QCursor.pos())
under_mouse = self.rect().contains(mouse_pos)
return under_mouse
def _check_anim_timer(self):
if not self.isVisible():
return
self.set_increasing(self._under_mouse)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self._mouse_pressed = True
super(CreateNextPageOverlay, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
if self._mouse_pressed:
self._mouse_pressed = False
if self.rect().contains(event.pos()):
self.clicked.emit()
super(CreateNextPageOverlay, self).mouseReleaseEvent(event)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
if self._anim_value == 0.0:
painter.end()
return
painter.setClipRect(event.rect())
painter.setRenderHints(
painter.Antialiasing
| painter.SmoothPixmapTransform
)
painter.setPen(QtCore.Qt.NoPen)
rect = QtCore.QRect(self.rect())
rect_width = rect.width()
rect_height = rect.height()
radius = rect_width * 0.2
x_offset = 0
y_offset = 0
if self._anim_value != 1.0:
x_offset += rect_width - (rect_width * self._anim_value)
arrow_height = rect_height * 0.4
arrow_half_height = arrow_height * 0.5
arrow_x_start = x_offset + ((rect_width - arrow_half_height) * 0.5)
arrow_x_end = arrow_x_start + arrow_half_height
center_y = rect.center().y()
painter.setBrush(self._bg_color)
painter.drawRoundedRect(
x_offset, y_offset,
rect_width + radius, rect_height,
radius, radius
)
src_arrow_path = QtGui.QPainterPath()
src_arrow_path.moveTo(arrow_x_start, center_y - arrow_half_height)
src_arrow_path.lineTo(arrow_x_end, center_y)
src_arrow_path.lineTo(arrow_x_start, center_y + arrow_half_height)
arrow_stroker = QtGui.QPainterPathStroker()
arrow_stroker.setWidth(min(4, arrow_half_height * 0.2))
arrow_path = arrow_stroker.createStroke(src_arrow_path)
painter.fillPath(arrow_path, self._arrow_color)
painter.end()

View file

@ -29,6 +29,8 @@ from .widgets import (
HelpButton,
HelpDialog,
CreateNextPageOverlay,
)
@ -225,8 +227,8 @@ class PublisherWindow(QtWidgets.QDialog):
# Floating publish frame
publish_frame = PublishFrame(controller, self.footer_border, self)
# Timer started on show -> connected to timer counter
# - helps to deffer on show logic by 3 event loops
create_overlay_button = CreateNextPageOverlay(self)
show_timer = QtCore.QTimer()
show_timer.setInterval(1)
show_timer.timeout.connect(self._on_show_timer)
@ -255,6 +257,9 @@ class PublisherWindow(QtWidgets.QDialog):
publish_btn.clicked.connect(self._on_publish_clicked)
publish_frame.details_page_requested.connect(self._go_to_details_tab)
create_overlay_button.clicked.connect(
self._on_create_overlay_button_click
)
controller.event_system.add_callback(
"instances.refresh.finished", self._on_instances_refresh
@ -310,6 +315,7 @@ class PublisherWindow(QtWidgets.QDialog):
self._publish_overlay = publish_overlay
self._publish_frame = publish_frame
self._content_widget = content_widget
self._content_stacked_layout = content_stacked_layout
self._overview_widget = overview_widget
@ -342,6 +348,9 @@ class PublisherWindow(QtWidgets.QDialog):
self._set_publish_visibility(False)
self._create_overlay_button = create_overlay_button
self._app_event_listener_installed = False
self._show_timer = show_timer
self._show_counter = 0
@ -360,6 +369,37 @@ class PublisherWindow(QtWidgets.QDialog):
def resizeEvent(self, event):
super(PublisherWindow, self).resizeEvent(event)
self._update_publish_frame_rect()
self._update_create_overlay_size()
def closeEvent(self, event):
self._uninstall_app_event_listener()
self.save_changes()
self._reset_on_show = True
self._controller.clear_thumbnail_temp_dir_path()
super(PublisherWindow, self).closeEvent(event)
def leaveEvent(self, event):
super(PublisherWindow, self).leaveEvent(event)
self._update_create_overlay_visibility()
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.MouseMove:
self._update_create_overlay_visibility(event.globalPos())
return super(PublisherWindow, self).eventFilter(obj, event)
def _install_app_event_listener(self):
if self._app_event_listener_installed:
return
self._app_event_listener_installed = True
app = QtWidgets.QApplication.instance()
app.installEventFilter(self)
def _uninstall_app_event_listener(self):
if not self._app_event_listener_installed:
return
self._app_event_listener_installed = False
app = QtWidgets.QApplication.instance()
app.removeEventFilter(self)
def keyPressEvent(self, event):
# Ignore escape button to close window
@ -390,17 +430,16 @@ class PublisherWindow(QtWidgets.QDialog):
# Reset counter when done for next show event
self._show_counter = 0
self._update_create_overlay_size()
self._update_create_overlay_visibility()
if self._is_current_tab("create"):
self._install_app_event_listener()
# Reset if requested
if self._reset_on_show:
self._reset_on_show = False
self.reset()
def closeEvent(self, event):
self.save_changes()
self._reset_on_show = True
self._controller.clear_thumbnail_temp_dir_path()
super(PublisherWindow, self).closeEvent(event)
def save_changes(self):
self._controller.save_changes()
@ -411,7 +450,7 @@ class PublisherWindow(QtWidgets.QDialog):
self._context_label.setText(label)
def _update_publish_details_widget(self, force=False):
if not force and self._tabs_widget.current_tab() != "details":
if not force and not self._is_current_tab("details"):
return
report_data = self.controller.get_publish_report()
@ -441,6 +480,10 @@ class PublisherWindow(QtWidgets.QDialog):
self._help_dialog.width(), self._help_dialog.height()
)
def _on_create_overlay_button_click(self):
self._create_overlay_button.set_under_mouse(False)
self._go_to_publish_tab()
def _on_tab_change(self, old_tab, new_tab):
if old_tab == "details":
self._publish_details_widget.close_details_popup()
@ -465,20 +508,36 @@ class PublisherWindow(QtWidgets.QDialog):
self._report_widget
)
is_create = new_tab == "create"
if is_create:
self._install_app_event_listener()
else:
self._uninstall_app_event_listener()
self._create_overlay_button.set_visible(is_create)
def _on_context_or_active_change(self):
self._validate_create_instances()
def _on_create_request(self):
self._go_to_create_tab()
def _set_current_tab(self, identifier):
self._tabs_widget.set_current_tab(identifier)
def _is_current_tab(self, identifier):
return self._tabs_widget.is_current_tab(identifier)
def _go_to_create_tab(self):
self._tabs_widget.set_current_tab("create")
self._set_current_tab("create")
def _go_to_publish_tab(self):
self._set_current_tab("publish")
def _go_to_details_tab(self):
self._tabs_widget.set_current_tab("details")
self._set_current_tab("details")
def _go_to_report_tab(self):
self._tabs_widget.set_current_tab("report")
self._set_current_tab("report")
def _set_publish_overlay_visibility(self, visible):
if visible:
@ -531,10 +590,10 @@ class PublisherWindow(QtWidgets.QDialog):
self._set_footer_enabled(False)
self._update_publish_details_widget()
if (
not self._tabs_widget.is_current_tab("create")
and not self._tabs_widget.is_current_tab("publish")
not self._is_current_tab("create")
and not self._is_current_tab("publish")
):
self._tabs_widget.set_current_tab("publish")
self._set_current_tab("publish")
def _on_publish_start(self):
self._create_tab.setEnabled(False)
@ -550,8 +609,8 @@ class PublisherWindow(QtWidgets.QDialog):
self._publish_details_widget.close_details_popup()
if self._tabs_widget.is_current_tab(self._create_tab):
self._tabs_widget.set_current_tab("publish")
if self._is_current_tab(self._create_tab):
self._set_current_tab("publish")
def _on_publish_validated_change(self, event):
if event["value"]:
@ -564,7 +623,7 @@ class PublisherWindow(QtWidgets.QDialog):
publish_has_crashed = self._controller.publish_has_crashed
validate_enabled = not publish_has_crashed
publish_enabled = not publish_has_crashed
if self._tabs_widget.is_current_tab("publish"):
if self._is_current_tab("publish"):
self._go_to_report_tab()
if validate_enabled:
@ -668,6 +727,36 @@ class PublisherWindow(QtWidgets.QDialog):
event["title"], new_failed_info, "Convertor:"
)
def _update_create_overlay_size(self):
metrics = self._create_overlay_button.fontMetrics()
height = int(metrics.height())
width = int(height * 0.7)
end_pos_x = self.width()
start_pos_x = end_pos_x - width
center = self._content_widget.parent().mapTo(
self,
self._content_widget.rect().center()
)
pos_y = center.y() - (height * 0.5)
self._create_overlay_button.setGeometry(
start_pos_x, pos_y,
width, height
)
def _update_create_overlay_visibility(self, global_pos=None):
if global_pos is None:
global_pos = QtGui.QCursor.pos()
under_mouse = False
my_pos = self.mapFromGlobal(global_pos)
if self.rect().contains(my_pos):
widget_geo = self._overview_widget.get_subset_views_geo()
widget_x = widget_geo.left() + (widget_geo.width() * 0.5)
under_mouse = widget_x < global_pos.x()
self._create_overlay_button.set_under_mouse(under_mouse)
class ErrorsMessageBox(ErrorMessageBox):
def __init__(self, error_title, failed_info, message_start, parent):