Compare commits

..

13 Commits

Author SHA1 Message Date
68b046c714 Bumped version to 1.5.2 2017-01-06 17:01:58 +01:00
cb20d6ee03 Fixed icon, the MOVE_UP_VEC icon was removed
This happened in Blender commit rBb2159b94bcd6c4e30c47b9970601e6f2ca2a0750
2017-01-06 17:01:06 +01:00
Dalai Felinto
645bdd950f Attract: prevent ui/console errors when no strip exists 2016-12-06 22:00:58 +01:00
Dalai Felinto
74a5830dae setup fdist option for files distribution (unzipped files)
This is the equivalent of `python setup.py bdist` and unzipping the outputted file. If no --dest-path is specified it dumps the files in the same folder as the .zip.

It is used for symlinking of the latest addon in production computers without having to deal with .zip files.

Review, design, lessons, patient orientations by Sybren Stüvel
2016-11-11 16:15:24 +01:00
da4d4df5fb Bumped version to 1.5.1 2016-11-11 09:28:10 +01:00
9c3098cc0d Attract: Added some poll methods 2016-11-11 09:26:52 +01:00
98beaf7fb7 Unlinking a single shot copies the shot ID to the clipboard.
This allows you to easily unlink one strip, and relink another. This cannot
be done for multiple shots simultaneously.
2016-11-11 09:23:39 +01:00
3364371ac6 Use '{nr of shots} Shots' instead of 'Selected Shots'
This is a bit shorter, and more concrete.
2016-11-11 09:22:59 +01:00
2723b07fa2 Nicer button layout for unlink & delete
This makes 'delete' harder to hit accidentally.
2016-11-11 09:17:25 +01:00
c2a037ca89 Added button to copy a shot ID to the clipboard 2016-11-11 09:15:04 +01:00
d3451d4de3 Icon tweaks 2016-11-11 09:14:51 +01:00
5094977614 Attract: "delete shots" now works on all selected Attract strips 2016-11-11 09:06:59 +01:00
Dalai Felinto
a11a55be22 Implement attract "Trim End" 2016-11-10 18:49:13 +01:00
3 changed files with 120 additions and 17 deletions

View File

