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

Commit

Permalink
Merge branch 'develop' into bugfix/fusion-removing-hardcoded-template…
Browse files Browse the repository at this point in the history
…-name
  • Loading branch information
jakubjezek001 authored Nov 16, 2023
2 parents 2b5c20e + 4519736 commit b0a678a
Show file tree
Hide file tree
Showing 120 changed files with 2,124 additions and 1,959 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ body:
label: Version
description: What version are you running? Look to OpenPype Tray
options:
- 3.17.6-nightly.3
- 3.17.6-nightly.2
- 3.17.6-nightly.1
- 3.17.5
Expand Down Expand Up @@ -134,7 +135,6 @@ body:
- 3.15.2-nightly.2
- 3.15.2-nightly.1
- 3.15.1
- 3.15.1-nightly.6
validations:
required: true
- type: dropdown
Expand Down
2 changes: 2 additions & 0 deletions openpype/hosts/blender/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
ls,
publish,
containerise,
BlenderHost,
)

from .plugin import (
Expand Down Expand Up @@ -47,6 +48,7 @@
"ls",
"publish",
"containerise",
"BlenderHost",

"Creator",
"Loader",
Expand Down
10 changes: 6 additions & 4 deletions openpype/hosts/blender/api/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def imprint(node: bpy.types.bpy_struct_meta_idprop, data: Dict):
# Support values evaluated at imprint
value = value()

if not isinstance(value, (int, float, bool, str, list)):
if not isinstance(value, (int, float, bool, str, list, dict)):
raise TypeError(f"Unsupported type: {type(value)}")

imprint_data[key] = value
Expand Down Expand Up @@ -278,9 +278,11 @@ def get_selected_collections():
list: A list of `bpy.types.Collection` objects that are currently
selected in the outliner.
"""
window = bpy.context.window or bpy.context.window_manager.windows[0]

try:
area = next(
area for area in bpy.context.window.screen.areas
area for area in window.screen.areas
if area.type == 'OUTLINER')
region = next(
region for region in area.regions
Expand All @@ -290,10 +292,10 @@ def get_selected_collections():
"must be in the main Blender window.") from e

with bpy.context.temp_override(
window=bpy.context.window,
window=window,
area=area,
region=region,
screen=bpy.context.window.screen
screen=window.screen
):
ids = bpy.context.selected_ids

Expand Down
32 changes: 30 additions & 2 deletions openpype/hosts/blender/api/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
TIMER_INTERVAL: float = 0.01 if platform.system() == "Windows" else 0.1


def execute_function_in_main_thread(f):
"""Decorator to move a function call into main thread items"""
def wrapper(*args, **kwargs):
mti = MainThreadItem(f, *args, **kwargs)
execute_in_main_thread(mti)
return wrapper


class BlenderApplication(QtWidgets.QApplication):
_instance = None
blender_windows = {}
Expand Down Expand Up @@ -238,8 +246,24 @@ def execute(self, context):

self.before_window_show()

def pull_to_front(window):
"""Pull window forward to screen.
If Window is minimized this will un-minimize, then it can be raised
and activated to the front.
"""
window.setWindowState(
(window.windowState() & ~QtCore.Qt.WindowMinimized) |
QtCore.Qt.WindowActive
)
window.raise_()
window.activateWindow()

if isinstance(self._window, ModuleType):
self._window.show()
pull_to_front(self._window)

# Pull window to the front
window = None
if hasattr(self._window, "window"):
window = self._window.window
Expand All @@ -254,6 +278,7 @@ def execute(self, context):
on_top_flags = origin_flags | QtCore.Qt.WindowStaysOnTopHint
self._window.setWindowFlags(on_top_flags)
self._window.show()
pull_to_front(self._window)

# if on_top_flags != origin_flags:
# self._window.setWindowFlags(origin_flags)
Expand All @@ -275,6 +300,10 @@ class LaunchCreator(LaunchQtApp):
def before_window_show(self):
self._window.refresh()

def execute(self, context):
host_tools.show_publisher(tab="create")
return {"FINISHED"}


class LaunchLoader(LaunchQtApp):
"""Launch Avalon Loader."""
Expand All @@ -299,7 +328,7 @@ class LaunchPublisher(LaunchQtApp):
bl_label = "Publish..."

def execute(self, context):
host_tools.show_publish()
host_tools.show_publisher(tab="publish")
return {"FINISHED"}


Expand Down Expand Up @@ -416,7 +445,6 @@ def draw(self, context):
layout.operator(SetResolution.bl_idname, text="Set Resolution")
layout.separator()
layout.operator(LaunchWorkFiles.bl_idname, text="Work Files...")
# TODO (jasper): maybe add 'Reload Pipeline'


def draw_avalon_menu(self, context):
Expand Down
109 changes: 109 additions & 0 deletions openpype/hosts/blender/api/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

import pyblish.api

from openpype.host import (
HostBase,
IWorkfileHost,
IPublishHost,
ILoadHost
)
from openpype.client import get_asset_by_name
from openpype.pipeline import (
schema,
Expand All @@ -29,6 +35,14 @@
)
import openpype.hosts.blender
from openpype.settings import get_project_settings
from .workio import (
open_file,
save_file,
current_file,
has_unsaved_changes,
file_extensions,
work_root,
)


HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.blender.__file__))
Expand All @@ -47,6 +61,101 @@
log = Logger.get_logger(__name__)


class BlenderHost(HostBase, IWorkfileHost, IPublishHost, ILoadHost):
name = "blender"

def install(self):
"""Override install method from HostBase.
Install Blender host functionality."""
install()

def get_containers(self) -> Iterator:
"""List containers from active Blender scene."""
return ls()

def get_workfile_extensions(self) -> List[str]:
"""Override get_workfile_extensions method from IWorkfileHost.
Get workfile possible extensions.
Returns:
List[str]: Workfile extensions.
"""
return file_extensions()

def save_workfile(self, dst_path: str = None):
"""Override save_workfile method from IWorkfileHost.
Save currently opened workfile.
Args:
dst_path (str): Where the current scene should be saved. Or use
current path if `None` is passed.
"""
save_file(dst_path if dst_path else bpy.data.filepath)

def open_workfile(self, filepath: str):
"""Override open_workfile method from IWorkfileHost.
Open workfile at specified filepath in the host.
Args:
filepath (str): Path to workfile.
"""
open_file(filepath)

def get_current_workfile(self) -> str:
"""Override get_current_workfile method from IWorkfileHost.
Retrieve currently opened workfile path.
Returns:
str: Path to currently opened workfile.
"""
return current_file()

def workfile_has_unsaved_changes(self) -> bool:
"""Override wokfile_has_unsaved_changes method from IWorkfileHost.
Returns True if opened workfile has no unsaved changes.
Returns:
bool: True if scene is saved and False if it has unsaved
modifications.
"""
return has_unsaved_changes()

def work_root(self, session) -> str:
"""Override work_root method from IWorkfileHost.
Modify workdir per host.
Args:
session (dict): Session context data.
Returns:
str: Path to new workdir.
"""
return work_root(session)

def get_context_data(self) -> dict:
"""Override abstract method from IPublishHost.
Get global data related to creation-publishing from workfile.
Returns:
dict: Context data stored using 'update_context_data'.
"""
property = bpy.context.scene.get(AVALON_PROPERTY)
if property:
return property.to_dict()
return {}

def update_context_data(self, data: dict, changes: dict):
"""Override abstract method from IPublishHost.
Store global context data to workfile.
Args:
data (dict): New data as are.
changes (dict): Only data that has been changed. Each value has
tuple with '(<old>, <new>)' value.
"""
bpy.context.scene[AVALON_PROPERTY] = data


def pype_excepthook_handler(*args):
traceback.print_exception(*args)

Expand Down
Loading

0 comments on commit b0a678a

Please sign in to comment.