space_view3d_stored_views: Restore release status: T63750 d9ffde707f
This commit is contained in:
parent
15b00e9396
commit
20a8e9d3f5
|
@ -0,0 +1,149 @@
|
|||
# ##### 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 #####
|
||||
|
||||
bl_info = {
|
||||
"name": "Stored Views",
|
||||
"description": "Save and restore User defined views, pov, layers and display configs",
|
||||
"author": "nfloyd, Francesco Siddi",
|
||||
"version": (0, 3, 7),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "View3D > Properties > Stored Views",
|
||||
"warning": "",
|
||||
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.5/"
|
||||
"Py/Scripts/3D_interaction/stored_views",
|
||||
"category": "3D View"
|
||||
}
|
||||
|
||||
"""
|
||||
ACKNOWLEDGMENT
|
||||
==============
|
||||
import/export functionality is mostly based
|
||||
on Bart Crouch's Theme Manager Addon
|
||||
|
||||
TODO: quadview complete support : investigate. Where's the data?
|
||||
TODO: lock_camera_and_layers. investigate usage
|
||||
TODO: list reordering
|
||||
|
||||
NOTE: logging setup has to be provided by the user in a separate config file
|
||||
as Blender will not try to configure logging by default in an add-on
|
||||
The Config File should be in the Blender Config folder > /scripts/startup/config_logging.py
|
||||
For setting up /location of the config folder see:
|
||||
https://docs.blender.org/manual/en/dev/getting_started/
|
||||
installing/configuration/directories.html
|
||||
For configuring logging itself in the file, general Python documentation should work
|
||||
As the logging calls are not configured, they can be kept in the other modules of this add-on
|
||||
and will not have output until the logging configuration is set up
|
||||
"""
|
||||
|
||||
# if "bpy" in locals():
|
||||
# import importlib
|
||||
# importlib.reload(core)
|
||||
# importlib.reload(ui)
|
||||
# importlib.reload(properties)
|
||||
# importlib.reload(operators)
|
||||
# importlib.reload(io)
|
||||
# else:
|
||||
import bpy
|
||||
from . import core
|
||||
from . import ui
|
||||
from . import properties
|
||||
from . import operators
|
||||
from . import io
|
||||
|
||||
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
PointerProperty,
|
||||
)
|
||||
from bpy.types import (
|
||||
AddonPreferences,
|
||||
Operator,
|
||||
)
|
||||
|
||||
|
||||
class VIEW3D_stored_views_initialize(Operator):
|
||||
bl_idname = "view3d.stored_views_initialize"
|
||||
bl_label = "Initialize"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not hasattr(bpy.types.Scene, 'stored_views')
|
||||
|
||||
def execute(self, context):
|
||||
bpy.types.Scene.stored_views = PointerProperty(
|
||||
type=properties.StoredViewsData
|
||||
)
|
||||
scenes = bpy.data.scenes
|
||||
for scene in scenes:
|
||||
core.DataStore.sanitize_data(scene)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Addon Preferences
|
||||
|
||||
class VIEW3D_stored_views_preferences(AddonPreferences):
|
||||
bl_idname = __name__
|
||||
|
||||
show_exporters : BoolProperty(
|
||||
name="Enable I/O Operators",
|
||||
default=False,
|
||||
description="Enable Import/Export Operations in the UI:\n"
|
||||
"Import Stored Views preset,\n"
|
||||
"Export Stored Views preset and \n"
|
||||
"Import stored views from scene",
|
||||
)
|
||||
view_3d_update_rate : IntProperty(
|
||||
name="3D view update",
|
||||
description="Update rate of the 3D view redraw\n"
|
||||
"Increse the value if the UI feels sluggish",
|
||||
min=1, max=10,
|
||||
default=1
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(self, "view_3d_update_rate", toggle=True)
|
||||
row.prop(self, "show_exporters", toggle=True)
|
||||
|
||||
|
||||
def register():
|
||||
ui.register()
|
||||
properties.register()
|
||||
operators.register()
|
||||
io.register()
|
||||
bpy.utils.register_class(VIEW3D_stored_views_initialize)
|
||||
bpy.utils.register_class(VIEW3D_stored_views_preferences)
|
||||
|
||||
|
||||
def unregister():
|
||||
ui.unregister()
|
||||
properties.unregister()
|
||||
operators.unregister()
|
||||
io.unregister()
|
||||
bpy.utils.unregister_class(VIEW3D_stored_views_initialize)
|
||||
bpy.utils.unregister_class(VIEW3D_stored_views_preferences)
|
||||
ui.VIEW3D_stored_views_draw.handle_remove(bpy.context)
|
||||
if hasattr(bpy.types.Scene, "stored_views"):
|
||||
del bpy.types.Scene.stored_views
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
|
@ -0,0 +1,369 @@
|
|||
# gpl authors: nfloyd, Francesco Siddi
|
||||
|
||||
|
||||
import logging
|
||||
module_logger = logging.getLogger(__name__)
|
||||
|
||||
import hashlib
|
||||
import bpy
|
||||
|
||||
|
||||
#Utility function get preferences setting for exporters
|
||||
def get_preferences():
|
||||
# replace the key if the add-on name changes
|
||||
addon = bpy.context.preferences.addons[__package__]
|
||||
show_warn = (addon.preferences.show_exporters if addon else False)
|
||||
|
||||
return show_warn
|
||||
|
||||
|
||||
class StoredView():
|
||||
def __init__(self, mode, index=None):
|
||||
self.logger = logging.getLogger('%s.StoredView' % __name__)
|
||||
self.scene = bpy.context.scene
|
||||
self.view3d = bpy.context.space_data
|
||||
self.index = index
|
||||
self.data_store = DataStore(mode=mode)
|
||||
|
||||
def save(self):
|
||||
if self.index == -1:
|
||||
stored_view, self.index = self.data_store.create()
|
||||
else:
|
||||
stored_view = self.data_store.get(self.index)
|
||||
self.from_v3d(stored_view)
|
||||
self.logger.debug('index: %s name: %s' % (self.data_store.current_index, stored_view.name))
|
||||
|
||||
def set(self):
|
||||
stored_view = self.data_store.get(self.index)
|
||||
self.update_v3d(stored_view)
|
||||
self.logger.debug('index: %s name: %s' % (self.data_store.current_index, stored_view.name))
|
||||
|
||||
def from_v3d(self, stored_view):
|
||||
raise NotImplementedError("Subclass must implement abstract method")
|
||||
|
||||
def update_v3d(self, stored_view):
|
||||
raise NotImplementedError("Subclass must implement abstract method")
|
||||
|
||||
@staticmethod
|
||||
def is_modified(context, stored_view):
|
||||
raise NotImplementedError("Subclass must implement abstract method")
|
||||
|
||||
|
||||
class POV(StoredView):
|
||||
def __init__(self, index=None):
|
||||
super().__init__(mode='POV', index=index)
|
||||
self.logger = logging.getLogger('%s.POV' % __name__)
|
||||
|
||||
def from_v3d(self, stored_view):
|
||||
view3d = self.view3d
|
||||
region3d = view3d.region_3d
|
||||
|
||||
stored_view.distance = region3d.view_distance
|
||||
stored_view.location = region3d.view_location
|
||||
stored_view.rotation = region3d.view_rotation
|
||||
stored_view.perspective_matrix_md5 = POV._get_perspective_matrix_md5(region3d)
|
||||
stored_view.perspective = region3d.view_perspective
|
||||
stored_view.lens = view3d.lens
|
||||
stored_view.clip_start = view3d.clip_start
|
||||
stored_view.clip_end = view3d.clip_end
|
||||
|
||||
if region3d.view_perspective == 'CAMERA':
|
||||
stored_view.camera_type = view3d.camera.type # type : 'CAMERA' or 'MESH'
|
||||
stored_view.camera_name = view3d.camera.name # store string instead of object
|
||||
if view3d.lock_object is not None:
|
||||
stored_view.lock_object_name = view3d.lock_object.name # idem
|
||||
else:
|
||||
stored_view.lock_object_name = ""
|
||||
stored_view.lock_cursor = view3d.lock_cursor
|
||||
stored_view.cursor_location = bpy.context.scene.cursor.location
|
||||
|
||||
def update_v3d(self, stored_view):
|
||||
view3d = self.view3d
|
||||
region3d = view3d.region_3d
|
||||
region3d.view_distance = stored_view.distance
|
||||
region3d.view_location = stored_view.location
|
||||
region3d.view_rotation = stored_view.rotation
|
||||
region3d.view_perspective = stored_view.perspective
|
||||
view3d.lens = stored_view.lens
|
||||
view3d.clip_start = stored_view.clip_start
|
||||
view3d.clip_end = stored_view.clip_end
|
||||
view3d.lock_cursor = stored_view.lock_cursor
|
||||
if stored_view.lock_cursor is True:
|
||||
# update cursor only if view is locked to cursor
|
||||
view3d.cursor_location = stored_view.cursor_location
|
||||
|
||||
if stored_view.perspective == "CAMERA":
|
||||
|
||||
lock_obj = self._get_object(stored_view.lock_object_name)
|
||||
if lock_obj:
|
||||
view3d.lock_object = lock_obj
|
||||
else:
|
||||
cam = self._get_object(stored_view.camera_name)
|
||||
if cam:
|
||||
view3d.camera = cam
|
||||
|
||||
@staticmethod
|
||||
def _get_object(name, pointer=None):
|
||||
return bpy.data.objects.get(name)
|
||||
|
||||
@staticmethod
|
||||
def is_modified(context, stored_view):
|
||||
# TODO: check for others param, currently only perspective
|
||||
# and perspective_matrix are checked
|
||||
POV.logger = logging.getLogger('%s.POV' % __name__)
|
||||
view3d = context.space_data
|
||||
region3d = view3d.region_3d
|
||||
if region3d.view_perspective != stored_view.perspective:
|
||||
POV.logger.debug('view_perspective')
|
||||
return True
|
||||
|
||||
md5 = POV._get_perspective_matrix_md5(region3d)
|
||||
if (md5 != stored_view.perspective_matrix_md5 and
|
||||
region3d.view_perspective != "CAMERA"):
|
||||
POV.logger.debug('perspective_matrix')
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _get_perspective_matrix_md5(region3d):
|
||||
md5 = hashlib.md5(str(region3d.perspective_matrix).encode('utf-8')).hexdigest()
|
||||
return md5
|
||||
|
||||
|
||||
# class Layers(StoredView):
|
||||
# def __init__(self, index=None):
|
||||
# super().__init__(mode='COLLECTIONS', index=index)
|
||||
# self.logger = logging.getLogger('%s.Layers' % __name__)
|
||||
|
||||
# def from_v3d(self, stored_view):
|
||||
# view3d = self.view3d
|
||||
# stored_view.view_layers = bpy.types.layer.collection
|
||||
# stored_view.scene_layers = self.scene.layers
|
||||
# stored_view.lock_camera = view3d.lock_camera
|
||||
|
||||
# def update_v3d(self, stored_view):
|
||||
# view3d = self.view3d
|
||||
# view3d.camera = stored_view.camera
|
||||
# if stored_view.camera is True:
|
||||
# self.scene.layers = stored_view.scene_layers
|
||||
# else:
|
||||
# view3d.layers = stored_view.view_layers
|
||||
|
||||
# @staticmethod
|
||||
# def is_modified(context, stored_view):
|
||||
# Layers.logger = logging.getLogger('%s.Layers' % __name__)
|
||||
# if stored_view.camera != context.space_data.camera:
|
||||
# Layers.logger.debug('lock_camera')
|
||||
# return True
|
||||
# if stored_view.camera is True:
|
||||
# for i in range(20):
|
||||
# if stored_view.scene_layers[i] != context.scene.layers[i]:
|
||||
# Layers.logger.debug('scene_layers[%s]' % (i, ))
|
||||
# return True
|
||||
# else:
|
||||
# for i in range(20):
|
||||
# if stored_view.view_layers[i] != context.space_data.view3d.layers[i]:
|
||||
# return True
|
||||
# return False
|
||||
|
||||
|
||||
# class Display(StoredView):
|
||||
# def __init__(self, index=None):
|
||||
# super().__init__(mode='DISPLAY', index=index)
|
||||
# self.logger = logging.getLogger('%s.Display' % __name__)
|
||||
|
||||
# def from_v3d(self, stored_view):
|
||||
# view3d = self.view3d
|
||||
# stored_view.viewport_shade = view3d.viewport_shade
|
||||
# stored_view.show_only_render = view3d.show_only_render
|
||||
# stored_view.show_outline_selected = view3d.show_outline_selected
|
||||
# stored_view.show_all_objects_origin = view3d.show_all_objects_origin
|
||||
# stored_view.show_relationship_lines = view3d.show_relationship_lines
|
||||
# stored_view.show_floor = view3d.show_floor
|
||||
# stored_view.show_axis_x = view3d.show_axis_x
|
||||
# stored_view.show_axis_y = view3d.show_axis_y
|
||||
# stored_view.show_axis_z = view3d.show_axis_z
|
||||
# stored_view.grid_lines = view3d.grid_lines
|
||||
# stored_view.grid_scale = view3d.grid_scale
|
||||
# stored_view.grid_subdivisions = view3d.grid_subdivisions
|
||||
# stored_view.material_mode = self.scene.game_settings.material_mode
|
||||
# stored_view.show_textured_solid = view3d.show_textured_solid
|
||||
|
||||
# def update_v3d(self, stored_view):
|
||||
# view3d = self.view3d
|
||||
# view3d.viewport_shade = stored_view.viewport_shade
|
||||
# view3d.show_only_render = stored_view.show_only_render
|
||||
# view3d.show_outline_selected = stored_view.show_outline_selected
|
||||
# view3d.show_all_objects_origin = stored_view.show_all_objects_origin
|
||||
# view3d.show_relationship_lines = stored_view.show_relationship_lines
|
||||
# view3d.show_floor = stored_view.show_floor
|
||||
# view3d.show_axis_x = stored_view.show_axis_x
|
||||
# view3d.show_axis_y = stored_view.show_axis_y
|
||||
# view3d.show_axis_z = stored_view.show_axis_z
|
||||
# view3d.grid_lines = stored_view.grid_lines
|
||||
# view3d.grid_scale = stored_view.grid_scale
|
||||
# view3d.grid_subdivisions = stored_view.grid_subdivisions
|
||||
# self.scene.game_settings.material_mode = stored_view.material_mode
|
||||
# view3d.show_textured_solid = stored_view.show_textured_solid
|
||||
|
||||
# @staticmethod
|
||||
# def is_modified(context, stored_view):
|
||||
# Display.logger = logging.getLogger('%s.Display' % __name__)
|
||||
# view3d = context.space_data
|
||||
# excludes = ["material_mode", "quad_view", "lock_rotation", "show_sync_view", "use_box_clip", "name"]
|
||||
# for k, v in stored_view.items():
|
||||
# if k not in excludes:
|
||||
# if getattr(view3d, k) != getattr(stored_view, k):
|
||||
# return True
|
||||
|
||||
# if stored_view.material_mode != context.scene.game_settings.material_mode:
|
||||
# Display.logger.debug('material_mode')
|
||||
# return True
|
||||
|
||||
|
||||
class View(StoredView):
|
||||
def __init__(self, index=None):
|
||||
super().__init__(mode='VIEW', index=index)
|
||||
self.logger = logging.getLogger('%s.View' % __name__)
|
||||
self.pov = POV()
|
||||
# self.layers = Layers()
|
||||
# self.display = Display()
|
||||
|
||||
def from_v3d(self, stored_view):
|
||||
self.pov.from_v3d(stored_view.pov)
|
||||
# self.layers.from_v3d(stored_view.layers)
|
||||
# self.display.from_v3d(stored_view.display)
|
||||
|
||||
def update_v3d(self, stored_view):
|
||||
self.pov.update_v3d(stored_view.pov)
|
||||
# self.layers.update_v3d(stored_view.layers)
|
||||
# self.display.update_v3d(stored_view.display)
|
||||
|
||||
@staticmethod
|
||||
def is_modified(context, stored_view):
|
||||
POV.is_modified(context, stored_view.pov) #or \
|
||||
# Layers.is_modified(context, stored_view.layers) or \
|
||||
# Display.is_modified(context, stored_view.display):
|
||||
return True
|
||||
# return False
|
||||
|
||||
|
||||
class DataStore():
|
||||
def __init__(self, scene=None, mode=None):
|
||||
if scene is None:
|
||||
scene = bpy.context.scene
|
||||
stored_views = scene.stored_views
|
||||
self.mode = mode
|
||||
|
||||
if mode is None:
|
||||
self.mode = stored_views.mode
|
||||
|
||||
if self.mode == 'VIEW':
|
||||
self.list = stored_views.view_list
|
||||
self.current_index = stored_views.current_indices[0]
|
||||
elif self.mode == 'POV':
|
||||
self.list = stored_views.pov_list
|
||||
self.current_index = stored_views.current_indices[1]
|
||||
elif self.mode == 'LAYERS':
|
||||
self.list = stored_views.layers_list
|
||||
self.current_index = stored_views.current_indices[2]
|
||||
elif self.mode == 'DISPLAY':
|
||||
self.list = stored_views.display_list
|
||||
self.current_index = stored_views.current_indices[3]
|
||||
|
||||
def create(self):
|
||||
item = self.list.add()
|
||||
item.name = self._generate_name()
|
||||
index = len(self.list) - 1
|
||||
self._set_current_index(index)
|
||||
return item, index
|
||||
|
||||
def get(self, index):
|
||||
self._set_current_index(index)
|
||||
return self.list[index]
|
||||
|
||||
def delete(self, index):
|
||||
if self.current_index > index:
|
||||
self._set_current_index(self.current_index - 1)
|
||||
elif self.current_index == index:
|
||||
self._set_current_index(-1)
|
||||
|
||||
self.list.remove(index)
|
||||
|
||||
def _set_current_index(self, index):
|
||||
self.current_index = index
|
||||
mode = self.mode
|
||||
stored_views = bpy.context.scene.stored_views
|
||||
if mode == 'VIEW':
|
||||
stored_views.current_indices[0] = index
|
||||
elif mode == 'POV':
|
||||
stored_views.current_indices[1] = index
|
||||
elif mode == 'LAYERS':
|
||||
stored_views.current_indices[2] = index
|
||||
elif mode == 'DISPLAY':
|
||||
stored_views.current_indices[3] = index
|
||||
|
||||
def _generate_name(self):
|
||||
default_name = str(self.mode)
|
||||
names = []
|
||||
for i in self.list:
|
||||
i_name = i.name
|
||||
if i_name.startswith(default_name):
|
||||
names.append(i_name)
|
||||
names.sort()
|
||||
try:
|
||||
l_name = names[-1]
|
||||
post_fix = l_name.rpartition('.')[2]
|
||||
if post_fix.isnumeric():
|
||||
post_fix = str(int(post_fix) + 1).zfill(3)
|
||||
else:
|
||||
if post_fix == default_name:
|
||||
post_fix = "001"
|
||||
return default_name + "." + post_fix
|
||||
except:
|
||||
return default_name
|
||||
|
||||
@staticmethod
|
||||
def sanitize_data(scene):
|
||||
|
||||
def check_objects_references(mode, list):
|
||||
to_remove = []
|
||||
for i, list_item in enumerate(list.items()):
|
||||
key, item = list_item
|
||||
if mode == 'POV' or mode == 'VIEWS':
|
||||
if mode == 'VIEWS':
|
||||
item = item.pov
|
||||
|
||||
if item.perspective == "CAMERA":
|
||||
|
||||
camera = bpy.data.objects.get(item.camera_name)
|
||||
if camera is None:
|
||||
try: # pick a default camera TODO: ask to pick?
|
||||
camera = bpy.data.cameras[0]
|
||||
item.camera_name = camera.name
|
||||
except: # couldn't find a camera in the scene
|
||||
pass
|
||||
|
||||
obj = bpy.data.objects.get(item.lock_object_name)
|
||||
if obj is None and camera is None:
|
||||
to_remove.append(i)
|
||||
|
||||
for i in reversed(to_remove):
|
||||
list.remove(i)
|
||||
|
||||
modes = ['POV', 'VIEW', 'DISPLAY', 'LAYERS']
|
||||
for mode in modes:
|
||||
data = DataStore(scene=scene, mode=mode)
|
||||
check_objects_references(mode, data.list)
|
||||
|
||||
|
||||
def stored_view_factory(mode, *args, **kwargs):
|
||||
if mode == 'POV':
|
||||
return POV(*args, **kwargs)
|
||||
elif mode == 'LAYERS':
|
||||
return Layers(*args, **kwargs)
|
||||
elif mode == 'DISPLAY':
|
||||
return Display(*args, **kwargs)
|
||||
elif mode == 'VIEW':
|
||||
return View(*args, **kwargs)
|
|
@ -0,0 +1,343 @@
|
|||
# gpl authors: nfloyd, Francesco Siddi
|
||||
|
||||
import gzip
|
||||
import os
|
||||
import pickle
|
||||
import shutil
|
||||
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
StringProperty,
|
||||
)
|
||||
from bpy_extras.io_utils import (
|
||||
ExportHelper,
|
||||
ImportHelper,
|
||||
)
|
||||
from .import bl_info
|
||||
from .core import get_preferences
|
||||
from .operators import DataStore
|
||||
|
||||
|
||||
# TODO: reinstate filters?
|
||||
class IO_Utils():
|
||||
|
||||
@staticmethod
|
||||
def get_preset_path():
|
||||
# locate stored_views preset folder
|
||||
paths = bpy.utils.preset_paths("stored_views")
|
||||
if not paths:
|
||||
# stored_views preset folder doesn't exist, so create it
|
||||
paths = [os.path.join(bpy.utils.user_resource('SCRIPTS'), "presets",
|
||||
"stored_views")]
|
||||
if not os.path.exists(paths[0]):
|
||||
os.makedirs(paths[0])
|
||||
|
||||
return(paths)
|
||||
|
||||
@staticmethod
|
||||
def stored_views_apply_from_scene(scene_name, replace=True):
|
||||
scene = bpy.context.scene
|
||||
scene_exists = True if scene_name in bpy.data.scenes.keys() else False
|
||||
|
||||
if scene_exists:
|
||||
sv = bpy.context.scene.stored_views
|
||||
# io_filters = sv.settings.io_filters
|
||||
|
||||
structs = [sv.view_list, sv.pov_list, sv.layers_list, sv.display_list]
|
||||
if replace is True:
|
||||
for st in structs: # clear swap and list
|
||||
while len(st) > 0:
|
||||
st.remove(0)
|
||||
|
||||
f_sv = bpy.data.scenes[scene_name].stored_views
|
||||
# f_sv = bpy.data.scenes[scene_name].stored_views
|
||||
f_structs = [f_sv.view_list, f_sv.pov_list, f_sv.layers_list, f_sv.display_list]
|
||||
"""
|
||||
is_filtered = [io_filters.views, io_filters.point_of_views,
|
||||
io_filters.layers, io_filters.displays]
|
||||
"""
|
||||
for i in range(len(f_structs)):
|
||||
"""
|
||||
if is_filtered[i] is False:
|
||||
continue
|
||||
"""
|
||||
for j in f_structs[i]:
|
||||
item = structs[i].add()
|
||||
# stored_views_copy_item(j, item)
|
||||
for k, v in j.items():
|
||||
item[k] = v
|
||||
DataStore.sanitize_data(scene)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def stored_views_export_to_blsv(filepath, name='Custom Preset'):
|
||||
# create dictionary with all information
|
||||
dump = {"info": {}, "data": {}}
|
||||
dump["info"]["script"] = bl_info['name']
|
||||
dump["info"]["script_version"] = bl_info['version']
|
||||
dump["info"]["version"] = bpy.app.version
|
||||
dump["info"]["preset_name"] = name
|
||||
|
||||
# get current stored views settings
|
||||
scene = bpy.context.scene
|
||||
sv = scene.stored_views
|
||||
|
||||
def dump_view_list(dict, list):
|
||||
if str(type(list)) == "<class 'bpy_prop_collection_idprop'>":
|
||||
for i, struct_dict in enumerate(list):
|
||||
dict[i] = {"name": str,
|
||||
"pov": {},
|
||||
"layers": {},
|
||||
"display": {}}
|
||||
dict[i]["name"] = struct_dict.name
|
||||
dump_item(dict[i]["pov"], struct_dict.pov)
|
||||
dump_item(dict[i]["layers"], struct_dict.layers)
|
||||
dump_item(dict[i]["display"], struct_dict.display)
|
||||
|
||||
def dump_list(dict, list):
|
||||
if str(type(list)) == "<class 'bpy_prop_collection_idprop'>":
|
||||
for i, struct in enumerate(list):
|
||||
dict[i] = {}
|
||||
dump_item(dict[i], struct)
|
||||
|
||||
def dump_item(dict, struct):
|
||||
for prop in struct.bl_rna.properties:
|
||||
if prop.identifier == "rna_type":
|
||||
# not a setting, so skip
|
||||
continue
|
||||
|
||||
val = getattr(struct, prop.identifier)
|
||||
if str(type(val)) in ["<class 'bpy_prop_array'>"]:
|
||||
# array
|
||||
dict[prop.identifier] = [v for v in val]
|
||||
# address the pickle limitations of dealing with the Vector class
|
||||
elif str(type(val)) in ["<class 'Vector'>",
|
||||
"<class 'Quaternion'>"]:
|
||||
dict[prop.identifier] = [v for v in val]
|
||||
else:
|
||||
# single value
|
||||
dict[prop.identifier] = val
|
||||
|
||||
# io_filters = sv.settings.io_filters
|
||||
dump["data"] = {"point_of_views": {},
|
||||
"layers": {},
|
||||
"displays": {},
|
||||
"views": {}}
|
||||
|
||||
others_data = [(dump["data"]["point_of_views"], sv.pov_list), # , io_filters.point_of_views),
|
||||
(dump["data"]["layers"], sv.layers_list), # , io_filters.layers),
|
||||
(dump["data"]["displays"], sv.display_list)] # , io_filters.displays)]
|
||||
for list_data in others_data:
|
||||
# if list_data[2] is True:
|
||||
dump_list(list_data[0], list_data[1])
|
||||
|
||||
views_data = (dump["data"]["views"], sv.view_list)
|
||||
# if io_filters.views is True:
|
||||
dump_view_list(views_data[0], views_data[1])
|
||||
|
||||
# save to file
|
||||
filepath = filepath
|
||||
filepath = bpy.path.ensure_ext(filepath, '.blsv')
|
||||
file = gzip.open(filepath, mode='wb')
|
||||
pickle.dump(dump, file, protocol=pickle.HIGHEST_PROTOCOL)
|
||||
file.close()
|
||||
|
||||
@staticmethod
|
||||
def stored_views_apply_preset(filepath, replace=True):
|
||||
if not filepath:
|
||||
return False
|
||||
|
||||
file = gzip.open(filepath, mode='rb')
|
||||
dump = pickle.load(file)
|
||||
file.close()
|
||||
# apply preset
|
||||
scene = bpy.context.scene
|
||||
sv = getattr(scene, "stored_views", None)
|
||||
|
||||
if not sv:
|
||||
return False
|
||||
|
||||
# io_filters = sv.settings.io_filters
|
||||
sv_data = {
|
||||
"point_of_views": sv.pov_list,
|
||||
"views": sv.view_list,
|
||||
"layers": sv.layers_list,
|
||||
"displays": sv.display_list
|
||||
}
|
||||
for sv_struct, props in dump["data"].items():
|
||||
"""
|
||||
is_filtered = getattr(io_filters, sv_struct)
|
||||
if is_filtered is False:
|
||||
continue
|
||||
"""
|
||||
sv_list = sv_data[sv_struct] # .list
|
||||
if replace is True: # clear swap and list
|
||||
while len(sv_list) > 0:
|
||||
sv_list.remove(0)
|
||||
for key, prop_struct in props.items():
|
||||
sv_item = sv_list.add()
|
||||
|
||||
for subprop, subval in prop_struct.items():
|
||||
if isinstance(subval, dict): # views : pov, layers, displays
|
||||
v_subprop = getattr(sv_item, subprop)
|
||||
for v_subkey, v_subval in subval.items():
|
||||
if isinstance(v_subval, list): # array like of pov,...
|
||||
v_array_like = getattr(v_subprop, v_subkey)
|
||||
for i in range(len(v_array_like)):
|
||||
v_array_like[i] = v_subval[i]
|
||||
else:
|
||||
setattr(v_subprop, v_subkey, v_subval) # others
|
||||
elif isinstance(subval, list):
|
||||
array_like = getattr(sv_item, subprop)
|
||||
for i in range(len(array_like)):
|
||||
array_like[i] = subval[i]
|
||||
else:
|
||||
setattr(sv_item, subprop, subval)
|
||||
|
||||
DataStore.sanitize_data(scene)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class VIEW3D_stored_views_import(Operator, ImportHelper):
|
||||
bl_idname = "stored_views.import_blsv"
|
||||
bl_label = "Import Stored Views preset"
|
||||
bl_description = "Import a .blsv preset file to the current Stored Views"
|
||||
|
||||
filename_ext = ".blsv"
|
||||
filter_glob = StringProperty(
|
||||
default="*.blsv",
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
replace = BoolProperty(
|
||||
name="Replace",
|
||||
default=True,
|
||||
description="Replace current stored views, otherwise append"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return get_preferences()
|
||||
|
||||
def execute(self, context):
|
||||
# the usual way is to not select the file in the file browser
|
||||
exists = os.path.isfile(self.filepath) if self.filepath else False
|
||||
if not exists:
|
||||
self.report({'WARNING'},
|
||||
"No filepath specified or file could not be found. Operation Cancelled")
|
||||
return {'CANCELLED'}
|
||||
|
||||
# apply chosen preset
|
||||
apply_preset = IO_Utils.stored_views_apply_preset(
|
||||
filepath=self.filepath, replace=self.replace
|
||||
)
|
||||
if not apply_preset:
|
||||
self.report({'WARNING'},
|
||||
"Please Initialize Stored Views first (in the 3D View Properties Area)")
|
||||
return {'CANCELLED'}
|
||||
|
||||
# copy preset to presets folder
|
||||
filename = os.path.basename(self.filepath)
|
||||
try:
|
||||
shutil.copyfile(self.filepath,
|
||||
os.path.join(IO_Utils.get_preset_path()[0], filename))
|
||||
except:
|
||||
self.report({'WARNING'},
|
||||
"Stored Views: preset applied, but installing failed (preset already exists?)")
|
||||
return{'CANCELLED'}
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_stored_views_import_from_scene(Operator):
|
||||
bl_idname = "stored_views.import_from_scene"
|
||||
bl_label = "Import stored views from scene"
|
||||
bl_description = "Import currently stored views from an another scene"
|
||||
|
||||
scene_name = StringProperty(
|
||||
name="Scene Name",
|
||||
description="A current blend scene",
|
||||
default=""
|
||||
)
|
||||
replace = BoolProperty(
|
||||
name="Replace",
|
||||
default=True,
|
||||
description="Replace current stored views, otherwise append"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return get_preferences()
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.prop_search(self, "scene_name", bpy.data, "scenes")
|
||||
layout.prop(self, "replace")
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def execute(self, context):
|
||||
# filepath should always be given
|
||||
if not self.scene_name:
|
||||
self.report({"WARNING"},
|
||||
"No scene name was given. Operation Cancelled")
|
||||
return{'CANCELLED'}
|
||||
|
||||
is_finished = IO_Utils.stored_views_apply_from_scene(
|
||||
self.scene_name, replace=self.replace
|
||||
)
|
||||
if not is_finished:
|
||||
self.report({"WARNING"},
|
||||
"Could not find the specified scene. Operation Cancelled")
|
||||
return {"CANCELLED"}
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_stored_views_export(Operator, ExportHelper):
|
||||
bl_idname = "stored_views.export_blsv"
|
||||
bl_label = "Export Stored Views preset"
|
||||
bl_description = "Export the current Stored Views to a .blsv preset file"
|
||||
|
||||
filename_ext = ".blsv"
|
||||
filepath = StringProperty(
|
||||
default=os.path.join(IO_Utils.get_preset_path()[0], "untitled")
|
||||
)
|
||||
filter_glob = StringProperty(
|
||||
default="*.blsv",
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
preset_name = StringProperty(
|
||||
name="Preset name",
|
||||
default="",
|
||||
description="Name of the stored views preset"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return get_preferences()
|
||||
|
||||
def execute(self, context):
|
||||
IO_Utils.stored_views_export_to_blsv(self.filepath, self.preset_name)
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
classes = (
|
||||
VIEW3D_stored_views_import,
|
||||
VIEW3D_stored_views_import_from_scene,
|
||||
VIEW3D_stored_views_export
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,182 @@
|
|||
# gpl authors: nfloyd, Francesco Siddi
|
||||
|
||||
import bpy
|
||||
from bpy.props import IntProperty
|
||||
from bpy.types import Operator
|
||||
from .core import (
|
||||
stored_view_factory,
|
||||
DataStore,
|
||||
)
|
||||
from .ui import init_draw
|
||||
|
||||
|
||||
class VIEW3D_stored_views_save(Operator):
|
||||
bl_idname = "stored_views.save"
|
||||
bl_label = "Save Current"
|
||||
bl_description = "Save the view 3d current state"
|
||||
|
||||
index : IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
mode = context.scene.stored_views.mode
|
||||
sv = stored_view_factory(mode, self.index)
|
||||
sv.save()
|
||||
context.scene.stored_views.view_modified = False
|
||||
init_draw(context)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_stored_views_set(Operator):
|
||||
bl_idname = "stored_views.set"
|
||||
bl_label = "Set"
|
||||
bl_description = "Update the view 3D according to this view"
|
||||
|
||||
index : IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
mode = context.scene.stored_views.mode
|
||||
sv = stored_view_factory(mode, self.index)
|
||||
sv.set()
|
||||
context.scene.stored_views.view_modified = False
|
||||
init_draw(context)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_stored_views_delete(Operator):
|
||||
bl_idname = "stored_views.delete"
|
||||
bl_label = "Delete"
|
||||
bl_description = "Delete this view"
|
||||
|
||||
index : IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
data = DataStore()
|
||||
data.delete(self.index)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_New_Camera_to_View(Operator):
|
||||
bl_idname = "stored_views.newcamera"
|
||||
bl_label = "New Camera To View"
|
||||
bl_description = "Add a new Active Camera and align it to this view"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (
|
||||
context.space_data is not None and
|
||||
context.space_data.type == 'VIEW_3D' and
|
||||
context.space_data.region_3d.view_perspective != 'CAMERA'
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
bpy.ops.object.camera_add()
|
||||
cam = context.active_object
|
||||
cam.name = "View_Camera"
|
||||
# make active camera by hand
|
||||
context.scene.camera = cam
|
||||
|
||||
bpy.ops.view3d.camera_to_view()
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Camera marker & switcher by Fsiddi
|
||||
class SetSceneCamera(Operator):
|
||||
bl_idname = "cameraselector.set_scene_camera"
|
||||
bl_label = "Set Scene Camera"
|
||||
bl_description = "Set chosen camera as the scene's active camera"
|
||||
|
||||
hide_others = False
|
||||
|
||||
def execute(self, context):
|
||||
chosen_camera = context.active_object
|
||||
scene = context.scene
|
||||
|
||||
if self.hide_others:
|
||||
for c in [o for o in scene.objects if o.type == 'CAMERA']:
|
||||
c.hide = (c != chosen_camera)
|
||||
scene.camera = chosen_camera
|
||||
bpy.ops.object.select_all(action ='DESELECT')
|
||||
chosen_camera.select_set(True)
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
if event.ctrl:
|
||||
self.hide_others = True
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
class PreviewSceneCamera(Operator):
|
||||
bl_idname = "cameraselector.preview_scene_camera"
|
||||
bl_label = "Preview Camera"
|
||||
bl_description = "Preview chosen camera and make scene's active camera"
|
||||
|
||||
def execute(self, context):
|
||||
chosen_camera = context.active_object
|
||||
bpy.ops.view3d.object_as_camera()
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
chosen_camera.select_set(True)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AddCameraMarker(Operator):
|
||||
bl_idname = "cameraselector.add_camera_marker"
|
||||
bl_label = "Add Camera Marker"
|
||||
bl_description = "Add a timeline marker bound to chosen camera"
|
||||
|
||||
def execute(self, context):
|
||||
chosen_camera = context.active_object
|
||||
scene = context.scene
|
||||
|
||||
current_frame = scene.frame_current
|
||||
marker = None
|
||||
for m in reversed(sorted(filter(lambda m: m.frame <= current_frame,
|
||||
scene.timeline_markers),
|
||||
key=lambda m: m.frame)):
|
||||
marker = m
|
||||
break
|
||||
if marker and (marker.camera == chosen_camera):
|
||||
# Cancel if the last marker at or immediately before
|
||||
# current frame is already bound to the camera.
|
||||
return {'CANCELLED'}
|
||||
|
||||
marker_name = "F_%02d_%s" % (current_frame, chosen_camera.name)
|
||||
if marker and (marker.frame == current_frame):
|
||||
# Reuse existing marker at current frame to avoid
|
||||
# overlapping bound markers.
|
||||
marker.name = marker_name
|
||||
else:
|
||||
marker = scene.timeline_markers.new(marker_name)
|
||||
marker.frame = scene.frame_current
|
||||
marker.camera = chosen_camera
|
||||
marker.select = True
|
||||
|
||||
for other_marker in [m for m in scene.timeline_markers if m != marker]:
|
||||
other_marker.select = True
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
classes = (
|
||||
VIEW3D_stored_views_save,
|
||||
VIEW3D_stored_views_set,
|
||||
VIEW3D_stored_views_delete,
|
||||
VIEW3D_New_Camera_to_View,
|
||||
SetSceneCamera,
|
||||
PreviewSceneCamera,
|
||||
AddCameraMarker
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,137 @@
|
|||
# gpl authors: nfloyd, Francesco Siddi
|
||||
import bpy
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
BoolVectorProperty,
|
||||
CollectionProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
EnumProperty,
|
||||
IntProperty,
|
||||
IntVectorProperty,
|
||||
PointerProperty,
|
||||
StringProperty,
|
||||
)
|
||||
|
||||
|
||||
class POVData(PropertyGroup):
|
||||
distance : FloatProperty()
|
||||
location : FloatVectorProperty(
|
||||
subtype='TRANSLATION'
|
||||
)
|
||||
rotation : FloatVectorProperty(
|
||||
subtype='QUATERNION',
|
||||
size=4
|
||||
)
|
||||
name : StringProperty()
|
||||
perspective : EnumProperty(
|
||||
items=[('PERSP', '', ''),
|
||||
('ORTHO', '', ''),
|
||||
('CAMERA', '', '')]
|
||||
)
|
||||
lens : FloatProperty()
|
||||
clip_start : FloatProperty()
|
||||
clip_end : FloatProperty()
|
||||
lock_cursor : BoolProperty()
|
||||
cursor_location : FloatVectorProperty()
|
||||
perspective_matrix_md5 = StringProperty()
|
||||
camera_name : StringProperty()
|
||||
camera_type : StringProperty()
|
||||
lock_object_name : StringProperty()
|
||||
|
||||
|
||||
class LayersData(PropertyGroup):
|
||||
view_layers : BoolVectorProperty(size=20)
|
||||
scene_layers : BoolVectorProperty(size=20)
|
||||
lock_camera_and_layers : BoolProperty()
|
||||
name : StringProperty()
|
||||
|
||||
|
||||
class DisplayData(PropertyGroup):
|
||||
name = StringProperty()
|
||||
viewport_shade = EnumProperty(
|
||||
items=[('BOUNDBOX', 'BOUNDBOX', 'BOUNDBOX'),
|
||||
('WIREFRAME', 'WIREFRAME', 'WIREFRAME'),
|
||||
('SOLID', 'SOLID', 'SOLID'),
|
||||
('TEXTURED', 'TEXTURED', 'TEXTURED'),
|
||||
('MATERIAL', 'MATERIAL', 'MATERIAL'),
|
||||
('RENDERED', 'RENDERED', 'RENDERED')]
|
||||
)
|
||||
show_only_render : BoolProperty()
|
||||
show_outline_selected : BoolProperty()
|
||||
show_all_objects_origin : BoolProperty()
|
||||
show_relationship_lines : BoolProperty()
|
||||
show_floor : BoolProperty()
|
||||
show_axis_x : BoolProperty()
|
||||
show_axis_y : BoolProperty()
|
||||
show_axis_z : BoolProperty()
|
||||
grid_lines : IntProperty()
|
||||
grid_scale : FloatProperty()
|
||||
grid_subdivisions : IntProperty()
|
||||
material_mode : StringProperty()
|
||||
show_textured_solid : BoolProperty()
|
||||
quad_view : BoolProperty()
|
||||
lock_rotation : BoolProperty()
|
||||
show_sync_view : BoolProperty()
|
||||
use_box_clip : BoolProperty()
|
||||
|
||||
|
||||
class ViewData(PropertyGroup):
|
||||
pov : PointerProperty(
|
||||
type=POVData
|
||||
)
|
||||
layers : PointerProperty(
|
||||
type=LayersData
|
||||
)
|
||||
display : PointerProperty(
|
||||
type=DisplayData
|
||||
)
|
||||
name : StringProperty()
|
||||
|
||||
|
||||
class StoredViewsData(PropertyGroup):
|
||||
pov_list : CollectionProperty(
|
||||
type=POVData
|
||||
)
|
||||
layers_list : CollectionProperty(
|
||||
type=LayersData
|
||||
)
|
||||
display_list : CollectionProperty(
|
||||
type=DisplayData
|
||||
)
|
||||
view_list : CollectionProperty(
|
||||
type=ViewData
|
||||
)
|
||||
mode : EnumProperty(
|
||||
name="Mode",
|
||||
items=[('VIEW', "View", "3D View settings"),
|
||||
('POV', "POV", "POV settings"),
|
||||
('LAYERS', "Layers", "Layers settings"),
|
||||
('DISPLAY', "Display", "Display settings")],
|
||||
default='VIEW'
|
||||
)
|
||||
current_indices : IntVectorProperty(
|
||||
size=4,
|
||||
default=[-1, -1, -1, -1]
|
||||
)
|
||||
view_modified : BoolProperty(
|
||||
default=False
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
POVData,
|
||||
LayersData,
|
||||
DisplayData,
|
||||
ViewData,
|
||||
StoredViewsData,
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,277 @@
|
|||
# gpl authors: nfloyd, Francesco Siddi
|
||||
|
||||
import logging
|
||||
module_logger = logging.getLogger(__name__)
|
||||
|
||||
import bpy
|
||||
import blf
|
||||
from . import core
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Panel,
|
||||
)
|
||||
|
||||
"""
|
||||
If view name display is enabled,
|
||||
it will check periodically if the view has been modified
|
||||
since last set.
|
||||
get_preferences_timer() is the time in seconds between these checks.
|
||||
It can be increased, if the view become sluggish
|
||||
It is set in the add-on preferences
|
||||
"""
|
||||
|
||||
|
||||
# Utility function get_preferences_timer for update of 3d view draw
|
||||
def get_preferences_timer():
|
||||
# replace the key if the add-on name changes
|
||||
# TODO: expose refresh rate to ui???
|
||||
addon = bpy.context.preferences.addons[__package__]
|
||||
timer_update = (addon.preferences.view_3d_update_rate if addon else False)
|
||||
|
||||
return timer_update
|
||||
|
||||
|
||||
def init_draw(context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
|
||||
if "stored_views_osd" not in context.window_manager:
|
||||
context.window_manager["stored_views_osd"] = False
|
||||
|
||||
if not context.window_manager["stored_views_osd"]:
|
||||
context.window_manager["stored_views_osd"] = True
|
||||
bpy.ops.stored_views.draw()
|
||||
|
||||
|
||||
def _draw_callback_px(self, context):
|
||||
if context.area and context.area.type == 'VIEW_3D':
|
||||
r_width = text_location = context.region.width
|
||||
r_height = context.region.height
|
||||
font_id = 0 # TODO: need to find out how best to get font_id
|
||||
|
||||
blf.size(font_id, 11, context.preferences.system.dpi)
|
||||
text_size = blf.dimensions(0, self.view_name)
|
||||
|
||||
# compute the text location
|
||||
text_location = 0
|
||||
overlap = context.preferences.system.use_region_overlap
|
||||
if overlap:
|
||||
for region in context.area.regions:
|
||||
if region.type == "UI":
|
||||
text_location = r_width - region.width
|
||||
|
||||
text_x = text_location - text_size[0] - 10
|
||||
text_y = r_height - text_size[1] - 8
|
||||
blf.position(font_id, text_x, text_y, 0)
|
||||
blf.draw(font_id, self.view_name)
|
||||
|
||||
|
||||
class VIEW3D_stored_views_draw(Operator):
|
||||
bl_idname = "stored_views.draw"
|
||||
bl_label = "Show current"
|
||||
bl_description = "Toggle the display current view name in the view 3D"
|
||||
|
||||
_handle = None
|
||||
_timer = None
|
||||
|
||||
@staticmethod
|
||||
def handle_add(self, context):
|
||||
VIEW3D_stored_views_draw._handle = bpy.types.SpaceView3D.draw_handler_add(
|
||||
_draw_callback_px, (self, context), 'WINDOW', 'POST_PIXEL')
|
||||
VIEW3D_stored_views_draw._timer = \
|
||||
context.window_manager.event_timer_add(get_preferences_timer(), window=context.window)
|
||||
|
||||
@staticmethod
|
||||
def handle_remove(context):
|
||||
if VIEW3D_stored_views_draw._handle is not None:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(VIEW3D_stored_views_draw._handle, 'WINDOW')
|
||||
if VIEW3D_stored_views_draw._timer is not None:
|
||||
context.window_manager.event_timer_remove(VIEW3D_stored_views_draw._timer)
|
||||
VIEW3D_stored_views_draw._handle = None
|
||||
VIEW3D_stored_views_draw._timer = None
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
# return context.mode == 'OBJECT'
|
||||
return True
|
||||
|
||||
def modal(self, context, event):
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
|
||||
if not context.area or context.area.type != "VIEW_3D":
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
data = core.DataStore()
|
||||
stored_views = context.scene.stored_views
|
||||
|
||||
if len(data.list) > 0 and \
|
||||
data.current_index >= 0 and \
|
||||
not stored_views.view_modified:
|
||||
|
||||
if not stored_views.view_modified:
|
||||
sv = data.list[data.current_index]
|
||||
self.view_name = sv.name
|
||||
if event.type == 'TIMER':
|
||||
is_modified = False
|
||||
if data.mode == 'VIEW':
|
||||
is_modified = core.View.is_modified(context, sv)
|
||||
elif data.mode == 'POV':
|
||||
is_modified = core.POV.is_modified(context, sv)
|
||||
elif data.mode == 'LAYERS':
|
||||
is_modified = core.Layers.is_modified(context, sv)
|
||||
elif data.mode == 'DISPLAY':
|
||||
is_modified = core.Display.is_modified(context, sv)
|
||||
if is_modified:
|
||||
module_logger.debug(
|
||||
'view modified - index: %s name: %s' % (data.current_index, sv.name)
|
||||
)
|
||||
self.view_name = ""
|
||||
stored_views.view_modified = is_modified
|
||||
|
||||
return {"PASS_THROUGH"}
|
||||
else:
|
||||
module_logger.debug('exit')
|
||||
context.window_manager["stored_views_osd"] = False
|
||||
VIEW3D_stored_views_draw.handle_remove(context)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def execute(self, context):
|
||||
if context.area.type == "VIEW_3D":
|
||||
self.view_name = ""
|
||||
VIEW3D_stored_views_draw.handle_add(self, context)
|
||||
context.window_manager.modal_handler_add(self)
|
||||
|
||||
return {"RUNNING_MODAL"}
|
||||
else:
|
||||
self.report({"WARNING"}, "View3D not found. Operation Cancelled")
|
||||
|
||||
return {"CANCELLED"}
|
||||
|
||||
|
||||
class VIEW3D_PT_properties_stored_views(Panel):
|
||||
bl_label = "Stored Views"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "StoredViews"
|
||||
|
||||
def draw(self, context):
|
||||
self.logger = logging.getLogger('%s Properties panel' % __name__)
|
||||
layout = self.layout
|
||||
|
||||
if bpy.ops.view3d.stored_views_initialize.poll():
|
||||
layout.operator("view3d.stored_views_initialize")
|
||||
return
|
||||
|
||||
stored_views = context.scene.stored_views
|
||||
|
||||
# UI : mode
|
||||
col = layout.column(align=True)
|
||||
col.prop_enum(stored_views, "mode", 'VIEW')
|
||||
row = layout.row(align=True)
|
||||
row.operator("view3d.camera_to_view", text="Camera To view")
|
||||
row.operator("stored_views.newcamera")
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop_enum(stored_views, "mode", 'POV')
|
||||
# row.prop_enum(stored_views, "mode", 'LAYERS')
|
||||
# row.prop_enum(stored_views, "mode", 'DISPLAY')
|
||||
|
||||
# UI : operators
|
||||
row = layout.row()
|
||||
row.operator("stored_views.save").index = -1
|
||||
|
||||
# IO Operators
|
||||
if core.get_preferences():
|
||||
row = layout.row(align=True)
|
||||
row.operator("stored_views.import_from_scene", text="Import from Scene")
|
||||
row.operator("stored_views.import_blsv", text="", icon="IMPORT")
|
||||
row.operator("stored_views.export_blsv", text="", icon="EXPORT")
|
||||
|
||||
data_store = core.DataStore()
|
||||
list = data_store.list
|
||||
# UI : items list
|
||||
if len(list) > 0:
|
||||
row = layout.row()
|
||||
box = row.box()
|
||||
# items list
|
||||
mode = stored_views.mode
|
||||
for i in range(len(list)):
|
||||
# associated icon
|
||||
icon_string = "MESH_CUBE" # default icon
|
||||
# TODO: icons for view
|
||||
if mode == 'POV':
|
||||
persp = list[i].perspective
|
||||
if persp == 'PERSP':
|
||||
icon_string = "MESH_CUBE"
|
||||
elif persp == 'ORTHO':
|
||||
icon_string = "MESH_PLANE"
|
||||
elif persp == 'CAMERA':
|
||||
if list[i].camera_type != 'CAMERA':
|
||||
icon_string = 'OBJECT_DATAMODE'
|
||||
else:
|
||||
icon_string = "OUTLINER_DATA_CAMERA"
|
||||
if mode == 'LAYERS':
|
||||
if list[i].lock_camera_and_layers is True:
|
||||
icon_string = 'SCENE_DATA'
|
||||
else:
|
||||
icon_string = 'RENDERLAYERS'
|
||||
if mode == 'DISPLAY':
|
||||
shade = list[i].viewport_shade
|
||||
if shade == 'TEXTURED':
|
||||
icon_string = 'TEXTURE_SHADED'
|
||||
if shade == 'MATERIAL':
|
||||
icon_string = 'MATERIAL_DATA'
|
||||
elif shade == 'SOLID':
|
||||
icon_string = 'SOLID'
|
||||
elif shade == 'WIREFRAME':
|
||||
icon_string = "WIRE"
|
||||
elif shade == 'BOUNDBOX':
|
||||
icon_string = 'BBOX'
|
||||
elif shade == 'RENDERED':
|
||||
icon_string = 'MATERIAL'
|
||||
# stored view row
|
||||
subrow = box.row(align=True)
|
||||
# current view indicator
|
||||
if data_store.current_index == i and context.scene.stored_views.view_modified is False:
|
||||
subrow.label(text="", icon='SMALL_TRI_RIGHT_VEC')
|
||||
subrow.operator("stored_views.set",
|
||||
text="", icon=icon_string).index = i
|
||||
subrow.prop(list[i], "name", text="")
|
||||
subrow.operator("stored_views.save",
|
||||
text="", icon="REC").index = i
|
||||
subrow.operator("stored_views.delete",
|
||||
text="", icon="PANEL_CLOSE").index = i
|
||||
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
layout.label(text="Camera Selector")
|
||||
cameras = sorted([o for o in scene.objects if o.type == 'CAMERA'],
|
||||
key=lambda o: o.name)
|
||||
|
||||
if len(cameras) > 0:
|
||||
for camera in cameras:
|
||||
row = layout.row(align=True)
|
||||
row.context_pointer_set("active_object", camera)
|
||||
row.operator("cameraselector.set_scene_camera",
|
||||
text=camera.name, icon='OUTLINER_DATA_CAMERA')
|
||||
row.operator("cameraselector.preview_scene_camera",
|
||||
text='', icon='RESTRICT_VIEW_OFF')
|
||||
row.operator("cameraselector.add_camera_marker",
|
||||
text='', icon='MARKER')
|
||||
else:
|
||||
layout.label(text="No cameras in this scene")
|
||||
|
||||
classes = (
|
||||
VIEW3D_stored_views_draw,
|
||||
VIEW3D_PT_properties_stored_views
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
Loading…
Reference in New Issue