mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge pull request #1143 from pypeclub/feature/launcher_animation
Animated launch in launcher tool
This commit is contained in:
commit
05f4b77d6b
4 changed files with 139 additions and 15 deletions
12
pype/tools/launcher/constants.py
Normal file
12
pype/tools/launcher/constants.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
from Qt import QtCore
|
||||
|
||||
|
||||
ACTION_ROLE = QtCore.Qt.UserRole
|
||||
GROUP_ROLE = QtCore.Qt.UserRole + 1
|
||||
VARIANT_GROUP_ROLE = QtCore.Qt.UserRole + 2
|
||||
ACTION_ID_ROLE = QtCore.Qt.UserRole + 3
|
||||
ANIMATION_START_ROLE = QtCore.Qt.UserRole + 4
|
||||
ANIMATION_STATE_ROLE = QtCore.Qt.UserRole + 5
|
||||
|
||||
|
||||
ANIMATION_LEN = 10
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
import time
|
||||
from Qt import QtCore, QtWidgets, QtGui
|
||||
from .constants import (
|
||||
ANIMATION_START_ROLE,
|
||||
ANIMATION_STATE_ROLE
|
||||
)
|
||||
|
||||
|
||||
class ActionDelegate(QtWidgets.QStyledItemDelegate):
|
||||
|
|
@ -9,8 +14,60 @@ class ActionDelegate(QtWidgets.QStyledItemDelegate):
|
|||
def __init__(self, group_roles, *args, **kwargs):
|
||||
super(ActionDelegate, self).__init__(*args, **kwargs)
|
||||
self.group_roles = group_roles
|
||||
self._anim_start_color = QtGui.QColor(178, 255, 246)
|
||||
self._anim_end_color = QtGui.QColor(5, 44, 50)
|
||||
|
||||
def _draw_animation(self, painter, option, index):
|
||||
grid_size = option.widget.gridSize()
|
||||
x_offset = int(
|
||||
(grid_size.width() / 2)
|
||||
- (option.rect.width() / 2)
|
||||
)
|
||||
item_x = option.rect.x() - x_offset
|
||||
rect_offset = grid_size.width() / 20
|
||||
size = grid_size.width() - (rect_offset * 2)
|
||||
anim_rect = QtCore.QRect(
|
||||
item_x + rect_offset,
|
||||
option.rect.y() + rect_offset,
|
||||
size,
|
||||
size
|
||||
)
|
||||
|
||||
painter.save()
|
||||
|
||||
painter.setBrush(QtCore.Qt.transparent)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
|
||||
gradient = QtGui.QConicalGradient()
|
||||
gradient.setCenter(anim_rect.center())
|
||||
gradient.setColorAt(0, self._anim_start_color)
|
||||
gradient.setColorAt(1, self._anim_end_color)
|
||||
|
||||
time_diff = time.time() - index.data(ANIMATION_START_ROLE)
|
||||
|
||||
# Repeat 4 times
|
||||
part_anim = 2.5
|
||||
part_time = time_diff % part_anim
|
||||
offset = (part_time / part_anim) * 360
|
||||
angle = (offset + 90) % 360
|
||||
|
||||
gradient.setAngle(-angle)
|
||||
|
||||
pen = QtGui.QPen(QtGui.QBrush(gradient), rect_offset)
|
||||
pen.setCapStyle(QtCore.Qt.RoundCap)
|
||||
painter.setPen(pen)
|
||||
painter.drawArc(
|
||||
anim_rect,
|
||||
-16 * (angle + 10),
|
||||
-16 * offset
|
||||
)
|
||||
|
||||
painter.restore()
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
if index.data(ANIMATION_STATE_ROLE):
|
||||
self._draw_animation(painter, option, index)
|
||||
|
||||
super(ActionDelegate, self).paint(painter, option, index)
|
||||
is_group = False
|
||||
for group_role in self.group_roles:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
import uuid
|
||||
import copy
|
||||
import logging
|
||||
import collections
|
||||
|
||||
from . import lib
|
||||
from .constants import (
|
||||
ACTION_ROLE,
|
||||
GROUP_ROLE,
|
||||
VARIANT_GROUP_ROLE,
|
||||
ACTION_ID_ROLE
|
||||
)
|
||||
from .actions import ApplicationAction
|
||||
from Qt import QtCore, QtGui
|
||||
from avalon.vendor import qtawesome
|
||||
|
|
@ -109,10 +116,6 @@ class TaskModel(QtGui.QStandardItemModel):
|
|||
|
||||
|
||||
class ActionModel(QtGui.QStandardItemModel):
|
||||
ACTION_ROLE = QtCore.Qt.UserRole
|
||||
GROUP_ROLE = QtCore.Qt.UserRole + 1
|
||||
VARIANT_GROUP_ROLE = QtCore.Qt.UserRole + 2
|
||||
|
||||
def __init__(self, dbcon, parent=None):
|
||||
super(ActionModel, self).__init__(parent=parent)
|
||||
self.dbcon = dbcon
|
||||
|
|
@ -123,6 +126,7 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
self.default_icon = qtawesome.icon("fa.cube", color="white")
|
||||
# Cache of available actions
|
||||
self._registered_actions = list()
|
||||
self.items_by_id = {}
|
||||
|
||||
def discover(self):
|
||||
"""Set up Actions cache. Run this for each new project."""
|
||||
|
|
@ -134,6 +138,7 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
actions.extend(app_actions)
|
||||
|
||||
self._registered_actions = actions
|
||||
self.items_by_id.clear()
|
||||
|
||||
def get_application_actions(self):
|
||||
actions = []
|
||||
|
|
@ -180,6 +185,7 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
# Validate actions based on compatibility
|
||||
self.clear()
|
||||
|
||||
self.items_by_id.clear()
|
||||
self._groups.clear()
|
||||
|
||||
actions = self.filter_compatible_actions(self._registered_actions)
|
||||
|
|
@ -235,8 +241,8 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
|
||||
item = QtGui.QStandardItem(icon, label)
|
||||
item.setData(label, QtCore.Qt.ToolTipRole)
|
||||
item.setData(actions, self.ACTION_ROLE)
|
||||
item.setData(True, self.VARIANT_GROUP_ROLE)
|
||||
item.setData(actions, ACTION_ROLE)
|
||||
item.setData(True, VARIANT_GROUP_ROLE)
|
||||
items_by_order[order].append(item)
|
||||
|
||||
for action in single_actions:
|
||||
|
|
@ -244,7 +250,7 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
label = lib.get_action_label(action)
|
||||
item = QtGui.QStandardItem(icon, label)
|
||||
item.setData(label, QtCore.Qt.ToolTipRole)
|
||||
item.setData(action, self.ACTION_ROLE)
|
||||
item.setData(action, ACTION_ROLE)
|
||||
items_by_order[action.order].append(item)
|
||||
|
||||
for group_name, actions in grouped_actions.items():
|
||||
|
|
@ -263,13 +269,16 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
icon = self.default_icon
|
||||
|
||||
item = QtGui.QStandardItem(icon, group_name)
|
||||
item.setData(actions, self.ACTION_ROLE)
|
||||
item.setData(True, self.GROUP_ROLE)
|
||||
item.setData(actions, ACTION_ROLE)
|
||||
item.setData(True, GROUP_ROLE)
|
||||
|
||||
items_by_order[order].append(item)
|
||||
|
||||
for order in sorted(items_by_order.keys()):
|
||||
for item in items_by_order[order]:
|
||||
item_id = str(uuid.uuid4())
|
||||
item.setData(item_id, ACTION_ID_ROLE)
|
||||
self.items_by_id[item_id] = item
|
||||
self.appendRow(item)
|
||||
|
||||
self.endResetModel()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import copy
|
||||
import time
|
||||
import collections
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
from avalon.vendor import qtawesome
|
||||
|
|
@ -7,6 +8,15 @@ from .delegates import ActionDelegate
|
|||
from . import lib
|
||||
from .models import TaskModel, ActionModel, ProjectModel
|
||||
from .flickcharm import FlickCharm
|
||||
from .constants import (
|
||||
ACTION_ROLE,
|
||||
GROUP_ROLE,
|
||||
VARIANT_GROUP_ROLE,
|
||||
ACTION_ID_ROLE,
|
||||
ANIMATION_START_ROLE,
|
||||
ANIMATION_STATE_ROLE,
|
||||
ANIMATION_LEN
|
||||
)
|
||||
|
||||
|
||||
class ProjectBar(QtWidgets.QWidget):
|
||||
|
|
@ -105,7 +115,7 @@ class ActionBar(QtWidgets.QWidget):
|
|||
|
||||
# TODO better group delegate
|
||||
delegate = ActionDelegate(
|
||||
[model.GROUP_ROLE, model.VARIANT_GROUP_ROLE],
|
||||
[GROUP_ROLE, VARIANT_GROUP_ROLE],
|
||||
self
|
||||
)
|
||||
view.setItemDelegate(delegate)
|
||||
|
|
@ -115,6 +125,13 @@ class ActionBar(QtWidgets.QWidget):
|
|||
self.model = model
|
||||
self.view = view
|
||||
|
||||
self._animated_items = set()
|
||||
|
||||
animation_timer = QtCore.QTimer()
|
||||
animation_timer.setInterval(50)
|
||||
animation_timer.timeout.connect(self._on_animation)
|
||||
self._animation_timer = animation_timer
|
||||
|
||||
# Make view flickable
|
||||
flick = FlickCharm(parent=view)
|
||||
flick.activateOn(view)
|
||||
|
|
@ -132,18 +149,46 @@ class ActionBar(QtWidgets.QWidget):
|
|||
def set_row_height(self, rows):
|
||||
self.setMinimumHeight(rows * 75)
|
||||
|
||||
def _on_animation(self):
|
||||
time_now = time.time()
|
||||
for action_id in tuple(self._animated_items):
|
||||
item = self.model.items_by_id.get(action_id)
|
||||
if not item:
|
||||
self._animated_items.remove(action_id)
|
||||
continue
|
||||
|
||||
start_time = item.data(ANIMATION_START_ROLE)
|
||||
if (time_now - start_time) > ANIMATION_LEN:
|
||||
item.setData(0, ANIMATION_STATE_ROLE)
|
||||
self._animated_items.remove(action_id)
|
||||
|
||||
if not self._animated_items:
|
||||
self._animation_timer.stop()
|
||||
|
||||
self.update()
|
||||
|
||||
def _start_animation(self, index):
|
||||
action_id = index.data(ACTION_ID_ROLE)
|
||||
item = self.model.items_by_id.get(action_id)
|
||||
if item:
|
||||
item.setData(time.time(), ANIMATION_START_ROLE)
|
||||
item.setData(1, ANIMATION_STATE_ROLE)
|
||||
self._animated_items.add(action_id)
|
||||
self._animation_timer.start()
|
||||
|
||||
def on_clicked(self, index):
|
||||
if not index.isValid():
|
||||
if not index or not index.isValid():
|
||||
return
|
||||
|
||||
is_group = index.data(self.model.GROUP_ROLE)
|
||||
is_variant_group = index.data(self.model.VARIANT_GROUP_ROLE)
|
||||
is_group = index.data(GROUP_ROLE)
|
||||
is_variant_group = index.data(VARIANT_GROUP_ROLE)
|
||||
if not is_group and not is_variant_group:
|
||||
action = index.data(self.model.ACTION_ROLE)
|
||||
action = index.data(ACTION_ROLE)
|
||||
self._start_animation(index)
|
||||
self.action_clicked.emit(action)
|
||||
return
|
||||
|
||||
actions = index.data(self.model.ACTION_ROLE)
|
||||
actions = index.data(ACTION_ROLE)
|
||||
|
||||
menu = QtWidgets.QMenu(self)
|
||||
actions_mapping = {}
|
||||
|
|
@ -203,6 +248,7 @@ class ActionBar(QtWidgets.QWidget):
|
|||
result = menu.exec_(QtGui.QCursor.pos())
|
||||
if result:
|
||||
action = actions_mapping[result]
|
||||
self._start_animation(index)
|
||||
self.action_clicked.emit(action)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue