From 5208583d8fc9026930f186306ebafb3332ad1081 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 12 Jun 2021 12:29:41 +0200 Subject: [PATCH 01/23] reversed logic of drawing in drawTrigon --- .../widgets/color_widgets/color_triangle.py | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/openpype/widgets/color_widgets/color_triangle.py b/openpype/widgets/color_widgets/color_triangle.py index d4db175d84..ed7fefa7e8 100644 --- a/openpype/widgets/color_widgets/color_triangle.py +++ b/openpype/widgets/color_widgets/color_triangle.py @@ -724,27 +724,29 @@ class QtColorTriangle(QtWidgets.QWidget): lx = leftX[y] rx = rightX[y] + # if the xdist is 0, don't draw anything. + xdist = rx - lx + if xdist == 0.0: + continue + lxi = int(floor(lx)) rxi = int(floor(rx)) rc = rightColors[y] lc = leftColors[y] - # if the xdist is 0, don't draw anything. - xdist = rx - lx - if xdist != 0.0: - r = lc.r - g = lc.g - b = lc.b - rdelta = (rc.r - r) / xdist - gdelta = (rc.g - g) / xdist - bdelta = (rc.b - b) / xdist + r = lc.r + g = lc.g + b = lc.b + rdelta = (rc.r - r) / xdist + gdelta = (rc.g - g) / xdist + bdelta = (rc.b - b) / xdist - # Inner loop 2. Draws the line from left to right. - for x in range(lxi, rxi + 1): - buf.setPixel(x, y, QtGui.qRgb(int(r), int(g), int(b))) - r += rdelta - g += gdelta - b += bdelta + # Inner loop 2. Draws the line from left to right. + for x in range(lxi, rxi): + buf.setPixel(x, y, QtGui.qRgb(int(r), int(g), int(b))) + r += rdelta + g += gdelta + b += bdelta def _radius_at(self, pos, rect): mousexdist = pos.x() - float(rect.center().x()) From fbea4e4f9d0504d4d4af8a7a3e91fbfc58143f0c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 12 Jun 2021 12:29:56 +0200 Subject: [PATCH 02/23] draw 2 more pixels on each side of trigon --- openpype/widgets/color_widgets/color_triangle.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openpype/widgets/color_widgets/color_triangle.py b/openpype/widgets/color_widgets/color_triangle.py index ed7fefa7e8..a6ee0e864f 100644 --- a/openpype/widgets/color_widgets/color_triangle.py +++ b/openpype/widgets/color_widgets/color_triangle.py @@ -741,6 +741,10 @@ class QtColorTriangle(QtWidgets.QWidget): gdelta = (rc.g - g) / xdist bdelta = (rc.b - b) / xdist + # Draw 2 more pixels on left side for smoothing + for x in range(lxi - 2, lxi): + buf.setPixel(x, y, QtGui.qRgb(int(r), int(g), int(b))) + # Inner loop 2. Draws the line from left to right. for x in range(lxi, rxi): buf.setPixel(x, y, QtGui.qRgb(int(r), int(g), int(b))) @@ -748,6 +752,10 @@ class QtColorTriangle(QtWidgets.QWidget): g += gdelta b += bdelta + # Draw 2 more pixels on right side for smoothing + for x in range(rxi, rxi + 3): + buf.setPixel(x, y, QtGui.qRgb(int(r), int(g), int(b))) + def _radius_at(self, pos, rect): mousexdist = pos.x() - float(rect.center().x()) mouseydist = pos.y() - float(rect.center().y()) From c9b30f276850bf12189c01a7ffdb49a5fe957b29 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 12 Jun 2021 12:30:39 +0200 Subject: [PATCH 03/23] draw trigon to different image which is painter over background with clipping --- .../widgets/color_widgets/color_triangle.py | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/openpype/widgets/color_widgets/color_triangle.py b/openpype/widgets/color_widgets/color_triangle.py index a6ee0e864f..f4a86c4fa5 100644 --- a/openpype/widgets/color_widgets/color_triangle.py +++ b/openpype/widgets/color_widgets/color_triangle.py @@ -241,7 +241,11 @@ class QtColorTriangle(QtWidgets.QWidget): # Blit the static generated background with the hue gradient onto # the double buffer. - buf = QtGui.QImage(self.bg_image.copy()) + buf = QtGui.QImage( + self.bg_image.width(), + self.bg_image.height(), + QtGui.QImage.Format_RGB32 + ) # Draw the trigon # Find the color with only the hue, and max value and saturation @@ -254,9 +258,21 @@ class QtColorTriangle(QtWidgets.QWidget): ) # Slow step: convert the image to a pixmap - pix = QtGui.QPixmap.fromImage(buf) + pix = self.bg_image.copy() pix_painter = QtGui.QPainter(pix) - pix_painter.setRenderHint(QtGui.QPainter.Antialiasing) + + pix_painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing) + + trigon_path = QtGui.QPainterPath() + trigon_path.moveTo(self.point_a) + trigon_path.lineTo(self.point_b) + trigon_path.lineTo(self.point_c) + trigon_path.closeSubpath() + pix_painter.setClipPath(trigon_path) + + pix_painter.drawImage(0, 0, buf) + + pix_painter.setClipping(False) # Draw an outline of the triangle pix_painter.setPen(self._triangle_outline_pen) From b2cc66ba2282934b04dc8b8fd2369bc08b39dcb1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Jun 2021 14:34:58 +0200 Subject: [PATCH 04/23] added smoothnes to alpha slider --- openpype/widgets/color_widgets/color_inputs.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/openpype/widgets/color_widgets/color_inputs.py b/openpype/widgets/color_widgets/color_inputs.py index eda8c618f1..ada8befd65 100644 --- a/openpype/widgets/color_widgets/color_inputs.py +++ b/openpype/widgets/color_widgets/color_inputs.py @@ -80,7 +80,7 @@ class AlphaSlider(QtWidgets.QSlider): painter.fillRect(event.rect(), QtCore.Qt.transparent) - painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform) + painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing) rect = self.style().subControlRect( QtWidgets.QStyle.CC_Slider, opt, @@ -135,19 +135,8 @@ class AlphaSlider(QtWidgets.QSlider): painter.save() - gradient = QtGui.QRadialGradient() - radius = handle_rect.height() / 2 - center_x = handle_rect.width() / 2 + handle_rect.x() - center_y = handle_rect.height() - gradient.setCenter(center_x, center_y) - gradient.setCenterRadius(radius) - gradient.setFocalPoint(center_x, center_y) - - gradient.setColorAt(0.9, QtGui.QColor(127, 127, 127)) - gradient.setColorAt(1, QtCore.Qt.transparent) - painter.setPen(QtCore.Qt.NoPen) - painter.setBrush(gradient) + painter.setBrush(QtGui.QColor(127, 127, 127)) painter.drawEllipse(handle_rect) painter.restore() From bf6504eac53ff536a6b677f89dd98b55a38924eb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Jun 2021 14:35:09 +0200 Subject: [PATCH 05/23] removed unused slide_style --- .../widgets/color_widgets/color_inputs.py | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/openpype/widgets/color_widgets/color_inputs.py b/openpype/widgets/color_widgets/color_inputs.py index ada8befd65..6f5d4baa02 100644 --- a/openpype/widgets/color_widgets/color_inputs.py +++ b/openpype/widgets/color_widgets/color_inputs.py @@ -4,35 +4,6 @@ from Qt import QtWidgets, QtCore, QtGui from .color_view import draw_checkerboard_tile -slide_style = """ -QSlider::groove:horizontal { - background: qlineargradient( - x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #000, stop: 1 #fff - ); - height: 8px; - border-radius: 4px; -} - -QSlider::handle:horizontal { - background: qlineargradient( - x1:0, y1:0, x2:1, y2:1, stop:0 #ddd, stop:1 #bbb - ); - border: 1px solid #777; - width: 8px; - margin-top: -1px; - margin-bottom: -1px; - border-radius: 4px; -} - -QSlider::handle:horizontal:hover { - background: qlineargradient( - x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ddd - ); - border: 1px solid #444;ff - border-radius: 4px; -}""" - - class AlphaSlider(QtWidgets.QSlider): def __init__(self, *args, **kwargs): super(AlphaSlider, self).__init__(*args, **kwargs) From bca04289ef1771f96679ab3da94fb957e9b0fdff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 12:16:33 +0200 Subject: [PATCH 06/23] set default subset template for review family in tvpaint --- .../settings/defaults/project_settings/global.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index b7fa5e32e8..c3c43c3b3b 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -232,6 +232,16 @@ ], "tasks": [], "template": "{family}{Task}_{Render_layer}_{Render_pass}" + }, + { + "families": [ + "review" + ], + "hosts": [ + "tvpaint" + ], + "tasks": [], + "template": "{family}{Task}" } ] }, From 18b8666b8166a89f570bbfd5d3c43a07e7327378 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 12:20:57 +0200 Subject: [PATCH 07/23] added workfile to families --- openpype/settings/defaults/project_settings/global.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index c3c43c3b3b..037fa63a29 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -235,7 +235,8 @@ }, { "families": [ - "review" + "review", + "workfile" ], "hosts": [ "tvpaint" From 00998f310d650dfa54bcfcfdd07e2397fdda8778 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 14:33:58 +0200 Subject: [PATCH 08/23] initial commit of subset name template docstrings --- .../settings_project_global.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/website/docs/project_settings/settings_project_global.md b/website/docs/project_settings/settings_project_global.md index 5c46cd185a..4bda13f91b 100644 --- a/website/docs/project_settings/settings_project_global.md +++ b/website/docs/project_settings/settings_project_global.md @@ -172,6 +172,38 @@ Applicable context filters: ## Tools Settings for OpenPype tools. +## Creator +Settings related to [Creator tool](artist_tools.md#details). + +### Subset name profiles +![global_tools_creator_subset_template](assets/global_tools_creator_subset_template.png) +Subset name helps to identify published content. More specific name helps with organization and avoid mixing of content. Subset name is defined using one of templates defined in Subset name profiles settings. The template is filled with information from context in which creation was triggered. + +Templates in settings are filtered by creator's family, host and task name. Template without filters is used as default template. It is recommend to set default template. If default template is not available `"{family}{Task}"` is used. + +**Formatting keys** + +All templates can contain text and formatting keys **family**, **task** and **variant** e.g. `"MyStudio_{family}_{task}"` (example - not recommended in production). + +|Key|Description| +|---|---| +|family|Creators family| +|task|Task under which is creation triggered| +|variant|User input in creator tool| + +**Formatting keys have 3 variants with different letter capitalization.** + +|Task|Key variant|Description|Result| +|---|---|---|---| +|`bgAnim`|`{task}`|Keep original value as is.|`bgAnim`| +|`bgAnim`|`{Task}`|Capitalize first letter of value.|`BgAnim`| +|`bgAnim`|`{TASK}`|Each letter which be capitalized.|`BGANIM`| + +Template may look like `"{family}{Task}{Variant}"`. + +Some creators may have other keys as their context may require more information or more specific values. Make sure you've read documentation of host you're using. + + ## Workfiles All settings related to Workfile tool. From d0cfbb03bdf22974d1665e4ef29f7d7b56d211f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 14:34:08 +0200 Subject: [PATCH 09/23] added screenshot --- .../global_tools_creator_subset_template.png | Bin 0 -> 17550 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 website/docs/project_settings/assets/global_tools_creator_subset_template.png diff --git a/website/docs/project_settings/assets/global_tools_creator_subset_template.png b/website/docs/project_settings/assets/global_tools_creator_subset_template.png new file mode 100644 index 0000000000000000000000000000000000000000..c4e863c4e0f28982c91e0d4768d113af200e4440 GIT binary patch literal 17550 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 Date: Wed, 16 Jun 2021 15:22:47 +0200 Subject: [PATCH 10/23] added admin tvpaint host documentation with families --- website/docs/admin_hosts_tvpaint.md | 41 +++++++++++++++++++++++++++++ website/sidebars.js | 3 ++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 website/docs/admin_hosts_tvpaint.md diff --git a/website/docs/admin_hosts_tvpaint.md b/website/docs/admin_hosts_tvpaint.md new file mode 100644 index 0000000000..4db8f89166 --- /dev/null +++ b/website/docs/admin_hosts_tvpaint.md @@ -0,0 +1,41 @@ +--- +id: admin_hosts_tvpaint +title: TVPaint +sidebar_label: TVPaint +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Families +Families that can be published form TVPaint using OpenPype integration. + +### renderLayer +Render layer is represented by TVPaint group and all layers under the group. Output of `renderLayer` family are all visible layers rendered together into png sequence. + +Render layer has additional keys for subset name template. It is possible to use **render_layer** and **render_pass**. + +- Key **render_layer** is alias for variant (user's input). +- For key **render_pass** is used predefined value `"Beauty"` (ATM value can't be changed). + +### renderPass +Render pass is represented by one or more TVPaint layers. Is dependent on created `renderLayer`. All layers must be in same group of `renderLayer`. + +Render pass has additional keys for subset name template. It is possible to use **render_layer** and **render_pass**. +- Key **render_layer** is filled with value of **render_pass** from `renderLayer` group. +- Key **render_pass** is alias for variant (user's input). + +:::note Subset name template +It is recommended to use same subset name template for both **renderLayer** and **renderPass** families. +- Example template: `"{family}{Task}_{Render_layer}_{Render_pass}"` +::: + +### review +Review of whole scene. Exports all visible layers into sequence which is then processed in ExtractReview plugin. It is possible to deactivate publishing of review after collection. + +### workfile +Publish workfile and create it's backup outside of workfiles directory. It is possible to deactivate publishing of workfile after collection. + +:::note Dynamic families +Families **review** and **workfile** are not manually created but are automatically generated during publishing. That's why it is recommended to not use **variant** key in their subset name template. Recommented subset name template is `"{family}{Task}"`. +::: diff --git a/website/sidebars.js b/website/sidebars.js index 59071ec34f..d38973e40f 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -90,7 +90,8 @@ module.exports = { "admin_hosts_maya", "admin_hosts_resolve", "admin_hosts_harmony", - "admin_hosts_aftereffects" + "admin_hosts_aftereffects", + "admin_hosts_tvpaint" ], }, { From 56b858defa287de328d6ba54508845ed30daa7f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 15:34:36 +0200 Subject: [PATCH 11/23] removed most of not important stuff from admin section --- website/docs/admin_hosts_tvpaint.md | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/website/docs/admin_hosts_tvpaint.md b/website/docs/admin_hosts_tvpaint.md index 4db8f89166..6c9c5ff881 100644 --- a/website/docs/admin_hosts_tvpaint.md +++ b/website/docs/admin_hosts_tvpaint.md @@ -7,35 +7,24 @@ sidebar_label: TVPaint import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -## Families -Families that can be published form TVPaint using OpenPype integration. - -### renderLayer -Render layer is represented by TVPaint group and all layers under the group. Output of `renderLayer` family are all visible layers rendered together into png sequence. +## Subset name templates +Definition of possibile subset name templates in TVPaint integration. +### [Render Layer](artist_hosts_tvpaint#render-layer) Render layer has additional keys for subset name template. It is possible to use **render_layer** and **render_pass**. - Key **render_layer** is alias for variant (user's input). - For key **render_pass** is used predefined value `"Beauty"` (ATM value can't be changed). -### renderPass -Render pass is represented by one or more TVPaint layers. Is dependent on created `renderLayer`. All layers must be in same group of `renderLayer`. - +### [Render pass](artist_hosts_tvpaint#render-pass) Render pass has additional keys for subset name template. It is possible to use **render_layer** and **render_pass**. - Key **render_layer** is filled with value of **render_pass** from `renderLayer` group. - Key **render_pass** is alias for variant (user's input). -:::note Subset name template +:::important Render Layer/Pass templates It is recommended to use same subset name template for both **renderLayer** and **renderPass** families. - Example template: `"{family}{Task}_{Render_layer}_{Render_pass}"` ::: -### review -Review of whole scene. Exports all visible layers into sequence which is then processed in ExtractReview plugin. It is possible to deactivate publishing of review after collection. - -### workfile -Publish workfile and create it's backup outside of workfiles directory. It is possible to deactivate publishing of workfile after collection. - -:::note Dynamic families -Families **review** and **workfile** are not manually created but are automatically generated during publishing. That's why it is recommended to not use **variant** key in their subset name template. Recommented subset name template is `"{family}{Task}"`. -::: +### [Review](artist_hosts_tvpaint#review) and Workfile +Families **review** and **workfile** are not manually created but are automatically generated during publishing. That's why it is recommended to not use **variant** key in their subset name template. From 774595fba8fada980453e0aed3e650ccb99ef043 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 15:43:50 +0200 Subject: [PATCH 12/23] updated review and workfile families in tvpaint docs --- website/docs/artist_hosts_tvpaint.md | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/website/docs/artist_hosts_tvpaint.md b/website/docs/artist_hosts_tvpaint.md index 19cb615158..2e831e64d8 100644 --- a/website/docs/artist_hosts_tvpaint.md +++ b/website/docs/artist_hosts_tvpaint.md @@ -45,7 +45,7 @@ In TVPaint you can find the Tools in OpenPype menu extension. The OpenPype Tools ## Create -In TVPaint you can create and publish **[Reviews](#review)**, **[Render Passes](#render-pass)**, and **[Render Layers](#render-layer)**. +In TVPaint you can create and publish **[Reviews](#review)**, **[Workfile](#workfile)**, **[Render Passes](#render-pass)** and **[Render Layers](#render-layer)**. You have the possibility to organize your layers by using `Color group`. @@ -67,26 +67,13 @@ OpenPype specifically never tries to guess what you want to publish from the sce When you want to publish `review` or `render layer` or `render pass`, open the `Creator` through the Tools menu `Create` button. -### Review +### Review +`Review` renders the whole file as is and sends the resulting QuickTime to Ftrack. +- Is automatically created during publishing. -
-
- -`Review` renders the whole file as is and sends the resulting QuickTime to Ftrack. - -To create reviewable quicktime of your animation: - -- select `Review` in the `Creator` -- press `Create` -- When you run [publish](#publish), file will be rendered and converted to quicktime.` - -
-
- -![createreview](assets/tvp_create_review.png) - -
-
+### Workfile +`Workfile` stores the source workfile as is during publishing (e.g. for backup). +- Is automatically created during publishing. ### Render Layer From 776e784df9c111cec4914e74e315fa62d615d790 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 15:44:07 +0200 Subject: [PATCH 13/23] added link to workfile family --- website/docs/admin_hosts_tvpaint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/admin_hosts_tvpaint.md b/website/docs/admin_hosts_tvpaint.md index 6c9c5ff881..a99cd19010 100644 --- a/website/docs/admin_hosts_tvpaint.md +++ b/website/docs/admin_hosts_tvpaint.md @@ -26,5 +26,5 @@ It is recommended to use same subset name template for both **renderLayer** and - Example template: `"{family}{Task}_{Render_layer}_{Render_pass}"` ::: -### [Review](artist_hosts_tvpaint#review) and Workfile +### [Review](artist_hosts_tvpaint#review) and [Workfile](artist_hosts_tvpaint#workfile) Families **review** and **workfile** are not manually created but are automatically generated during publishing. That's why it is recommended to not use **variant** key in their subset name template. From a9d51ce003b99b6d8c51e3ef7394d257c71ded40 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Jun 2021 15:44:15 +0200 Subject: [PATCH 14/23] removed unused image --- website/docs/assets/tvp_create_review.png | Bin 30635 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 website/docs/assets/tvp_create_review.png diff --git a/website/docs/assets/tvp_create_review.png b/website/docs/assets/tvp_create_review.png deleted file mode 100644 index d6e9f6342850dda4afbc534b4678dacd8366b264..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30635 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 Date: Wed, 16 Jun 2021 15:51:20 +0200 Subject: [PATCH 15/23] rephrasing subset templates --- website/docs/project_settings/settings_project_global.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/docs/project_settings/settings_project_global.md b/website/docs/project_settings/settings_project_global.md index 4bda13f91b..e6336c36e2 100644 --- a/website/docs/project_settings/settings_project_global.md +++ b/website/docs/project_settings/settings_project_global.md @@ -177,9 +177,10 @@ Settings related to [Creator tool](artist_tools.md#details). ### Subset name profiles ![global_tools_creator_subset_template](assets/global_tools_creator_subset_template.png) -Subset name helps to identify published content. More specific name helps with organization and avoid mixing of content. Subset name is defined using one of templates defined in Subset name profiles settings. The template is filled with information from context in which creation was triggered. -Templates in settings are filtered by creator's family, host and task name. Template without filters is used as default template. It is recommend to set default template. If default template is not available `"{family}{Task}"` is used. +Subset name helps to identify published content. More specific name helps with organization and avoid mixing of published content. Subset name is defined using one of templates defined in **Subset name profiles settings**. The template is filled with context information at the time of creation. + +Usage of template is defined by profile filtering using creator's family, host and task name. Profile without filters is used as default template and it is recommend to set default template. If default template is not available `"{family}{Task}"` is used. **Formatting keys** From 855d5a9ae410fcd67405e90c51fb16b1d2120e80 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Jun 2021 13:46:59 +0200 Subject: [PATCH 16/23] use layer name instead of group name for default render layer variant --- .../plugins/create/create_render_layer.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/tvpaint/plugins/create/create_render_layer.py b/openpype/hosts/tvpaint/plugins/create/create_render_layer.py index eeb7d32d50..af6c0f0eee 100644 --- a/openpype/hosts/tvpaint/plugins/create/create_render_layer.py +++ b/openpype/hosts/tvpaint/plugins/create/create_render_layer.py @@ -58,18 +58,14 @@ class CreateRenderlayer(plugin.Creator): # Get currently selected layers layers_data = lib.layers_data() - group_ids = set() - for layer in layers_data: - if layer["selected"]: - group_ids.add(layer["group_id"]) - + selected_layers = [ + layer + for layer in layers_data + if layer["selected"] + ] # Return layer name if only one is selected - if len(group_ids) == 1: - group_id = list(group_ids)[0] - groups_data = lib.groups_data() - for group in groups_data: - if group["group_id"] == group_id: - return group["name"] + if len(selected_layers) == 1: + return selected_layers[0]["name"] # Use defaults if cls.defaults: From 4ecc8669717faf0e4113723ea04f645dabe32276 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Jun 2021 15:00:13 +0200 Subject: [PATCH 17/23] ProjectModel has resetless logic of refresh --- openpype/tools/launcher/models.py | 52 +++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 25b6dcdbf0..846a07e081 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -325,19 +325,59 @@ class ProjectModel(QtGui.QStandardItemModel): self.hide_invisible = False self.project_icon = qtawesome.icon("fa.map", color="white") + self._project_names = set() def refresh(self): - self.clear() - self.beginResetModel() - + project_names = set() for project_doc in self.get_projects(): - item = QtGui.QStandardItem(self.project_icon, project_doc["name"]) - self.appendRow(item) + project_names.add(project_doc["name"]) - self.endResetModel() + origin_project_names = set(self._project_names) + self._project_names = project_names + + project_names_to_remove = origin_project_names - project_names + if project_names_to_remove: + row_counts = {} + continuous = None + for row in range(self.rowCount()): + index = self.index(row, 0) + index_name = index.data(QtCore.Qt.DisplayRole) + if index_name in project_names_to_remove: + if continuous is None: + continuous = row + row_counts[continuous] = 0 + row_counts[continuous] += 1 + else: + continuous = None + + for row in reversed(sorted(row_counts.keys())): + count = row_counts[row] + self.removeRows(row, count) + + continuous = None + row_counts = {} + for idx, project_name in enumerate(sorted(project_names)): + if project_name in origin_project_names: + continuous = None + continue + + if continuous is None: + continuous = idx + row_counts[continuous] = [] + + row_counts[continuous].append(project_name) + + for row in reversed(sorted(row_counts.keys())): + items = [] + for project_name in row_counts[row]: + item = QtGui.QStandardItem(self.project_icon, project_name) + items.append(item) + + self.invisibleRootItem().insertRows(row, items) def get_projects(self): project_docs = [] + for project_doc in sorted( self.dbcon.projects(), key=lambda x: x["name"] ): From 912c6b3b575e4e66e7de35168890917cc2b810a0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Jun 2021 15:08:45 +0200 Subject: [PATCH 18/23] added refresh timer which will update projects each 10 seconds --- openpype/tools/launcher/widgets.py | 22 ++++++++++++++++++++++ openpype/tools/launcher/window.py | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index 22b08d7d15..59fa2b729e 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -22,6 +22,9 @@ from .constants import ( class ProjectBar(QtWidgets.QWidget): project_changed = QtCore.Signal(int) + # Project list will be refreshed each 10000 msecs + refresh_interval = 10000 + def __init__(self, dbcon, parent=None): super(ProjectBar, self).__init__(parent) @@ -47,14 +50,19 @@ class ProjectBar(QtWidgets.QWidget): QtWidgets.QSizePolicy.Maximum ) + refresh_timer = QtCore.QTimer() + refresh_timer.setInterval(self.refresh_interval) + self.model = model self.project_delegate = project_delegate self.project_combobox = project_combobox + self.refresh_timer = refresh_timer # Initialize self.refresh() # Signals + refresh_timer.timeout.connect(self._on_refresh_timeout) self.project_combobox.currentIndexChanged.connect(self.project_changed) # Set current project by default if it's set. @@ -62,6 +70,20 @@ class ProjectBar(QtWidgets.QWidget): if project_name: self.set_project(project_name) + def showEvent(self, event): + if not self.refresh_timer.isActive(): + self.refresh_timer.start() + super(ProjectBar, self).showEvent(event) + + def _on_refresh_timeout(self): + if not self.isVisible(): + # Stop timer if widget is not visible + self.refresh_timer.stop() + + elif self.isActiveWindow(): + # Refresh projects if window is active + self.model.refresh() + def get_current_project(self): return self.project_combobox.currentText() diff --git a/openpype/tools/launcher/window.py b/openpype/tools/launcher/window.py index af749814b7..25aa273ca0 100644 --- a/openpype/tools/launcher/window.py +++ b/openpype/tools/launcher/window.py @@ -91,6 +91,8 @@ class ProjectsPanel(QtWidgets.QWidget): """Projects Page""" project_clicked = QtCore.Signal(str) + # Refresh projects each 10000 msecs + refresh_interval = 10000 def __init__(self, dbcon, parent=None): super(ProjectsPanel, self).__init__(parent=parent) @@ -111,16 +113,36 @@ class ProjectsPanel(QtWidgets.QWidget): layout.addWidget(view) + refresh_timer = QtCore.QTimer() + refresh_timer.setInterval(self.refresh_interval) + + refresh_timer.timeout.connect(self._on_refresh_timeout) view.clicked.connect(self.on_clicked) self.model = model self.view = view + self.refresh_timer = refresh_timer def on_clicked(self, index): if index.isValid(): project_name = index.data(QtCore.Qt.DisplayRole) self.project_clicked.emit(project_name) + def showEvent(self, event): + self.model.refresh() + if not self.refresh_timer.isActive(): + self.refresh_timer.start() + super(ProjectsPanel, self).showEvent(event) + + def _on_refresh_timeout(self): + if not self.isVisible(): + # Stop timer if widget is not visible + self.refresh_timer.stop() + + elif self.isActiveWindow(): + # Refresh projects if window is active + self.model.refresh() + class AssetsPanel(QtWidgets.QWidget): """Assets page""" From d6e345addc67006c2e1d48e30c9a4c0c0b95e378 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Jun 2021 15:09:09 +0200 Subject: [PATCH 19/23] removed unnecessary refresh calls --- openpype/tools/launcher/window.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/tools/launcher/window.py b/openpype/tools/launcher/window.py index 25aa273ca0..5e47cfd154 100644 --- a/openpype/tools/launcher/window.py +++ b/openpype/tools/launcher/window.py @@ -108,7 +108,6 @@ class ProjectsPanel(QtWidgets.QWidget): flick.activateOn(view) model = ProjectModel(self.dbcon) model.hide_invisible = True - model.refresh() view.setModel(model) layout.addWidget(view) @@ -434,7 +433,6 @@ class LauncherWindow(QtWidgets.QDialog): def on_back_clicked(self): self.dbcon.Session["AVALON_PROJECT"] = None self.set_page(0) - self.project_panel.model.refresh() # Refresh projects self.discover_actions() def on_action_clicked(self, action): From 8d9ccaf45bb6a0c5d96455359eb5d43fb317aee8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Jun 2021 15:15:27 +0200 Subject: [PATCH 20/23] simplified refreshing of project bar --- openpype/tools/launcher/widgets.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index 59fa2b729e..11301aba64 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -91,27 +91,14 @@ class ProjectBar(QtWidgets.QWidget): index = self.project_combobox.findText(project_name) if index < 0: # Try refresh combobox model - self.project_combobox.blockSignals(True) - self.model.refresh() - self.project_combobox.blockSignals(False) - + self.refresh() index = self.project_combobox.findText(project_name) if index >= 0: self.project_combobox.setCurrentIndex(index) def refresh(self): - prev_project_name = self.get_current_project() - - # Refresh without signals - self.project_combobox.blockSignals(True) - self.model.refresh() - self.set_project(prev_project_name) - - self.project_combobox.blockSignals(False) - - self.project_changed.emit(self.project_combobox.currentIndex()) class ActionBar(QtWidgets.QWidget): From 193296ffaa63732eb43938b7b81e247218d76156 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Jun 2021 15:15:44 +0200 Subject: [PATCH 21/23] dont refresh on init --- openpype/tools/launcher/widgets.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index 11301aba64..0e8caeb278 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -58,9 +58,6 @@ class ProjectBar(QtWidgets.QWidget): self.project_combobox = project_combobox self.refresh_timer = refresh_timer - # Initialize - self.refresh() - # Signals refresh_timer.timeout.connect(self._on_refresh_timeout) self.project_combobox.currentIndexChanged.connect(self.project_changed) From 5872a1364caeaa0739b5b9cc421644fd6e66dbf4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Jun 2021 15:24:54 +0200 Subject: [PATCH 22/23] added refresh timer for actions --- openpype/tools/launcher/window.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/openpype/tools/launcher/window.py b/openpype/tools/launcher/window.py index 5e47cfd154..a6d34bbe9d 100644 --- a/openpype/tools/launcher/window.py +++ b/openpype/tools/launcher/window.py @@ -297,6 +297,8 @@ class AssetsPanel(QtWidgets.QWidget): class LauncherWindow(QtWidgets.QDialog): """Launcher interface""" + # Refresh actions each 10000msecs + actions_refresh_timeout = 10000 def __init__(self, parent=None): super(LauncherWindow, self).__init__(parent) @@ -365,6 +367,10 @@ class LauncherWindow(QtWidgets.QDialog): layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) + actions_refresh_timer = QtCore.QTimer() + actions_refresh_timer.setInterval(self.actions_refresh_timeout) + + self.actions_refresh_timer = actions_refresh_timer self.message_label = message_label self.project_panel = project_panel self.asset_panel = asset_panel @@ -374,6 +380,7 @@ class LauncherWindow(QtWidgets.QDialog): self._page = 0 # signals + actions_refresh_timer.timeout.connect(self._on_action_timer) actions_bar.action_clicked.connect(self.on_action_clicked) action_history.trigger_history.connect(self.on_history_action) project_panel.project_clicked.connect(self.on_project_clicked) @@ -388,9 +395,11 @@ class LauncherWindow(QtWidgets.QDialog): self.resize(520, 740) def showEvent(self, event): - super().showEvent(event) - # TODO implement refresh/reset which will trigger updating - self.discover_actions() + if not self.actions_refresh_timer.isActive(): + self.actions_refresh_timer.start() + self.discover_actions() + + super(LauncherWindow, self).showEvent(event) def set_page(self, page): current = self.page_slider.currentIndex() @@ -423,6 +432,15 @@ class LauncherWindow(QtWidgets.QDialog): def filter_actions(self): self.actions_bar.filter_actions() + def _on_action_timer(self): + if not self.isVisible(): + # Stop timer if widget is not visible + self.actions_refresh_timer.stop() + + elif self.isActiveWindow(): + # Refresh projects if window is active + self.discover_actions() + def on_project_clicked(self, project_name): self.dbcon.Session["AVALON_PROJECT"] = project_name # Refresh projects From 235059f9cdcae4fadad3f1c90c10c1636618dc13 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 19 Jun 2021 03:47:04 +0000 Subject: [PATCH 23/23] [Automated] Bump version --- CHANGELOG.md | 54 ++++++++++++++++++++++++++++++++++++++++++++- openpype/version.py | 2 +- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 043295eb8c..d7c0a25c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,59 @@ # Changelog +## [3.2.0-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) + +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/2.18.3...HEAD) + +**🚀 Enhancements** + +- Autoupdate launcher [\#1725](https://github.com/pypeclub/OpenPype/pull/1725) +- Subset template and TVPaint subset template docs [\#1717](https://github.com/pypeclub/OpenPype/pull/1717) +- Overscan color extract review [\#1701](https://github.com/pypeclub/OpenPype/pull/1701) +- Nuke: Prerender Frame Range by default [\#1699](https://github.com/pypeclub/OpenPype/pull/1699) +- Smoother edges of color triangle [\#1695](https://github.com/pypeclub/OpenPype/pull/1695) + +**🐛 Bug fixes** + +- TVPaint use layer name for default variant [\#1724](https://github.com/pypeclub/OpenPype/pull/1724) +- Default subset template for TVPaint review and workfile families [\#1716](https://github.com/pypeclub/OpenPype/pull/1716) +- Maya: Extract review hotfix [\#1714](https://github.com/pypeclub/OpenPype/pull/1714) +- Settings: Imageio improving granularity [\#1711](https://github.com/pypeclub/OpenPype/pull/1711) + +## [2.18.3](https://github.com/pypeclub/OpenPype/tree/2.18.3) (2021-06-18) + +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/2.18.2...2.18.3) + +**🐛 Bug fixes** + +- Remove publish highlight icon in AE [\#1664](https://github.com/pypeclub/OpenPype/pull/1664) + +**Merged pull requests:** + +- Sync main 2.x back to 2.x develop [\#1715](https://github.com/pypeclub/OpenPype/pull/1715) +- global: removing obsolete ftrack validator plugin [\#1710](https://github.com/pypeclub/OpenPype/pull/1710) +- \#683 - Validate frame range in Standalone Publisher [\#1680](https://github.com/pypeclub/OpenPype/pull/1680) +- Maya: Split model content validator [\#1654](https://github.com/pypeclub/OpenPype/pull/1654) + +## [2.18.2](https://github.com/pypeclub/OpenPype/tree/2.18.2) (2021-06-16) + +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.1.0...2.18.2) + +**🚀 Enhancements** + +- StandalonePublisher: adding exception for adding `delete` tag to repre [\#1650](https://github.com/pypeclub/OpenPype/pull/1650) + +**🐛 Bug fixes** + +- Maya: Extract review hotfix - 2.x backport [\#1713](https://github.com/pypeclub/OpenPype/pull/1713) +- StandalonePublisher: instance data attribute `keepSequence` [\#1668](https://github.com/pypeclub/OpenPype/pull/1668) + +**Merged pull requests:** + +- 1698 Nuke: Prerender Frame Range by default [\#1709](https://github.com/pypeclub/OpenPype/pull/1709) + ## [3.1.0](https://github.com/pypeclub/OpenPype/tree/3.1.0) (2021-06-15) -[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.0.0...3.1.0) +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.1.0-nightly.4...3.1.0) **🚀 Enhancements** @@ -33,6 +84,7 @@ - Fix missing dbm python module [\#1652](https://github.com/pypeclub/OpenPype/pull/1652) - Transparent branches in view on Mac [\#1648](https://github.com/pypeclub/OpenPype/pull/1648) - Add asset on task item [\#1646](https://github.com/pypeclub/OpenPype/pull/1646) +- Project manager save and queue [\#1645](https://github.com/pypeclub/OpenPype/pull/1645) - New project anatomy values [\#1644](https://github.com/pypeclub/OpenPype/pull/1644) **Merged pull requests:** diff --git a/openpype/version.py b/openpype/version.py index 4312333660..ece0359506 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.1.0" +__version__ = "3.2.0-nightly.1"