@@ -21,7 +21,7 @@
bl_info = {
'name': 'Blender Cloud',
"author": "Sybren A. Stüvel, Francesco Siddi, Inês Almeida, Antony Riakiotakis",
'version': (1, 5, 0),
'version': (1, 5, 2),
'blender': (2, 77, 0),
'location': 'Addon Preferences panel, and Ctrl+Shift+Alt+A anywhere for texture browser',
'description': 'Texture library browser and Blender Sync. Requires the Blender ID addon '

View File

@@ -70,8 +70,12 @@ def active_strip(context):
def selected_shots(context):
"""Generator, yields selected strips if they are Attract shots."""
selected_sequences = context.selected_sequences
for strip in context.selected_sequences:
if selected_sequences is None:
return
for strip in selected_sequences:
atc_object_id = getattr(strip, 'atc_object_id')
if not atc_object_id:
continue
@@ -81,6 +85,11 @@ def selected_shots(context):
def all_shots(context):
"""Generator, yields all strips if they are Attract shots."""
sequence_editor = context.scene.sequence_editor
if sequence_editor is None:
# we should throw an exception, but at least this change prevents an error
return []
for strip in context.scene.sequence_editor.sequences_all:
atc_object_id = getattr(strip, 'atc_object_id')
@@ -170,7 +179,7 @@ class ToolsPanel(Panel):
selshots = list(selected_shots(context))
if strip and strip.type in strip_types and strip.atc_object_id:
if len(selshots) > 1:
noun = 'Selected Shots'
noun = '%i Shots' % len(selshots)
else:
noun = 'This Shot'
@@ -193,20 +202,29 @@ class ToolsPanel(Panel):
sub = layout.column(align=True)
row = sub.row(align=True)
if bpy.ops.attract.submit_selected.poll():
row.operator('attract.submit_selected', text='Submit %s' % noun)
row.operator('attract.submit_selected',
text='Submit %s' % noun,
icon='TRIA_UP')
else:
row.operator(ATTRACT_OT_submit_all.bl_idname)
row.operator(AttractShotFetchUpdate.bl_idname,
text='', icon='FILE_REFRESH')
row.operator(ATTRACT_OT_shot_open_in_browser.bl_idname,
text='', icon='WORLD')
row.operator(ATTRACT_OT_copy_id_to_clipboard.bl_idname,
text='', icon='COPYDOWN')
sub.operator(ATTRACT_OT_make_shot_thumbnail.bl_idname,
text='Render Thumbnail for %s' % noun)
text='Render Thumbnail for %s' % noun,
icon='RENDER_STILL')
# Group more dangerous operations.
dangerous_sub = layout.column(align=True)
dangerous_sub.operator(AttractShotDelete.bl_idname)
dangerous_sub.operator('attract.strip_unlink')
dangerous_sub = layout.split(0.6, align=True)
dangerous_sub.operator('attract.strip_unlink',
text='Unlink %s' % noun,
icon='PANEL_CLOSE')
dangerous_sub.operator(AttractShotDelete.bl_idname,
text='Delete %s' % noun,
icon='CANCEL')
elif context.selected_sequences:
if len(context.selected_sequences) > 1:
@@ -272,6 +290,7 @@ class AttractOperatorMixin:
'notes': '',
'used_in_edit': True,
'trim_start_in_frames': strip.frame_offset_start,
'trim_end_in_frames': strip.frame_offset_end,
'duration_in_edit_in_frames': strip.frame_final_duration,
'cut_in_timeline_in_frames': strip.frame_final_start},
'order': 0,
@@ -306,6 +325,7 @@ class AttractOperatorMixin:
'$set': {
'name': strip.atc_name,
'properties.trim_start_in_frames': strip.frame_offset_start,
'properties.trim_end_in_frames': strip.frame_offset_end,
'properties.duration_in_edit_in_frames': strip.frame_final_duration,
'properties.cut_in_timeline_in_frames': strip.frame_final_start,
'properties.status': strip.atc_status,
@@ -411,6 +431,10 @@ class ATTRACT_OT_shot_open_in_browser(AttractOperatorMixin, Operator):
bl_label = 'Open in Browser'
bl_description = 'Opens a webbrowser to show the shot on Attract'
@classmethod
def poll(cls, context):
return bool(context.selected_sequences and active_strip(context))
def execute(self, context):
from ..blender import PILLAR_WEB_SERVER_URL
import webbrowser
@@ -433,6 +457,10 @@ class AttractShotDelete(AttractOperatorMixin, Operator):
confirm = bpy.props.BoolProperty(name='confirm')
@classmethod
def poll(cls, context):
return bool(context.selected_sequences)
def execute(self, context):
from .. import pillar
@@ -440,13 +468,22 @@ class AttractShotDelete(AttractOperatorMixin, Operator):
self.report({'WARNING'}, 'Delete aborted.')
return {'CANCELLED'}
strip = active_strip(context)
node = pillar.sync_call(Node.find, strip.atc_object_id)
if not pillar.sync_call(node.delete):
print('Unable to delete the strip node on Attract.')
return {'CANCELLED'}
removed = kept = 0
for strip in selected_shots(context):
node = pillar.sync_call(Node.find, strip.atc_object_id)
if not pillar.sync_call(node.delete):
self.report({'ERROR'}, 'Unable to delete shot %s on Attract.' % strip.atc_name)
kept += 1
continue
remove_atc_props(strip)
removed += 1
if kept:
self.report({'ERROR'}, 'Removed %i shots, but was unable to remove %i' %
(removed, kept))
else:
self.report({'INFO'}, 'Removed all %i shots from Attract' % removed)
remove_atc_props(strip)
draw.tag_redraw_all_sequencer_editors()
return {'FINISHED'}
@@ -457,7 +494,14 @@ class AttractShotDelete(AttractOperatorMixin, Operator):
def draw(self, context):
layout = self.layout
col = layout.column()
col.prop(self, 'confirm', text="I hereby confirm: delete this shot from The Edit.")
selshots = list(selected_shots(context))
if len(selshots) > 1:
noun = '%i shots' % len(selshots)
else:
noun = 'this shot'
col.prop(self, 'confirm', text="I hereby confirm: delete %s from The Edit." % noun)
class AttractStripUnlink(AttractOperatorMixin, Operator):
@@ -465,6 +509,10 @@ class AttractStripUnlink(AttractOperatorMixin, Operator):
bl_label = 'Unlink Shot From This Strip'
bl_description = 'Remove Attract props from the selected strip(s)'
@classmethod
def poll(cls, context):
return bool(context.selected_sequences)
def execute(self, context):
unlinked_ids = set()
@@ -487,7 +535,13 @@ class AttractStripUnlink(AttractOperatorMixin, Operator):
node = Node({'_id': oid})
pillar.sync_call(node.patch, {'op': 'unlink'})
self.report({'INFO'}, 'Shot %s has been marked as Unused.' % oid)
if len(unlinked_ids) == 1:
shot_id = unlinked_ids.pop()
context.window_manager.clipboard = shot_id
self.report({'INFO'}, 'Copied unlinked shot ID %s to clipboard' % shot_id)
else:
self.report({'INFO'}, '%i shots have been marked as Unused.' % len(unlinked_ids))
draw.tag_redraw_all_sequencer_editors()
return {'FINISHED'}
@@ -813,6 +867,23 @@ class ATTRACT_OT_make_shot_thumbnail(AttractOperatorMixin,
return file_id
class ATTRACT_OT_copy_id_to_clipboard(AttractOperatorMixin, Operator):
bl_idname = 'attract.copy_id_to_clipboard'
bl_label = 'Copy shot ID to clipboard'
@classmethod
def poll(cls, context):
return bool(context.selected_sequences and active_strip(context))
def execute(self, context):
strip = active_strip(context)
context.window_manager.clipboard = strip.atc_object_id
self.report({'INFO'}, 'Shot ID %s copied to clipboard' % strip.atc_object_id)
return {'FINISHED'}
def draw_strip_movie_meta(self, context):
strip = active_strip(context)
if not strip:
@@ -869,6 +940,7 @@ def register():
bpy.utils.register_class(ATTRACT_OT_open_meta_blendfile)
bpy.utils.register_class(ATTRACT_OT_shot_open_in_browser)
bpy.utils.register_class(ATTRACT_OT_make_shot_thumbnail)
bpy.utils.register_class(ATTRACT_OT_copy_id_to_clipboard)
bpy.app.handlers.scene_update_post.append(scene_update_post_handler)
draw.callback_enable()

View File

@@ -18,11 +18,13 @@
# ##### END GPL LICENSE BLOCK #####
import glob
import os
import sys
import shutil
import subprocess
import re
import pathlib
import zipfile
from distutils import log
from distutils.core import Command
@@ -168,6 +170,34 @@ class BlenderAddonBdist(bdist):
super().run()
# noinspection PyAttributeOutsideInit
class BlenderAddonFdist(BlenderAddonBdist):
"""Ensures that 'python setup.py fdist' creates a plain folder structure."""
user_options = [
('dest-path=', None, 'addon installation path'),
]
def initialize_options(self):
super().initialize_options()
self.dest_path = None # path that will contain the addon
def run(self):
super().run()
# dist_files is a list of tuples ('bdist', 'any', 'filepath')
filepath = self.distribution.dist_files[0][2]
# if dest_path is not specified use the filename as the dest_path (minus the .zip)
assert filepath.endswith('.zip')
target_folder = self.dest_path or filepath[:-4]
print('Unzipping the package on {}.'.format(target_folder))
with zipfile.ZipFile(filepath, 'r') as zip_ref:
zip_ref.extractall(target_folder)
# noinspection PyAttributeOutsideInit
class BlenderAddonInstall(install):
"""Ensures the module is placed at the root of the zip file."""
@@ -191,12 +221,13 @@ class AvoidEggInfo(install_egg_info):
setup(
cmdclass={'bdist': BlenderAddonBdist,
'fdist': BlenderAddonFdist,
'install': BlenderAddonInstall,
'install_egg_info': AvoidEggInfo,
'wheels': BuildWheels},
name='blender_cloud',
description='The Blender Cloud addon allows browsing the Blender Cloud from Blender.',
version='1.5.0',
version='1.5.2',
author='Sybren A. Stüvel',
author_email='sybren@stuvel.eu',
packages=find_packages('.'),