diff --git a/CHANGELOG.md b/CHANGELOG.md index 53b452d..5c1e6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Blender Cloud changelog + +## Version 1.9.4 (2018-11-01) + +- Fixed Python 3.6 and Blender 2.79b incompatibilities accidentally introduced in 1.9.3. + + ## Version 1.9.3 (2018-10-30) - Fix drawing of Attract strips in the VSE on Blender 2.8. diff --git a/blender_cloud/attract/__init__.py b/blender_cloud/attract/__init__.py index a6bd046..cd55fcd 100644 --- a/blender_cloud/attract/__init__.py +++ b/blender_cloud/attract/__init__.py @@ -48,7 +48,12 @@ if "bpy" in locals(): async_loop = importlib.reload(async_loop) blender = importlib.reload(blender) else: - from . import draw + import bpy + + if bpy.app.version < (2, 80): + from . import draw_27 as draw + else: + from . import draw from .. import pillar, async_loop, blender import bpy diff --git a/blender_cloud/attract/draw_27.py b/blender_cloud/attract/draw_27.py new file mode 100644 index 0000000..1150e2d --- /dev/null +++ b/blender_cloud/attract/draw_27.py @@ -0,0 +1,182 @@ +# ##### 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()