Remove code to support Blender 2.79 and older
This commit is contained in:
parent
8b49c5505e
commit
14778e5c08
@ -47,15 +47,11 @@ if "bpy" in locals():
|
|||||||
pillar = importlib.reload(pillar)
|
pillar = importlib.reload(pillar)
|
||||||
async_loop = importlib.reload(async_loop)
|
async_loop = importlib.reload(async_loop)
|
||||||
blender = importlib.reload(blender)
|
blender = importlib.reload(blender)
|
||||||
compatibility = importlib.reload(compatibility)
|
|
||||||
else:
|
else:
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
if bpy.app.version < (2, 80):
|
from . import draw
|
||||||
from . import draw_27 as draw
|
from .. import pillar, async_loop, blender
|
||||||
else:
|
|
||||||
from . import draw
|
|
||||||
from .. import pillar, async_loop, blender, compatibility
|
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import pillarsdk
|
import pillarsdk
|
||||||
@ -266,7 +262,7 @@ class ATTRACT_PT_tools(AttractPollMixin, Panel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Group more dangerous operations.
|
# 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(
|
dangerous_sub.operator(
|
||||||
"attract.strip_unlink", text="Unlink %s" % noun, icon="PANEL_CLOSE"
|
"attract.strip_unlink", text="Unlink %s" % noun, icon="PANEL_CLOSE"
|
||||||
)
|
)
|
||||||
@ -433,12 +429,11 @@ class ATTRACT_OT_shot_fetch_update(AttractOperatorMixin, Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class ATTRACT_OT_shot_relink(AttractOperatorMixin, Operator):
|
class ATTRACT_OT_shot_relink(AttractOperatorMixin, Operator):
|
||||||
bl_idname = "attract.shot_relink"
|
bl_idname = "attract.shot_relink"
|
||||||
bl_label = "Relink With Attract"
|
bl_label = "Relink With Attract"
|
||||||
|
|
||||||
strip_atc_object_id = bpy.props.StringProperty()
|
strip_atc_object_id: bpy.props.StringProperty()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -505,13 +500,12 @@ class ATTRACT_OT_shot_open_in_browser(AttractOperatorMixin, Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class ATTRACT_OT_shot_delete(AttractOperatorMixin, Operator):
|
class ATTRACT_OT_shot_delete(AttractOperatorMixin, Operator):
|
||||||
bl_idname = "attract.shot_delete"
|
bl_idname = "attract.shot_delete"
|
||||||
bl_label = "Delete Shot"
|
bl_label = "Delete Shot"
|
||||||
bl_description = "Remove this shot from Attract"
|
bl_description = "Remove this shot from Attract"
|
||||||
|
|
||||||
confirm = bpy.props.BoolProperty(name="confirm")
|
confirm: bpy.props.BoolProperty(name="confirm")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -971,13 +965,12 @@ class ATTRACT_OT_copy_id_to_clipboard(AttractOperatorMixin, Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class ATTRACT_OT_project_open_in_browser(Operator):
|
class ATTRACT_OT_project_open_in_browser(Operator):
|
||||||
bl_idname = "attract.project_open_in_browser"
|
bl_idname = "attract.project_open_in_browser"
|
||||||
bl_label = "Open Project in Browser"
|
bl_label = "Open Project in Browser"
|
||||||
bl_description = "Opens a webbrowser to show the project in Attract"
|
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):
|
def execute(self, context):
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
@ -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 #####
|
|
||||||
|
|
||||||
# <pep8 compliant>
|
|
||||||
|
|
||||||
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()
|
|
@ -36,7 +36,7 @@ from bpy.props import (
|
|||||||
)
|
)
|
||||||
import rna_prop_ui
|
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
|
from .utils import pyside_cache, redraw
|
||||||
|
|
||||||
PILLAR_WEB_SERVER_URL = os.environ.get("BCLOUD_SERVER", "https://cloud.blender.org/")
|
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]
|
return [(v, v, "") for v in versions]
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class SyncStatusProperties(PropertyGroup):
|
class SyncStatusProperties(PropertyGroup):
|
||||||
status = EnumProperty(
|
status: EnumProperty(
|
||||||
items=[
|
items=[
|
||||||
("NONE", "NONE", "We have done nothing at all yet."),
|
("NONE", "NONE", "We have done nothing at all yet."),
|
||||||
(
|
(
|
||||||
@ -75,14 +74,14 @@ class SyncStatusProperties(PropertyGroup):
|
|||||||
update=redraw,
|
update=redraw,
|
||||||
)
|
)
|
||||||
|
|
||||||
version = EnumProperty(
|
version: EnumProperty(
|
||||||
items=blender_syncable_versions,
|
items=blender_syncable_versions,
|
||||||
name="Version of Blender from which to pull",
|
name="Version of Blender from which to pull",
|
||||||
description="Version of Blender from which to pull",
|
description="Version of Blender from which to pull",
|
||||||
)
|
)
|
||||||
|
|
||||||
message = StringProperty(name="message", update=redraw)
|
message: StringProperty(name="message", update=redraw)
|
||||||
level = EnumProperty(
|
level: EnumProperty(
|
||||||
items=[
|
items=[
|
||||||
("INFO", "INFO", ""),
|
("INFO", "INFO", ""),
|
||||||
("WARNING", "WARNING", ""),
|
("WARNING", "WARNING", ""),
|
||||||
@ -152,9 +151,8 @@ def project_extensions(project_id) -> set:
|
|||||||
return set(proj.get("enabled_for", ()))
|
return set(proj.get("enabled_for", ()))
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class BlenderCloudProjectGroup(PropertyGroup):
|
class BlenderCloudProjectGroup(PropertyGroup):
|
||||||
status = EnumProperty(
|
status: EnumProperty(
|
||||||
items=[
|
items=[
|
||||||
("NONE", "NONE", "We have done nothing at all yet"),
|
("NONE", "NONE", "We have done nothing at all yet"),
|
||||||
(
|
(
|
||||||
@ -168,7 +166,7 @@ class BlenderCloudProjectGroup(PropertyGroup):
|
|||||||
update=redraw,
|
update=redraw,
|
||||||
)
|
)
|
||||||
|
|
||||||
project = EnumProperty(
|
project: EnumProperty(
|
||||||
items=bcloud_available_projects,
|
items=bcloud_available_projects,
|
||||||
name="Cloud project",
|
name="Cloud project",
|
||||||
description="Which Blender Cloud project to work with",
|
description="Which Blender Cloud project to work with",
|
||||||
@ -187,26 +185,25 @@ class BlenderCloudProjectGroup(PropertyGroup):
|
|||||||
project_specific.handle_project_update()
|
project_specific.handle_project_update()
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class BlenderCloudPreferences(AddonPreferences):
|
class BlenderCloudPreferences(AddonPreferences):
|
||||||
bl_idname = ADDON_NAME
|
bl_idname = ADDON_NAME
|
||||||
|
|
||||||
# The following property is read-only to limit the scope of the
|
# The following property is read-only to limit the scope of the
|
||||||
# addon and allow for proper testing within this scope.
|
# addon and allow for proper testing within this scope.
|
||||||
pillar_server = StringProperty(
|
pillar_server: StringProperty(
|
||||||
name="Blender Cloud Server",
|
name="Blender Cloud Server",
|
||||||
description="URL of the Blender Cloud backend server",
|
description="URL of the Blender Cloud backend server",
|
||||||
default=PILLAR_SERVER_URL,
|
default=PILLAR_SERVER_URL,
|
||||||
get=lambda self: PILLAR_SERVER_URL,
|
get=lambda self: PILLAR_SERVER_URL,
|
||||||
)
|
)
|
||||||
|
|
||||||
local_texture_dir = StringProperty(
|
local_texture_dir: StringProperty(
|
||||||
name="Default Blender Cloud Texture Storage Directory",
|
name="Default Blender Cloud Texture Storage Directory",
|
||||||
subtype="DIR_PATH",
|
subtype="DIR_PATH",
|
||||||
default="//textures",
|
default="//textures",
|
||||||
)
|
)
|
||||||
|
|
||||||
open_browser_after_share = BoolProperty(
|
open_browser_after_share: BoolProperty(
|
||||||
name="Open Browser after Sharing File",
|
name="Open Browser after Sharing File",
|
||||||
description="When enabled, Blender will open a webbrowser",
|
description="When enabled, Blender will open a webbrowser",
|
||||||
default=True,
|
default=True,
|
||||||
@ -214,9 +211,9 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
|
|
||||||
# TODO: store project-dependent properties with the project, so that people
|
# TODO: store project-dependent properties with the project, so that people
|
||||||
# can switch projects and the Attract and Flamenco properties switch with it.
|
# 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",
|
name="Local Project Path",
|
||||||
description="Local path of your Attract project, used to search for blend files; "
|
description="Local path of your Attract project, used to search for blend files; "
|
||||||
"usually best to set to an absolute path",
|
"usually best to set to an absolute path",
|
||||||
@ -225,29 +222,29 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
update=project_specific.store,
|
update=project_specific.store,
|
||||||
)
|
)
|
||||||
|
|
||||||
flamenco_manager = PointerProperty(type=flamenco.FlamencoManagerGroup)
|
flamenco_manager: PointerProperty(type=flamenco.FlamencoManagerGroup)
|
||||||
flamenco_exclude_filter = StringProperty(
|
flamenco_exclude_filter: StringProperty(
|
||||||
name="File Exclude Filter",
|
name="File Exclude Filter",
|
||||||
description='Space-separated list of filename filters, like "*.abc *.mkv", to prevent '
|
description='Space-separated list of filename filters, like "*.abc *.mkv", to prevent '
|
||||||
"matching files from being packed into the output directory",
|
"matching files from being packed into the output directory",
|
||||||
default="",
|
default="",
|
||||||
update=project_specific.store,
|
update=project_specific.store,
|
||||||
)
|
)
|
||||||
flamenco_job_file_path = StringProperty(
|
flamenco_job_file_path: StringProperty(
|
||||||
name="Job Storage Path",
|
name="Job Storage Path",
|
||||||
description="Path where to store job files, should be accesible for Workers too",
|
description="Path where to store job files, should be accesible for Workers too",
|
||||||
subtype="DIR_PATH",
|
subtype="DIR_PATH",
|
||||||
default=tempfile.gettempdir(),
|
default=tempfile.gettempdir(),
|
||||||
update=project_specific.store,
|
update=project_specific.store,
|
||||||
)
|
)
|
||||||
flamenco_job_output_path = StringProperty(
|
flamenco_job_output_path: StringProperty(
|
||||||
name="Job Output Path",
|
name="Job Output Path",
|
||||||
description="Path where to store output files, should be accessible for Workers",
|
description="Path where to store output files, should be accessible for Workers",
|
||||||
subtype="DIR_PATH",
|
subtype="DIR_PATH",
|
||||||
default=tempfile.gettempdir(),
|
default=tempfile.gettempdir(),
|
||||||
update=project_specific.store,
|
update=project_specific.store,
|
||||||
)
|
)
|
||||||
flamenco_job_output_strip_components = IntProperty(
|
flamenco_job_output_strip_components: IntProperty(
|
||||||
name="Job Output Path Strip Components",
|
name="Job Output Path Strip Components",
|
||||||
description="The final output path comprises of the job output path, and the blend file "
|
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 "
|
"path relative to the project with this many path components stripped off "
|
||||||
@ -257,7 +254,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
soft_max=4,
|
soft_max=4,
|
||||||
update=project_specific.store,
|
update=project_specific.store,
|
||||||
)
|
)
|
||||||
flamenco_relative_only = BoolProperty(
|
flamenco_relative_only: BoolProperty(
|
||||||
name="Relative Paths Only",
|
name="Relative Paths Only",
|
||||||
description="When enabled, only assets that are referred to with a relative path are "
|
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 "
|
"packed, and assets referred to by an absolute path are excluded from the "
|
||||||
@ -266,12 +263,12 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
update=project_specific.store,
|
update=project_specific.store,
|
||||||
)
|
)
|
||||||
|
|
||||||
flamenco_open_browser_after_submit = BoolProperty(
|
flamenco_open_browser_after_submit: BoolProperty(
|
||||||
name="Open Browser after Submitting Job",
|
name="Open Browser after Submitting Job",
|
||||||
description="When enabled, Blender will open a webbrowser",
|
description="When enabled, Blender will open a webbrowser",
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
flamenco_show_quit_after_submit_button = BoolProperty(
|
flamenco_show_quit_after_submit_button: BoolProperty(
|
||||||
name='Show "Submit & Quit" button',
|
name='Show "Submit & Quit" button',
|
||||||
description='When enabled, next to the "Render on Flamenco" button there will be a 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 '
|
'"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
|
bss = context.window_manager.blender_sync_status
|
||||||
bsync_box = layout.box()
|
bsync_box = layout.box()
|
||||||
bsync_box.enabled = msg_icon != "ERROR"
|
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"))
|
row.label(text="Blender Sync with Blender Cloud", icon_value=icon("CLOUD"))
|
||||||
|
|
||||||
icon_for_level = {
|
icon_for_level = {
|
||||||
@ -386,7 +383,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
layout.enabled = bss.status in {"NONE", "IDLE"}
|
layout.enabled = bss.status in {"NONE", "IDLE"}
|
||||||
|
|
||||||
buttons = layout.column()
|
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_push = row_buttons.row()
|
||||||
row_pull = row_buttons.row(align=True)
|
row_pull = row_buttons.row(align=True)
|
||||||
|
|
||||||
@ -411,7 +408,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
props.action = "PULL"
|
props.action = "PULL"
|
||||||
props.blender_version = bss.version
|
props.blender_version = bss.version
|
||||||
row_pull.operator(
|
row_pull.operator(
|
||||||
"pillar.sync", text="", icon=compatibility.SYNC_SELECT_VERSION_ICON
|
"pillar.sync", text="", icon="DOWNARROW_HLT"
|
||||||
).action = "SELECT"
|
).action = "SELECT"
|
||||||
else:
|
else:
|
||||||
row_pull.label(text="Cloud Sync is running.")
|
row_pull.label(text="Cloud Sync is running.")
|
||||||
@ -460,7 +457,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
header_row = flamenco_box.row(align=True)
|
header_row = flamenco_box.row(align=True)
|
||||||
header_row.label(text="Flamenco:", icon_value=icon("CLOUD"))
|
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_split.label(text="Manager:")
|
||||||
manager_box = manager_split.row(align=True)
|
manager_box = manager_split.row(align=True)
|
||||||
|
|
||||||
@ -477,7 +474,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
else:
|
else:
|
||||||
manager_box.label(text="Fetching available managers.")
|
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_split.label(text="Job File Path:")
|
||||||
path_box = path_split.row(align=True)
|
path_box = path_split.row(align=True)
|
||||||
path_box.prop(self, "flamenco_job_file_path", text="")
|
path_box.prop(self, "flamenco_job_file_path", text="")
|
||||||
@ -487,7 +484,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
props.path = self.flamenco_job_file_path
|
props.path = self.flamenco_job_file_path
|
||||||
|
|
||||||
job_output_box = flamenco_box.column(align=True)
|
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_split.label(text="Job Output Path:")
|
||||||
path_box = path_split.row(align=True)
|
path_box = path_split.row(align=True)
|
||||||
path_box.prop(self, "flamenco_job_output_path", text="")
|
path_box.prop(self, "flamenco_job_output_path", text="")
|
||||||
@ -497,7 +494,7 @@ class BlenderCloudPreferences(AddonPreferences):
|
|||||||
props.path = self.flamenco_job_output_path
|
props.path = self.flamenco_job_output_path
|
||||||
job_output_box.prop(self, "flamenco_exclude_filter")
|
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.label(text="Strip Components:")
|
||||||
prop_split.prop(self, "flamenco_job_output_strip_components", text="")
|
prop_split.prop(self, "flamenco_job_output_strip_components", text="")
|
||||||
|
|
||||||
@ -586,13 +583,12 @@ class PILLAR_OT_subscribe(Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class PILLAR_OT_project_open_in_browser(Operator):
|
class PILLAR_OT_project_open_in_browser(Operator):
|
||||||
bl_idname = "pillar.project_open_in_browser"
|
bl_idname = "pillar.project_open_in_browser"
|
||||||
bl_label = "Open in Browser"
|
bl_label = "Open in Browser"
|
||||||
bl_description = "Opens a webbrowser to show the project"
|
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):
|
def execute(self, context):
|
||||||
if not self.project_id:
|
if not self.project_id:
|
||||||
|
@ -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}
|
|
@ -34,13 +34,12 @@ if "bpy" in locals():
|
|||||||
bat_interface = importlib.reload(bat_interface)
|
bat_interface = importlib.reload(bat_interface)
|
||||||
sdk = importlib.reload(sdk)
|
sdk = importlib.reload(sdk)
|
||||||
blender = importlib.reload(blender)
|
blender = importlib.reload(blender)
|
||||||
compatibility = importlib.reload(compatibility)
|
|
||||||
except NameError:
|
except NameError:
|
||||||
from . import bat_interface, sdk
|
from . import bat_interface, sdk
|
||||||
from .. import blender, compatibility
|
from .. import blender
|
||||||
else:
|
else:
|
||||||
from . import bat_interface, sdk
|
from . import bat_interface, sdk
|
||||||
from .. import blender, compatibility
|
from .. import blender
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import AddonPreferences, Operator, WindowManager, Scene, PropertyGroup
|
from bpy.types import AddonPreferences, Operator, WindowManager, Scene, PropertyGroup
|
||||||
@ -130,31 +129,20 @@ def manager_updated(self: "FlamencoManagerGroup", context):
|
|||||||
def silently_quit_blender():
|
def silently_quit_blender():
|
||||||
"""Quit Blender without any confirmation popup."""
|
"""Quit Blender without any confirmation popup."""
|
||||||
|
|
||||||
try:
|
prefs = bpy.context.preferences
|
||||||
prefs = bpy.context.preferences
|
prefs.view.use_save_prompt = False
|
||||||
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
|
|
||||||
|
|
||||||
bpy.ops.wm.quit_blender()
|
bpy.ops.wm.quit_blender()
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class FlamencoManagerGroup(PropertyGroup):
|
class FlamencoManagerGroup(PropertyGroup):
|
||||||
manager = EnumProperty(
|
manager: EnumProperty(
|
||||||
items=available_managers,
|
items=available_managers,
|
||||||
name="Flamenco Manager",
|
name="Flamenco Manager",
|
||||||
description="Which Flamenco Manager to use for jobs",
|
description="Which Flamenco Manager to use for jobs",
|
||||||
update=manager_updated,
|
update=manager_updated,
|
||||||
)
|
)
|
||||||
|
|
||||||
status = EnumProperty(
|
status: EnumProperty(
|
||||||
items=[
|
items=[
|
||||||
("NONE", "NONE", "We have done nothing at all yet"),
|
("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
|
return True
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class FLAMENCO_OT_render(
|
class FLAMENCO_OT_render(
|
||||||
async_loop.AsyncModalOperatorMixin,
|
async_loop.AsyncModalOperatorMixin,
|
||||||
pillar.AuthenticatedPillarOperatorMixin,
|
pillar.AuthenticatedPillarOperatorMixin,
|
||||||
@ -309,7 +296,7 @@ class FLAMENCO_OT_render(
|
|||||||
stop_upon_exception = True
|
stop_upon_exception = True
|
||||||
log = logging.getLogger("%s.FLAMENCO_OT_render" % __name__)
|
log = logging.getLogger("%s.FLAMENCO_OT_render" % __name__)
|
||||||
|
|
||||||
quit_after_submit = BoolProperty()
|
quit_after_submit: BoolProperty()
|
||||||
|
|
||||||
async def async_execute(self, context):
|
async def async_execute(self, context):
|
||||||
# Refuse to start if the file hasn't been saved. It's okay if
|
# 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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class FLAMENCO_OT_explore_file_path(FlamencoPollMixin, Operator):
|
class FLAMENCO_OT_explore_file_path(FlamencoPollMixin, Operator):
|
||||||
"""Opens the Flamenco job storage path in a file explorer.
|
"""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_label = "Open in file explorer"
|
||||||
bl_description = __doc__.rstrip(".")
|
bl_description = __doc__.rstrip(".")
|
||||||
|
|
||||||
path = StringProperty(
|
path: StringProperty(name="Path", description="Path to explore", subtype="DIR_PATH")
|
||||||
name="Path", description="Path to explore", subtype="DIR_PATH"
|
|
||||||
)
|
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
import platform
|
import platform
|
||||||
@ -940,13 +924,12 @@ class FLAMENCO_OT_disable_output_path_override(Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class FLAMENCO_OT_set_recommended_sample_cap(Operator):
|
class FLAMENCO_OT_set_recommended_sample_cap(Operator):
|
||||||
bl_idname = "flamenco.set_recommended_sample_cap"
|
bl_idname = "flamenco.set_recommended_sample_cap"
|
||||||
bl_label = "Set Recommended Maximum Sample Count"
|
bl_label = "Set Recommended Maximum Sample Count"
|
||||||
bl_description = "Set the recommended maximum samples per render task"
|
bl_description = "Set the recommended maximum samples per render task"
|
||||||
|
|
||||||
sample_cap = IntProperty()
|
sample_cap: IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
context.scene.flamenco_render_chunk_sample_cap = self.sample_cap
|
context.scene.flamenco_render_chunk_sample_cap = self.sample_cap
|
||||||
@ -1112,7 +1095,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
|||||||
|
|
||||||
prefs = preferences()
|
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:")
|
labeled_row.label(text="Manager:")
|
||||||
prop_btn_row = labeled_row.row(align=True)
|
prop_btn_row = labeled_row.row(align=True)
|
||||||
|
|
||||||
@ -1130,7 +1113,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
|||||||
else:
|
else:
|
||||||
prop_btn_row.label(text="Fetching available managers.")
|
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.label(text="Job Type:")
|
||||||
labeled_row.prop(context.scene, "flamenco_render_job_type", text="")
|
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)
|
sample_count = scene_sample_count(context.scene)
|
||||||
recommended_cap = sample_count // 4
|
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)
|
split.label(text="Total Sample Count: %d" % sample_count)
|
||||||
props = split.operator(
|
props = split.operator(
|
||||||
"flamenco.set_recommended_sample_cap",
|
"flamenco.set_recommended_sample_cap",
|
||||||
@ -1181,7 +1164,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
|||||||
else:
|
else:
|
||||||
box.prop(context.scene, "flamenco_render_fchunk_size")
|
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:")
|
labeled_row.label(text="Frame Range:")
|
||||||
prop_btn_row = labeled_row.row(align=True)
|
prop_btn_row = labeled_row.row(align=True)
|
||||||
prop_btn_row.prop(context.scene, "flamenco_render_frame_range", text="")
|
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)
|
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:")
|
labeled_row.label(text="Storage:")
|
||||||
prop_btn_row = labeled_row.row(align=True)
|
prop_btn_row = labeled_row.row(align=True)
|
||||||
prop_btn_row.label(text=prefs.flamenco_job_file_path)
|
prop_btn_row.label(text=prefs.flamenco_job_file_path)
|
||||||
@ -1217,7 +1200,7 @@ class FLAMENCO_PT_render(bpy.types.Panel, FlamencoPollMixin):
|
|||||||
)
|
)
|
||||||
return
|
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:")
|
labeled_row.label(text="Output:")
|
||||||
prop_btn_row = labeled_row.row(align=True)
|
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)
|
props.path = str(render_output.parent)
|
||||||
|
|
||||||
if context.scene.flamenco_do_override_output_path:
|
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="Effective Output Path:")
|
||||||
labeled_row.label(text=str(render_output))
|
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
|
flamenco_status = context.window_manager.flamenco_status
|
||||||
if flamenco_status in {"IDLE", "ABORTED", "DONE"}:
|
if flamenco_status in {"IDLE", "ABORTED", "DONE"}:
|
||||||
if prefs.flamenco_show_quit_after_submit_button:
|
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:
|
else:
|
||||||
ui = layout
|
ui = layout
|
||||||
ui.operator(
|
ui.operator(
|
||||||
|
@ -25,7 +25,7 @@ import bpy
|
|||||||
import pillarsdk
|
import pillarsdk
|
||||||
from pillarsdk import exceptions as sdk_exceptions
|
from pillarsdk import exceptions as sdk_exceptions
|
||||||
from .pillar import pillar_call
|
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"}
|
REQUIRES_ROLES_FOR_IMAGE_SHARING = {"subscriber", "demo"}
|
||||||
IMAGE_SHARING_GROUP_NODE_NAME = "Image sharing"
|
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"]
|
return share_group["_id"]
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class PILLAR_OT_image_share(
|
class PILLAR_OT_image_share(
|
||||||
pillar.PillarOperatorMixin, async_loop.AsyncModalOperatorMixin, bpy.types.Operator
|
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
|
share_group_id = None # top-level share group node ID
|
||||||
user_id = None
|
user_id = None
|
||||||
|
|
||||||
target = bpy.props.EnumProperty(
|
target: bpy.props.EnumProperty(
|
||||||
items=[
|
items=[
|
||||||
("FILE", "File", "Share an image file"),
|
("FILE", "File", "Share an image file"),
|
||||||
("DATABLOCK", "Datablock", "Share an image datablock"),
|
("DATABLOCK", "Datablock", "Share an image datablock"),
|
||||||
@ -81,19 +80,19 @@ class PILLAR_OT_image_share(
|
|||||||
default="SCREENSHOT",
|
default="SCREENSHOT",
|
||||||
)
|
)
|
||||||
|
|
||||||
name = bpy.props.StringProperty(
|
name: bpy.props.StringProperty(
|
||||||
name="name", description="File or datablock name to sync"
|
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
|
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
|
name="screenshot_use_multiview", description="Use Multi-View", default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
screenshot_full = bpy.props.BoolProperty(
|
screenshot_full: bpy.props.BoolProperty(
|
||||||
name="screenshot_full",
|
name="screenshot_full",
|
||||||
description="Full Screen, Capture the whole window (otherwise only capture the active area)",
|
description="Full Screen, Capture the whole window (otherwise only capture the active area)",
|
||||||
default=False,
|
default=False,
|
||||||
|
@ -35,7 +35,7 @@ import asyncio
|
|||||||
import pillarsdk
|
import pillarsdk
|
||||||
from pillarsdk import exceptions as sdk_exceptions
|
from pillarsdk import exceptions as sdk_exceptions
|
||||||
from .pillar import pillar_call
|
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"]
|
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
|
# noinspection PyAttributeOutsideInit
|
||||||
@compatibility.convert_properties
|
|
||||||
class PILLAR_OT_sync(
|
class PILLAR_OT_sync(
|
||||||
pillar.PillarOperatorMixin, async_loop.AsyncModalOperatorMixin, bpy.types.Operator
|
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_id = "" # top-level sync group node ID
|
||||||
sync_group_versioned_id = "" # sync group node ID for the given Blender version.
|
sync_group_versioned_id = "" # sync group node ID for the given Blender version.
|
||||||
|
|
||||||
action = bpy.props.EnumProperty(
|
action: bpy.props.EnumProperty(
|
||||||
items=[
|
items=[
|
||||||
("PUSH", "Push", "Push settings to the Blender Cloud"),
|
("PUSH", "Push", "Push settings to the Blender Cloud"),
|
||||||
("PULL", "Pull", "Pull settings from 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]
|
CURRENT_BLENDER_VERSION = "%i.%i" % bpy.app.version[:2]
|
||||||
blender_version = bpy.props.StringProperty(
|
blender_version: bpy.props.StringProperty(
|
||||||
name="blender_version",
|
name="blender_version",
|
||||||
description="Blender version to sync for",
|
description="Blender version to sync for",
|
||||||
default=CURRENT_BLENDER_VERSION,
|
default=CURRENT_BLENDER_VERSION,
|
||||||
|
@ -26,16 +26,11 @@ import bpy
|
|||||||
import bgl
|
import bgl
|
||||||
|
|
||||||
import pillarsdk
|
import pillarsdk
|
||||||
from .. import async_loop, compatibility, pillar, cache, blender, utils
|
from .. import async_loop, pillar, cache, blender, utils
|
||||||
from . import (
|
from . import (
|
||||||
menu_item as menu_item_mod,
|
menu_item as menu_item_mod,
|
||||||
) # so that we can have menu items called 'menu_item'
|
) # so that we can have menu items called 'menu_item'
|
||||||
from . import nodes
|
from . import draw, nodes
|
||||||
|
|
||||||
if bpy.app.version < (2, 80):
|
|
||||||
from . import draw_27 as draw
|
|
||||||
else:
|
|
||||||
from . import draw
|
|
||||||
|
|
||||||
REQUIRED_ROLES_FOR_TEXTURE_BROWSER = {"subscriber", "demo"}
|
REQUIRED_ROLES_FOR_TEXTURE_BROWSER = {"subscriber", "demo"}
|
||||||
MOUSE_SCROLL_PIXELS_PER_TICK = 50
|
MOUSE_SCROLL_PIXELS_PER_TICK = 50
|
||||||
@ -686,7 +681,6 @@ class BlenderCloudBrowser(
|
|||||||
self.scroll_offset_target = self.scroll_offset = 0
|
self.scroll_offset_target = self.scroll_offset = 0
|
||||||
|
|
||||||
|
|
||||||
@compatibility.convert_properties
|
|
||||||
class PILLAR_OT_switch_hdri(
|
class PILLAR_OT_switch_hdri(
|
||||||
pillar.PillarOperatorMixin, async_loop.AsyncModalOperatorMixin, bpy.types.Operator
|
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)
|
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"
|
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"
|
name="file_uuid", description="File ID to download"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -834,7 +828,7 @@ def _hdri_download_panel(self, current_image):
|
|||||||
)
|
)
|
||||||
return
|
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.label(text="HDRi", icon_value=blender.icon("CLOUD"))
|
||||||
row.prop(current_image, "hdri_variation", text="")
|
row.prop(current_image, "hdri_variation", text="")
|
||||||
|
|
||||||
|
@ -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)
|
|
Reference in New Issue
Block a user