From 14778e5c082d61f8a549e45a942d3e563416586c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 16 Feb 2021 11:33:48 +0100 Subject: [PATCH] Remove code to support Blender 2.79 and older --- blender_cloud/attract/__init__.py | 19 +-- blender_cloud/attract/draw_27.py | 189 ---------------------- blender_cloud/blender.py | 60 ++++--- blender_cloud/compatibility.py | 71 -------- blender_cloud/flamenco/__init__.py | 51 ++---- blender_cloud/image_sharing.py | 13 +- blender_cloud/settings_sync.py | 7 +- blender_cloud/texture_browser/__init__.py | 16 +- blender_cloud/texture_browser/draw_27.py | 98 ----------- 9 files changed, 65 insertions(+), 459 deletions(-) delete mode 100644 blender_cloud/attract/draw_27.py delete mode 100644 blender_cloud/compatibility.py delete mode 100644 blender_cloud/texture_browser/draw_27.py diff --git a/blender_cloud/attract/__init__.py b/blender_cloud/attract/__init__.py index d603956..6fe392e 100644 --- a/blender_cloud/attract/__init__.py +++ b/blender_cloud/attract/__init__.py @@ -47,15 +47,11 @@ if "bpy" in locals(): pillar = importlib.reload(pillar) async_loop = importlib.reload(async_loop) blender = importlib.reload(blender) - compatibility = importlib.reload(compatibility) else: import bpy - if bpy.app.version < (2, 80): - from . import draw_27 as draw - else: - from . import draw - from .. import pillar, async_loop, blender, compatibility + from . import draw + from .. import pillar, async_loop, blender import bpy import pillarsdk @@ -266,7 +262,7 @@ class ATTRACT_PT_tools(AttractPollMixin, Panel): ) # Group more dangerous operations. - dangerous_sub = layout.split(**compatibility.factor(0.6), align=True) + dangerous_sub = layout.split(factor=0.6, align=True) dangerous_sub.operator( "attract.strip_unlink", text="Unlink %s" % noun, icon="PANEL_CLOSE" ) @@ -433,12 +429,11 @@ class ATTRACT_OT_shot_fetch_update(AttractOperatorMixin, Operator): return {"FINISHED"} -@compatibility.convert_properties class ATTRACT_OT_shot_relink(AttractOperatorMixin, Operator): bl_idname = "attract.shot_relink" bl_label = "Relink With Attract" - strip_atc_object_id = bpy.props.StringProperty() + strip_atc_object_id: bpy.props.StringProperty() @classmethod def poll(cls, context): @@ -505,13 +500,12 @@ class ATTRACT_OT_shot_open_in_browser(AttractOperatorMixin, Operator): return {"FINISHED"} -@compatibility.convert_properties class ATTRACT_OT_shot_delete(AttractOperatorMixin, Operator): bl_idname = "attract.shot_delete" bl_label = "Delete Shot" bl_description = "Remove this shot from Attract" - confirm = bpy.props.BoolProperty(name="confirm") + confirm: bpy.props.BoolProperty(name="confirm") @classmethod def poll(cls, context): @@ -971,13 +965,12 @@ class ATTRACT_OT_copy_id_to_clipboard(AttractOperatorMixin, Operator): return {"FINISHED"} -@compatibility.convert_properties class ATTRACT_OT_project_open_in_browser(Operator): bl_idname = "attract.project_open_in_browser" bl_label = "Open Project in Browser" bl_description = "Opens a webbrowser to show the project in Attract" - project_id = bpy.props.StringProperty(name="Project ID", default="") + project_id: bpy.props.StringProperty(name="Project ID", default="") def execute(self, context): import webbrowser diff --git a/blender_cloud/attract/draw_27.py b/blender_cloud/attract/draw_27.py deleted file mode 100644 index 251d675..0000000 --- a/blender_cloud/attract/draw_27.py +++ /dev/null @@ -1,189 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# - -import bpy -import logging -import collections - -log = logging.getLogger(__name__) - -strip_status_colour = { - None: (0.7, 0.7, 0.7), - "approved": (0.6392156862745098, 0.8784313725490196, 0.30196078431372547), - "final": (0.9058823529411765, 0.9607843137254902, 0.8274509803921568), - "in_progress": (1.0, 0.7450980392156863, 0.0), - "on_hold": (0.796078431372549, 0.6196078431372549, 0.08235294117647059), - "review": (0.8941176470588236, 0.9607843137254902, 0.9764705882352941), - "todo": (1.0, 0.5019607843137255, 0.5019607843137255), -} - -CONFLICT_COLOUR = (0.576, 0.118, 0.035) # RGB tuple - - -def get_strip_rectf(strip): - # Get x and y in terms of the grid's frames and channels - x1 = strip.frame_final_start - x2 = strip.frame_final_end - y1 = strip.channel + 0.2 - y2 = strip.channel - 0.2 + 1 - - return x1, y1, x2, y2 - - -def draw_underline_in_strip(strip_coords, pixel_size_x, color): - from bgl import glColor4f, glRectf, glEnable, glDisable, GL_BLEND - import bgl - - context = bpy.context - - # Strip coords - s_x1, s_y1, s_x2, s_y2 = strip_coords - - # be careful not to draw over the current frame line - cf_x = context.scene.frame_current_final - - bgl.glPushAttrib(bgl.GL_COLOR_BUFFER_BIT | bgl.GL_LINE_BIT) - - glColor4f(*color) - glEnable(GL_BLEND) - bgl.glLineWidth(2) - bgl.glBegin(bgl.GL_LINES) - - bgl.glVertex2f(s_x1, s_y1) - if s_x1 < cf_x < s_x2: - # Bad luck, the line passes our strip - bgl.glVertex2f(cf_x - pixel_size_x, s_y1) - bgl.glVertex2f(cf_x + pixel_size_x, s_y1) - bgl.glVertex2f(s_x2, s_y1) - - bgl.glEnd() - bgl.glPopAttrib() - - -def draw_strip_conflict(strip_coords, pixel_size_x): - """Draws conflicting states between strips.""" - - import bgl - - s_x1, s_y1, s_x2, s_y2 = strip_coords - bgl.glPushAttrib(bgl.GL_COLOR_BUFFER_BIT | bgl.GL_LINE_BIT) - - # Always draw the full rectangle, the conflict should be resolved and thus stand out. - bgl.glColor3f(*CONFLICT_COLOUR) - bgl.glLineWidth(2) - - bgl.glBegin(bgl.GL_LINE_LOOP) - bgl.glVertex2f(s_x1, s_y1) - bgl.glVertex2f(s_x2, s_y1) - bgl.glVertex2f(s_x2, s_y2) - bgl.glVertex2f(s_x1, s_y2) - bgl.glEnd() - - bgl.glPopAttrib() - - -def draw_callback_px(): - context = bpy.context - - if not context.scene.sequence_editor: - return - - from . import shown_strips - - region = context.region - xwin1, ywin1 = region.view2d.region_to_view(0, 0) - xwin2, ywin2 = region.view2d.region_to_view(region.width, region.height) - one_pixel_further_x, one_pixel_further_y = region.view2d.region_to_view(1, 1) - pixel_size_x = one_pixel_further_x - xwin1 - - strips = shown_strips(context) - - for strip in strips: - if not strip.atc_object_id: - continue - - # Get corners (x1, y1), (x2, y2) of the strip rectangle in px region coords - strip_coords = get_strip_rectf(strip) - - # check if any of the coordinates are out of bounds - if ( - strip_coords[0] > xwin2 - or strip_coords[2] < xwin1 - or strip_coords[1] > ywin2 - or strip_coords[3] < ywin1 - ): - continue - - # Draw - status = strip.atc_status - if status in strip_status_colour: - color = strip_status_colour[status] - else: - color = strip_status_colour[None] - - alpha = 1.0 if strip.atc_is_synced else 0.5 - - draw_underline_in_strip(strip_coords, pixel_size_x, color + (alpha,)) - if strip.atc_is_synced and strip.atc_object_id_conflict: - draw_strip_conflict(strip_coords, pixel_size_x) - - -def tag_redraw_all_sequencer_editors(): - context = bpy.context - - # Py cant access notifiers - for window in context.window_manager.windows: - for area in window.screen.areas: - if area.type == "SEQUENCE_EDITOR": - for region in area.regions: - if region.type == "WINDOW": - region.tag_redraw() - - -# This is a list so it can be changed instead of set -# if it is only changed, it does not have to be declared as a global everywhere -cb_handle = [] - - -def callback_enable(): - if cb_handle: - return - - cb_handle[:] = ( - bpy.types.SpaceSequenceEditor.draw_handler_add( - draw_callback_px, (), "WINDOW", "POST_VIEW" - ), - ) - - tag_redraw_all_sequencer_editors() - - -def callback_disable(): - if not cb_handle: - return - - try: - bpy.types.SpaceSequenceEditor.draw_handler_remove(cb_handle[0], "WINDOW") - except ValueError: - # Thrown when already removed. - pass - cb_handle.clear() - - tag_redraw_all_sequencer_editors() diff --git a/blender_cloud/blender.py b/blender_cloud/blender.py index 5549bbd..871c5f3 100644 --- a/blender_cloud/blender.py +++ b/blender_cloud/blender.py @@ -36,7 +36,7 @@ from bpy.props import ( ) import rna_prop_ui -from . import compatibility, pillar, async_loop, flamenco, project_specific +from . import pillar, async_loop, flamenco, project_specific from .utils import pyside_cache, redraw PILLAR_WEB_SERVER_URL = os.environ.get("BCLOUD_SERVER", "https://cloud.blender.org/") @@ -58,9 +58,8 @@ def blender_syncable_versions(self, context): return [(v, v, "") for v in versions] -@compatibility.convert_properties class SyncStatusProperties(PropertyGroup): - status = EnumProperty( + status: EnumProperty( items=[ ("NONE", "NONE", "We have done nothing at all yet."), ( @@ -75,14 +74,14 @@ class SyncStatusProperties(PropertyGroup): update=redraw, ) - version = EnumProperty( + version: EnumProperty( items=blender_syncable_versions, name="Version of Blender from which to pull", description="Version of Blender from which to pull", ) - message = StringProperty(name="message", update=redraw) - level = EnumProperty( + message: StringProperty(name="message", update=redraw) + level: EnumProperty( items=[ ("INFO", "INFO", ""), ("WARNING", "WARNING", ""), @@ -152,9 +151,8 @@ def project_extensions(project_id) -> set: return set(proj.get("enabled_for", ())) -@compatibility.convert_properties class BlenderCloudProjectGroup(PropertyGroup): - status = EnumProperty( + status: EnumProperty( items=[ ("NONE", "NONE", "We have done nothing at all yet"), ( @@ -168,7 +166,7 @@ class BlenderCloudProjectGroup(PropertyGroup): update=redraw, ) - project = EnumProperty( + project: EnumProperty( items=bcloud_available_projects, name="Cloud project", description="Which Blender Cloud project to work with", @@ -187,26 +185,25 @@ class BlenderCloudProjectGroup(PropertyGroup): project_specific.handle_project_update() -@compatibility.convert_properties class BlenderCloudPreferences(AddonPreferences): bl_idname = ADDON_NAME # The following property is read-only to limit the scope of the # addon and allow for proper testing within this scope. - pillar_server = StringProperty( + pillar_server: StringProperty( name="Blender Cloud Server", description="URL of the Blender Cloud backend server", default=PILLAR_SERVER_URL, get=lambda self: PILLAR_SERVER_URL, ) - local_texture_dir = StringProperty( + local_texture_dir: StringProperty( name="Default Blender Cloud Texture Storage Directory", subtype="DIR_PATH", default="//textures", ) - open_browser_after_share = BoolProperty( + open_browser_after_share: BoolProperty( name="Open Browser after Sharing File", description="When enabled, Blender will open a webbrowser", default=True, @@ -214,9 +211,9 @@ class BlenderCloudPreferences(AddonPreferences): # TODO: store project-dependent properties with the project, so that people # can switch projects and the Attract and Flamenco properties switch with it. - project = PointerProperty(type=BlenderCloudProjectGroup) + project: PointerProperty(type=BlenderCloudProjectGroup) - cloud_project_local_path = StringProperty( + cloud_project_local_path: StringProperty( name="Local Project Path", description="Local path of your Attract project, used to search for blend files; " "usually best to set to an absolute path", @@ -225,29 +222,29 @@ class BlenderCloudPreferences(AddonPreferences): update=project_specific.store, ) - flamenco_manager = PointerProperty(type=flamenco.FlamencoManagerGroup) - flamenco_exclude_filter = StringProperty( + flamenco_manager: PointerProperty(type=flamenco.FlamencoManagerGroup) + flamenco_exclude_filter: StringProperty( name="File Exclude Filter", description='Space-separated list of filename filters, like "*.abc *.mkv", to prevent ' "matching files from being packed into the output directory", default="", update=project_specific.store, ) - flamenco_job_file_path = StringProperty( + flamenco_job_file_path: StringProperty( name="Job Storage Path", description="Path where to store job files, should be accesible for Workers too", subtype="DIR_PATH", default=tempfile.gettempdir(), update=project_specific.store, ) - flamenco_job_output_path = StringProperty( + flamenco_job_output_path: StringProperty( name="Job Output Path", description="Path where to store output files, should be accessible for Workers", subtype="DIR_PATH", default=tempfile.gettempdir(), update=project_specific.store, ) - flamenco_job_output_strip_components = IntProperty( + flamenco_job_output_strip_components: IntProperty( name="Job Output Path Strip Components", description="The final output path comprises of the job output path, and the blend file " "path relative to the project with this many path components stripped off " @@ -257,7 +254,7 @@ class BlenderCloudPreferences(AddonPreferences): soft_max=4, update=project_specific.store, ) - flamenco_relative_only = BoolProperty( + flamenco_relative_only: BoolProperty( name="Relative Paths Only", description="When enabled, only assets that are referred to with a relative path are " "packed, and assets referred to by an absolute path are excluded from the " @@ -266,12 +263,12 @@ class BlenderCloudPreferences(AddonPreferences): update=project_specific.store, ) - flamenco_open_browser_after_submit = BoolProperty( + flamenco_open_browser_after_submit: BoolProperty( name="Open Browser after Submitting Job", description="When enabled, Blender will open a webbrowser", default=True, ) - flamenco_show_quit_after_submit_button = BoolProperty( + flamenco_show_quit_after_submit_button: BoolProperty( name='Show "Submit & Quit" button', description='When enabled, next to the "Render on Flamenco" button there will be a button ' '"Submit & Quit" that silently quits Blender after submitting the render job ' @@ -343,7 +340,7 @@ class BlenderCloudPreferences(AddonPreferences): bss = context.window_manager.blender_sync_status bsync_box = layout.box() bsync_box.enabled = msg_icon != "ERROR" - row = bsync_box.row().split(**compatibility.factor(0.33)) + row = bsync_box.row().split(factor=0.33) row.label(text="Blender Sync with Blender Cloud", icon_value=icon("CLOUD")) icon_for_level = { @@ -386,7 +383,7 @@ class BlenderCloudPreferences(AddonPreferences): layout.enabled = bss.status in {"NONE", "IDLE"} buttons = layout.column() - row_buttons = buttons.row().split(**compatibility.factor(0.5)) + row_buttons = buttons.row().split(factor=0.5) row_push = row_buttons.row() row_pull = row_buttons.row(align=True) @@ -411,7 +408,7 @@ class BlenderCloudPreferences(AddonPreferences): props.action = "PULL" props.blender_version = bss.version row_pull.operator( - "pillar.sync", text="", icon=compatibility.SYNC_SELECT_VERSION_ICON + "pillar.sync", text="", icon="DOWNARROW_HLT" ).action = "SELECT" else: row_pull.label(text="Cloud Sync is running.") @@ -460,7 +457,7 @@ class BlenderCloudPreferences(AddonPreferences): header_row = flamenco_box.row(align=True) header_row.label(text="Flamenco:", icon_value=icon("CLOUD")) - manager_split = flamenco_box.split(**compatibility.factor(0.32), align=True) + manager_split = flamenco_box.split(factor=0.32, align=True) manager_split.label(text="Manager:") manager_box = manager_split.row(align=True) @@ -477,7 +474,7 @@ class BlenderCloudPreferences(AddonPreferences): else: manager_box.label(text="Fetching available managers.") - path_split = flamenco_box.split(**compatibility.factor(0.32), align=True) + path_split = flamenco_box.split(factor=0.32, align=True) path_split.label(text="Job File Path:") path_box = path_split.row(align=True) path_box.prop(self, "flamenco_job_file_path", text="") @@ -487,7 +484,7 @@ class BlenderCloudPreferences(AddonPreferences): props.path = self.flamenco_job_file_path job_output_box = flamenco_box.column(align=True) - path_split = job_output_box.split(**compatibility.factor(0.32), align=True) + path_split = job_output_box.split(factor=0.32, align=True) path_split.label(text="Job Output Path:") path_box = path_split.row(align=True) path_box.prop(self, "flamenco_job_output_path", text="") @@ -497,7 +494,7 @@ class BlenderCloudPreferences(AddonPreferences): props.path = self.flamenco_job_output_path job_output_box.prop(self, "flamenco_exclude_filter") - prop_split = job_output_box.split(**compatibility.factor(0.32), align=True) + prop_split = job_output_box.split(factor=0.32, align=True) prop_split.label(text="Strip Components:") prop_split.prop(self, "flamenco_job_output_strip_components", text="") @@ -586,13 +583,12 @@ class PILLAR_OT_subscribe(Operator): return {"FINISHED"} -@compatibility.convert_properties class PILLAR_OT_project_open_in_browser(Operator): bl_idname = "pillar.project_open_in_browser" bl_label = "Open in Browser" bl_description = "Opens a webbrowser to show the project" - project_id = StringProperty(name="Project ID") + project_id: StringProperty(name="Project ID") def execute(self, context): if not self.project_id: diff --git a/blender_cloud/compatibility.py b/blender_cloud/compatibility.py deleted file mode 100644 index 7ec38ec..0000000 --- a/blender_cloud/compatibility.py +++ /dev/null @@ -1,71 +0,0 @@ -"""Compatibility functions to support Blender 2.79 and 2.80+ in one code base.""" -import functools - -import bpy - - -if bpy.app.version < (2, 80): - SYNC_SELECT_VERSION_ICON = "DOTSDOWN" -else: - SYNC_SELECT_VERSION_ICON = "DOWNARROW_HLT" - - -# Get references to all property definition functions in bpy.props, -# so that they can be used to replace 'x = IntProperty()' to 'x: IntProperty()' -# dynamically when working on Blender 2.80+ -__all_prop_funcs = { - getattr(bpy.props, propname) - for propname in dir(bpy.props) - if propname.endswith("Property") -} - - -def convert_properties(class_): - """Class decorator to avoid warnings in Blender 2.80+ - - This decorator replaces property definitions like this: - - someprop = bpy.props.IntProperty() - - to annotations, as introduced in Blender 2.80: - - someprop: bpy.props.IntProperty() - - No-op if running on Blender 2.79 or older. - """ - - if bpy.app.version < (2, 80): - return class_ - - if not hasattr(class_, "__annotations__"): - class_.__annotations__ = {} - - attrs_to_delete = [] - for name, value in class_.__dict__.items(): - if not isinstance(value, tuple) or len(value) != 2: - continue - - prop_func, kwargs = value - if prop_func not in __all_prop_funcs: - continue - - # This is a property definition, replace it with annotation. - attrs_to_delete.append(name) - class_.__annotations__[name] = value - - for attr_name in attrs_to_delete: - delattr(class_, attr_name) - - return class_ - - -@functools.lru_cache() -def factor(factor: float) -> dict: - """Construct keyword argument for UILayout.split(). - - On Blender 2.8 this returns {'factor': factor}, and on earlier Blenders it returns - {'percentage': factor}. - """ - if bpy.app.version < (2, 80, 0): - return {"percentage": factor} - return {"factor": factor} diff --git a/blender_cloud/flamenco/__init__.py b/blender_cloud/flamenco/__init__.py index a07af83..21e1399 100644 --- a/blender_cloud/flamenco/__init__.py +++ b/blender_cloud/flamenco/__init__.py @@ -34,13 +34,12 @@ if "bpy" in locals(): bat_interface = importlib.reload(bat_interface) sdk = importlib.reload(sdk) blender = importlib.reload(blender) - compatibility = importlib.reload(compatibility) except NameError: from . import bat_interface, sdk - from .. import blender, compatibility + from .. import blender else: from . import bat_interface, sdk - from .. import blender, compatibility + from .. import blender import bpy from bpy.types import AddonPreferences, Operator, WindowManager, Scene, PropertyGroup @@ -130,31 +129,20 @@ def manager_updated(self: "FlamencoManagerGroup", context): def silently_quit_blender(): """Quit Blender without any confirmation popup.""" - try: - prefs = bpy.context.preferences - except AttributeError: - # Backward compatibility with Blender < 2.80 - prefs = bpy.context.user_preferences - - try: - prefs.view.use_save_prompt = False - except AttributeError: - # Backward compatibility with Blender < 2.80 - prefs.view.use_quit_dialog = False - + prefs = bpy.context.preferences + prefs.view.use_save_prompt = False bpy.ops.wm.quit_blender() -@compatibility.convert_properties class FlamencoManagerGroup(PropertyGroup): - manager = EnumProperty( + manager: EnumProperty( items=available_managers, name="Flamenco Manager", description="Which Flamenco Manager to use for jobs", update=manager_updated, ) - status = EnumProperty( + status: EnumProperty( items=[ ("NONE", "NONE", "We have done nothing at all yet"), ( @@ -293,7 +281,6 @@ def is_file_inside_job_storage(prefs, current_file: typing.Union[str, Path]) -> return True -@compatibility.convert_properties class FLAMENCO_OT_render( async_loop.AsyncModalOperatorMixin, pillar.AuthenticatedPillarOperatorMixin, @@ -309,7 +296,7 @@ class FLAMENCO_OT_render( stop_upon_exception = True log = logging.getLogger("%s.FLAMENCO_OT_render" % __name__) - quit_after_submit = BoolProperty() + quit_after_submit: BoolProperty() async def async_execute(self, context): # Refuse to start if the file hasn't been saved. It's okay if @@ -864,7 +851,6 @@ class FLAMENCO_OT_abort(Operator, FlamencoPollMixin): return {"FINISHED"} -@compatibility.convert_properties class FLAMENCO_OT_explore_file_path(FlamencoPollMixin, Operator): """Opens the Flamenco job storage path in a file explorer. @@ -875,9 +861,7 @@ class FLAMENCO_OT_explore_file_path(FlamencoPollMixin, Operator): bl_label = "Open in file explorer" bl_description = __doc__.rstrip(".") - path = StringProperty( - name="Path", description="Path to explore", subtype="DIR_PATH" - ) + path: StringProperty(name="Path", description="Path to explore", subtype="DIR_PATH") def execute(self, context): import platform @@ -940,13 +924,12 @@ class FLAMENCO_OT_disable_output_path_override(Operator): return {"FINISHED"} -@compatibility.convert_properties class FLAMENCO_OT_set_recommended_sample_cap(Operator): bl_idname = "flamenco.set_recommended_sample_cap" bl_label = "Set Recommended Maximum Sample Count" bl_description = "Set the recommended maximum samples per render task" - sample_cap = IntProperty() + sample_cap: IntProperty() def execute(self, context): context.scene.flamenco_render_chunk_sample_cap = self.sample_cap @@ -1112,7 +1095,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): prefs = preferences() - labeled_row = layout.split(**compatibility.factor(0.25), align=True) + labeled_row = layout.split(factor=0.25, align=True) labeled_row.label(text="Manager:") prop_btn_row = labeled_row.row(align=True) @@ -1130,7 +1113,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): else: prop_btn_row.label(text="Fetching available managers.") - labeled_row = layout.split(**compatibility.factor(0.25), align=True) + labeled_row = layout.split(factor=0.25, align=True) labeled_row.label(text="Job Type:") labeled_row.prop(context.scene, "flamenco_render_job_type", text="") @@ -1160,7 +1143,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): sample_count = scene_sample_count(context.scene) recommended_cap = sample_count // 4 - split = box.split(**compatibility.factor(0.4)) + split = box.split(factor=0.4) split.label(text="Total Sample Count: %d" % sample_count) props = split.operator( "flamenco.set_recommended_sample_cap", @@ -1181,7 +1164,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): else: box.prop(context.scene, "flamenco_render_fchunk_size") - labeled_row = layout.split(**compatibility.factor(0.25), align=True) + labeled_row = layout.split(factor=0.25, align=True) labeled_row.label(text="Frame Range:") prop_btn_row = labeled_row.row(align=True) prop_btn_row.prop(context.scene, "flamenco_render_frame_range", text="") @@ -1194,7 +1177,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): paths_layout = layout.column(align=True) - labeled_row = paths_layout.split(**compatibility.factor(0.25), align=True) + labeled_row = paths_layout.split(factor=0.25, align=True) labeled_row.label(text="Storage:") prop_btn_row = labeled_row.row(align=True) prop_btn_row.label(text=prefs.flamenco_job_file_path) @@ -1217,7 +1200,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): ) return - labeled_row = paths_layout.split(**compatibility.factor(0.25), align=True) + labeled_row = paths_layout.split(factor=0.25, align=True) labeled_row.label(text="Output:") prop_btn_row = labeled_row.row(align=True) @@ -1237,7 +1220,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): props.path = str(render_output.parent) if context.scene.flamenco_do_override_output_path: - labeled_row = paths_layout.split(**compatibility.factor(0.25), align=True) + labeled_row = paths_layout.split(factor=0.25, align=True) labeled_row.label(text="Effective Output Path:") labeled_row.label(text=str(render_output)) @@ -1247,7 +1230,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin): flamenco_status = context.window_manager.flamenco_status if flamenco_status in {"IDLE", "ABORTED", "DONE"}: if prefs.flamenco_show_quit_after_submit_button: - ui = layout.split(**compatibility.factor(0.75), align=True) + ui = layout.split(factor=0.75, align=True) else: ui = layout ui.operator( diff --git a/blender_cloud/image_sharing.py b/blender_cloud/image_sharing.py index 2d0faac..7a2ad31 100644 --- a/blender_cloud/image_sharing.py +++ b/blender_cloud/image_sharing.py @@ -25,7 +25,7 @@ import bpy import pillarsdk from pillarsdk import exceptions as sdk_exceptions from .pillar import pillar_call -from . import async_loop, compatibility, pillar, home_project, blender +from . import async_loop, pillar, home_project, blender REQUIRES_ROLES_FOR_IMAGE_SHARING = {"subscriber", "demo"} IMAGE_SHARING_GROUP_NODE_NAME = "Image sharing" @@ -56,7 +56,6 @@ async def find_image_sharing_group_id(home_project_id, user_id): return share_group["_id"] -@compatibility.convert_properties class PILLAR_OT_image_share( pillar.PillarOperatorMixin, async_loop.AsyncModalOperatorMixin, bpy.types.Operator ): @@ -71,7 +70,7 @@ class PILLAR_OT_image_share( share_group_id = None # top-level share group node ID user_id = None - target = bpy.props.EnumProperty( + target: bpy.props.EnumProperty( items=[ ("FILE", "File", "Share an image file"), ("DATABLOCK", "Datablock", "Share an image datablock"), @@ -81,19 +80,19 @@ class PILLAR_OT_image_share( default="SCREENSHOT", ) - name = bpy.props.StringProperty( + name: bpy.props.StringProperty( name="name", description="File or datablock name to sync" ) - screenshot_show_multiview = bpy.props.BoolProperty( + screenshot_show_multiview: bpy.props.BoolProperty( name="screenshot_show_multiview", description="Enable Multi-View", default=False ) - screenshot_use_multiview = bpy.props.BoolProperty( + screenshot_use_multiview: bpy.props.BoolProperty( name="screenshot_use_multiview", description="Use Multi-View", default=False ) - screenshot_full = bpy.props.BoolProperty( + screenshot_full: bpy.props.BoolProperty( name="screenshot_full", description="Full Screen, Capture the whole window (otherwise only capture the active area)", default=False, diff --git a/blender_cloud/settings_sync.py b/blender_cloud/settings_sync.py index ba92e34..d3ca715 100644 --- a/blender_cloud/settings_sync.py +++ b/blender_cloud/settings_sync.py @@ -35,7 +35,7 @@ import asyncio import pillarsdk from pillarsdk import exceptions as sdk_exceptions from .pillar import pillar_call -from . import async_loop, blender, compatibility, pillar, cache, blendfile, home_project +from . import async_loop, blender, pillar, cache, blendfile, home_project SETTINGS_FILES_TO_UPLOAD = ["userpref.blend", "startup.blend"] @@ -214,7 +214,6 @@ async def available_blender_versions(home_project_id: str, user_id: str) -> list # noinspection PyAttributeOutsideInit -@compatibility.convert_properties class PILLAR_OT_sync( pillar.PillarOperatorMixin, async_loop.AsyncModalOperatorMixin, bpy.types.Operator ): @@ -227,7 +226,7 @@ class PILLAR_OT_sync( sync_group_id = "" # top-level sync group node ID sync_group_versioned_id = "" # sync group node ID for the given Blender version. - action = bpy.props.EnumProperty( + action: bpy.props.EnumProperty( items=[ ("PUSH", "Push", "Push settings to the Blender Cloud"), ("PULL", "Pull", "Pull settings from the Blender Cloud"), @@ -238,7 +237,7 @@ class PILLAR_OT_sync( ) CURRENT_BLENDER_VERSION = "%i.%i" % bpy.app.version[:2] - blender_version = bpy.props.StringProperty( + blender_version: bpy.props.StringProperty( name="blender_version", description="Blender version to sync for", default=CURRENT_BLENDER_VERSION, diff --git a/blender_cloud/texture_browser/__init__.py b/blender_cloud/texture_browser/__init__.py index f499970..15de606 100644 --- a/blender_cloud/texture_browser/__init__.py +++ b/blender_cloud/texture_browser/__init__.py @@ -26,16 +26,11 @@ import bpy import bgl import pillarsdk -from .. import async_loop, compatibility, pillar, cache, blender, utils +from .. import async_loop, pillar, cache, blender, utils from . import ( menu_item as menu_item_mod, ) # so that we can have menu items called 'menu_item' -from . import nodes - -if bpy.app.version < (2, 80): - from . import draw_27 as draw -else: - from . import draw +from . import draw, nodes REQUIRED_ROLES_FOR_TEXTURE_BROWSER = {"subscriber", "demo"} MOUSE_SCROLL_PIXELS_PER_TICK = 50 @@ -686,7 +681,6 @@ class BlenderCloudBrowser( self.scroll_offset_target = self.scroll_offset = 0 -@compatibility.convert_properties class PILLAR_OT_switch_hdri( pillar.PillarOperatorMixin, async_loop.AsyncModalOperatorMixin, bpy.types.Operator ): @@ -698,11 +692,11 @@ class PILLAR_OT_switch_hdri( log = logging.getLogger("bpy.ops.%s" % bl_idname) - image_name = bpy.props.StringProperty( + image_name: bpy.props.StringProperty( name="image_name", description="Name of the image block to replace" ) - file_uuid = bpy.props.StringProperty( + file_uuid: bpy.props.StringProperty( name="file_uuid", description="File ID to download" ) @@ -834,7 +828,7 @@ def _hdri_download_panel(self, current_image): ) return - row = self.layout.row(align=True).split(**compatibility.factor(0.3)) + row = self.layout.row(align=True).split(factor=0.3) row.label(text="HDRi", icon_value=blender.icon("CLOUD")) row.prop(current_image, "hdri_variation", text="") diff --git a/blender_cloud/texture_browser/draw_27.py b/blender_cloud/texture_browser/draw_27.py deleted file mode 100644 index 1809da3..0000000 --- a/blender_cloud/texture_browser/draw_27.py +++ /dev/null @@ -1,98 +0,0 @@ -"""OpenGL drawing code for the texture browser. - -Requires Blender 2.79 or older. -""" - -import typing - -import bgl -import blf -import bpy - -Float2 = typing.Tuple[float, float] -Float3 = typing.Tuple[float, float, float] -Float4 = typing.Tuple[float, float, float, float] - - -def text( - pos2d: Float2, - display_text: typing.Union[str, typing.List[str]], - rgba: Float4 = (1.0, 1.0, 1.0, 1.0), - fsize=12, - align="L", -): - """Draw text with the top-left corner at 'pos2d'.""" - - dpi = bpy.context.user_preferences.system.dpi - gap = 12 - x_pos, y_pos = pos2d - font_id = 0 - blf.size(font_id, fsize, dpi) - - # Compute the height of one line. - mwidth, mheight = blf.dimensions(font_id, "Tp") # Use high and low letters. - mheight *= 1.5 - - # Split text into lines. - if isinstance(display_text, str): - mylines = display_text.split("\n") - else: - mylines = display_text - maxwidth = 0 - maxheight = len(mylines) * mheight - - for idx, line in enumerate(mylines): - text_width, text_height = blf.dimensions(font_id, line) - if align == "C": - newx = x_pos - text_width / 2 - elif align == "R": - newx = x_pos - text_width - gap - else: - newx = x_pos - - # Draw - blf.position(font_id, newx, y_pos - mheight * idx, 0) - bgl.glColor4f(*rgba) - blf.draw(font_id, " " + line) - - # saves max width - if maxwidth < text_width: - maxwidth = text_width - - return maxwidth, maxheight - - -def aabox(v1: Float2, v2: Float2, rgba: Float4): - """Draw an axis-aligned box.""" - - bgl.glColor4f(*rgba) - bgl.glRectf(*v1, *v2) - - -def aabox_with_texture(v1: Float2, v2: Float2): - """Draw an axis-aligned box with a texture.""" - - bgl.glColor4f(1.0, 1.0, 1.0, 1.0) - - bgl.glEnable(bgl.GL_TEXTURE_2D) - bgl.glBegin(bgl.GL_QUADS) - bgl.glTexCoord2d(0, 0) - bgl.glVertex2d(v1[0], v1[1]) - bgl.glTexCoord2d(0, 1) - bgl.glVertex2d(v1[0], v2[1]) - bgl.glTexCoord2d(1, 1) - bgl.glVertex2d(v2[0], v2[1]) - bgl.glTexCoord2d(1, 0) - bgl.glVertex2d(v2[0], v1[1]) - bgl.glEnd() - bgl.glDisable(bgl.GL_TEXTURE_2D) - - -def bind_texture(texture: bpy.types.Image): - """Bind a Blender image to a GL texture slot.""" - bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode[0]) - - -def load_texture(texture: bpy.types.Image) -> int: - """Load the texture, return OpenGL error code.""" - return texture.gl_load(filter=bgl.GL_NEAREST, mag=bgl.GL_NEAREST)