diff --git a/openpype/settings/entities/dict_mutable_keys_entity.py b/openpype/settings/entities/dict_mutable_keys_entity.py index 7ba44ed0df..19eb83072e 100644 --- a/openpype/settings/entities/dict_mutable_keys_entity.py +++ b/openpype/settings/entities/dict_mutable_keys_entity.py @@ -277,21 +277,24 @@ class DictMutableKeysEntity(EndpointEntity): self.on_change() - def _metadata_for_current_state(self): + def _get_metadata_for_state(self, state): if ( - self._override_state is OverrideState.PROJECT + state is OverrideState.PROJECT and self._project_override_value is not NOT_SET ): return self._project_override_metadata if ( - self._override_state >= OverrideState.STUDIO + state >= OverrideState.STUDIO and self._studio_override_value is not NOT_SET ): return self._studio_override_metadata return self._default_metadata + def _metadata_for_current_state(self): + return self._get_metadata_for_state(self._override_state) + def set_override_state(self, state): # Trigger override state change of root if is not same if self.root_item.override_state is not state: @@ -519,6 +522,9 @@ class DictMutableKeysEntity(EndpointEntity): self.had_project_override = value is not NOT_SET def _discard_changes(self, on_change_trigger): + if not self.can_discard_changes: + return + self.set_override_state(self._override_state) on_change_trigger.append(self.on_change) @@ -527,6 +533,9 @@ class DictMutableKeysEntity(EndpointEntity): self.on_change() def _remove_from_studio_default(self, on_change_trigger): + if not self.can_remove_from_studio_default: + return + value = self._default_value if value is NOT_SET: value = self.value_on_not_set @@ -536,13 +545,23 @@ class DictMutableKeysEntity(EndpointEntity): # Simulate `clear` method without triggering value change for key in tuple(self.children_by_key.keys()): - child_obj = self.children_by_key.pop(key) + self.children_by_key.pop(key) + + metadata = self._get_metadata_for_state(OverrideState.DEFAULTS) + metadata_labels = metadata.get(M_DYNAMIC_KEY_LABEL) or {} + children_label_by_id = {} # Create new children for _key, _value in new_value.items(): - child_obj = self._add_key(_key) - child_obj.update_default_value(_value) - child_obj.set_override_state(self._override_state) + child_entity = self._add_key(_key) + child_entity.update_default_value(_value) + label = metadata_labels.get(_key) + if label: + children_label_by_id[child_entity.id] = label + + child_entity.set_override_state(self._override_state) + + self.children_label_by_id = children_label_by_id self._ignore_child_changes = False @@ -555,10 +574,7 @@ class DictMutableKeysEntity(EndpointEntity): self.on_change() def _remove_from_project_override(self, on_change_trigger): - if self._override_state is not OverrideState.PROJECT: - return - - if not self.has_project_override: + if not self.can_remove_from_project_override: return if self._has_studio_override: @@ -574,15 +590,26 @@ class DictMutableKeysEntity(EndpointEntity): # Simulate `clear` method without triggering value change for key in tuple(self.children_by_key.keys()): - child_obj = self.children_by_key.pop(key) + self.children_by_key.pop(key) + + metadata = self._get_metadata_for_state(OverrideState.STUDIO) + metadata_labels = metadata.get(M_DYNAMIC_KEY_LABEL) or {} + children_label_by_id = {} # Create new children for _key, _value in new_value.items(): - child_obj = self._add_key(_key) - child_obj.update_default_value(_value) + child_entity = self._add_key(_key) + child_entity.update_default_value(_value) if self._has_studio_override: - child_obj.update_studio_value(_value) - child_obj.set_override_state(self._override_state) + child_entity.update_studio_value(_value) + + label = metadata_labels.get(_key) + if label: + children_label_by_id[child_entity.id] = label + + child_entity.set_override_state(self._override_state) + + self.children_label_by_id = children_label_by_id self._ignore_child_changes = False diff --git a/openpype/settings/entities/input_entities.py b/openpype/settings/entities/input_entities.py index e897576d43..2ca20542ef 100644 --- a/openpype/settings/entities/input_entities.py +++ b/openpype/settings/entities/input_entities.py @@ -251,6 +251,9 @@ class InputEntity(EndpointEntity): self._current_value = copy.deepcopy(value) def _discard_changes(self, on_change_trigger=None): + if not self.can_discard_changes: + return + self._value_is_modified = False if self._override_state >= OverrideState.PROJECT: self._has_project_override = self.had_project_override @@ -286,6 +289,9 @@ class InputEntity(EndpointEntity): self.on_change() def _remove_from_studio_default(self, on_change_trigger): + if not self.can_remove_from_studio_default: + return + value = self._default_value if value is NOT_SET: value = self.value_on_not_set @@ -301,10 +307,7 @@ class InputEntity(EndpointEntity): self.on_change() def _remove_from_project_override(self, on_change_trigger): - if self._override_state is not OverrideState.PROJECT: - return - - if not self._has_project_override: + if not self.can_remove_from_project_override: return self._has_project_override = False diff --git a/openpype/settings/entities/list_entity.py b/openpype/settings/entities/list_entity.py index c6155b78f8..ee647264b7 100644 --- a/openpype/settings/entities/list_entity.py +++ b/openpype/settings/entities/list_entity.py @@ -343,7 +343,7 @@ class ListEntity(EndpointEntity): return output def _discard_changes(self, on_change_trigger): - if self._override_state is OverrideState.NOT_DEFINED: + if not self.can_discard_changes: return not_set = object() @@ -405,7 +405,7 @@ class ListEntity(EndpointEntity): self.on_change() def _remove_from_studio_default(self, on_change_trigger): - if self._override_state is not OverrideState.STUDIO: + if not self.can_remove_from_studio_default: return value = self._default_value @@ -433,10 +433,7 @@ class ListEntity(EndpointEntity): self.on_change() def _remove_from_project_override(self, on_change_trigger): - if self._override_state is not OverrideState.PROJECT: - return - - if not self.has_project_override: + if not self.can_remove_from_project_override: return if self._has_studio_override: diff --git a/website/docs/admin_hosts_blender.md b/website/docs/admin_hosts_blender.md new file mode 100644 index 0000000000..0655e5341a --- /dev/null +++ b/website/docs/admin_hosts_blender.md @@ -0,0 +1,83 @@ +--- +id: admin_hosts_blender +title: Blender +sidebar_label: Blender +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Blender requirements +Blender integration requires to use **PySide2** module inside blender. Module is different for Blender versions and platforms so can't be bundled with OpenPype. + +### How to install + +:::info Permissions +This step requires Admin persmission. +::: + + + + + +Find python executable inside your Blender installation folder. It is usually located in **C:\\Program Files\\Blender Foundation\\Blender {version}\\{version}\\python\\bin\\python.exe** (This may differ in future blender version). + +Open Powershell or Command Prompt as Administrator and run commands below. + +*Replace `C:\Program Files\Blender Foundation\Blender 2.83\2.83\python\bin` with your path.* + +```bash +# Change directory to python executable directory. +> cd C:\Program Files\Blender Foundation\Blender 2.83\2.83\python\bin + +# Run pip install command. +> python -m pip install PySide2 +``` + + + + + +Procedure may differ based on Linux distribution and blender distribution. Some Blender distributions are using system Python in that case it is required to install PySide2 using pip to system python (Not tested). + +**These instructions are for Blender using bundled python.** + +Find python executable inside your blender application. + +:::note Find python executable in Blender +You can launch Blender and in "Scripting" section enter commands to console. +```bash +>>> import bpy +>>> print(bpy.app.binary_path_python) +'/path/to/python/executable' +``` +::: + +Open terminal and run pip install command below. + +*Replace `/usr/bin/blender/2.83/python/bin/python3.7m` with your path.* +```bash +> /usr/bin/blender/2.83/python/bin/python3.7m -m pip install PySide2 +``` + +:::warning No module named pip +If you get error `No module named pip` you'll have to do few steps first. Open new terminal and run the python executable from Blender (entering full path). +```bash +# Run Python executable +> /usr/bin/blender/2.83/python/bin/python3.7m +# Python process should start +>>> import ensurepip +>>> ensurepip.bootstrap() +``` +You can close new terminal. Run pip install command above again. Now should work as expected. +::: + + + + diff --git a/website/docs/admin_settings_project.md b/website/docs/admin_settings_project.md deleted file mode 100644 index a30c0f0082..0000000000 --- a/website/docs/admin_settings_project.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -id: admin_settings_project -title: Project Settings -sidebar_label: Project Settings ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - - -PROJECT Settings \ No newline at end of file diff --git a/website/docs/project_settings/assets/global_extract_review_letter_box.png b/website/docs/project_settings/assets/global_extract_review_letter_box.png new file mode 100644 index 0000000000..7cd9ecbdd6 Binary files /dev/null and b/website/docs/project_settings/assets/global_extract_review_letter_box.png differ diff --git a/website/docs/project_settings/assets/global_extract_review_letter_box_settings.png b/website/docs/project_settings/assets/global_extract_review_letter_box_settings.png new file mode 100644 index 0000000000..9ad9c05f43 Binary files /dev/null and b/website/docs/project_settings/assets/global_extract_review_letter_box_settings.png differ diff --git a/website/docs/project_settings/assets/global_extract_review_output_defs.png b/website/docs/project_settings/assets/global_extract_review_output_defs.png new file mode 100644 index 0000000000..0dc8329324 Binary files /dev/null and b/website/docs/project_settings/assets/global_extract_review_output_defs.png differ diff --git a/website/docs/project_settings/assets/global_extract_review_profiles.png b/website/docs/project_settings/assets/global_extract_review_profiles.png new file mode 100644 index 0000000000..1b91786ff6 Binary files /dev/null and b/website/docs/project_settings/assets/global_extract_review_profiles.png differ diff --git a/website/docs/project_settings/settings_project_global.md b/website/docs/project_settings/settings_project_global.md new file mode 100644 index 0000000000..a90e5caeef --- /dev/null +++ b/website/docs/project_settings/settings_project_global.md @@ -0,0 +1,69 @@ +--- +id: settings_project_global +title: Project Global Setting +sidebar_label: Global +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Project settings can have project specific values. Each new project is using studio values defined in **default** project but these values can be modified or overriden per project. + +:::warning Default studio values +Projects always use default project values unless they have [project override](../admin_settings#project-overrides) (orage colour). Any changes in default project may affect all existing projects. +::: + +## Publish plugins + +Publish plugins used across all integrations. + +### Extract Review +Plugin responsible for automatic FFmpeg conversion to variety of formats. + +Extract review is using profile filtering to be able render different outputs for different situations. + +**Profile filters** + +You can define multiple profiles for different contexts. Profile with filters matching the current context the most, is used. You can define profile without filters and use it as **default**. Only **one or none** profile will be processed per instance. + +All context filters are lists which may contain strings or Regular expressions (RegEx). +- **`hosts`** - Host from which publishing was triggered. `["maya", "nuke"]` +- **`families`** - Main family of processed instance. `["plate", "model"]` + +:::important Filtering +Filters are optional. In case when multiple profiles match current context, profile with higher number of matched filters has higher priority that profile without filters. +::: + +![global_extract_review_profiles](assets/global_extract_review_profiles.png) + +**Output Definitions** + + +Profile may generate multiple outputs from a single input. Each output must define unique name and output extension (use the extension without a dot e.g. **mp4**). All other settings of output definition are optional. + +![global_extract_review_output_defs](assets/global_extract_review_output_defs.png) +- **`Tags`** + Define what will happen to output. + +- **`FFmpeg arguments`** + These arguments are appended to ffmpeg arguments auto generated by publish plugin. Some of arguments are handled automatically like rescaling or letterboxes. + - **Video filters** additional FFmpeg filters that would be defined in `-filter:v` or `-vf` command line arguments. + - **Audio filters** additional FFmpeg filters that would be defined in `-filter:a` or `-af` command line arguments. + - **Input arguments** input definition arguments of video or image sequence - this setting has limitations as you have to know what is input. + - **Output arguments** other FFmpeg output arguments like codec definition. + +- **`Output width`** and **`Output height`** + - it is possible to rescale output to specified resolution and keep aspect ratio. + - If value is set to 0, source resolution will be used. + +- **`Letter Box`** + - **Enabled** - Enable letter boxes + - **Ratio** - Ratio of letter boxes + - **Type** - **Letterbox** (horizontal bars) or **Pillarbox** (vertical bars) + - **Fill color** - Fill color of boxes (RGBA: 0-255) + - **Line Thickness** - Line thickness on the edge of box (set to `0` to turn off) + - **Fill color** - Line color on the edge of box (RGBA: 0-255) + - **Example** + + ![global_extract_review_letter_box_settings](assets/global_extract_review_letter_box_settings.png) + ![global_extract_review_letter_box](assets/global_extract_review_letter_box.png) diff --git a/website/sidebars.js b/website/sidebars.js index 842d7a0a49..4f5b7d604d 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -57,7 +57,13 @@ module.exports = { "admin_settings", "admin_settings_system", "admin_settings_project_anatomy", - "admin_settings_project", + { + type: "category", + label: "Project Settings", + items: [ + "project_settings/settings_project_global" + ], + }, ], }, { @@ -71,6 +77,13 @@ module.exports = { "module_clockify" ], }, + { + type: "category", + label: "Integrations", + items: [ + "admin_hosts_blender" + ], + }, { type: "category", label: "Releases",