mirror of
https://github.com/blender/blender-addons.git
synced 2025-08-16 15:35:05 +00:00

Move copyright text to SPDX-FileCopyrightText or set to the Blender Foundation so "make check_licenses" now runs without warnings.
285 lines
10 KiB
Python
285 lines
10 KiB
Python
# SPDX-FileCopyrightText: 2017-2023 Blender Foundation
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
# 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):
|
|
area = context.area
|
|
if area and area.type == 'VIEW_3D':
|
|
ui_scale = context.preferences.system.ui_scale
|
|
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 * ui_scale)
|
|
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 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 = "View"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
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='CHECKMARK')
|
|
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)
|