Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Animated launch in launcher tool #1143

Merged
merged 5 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions pype/tools/launcher/constants.py
Original file line number Diff line number Diff line change
@@ -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
57 changes: 57 additions & 0 deletions pype/tools/launcher/delegates.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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:
Expand Down
27 changes: 18 additions & 9 deletions pype/tools/launcher/models.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -109,10 +116,6 @@ def headerData(self, section, orientation, role):


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
Expand All @@ -123,6 +126,7 @@ def __init__(self, dbcon, parent=None):
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."""
Expand All @@ -134,6 +138,7 @@ def discover(self):
actions.extend(app_actions)

self._registered_actions = actions
self.items_by_id.clear()

def get_application_actions(self):
actions = []
Expand Down Expand Up @@ -180,6 +185,7 @@ def filter_actions(self):
# Validate actions based on compatibility
self.clear()

self.items_by_id.clear()
self._groups.clear()

actions = self.filter_compatible_actions(self._registered_actions)
Expand Down Expand Up @@ -235,16 +241,16 @@ def filter_actions(self):

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:
icon = self.get_icon(action)
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():
Expand All @@ -263,13 +269,16 @@ def filter_actions(self):
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()
Expand Down
58 changes: 52 additions & 6 deletions pype/tools/launcher/widgets.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import time
import collections
from Qt import QtWidgets, QtCore, QtGui
from avalon.vendor import qtawesome
Expand All @@ -7,6 +8,15 @@
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):
Expand Down Expand Up @@ -105,7 +115,7 @@ def __init__(self, dbcon, parent=None):

# TODO better group delegate
delegate = ActionDelegate(
[model.GROUP_ROLE, model.VARIANT_GROUP_ROLE],
[GROUP_ROLE, VARIANT_GROUP_ROLE],
self
)
view.setItemDelegate(delegate)
Expand All @@ -115,6 +125,13 @@ def __init__(self, dbcon, parent=None):
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)
Expand All @@ -132,18 +149,46 @@ def filter_actions(self):
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 = {}
Expand Down Expand Up @@ -203,6 +248,7 @@ def on_clicked(self, index):
result = menu.exec_(QtGui.QCursor.pos())
if result:
action = actions_mapping[result]
self._start_animation(index)
self.action_clicked.emit(action)


Expand Down