work
save startup blend for animation tab & whatnot
This commit is contained in:
@@ -21,6 +21,7 @@ import logging
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
from typing import Any, Optional, Set, Tuple, Union
|
||||
|
||||
import bpy
|
||||
import mathutils
|
||||
@@ -28,8 +29,6 @@ from bpy.props import IntProperty, StringProperty
|
||||
from bpy_extras import view3d_utils
|
||||
from mathutils import Vector
|
||||
|
||||
from typing import Any, Optional, Tuple, Set, Union
|
||||
|
||||
from . import (
|
||||
bg_blender,
|
||||
colors,
|
||||
@@ -38,11 +37,12 @@ from . import (
|
||||
image_utils,
|
||||
paths,
|
||||
reports,
|
||||
search,
|
||||
ui,
|
||||
ui_bgl,
|
||||
ui_panels,
|
||||
utils,
|
||||
search,
|
||||
viewport_utils,
|
||||
)
|
||||
from .bl_ui_widgets.bl_ui_button import BL_UI_Button
|
||||
from .bl_ui_widgets.bl_ui_drag_panel import BL_UI_Drag_Panel
|
||||
@@ -56,11 +56,8 @@ handler_2d = None
|
||||
handler_3d = None
|
||||
|
||||
|
||||
DEAD_ZONE = 5 # pixels
|
||||
"""Number of pixels mouse must move to start drag operation."""
|
||||
|
||||
DRAG_THRESHOLD = 10 # pixels
|
||||
"""Number of pixels mouse must move to consider as a drag (vs click)."""
|
||||
DEFAULT_DRAG_THRESHOLD = 30 # pixels
|
||||
"""Pointer travel in pixels needed before we start rendering full drag hints."""
|
||||
|
||||
|
||||
def is_draw_cb_available(self: bpy.types.Operator, context: bpy.types.Context) -> bool:
|
||||
@@ -106,8 +103,8 @@ def draw_callback_dragging(
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
# Only draw 2D elements in the active region where the mouse is. Guard against destroyed operator.
|
||||
|
||||
# Only draw 2D elements in the active region where the mouse is. Guard against destroyed operator.
|
||||
if not is_draw_cb_available(self, context):
|
||||
return
|
||||
|
||||
@@ -356,6 +353,10 @@ def draw_callback_3d_dragging(
|
||||
if not utils.guard_from_crash():
|
||||
return
|
||||
|
||||
# ignore unless we are dragging
|
||||
if not self.drag:
|
||||
return
|
||||
|
||||
# Only draw 3D elements in VIEW_3D areas, not in outliner
|
||||
if context.area.type != "VIEW_3D":
|
||||
return
|
||||
@@ -522,19 +523,6 @@ def draw_progress(
|
||||
ui_bgl.draw_text(text, x, y + 8, 16, color)
|
||||
|
||||
|
||||
def find_and_activate_instancers(
|
||||
obj: bpy.types.Object,
|
||||
) -> Optional[bpy.types.Object]:
|
||||
for ob in bpy.context.visible_objects:
|
||||
if (
|
||||
ob.instance_type == "COLLECTION"
|
||||
and ob.instance_collection
|
||||
and obj.name in ob.instance_collection.objects
|
||||
):
|
||||
utils.activate(ob)
|
||||
return ob
|
||||
|
||||
|
||||
def mouse_raycast(
|
||||
region: bpy.types.Region, rv3d: bpy.types.RegionView3D, mx: int, my: int
|
||||
) -> Tuple[
|
||||
@@ -741,11 +729,9 @@ def deep_ray_cast(ray_origin: Vector, vec: Vector) -> Tuple[
|
||||
def object_in_particle_collection(o: bpy.types.Object) -> bool:
|
||||
"""checks if an object is in a particle system as instance, to not snap to it and not to try to attach material."""
|
||||
for p in bpy.data.particles:
|
||||
if p.render_type == "COLLECTION":
|
||||
if p.instance_collection:
|
||||
for o1 in p.instance_collection.objects:
|
||||
if o1 == o:
|
||||
return True
|
||||
if p.render_type == "COLLECTION" and p.instance_collection:
|
||||
if o in p.instance_collection.objects:
|
||||
return True
|
||||
if p.render_type == "COLLECTION":
|
||||
if p.instance_object == o:
|
||||
return True
|
||||
@@ -774,22 +760,6 @@ def get_node_tree(context: bpy.types.Context) -> bpy.types.NodeTree:
|
||||
return context.scene.compositing_node_group
|
||||
|
||||
|
||||
def assign_node_tree(
|
||||
node_space: bpy.types.SpaceNodeEditor, node_tree: bpy.types.NodeTree
|
||||
) -> None:
|
||||
"""Blender version invariant way to assign a node tree to the current node editor."""
|
||||
if bpy.app.version < (5, 0, 0):
|
||||
node_space.node_tree = node_tree
|
||||
return
|
||||
|
||||
# blender 5.0+
|
||||
# recover the node_group from data and assign it
|
||||
if hasattr(node_space, "node_group"):
|
||||
node_space.node_group = bpy.data.node_groups[node_tree.name]
|
||||
elif hasattr(node_space, "node_tree"):
|
||||
node_space.node_tree = node_tree
|
||||
|
||||
|
||||
class AssetDragOperator(bpy.types.Operator):
|
||||
"""Drag & drop assets into scene. Operator being drawn when dragging asset."""
|
||||
|
||||
@@ -797,9 +767,9 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
bl_label = "BlenderKit asset drag drop"
|
||||
|
||||
asset_search_index: IntProperty(name="Active Index", default=0) # type: ignore
|
||||
drag_length: IntProperty(name="Drag_length", default=0) # type: ignore
|
||||
|
||||
object_name = None
|
||||
active_operator_id = None
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -813,32 +783,28 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
self.hovered_outliner_element: Union[bpy.types.Object, bpy.types.Collection] = (
|
||||
None
|
||||
)
|
||||
self.active_window = None
|
||||
self.active_area = None
|
||||
self.active_region = None
|
||||
|
||||
self.orig_active_object = None
|
||||
self.orig_selected_objects = None
|
||||
self.orig_active_collection = None
|
||||
|
||||
self.downloader = None
|
||||
|
||||
# Mouse tracking variables
|
||||
self.start_mouse_x = None
|
||||
self.start_mouse_y = None
|
||||
self.start_mouse_x = 0
|
||||
self.start_mouse_y = 0
|
||||
|
||||
self.mouse_x = 0
|
||||
self.mouse_y = 0
|
||||
self.mouse_screen_x = 0
|
||||
self.mouse_screen_y = 0
|
||||
self.steps = 0
|
||||
|
||||
# Store the initial active region pointer
|
||||
self.active_region_pointer = None
|
||||
|
||||
# Initialize outliner tracking variables
|
||||
self.hovered_outliner_element = None
|
||||
self.outliner_area = None
|
||||
self.outliner_region = None
|
||||
self.orig_selected_objects = None
|
||||
self.orig_active_object = None
|
||||
self.orig_active_collection = None
|
||||
self.prev_area_type = None
|
||||
|
||||
# Initialize node editor tracking
|
||||
@@ -858,6 +824,8 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
|
||||
self.iname = ""
|
||||
self.drag = False
|
||||
self.steps = 0
|
||||
self.closed_assetbar = False
|
||||
|
||||
def handlers_remove(self) -> None:
|
||||
"""Remove all draw handlers."""
|
||||
@@ -873,11 +841,8 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
self, nodegroup_type: str, editor_type: Optional[str] = None
|
||||
) -> bool:
|
||||
"""Check if a nodegroup of a specific type is compatible with the given editor type."""
|
||||
# Direct matches
|
||||
if nodegroup_type == editor_type:
|
||||
return True
|
||||
# Generic nodegroups can work in any editor
|
||||
elif nodegroup_type is None:
|
||||
# Direct matches, or invalid editor
|
||||
if not nodegroup_type or nodegroup_type == editor_type:
|
||||
return True
|
||||
# Otherwise, not compatible
|
||||
return False
|
||||
@@ -958,7 +923,7 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
|
||||
if obj.type == "MESH":
|
||||
temp_mesh = object_eval.to_mesh()
|
||||
mapping = create_material_mapping(obj, temp_mesh)
|
||||
_mapping = create_material_mapping(obj, temp_mesh)
|
||||
target_slot = temp_mesh.polygons[self.face_index].material_index
|
||||
object_eval.to_mesh_clear()
|
||||
else:
|
||||
@@ -1073,7 +1038,7 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
target_collection = ""
|
||||
|
||||
# Check what type of element we're dropping on
|
||||
element_type = type(self.hovered_outliner_element).__name__
|
||||
_element_type = type(self.hovered_outliner_element).__name__
|
||||
|
||||
# If dropping on a collection, set target_collection parameter
|
||||
if isinstance(self.hovered_outliner_element, bpy.types.Collection):
|
||||
@@ -1480,10 +1445,10 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
|
||||
for window in wins:
|
||||
# first let's test if it's in this window, so we know we shall continue
|
||||
window_x = window.x * self.resolution_factor
|
||||
window_y = window.y * self.resolution_factor
|
||||
window_width = window.width * self.resolution_factor
|
||||
window_height = window.height * self.resolution_factor
|
||||
window_x = window.x
|
||||
window_y = window.y
|
||||
window_width = window.width
|
||||
window_height = window.height
|
||||
if (
|
||||
x < window_x
|
||||
or x > window_x + window_width
|
||||
@@ -1513,7 +1478,6 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
return None
|
||||
|
||||
context = bpy.context
|
||||
scene = context.scene
|
||||
view_layer = context.view_layer
|
||||
selected_objects = context.selected_objects
|
||||
active_object = context.active_object
|
||||
@@ -1630,11 +1594,14 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
):
|
||||
"""Get the active object under the mouse cursor during drag."""
|
||||
|
||||
region_data = None
|
||||
|
||||
for space in active_area.spaces:
|
||||
if space.type == "VIEW_3D":
|
||||
region_data = space.region_3d
|
||||
# precise placement in ortho views, and quad view
|
||||
region_data = viewport_utils.region_data_for_view(active_area, active_region)
|
||||
if region_data is None:
|
||||
for space in active_area.spaces:
|
||||
if space.type == "VIEW_3D":
|
||||
region_data = getattr(space, "region_3d", None)
|
||||
if region_data is not None:
|
||||
break
|
||||
|
||||
# Need to temporarily override context for raycasting
|
||||
if bpy.app.version < (3, 2, 0): # B3.0, B3.1 - custom context override
|
||||
@@ -1643,9 +1610,7 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
"screen": active_window.screen,
|
||||
"area": active_area,
|
||||
"region": active_region,
|
||||
"region_data": active_area.spaces[
|
||||
0
|
||||
].region_3d, # Get region_data from space_data
|
||||
"region_data": region_data,
|
||||
"scene": context.scene,
|
||||
"view_layer": context.view_layer,
|
||||
}
|
||||
@@ -1757,69 +1722,70 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
self.in_node_editor = False
|
||||
self.node_editor_type = None
|
||||
|
||||
def _cleanup_drag(self, ui_props, cls, *, reopen_assetbar: bool = False) -> None:
|
||||
"""Shared teardown: remove handlers, restore cursor, reset drag state."""
|
||||
self.handlers_remove()
|
||||
bpy.context.window.cursor_modal_restore()
|
||||
ui_props.dragging = False
|
||||
if self.closed_assetbar:
|
||||
bpy.ops.view3d.run_assetbar_fix_context(keep_running=True, do_search=False)
|
||||
if reopen_assetbar:
|
||||
bpy.ops.view3d.blenderkit_asset_bar_widget(
|
||||
"INVOKE_REGION_WIN", do_search=False
|
||||
)
|
||||
cls.active_operator_id = None
|
||||
|
||||
def modal(self, context: bpy.types.Context, event: bpy.types.Event) -> Set[str]:
|
||||
cls = type(self)
|
||||
ui_props = bpy.context.window_manager.blenderkitUI
|
||||
|
||||
self.resolution_factor = (
|
||||
bpy.context.preferences.system.pixel_size
|
||||
/ bpy.context.preferences.view.ui_scale
|
||||
)
|
||||
self.mouse_screen_x = int(
|
||||
context.window.x * self.resolution_factor + event.mouse_x
|
||||
)
|
||||
self.mouse_screen_y = int(
|
||||
context.window.y * self.resolution_factor + event.mouse_y
|
||||
)
|
||||
self.mouse_screen_x = int(context.window.x + event.mouse_x)
|
||||
self.mouse_screen_y = int(context.window.y + event.mouse_y)
|
||||
|
||||
# Find the active region under the mouse cursor using actual screen coordinates
|
||||
self.active_window, self.active_area, self.active_region = (
|
||||
self.find_active_region(self.mouse_screen_x, self.mouse_screen_y)
|
||||
found_window, found_area, found_region = self.find_active_region(
|
||||
self.mouse_screen_x, self.mouse_screen_y
|
||||
)
|
||||
if (
|
||||
found_region is not None
|
||||
and found_area is not None
|
||||
and found_window is not None
|
||||
):
|
||||
self.active_window, self.active_area, self.active_region = (
|
||||
found_window,
|
||||
found_area,
|
||||
found_region,
|
||||
)
|
||||
# --- CURSOR VISIBILITY FIX ---
|
||||
if self.active_region is None or self.active_area is None:
|
||||
bpy.context.window.cursor_modal_set("STOP")
|
||||
# bpy.context.window.cursor_modal_set("STOP")
|
||||
bpy.context.window.cursor_modal_restore()
|
||||
return {"PASS_THROUGH"}
|
||||
elif self.drag:
|
||||
|
||||
if self.drag:
|
||||
bpy.context.window.cursor_modal_set("NONE")
|
||||
|
||||
# Convert screen coords (bottom-left) to region-local coords
|
||||
# window.x/y and region.x/y are also in bottom-left coordinate system
|
||||
self.mouse_x = int(
|
||||
self.mouse_screen_x
|
||||
- self.active_window.x * self.resolution_factor
|
||||
- self.active_region.x
|
||||
self.mouse_screen_x - self.active_window.x - self.active_region.x
|
||||
)
|
||||
self.mouse_y = int(
|
||||
self.mouse_screen_y
|
||||
- self.active_window.y * self.resolution_factor
|
||||
- self.active_region.y
|
||||
self.mouse_screen_y - self.active_window.y - self.active_region.y
|
||||
)
|
||||
|
||||
if self.start_mouse_x is None or self.start_mouse_y is None:
|
||||
self.start_mouse_x = self.mouse_x
|
||||
self.start_mouse_y = self.mouse_y
|
||||
|
||||
# --- REDRAW ALL WINDOWS/AREAS FOR MULTI-WINDOW DRAG ---
|
||||
# redraw all windows to update cursor and other elements
|
||||
for window in bpy.context.window_manager.windows:
|
||||
for area in window.screen.areas:
|
||||
area.tag_redraw()
|
||||
|
||||
current_area_type = self.active_area.type if self.active_area else None
|
||||
current_area_type = self.active_area.type
|
||||
|
||||
# Check if we're transitioning out of the outliner
|
||||
if (
|
||||
self.prev_area_type
|
||||
and self.prev_area_type == "OUTLINER"
|
||||
and current_area_type != "OUTLINER"
|
||||
):
|
||||
# If we're leaving the outliner, restore the original selection
|
||||
if self.prev_area_type == "OUTLINER" and current_area_type != "OUTLINER":
|
||||
self.restore_original_selection()
|
||||
|
||||
# shift pressed
|
||||
if event.shift:
|
||||
self.shift_pressed = True
|
||||
else:
|
||||
self.shift_pressed = False
|
||||
self.shift_pressed = event.shift
|
||||
|
||||
# Track if we're in a node editor
|
||||
self._handle_node_editor_type(current_area_type, self.active_area)
|
||||
@@ -1832,12 +1798,8 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
# Store the active region pointer for drawing 2D elements only in this region
|
||||
self.active_region_pointer = self.active_region.as_pointer()
|
||||
|
||||
# Make sure all 3D views get redrawn
|
||||
for area in context.screen.areas:
|
||||
area.tag_redraw()
|
||||
|
||||
# Handle outliner interaction
|
||||
if self.active_area.type == "OUTLINER":
|
||||
if current_area_type == "OUTLINER":
|
||||
self.hovered_outliner_element = self.find_outliner_element_under_mouse()
|
||||
self.outliner_window = self.active_window
|
||||
self.outliner_area = self.active_area
|
||||
@@ -1853,48 +1815,46 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
self.active_region_pointer = context.region.as_pointer()
|
||||
|
||||
# are we dragging already?
|
||||
delta_x = abs(self.start_mouse_x - self.mouse_screen_x)
|
||||
delta_y = abs(self.start_mouse_y - self.mouse_screen_y)
|
||||
if not self.drag and (
|
||||
abs(self.start_mouse_x - self.mouse_x) > DRAG_THRESHOLD
|
||||
or abs(self.start_mouse_y - self.mouse_y) > DRAG_THRESHOLD
|
||||
delta_x > DEFAULT_DRAG_THRESHOLD or delta_y > DEFAULT_DRAG_THRESHOLD
|
||||
):
|
||||
self.drag = True
|
||||
|
||||
if self.drag and ui_props.assetbar_on:
|
||||
# turn off asset bar here, shout start again after finishing drag drop.
|
||||
if self.drag and ui_props.assetbar_on and not self.closed_assetbar:
|
||||
# turn off asset bar here; reopen after placement when we actually dragged
|
||||
ui_props.turn_off = True
|
||||
|
||||
if (
|
||||
event.type == "ESC"
|
||||
or not ui.mouse_in_region(context.region, self.mouse_x, self.mouse_y)
|
||||
) and (not self.drag or self.steps < DEAD_ZONE):
|
||||
# this case is for canceling from inside popup card when there's an escape attempt to close the window
|
||||
return {"PASS_THROUGH"}
|
||||
self.closed_assetbar = True
|
||||
|
||||
if event.type in {"RIGHTMOUSE", "ESC"}:
|
||||
# Restore original selection if we changed it
|
||||
self.restore_original_selection()
|
||||
|
||||
self.handlers_remove()
|
||||
bpy.context.window.cursor_modal_restore()
|
||||
ui_props.dragging = False
|
||||
bpy.ops.view3d.blenderkit_asset_bar_widget(
|
||||
"INVOKE_REGION_WIN", do_search=False
|
||||
)
|
||||
|
||||
self._cleanup_drag(ui_props, cls, reopen_assetbar=True)
|
||||
return {"CANCELLED"}
|
||||
|
||||
self.steps += 1
|
||||
|
||||
if (
|
||||
event.type == "ESC"
|
||||
or not ui.mouse_in_region(context.region, self.mouse_x, self.mouse_y)
|
||||
) and (not self.drag or self.steps < 5):
|
||||
# this case is for canceling from inside popup card when there's an escape attempt to close the window
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
sprops = bpy.context.window_manager.blenderkit_models
|
||||
if event.type == "WHEELUPMOUSE":
|
||||
sprops.offset_rotation_amount += sprops.offset_rotation_step
|
||||
elif event.type == "WHEELDOWNMOUSE":
|
||||
sprops.offset_rotation_amount -= sprops.offset_rotation_step
|
||||
|
||||
if (
|
||||
event.type == "MOUSEMOVE"
|
||||
or event.type == "WHEELUPMOUSE"
|
||||
or event.type == "WHEELDOWNMOUSE"
|
||||
):
|
||||
|
||||
if event.type in {
|
||||
"MOUSEMOVE",
|
||||
"INBETWEEN_MOUSEMOVE",
|
||||
"WHEELUPMOUSE",
|
||||
"WHEELDOWNMOUSE",
|
||||
}:
|
||||
# sometimes active area or region can be None, so we need to check for that
|
||||
if self.active_area is None or self.active_region is None:
|
||||
return {"RUNNING_MODAL"}
|
||||
@@ -1904,11 +1864,7 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
self.has_hit = False
|
||||
|
||||
# Only perform raycasting in 3D view areas
|
||||
if (
|
||||
self.active_region
|
||||
and self.active_area
|
||||
and self.active_area.type == "VIEW_3D"
|
||||
):
|
||||
if current_area_type == "VIEW_3D":
|
||||
# prefetch the drag active object info
|
||||
self.drag_raycast_3d_view(
|
||||
context,
|
||||
@@ -1921,21 +1877,15 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
if self.asset_data["assetType"] in ["model", "printable"]:
|
||||
self.snapped_bbox_min = Vector(self.asset_data["bbox_min"])
|
||||
self.snapped_bbox_max = Vector(self.asset_data["bbox_max"])
|
||||
elif self.active_area.type != "VIEW_3D":
|
||||
elif current_area_type != "VIEW_3D":
|
||||
# In outliner, don't do raycasting, but keep has_hit to avoid errors
|
||||
self.has_hit = False
|
||||
|
||||
if event.type == "LEFTMOUSE" and event.value == "RELEASE":
|
||||
self.mouse_release(context) # Pass context here
|
||||
self.handlers_remove()
|
||||
bpy.context.window.cursor_modal_restore()
|
||||
|
||||
bpy.ops.view3d.run_assetbar_fix_context(keep_running=True, do_search=False)
|
||||
ui_props.dragging = False
|
||||
self.mouse_release(context)
|
||||
self._cleanup_drag(ui_props, cls)
|
||||
return {"FINISHED"}
|
||||
|
||||
self.steps += 1
|
||||
|
||||
# pass event to assetbar so it can close itself
|
||||
if ui_props.assetbar_on and ui_props.turn_off:
|
||||
return {"PASS_THROUGH"}
|
||||
@@ -1946,9 +1896,29 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
# Before registering callbacks, check for canceling situations: login and localdir popups, sculpt popup/switch
|
||||
sr = search.get_search_results()
|
||||
ui_props = bpy.context.window_manager.blenderkitUI
|
||||
if ui_props.dragging:
|
||||
return {"CANCELLED"}
|
||||
cls = type(self)
|
||||
if cls.active_operator_id is not None and cls.active_operator_id != id(self):
|
||||
return {"CANCELLED"}
|
||||
# Acquire drag lock immediately so concurrent invoke paths cannot race while this invoke initializes.
|
||||
ui_props.dragging = True
|
||||
cls.active_operator_id = id(self)
|
||||
self.closed_assetbar = False
|
||||
# Use the asset_search_index parameter passed to the operator, not the global ui_props.active_index
|
||||
# This is critical for multi-window support where active_index is shared across windows
|
||||
self.asset_data = dict(sr[self.asset_search_index])
|
||||
|
||||
# Initialize drag-start coordinates immediately in invoke. If mouse-move
|
||||
# events are sparse (or arrive late), we still compute threshold against
|
||||
# the true click/press origin instead of first modal tick.
|
||||
self.mouse_screen_x = int(context.window.x + event.mouse_x)
|
||||
self.mouse_screen_y = int(context.window.y + event.mouse_y)
|
||||
self.start_mouse_x = self.mouse_screen_x
|
||||
self.start_mouse_y = self.mouse_screen_y
|
||||
# Author assets should not be dragged, cancel immediately
|
||||
if self.asset_data.get("assetType") == "author":
|
||||
return {"CANCELLED"}
|
||||
# add-ons
|
||||
if self.asset_data.get("assetType") == "addon" and not self.asset_data.get(
|
||||
"canDownload"
|
||||
@@ -1959,6 +1929,8 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
bpy.ops.wm.blenderkit_url_dialog(
|
||||
"INVOKE_REGION_WIN", url=url, message=message, link_text=link_text
|
||||
)
|
||||
ui_props.dragging = False
|
||||
cls.active_operator_id = None
|
||||
return {"CANCELLED"}
|
||||
|
||||
if not self.asset_data.get("canDownload"):
|
||||
@@ -1969,6 +1941,8 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
bpy.ops.wm.blenderkit_url_dialog(
|
||||
"INVOKE_REGION_WIN", url=url, message=message, link_text=link_text
|
||||
)
|
||||
ui_props.dragging = False
|
||||
cls.active_operator_id = None
|
||||
return {"CANCELLED"}
|
||||
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
@@ -1982,26 +1956,31 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
bpy.ops.wm.blenderkit_url_dialog(
|
||||
"INVOKE_REGION_WIN", url=url, message=message, link_text=link_text
|
||||
)
|
||||
ui_props.dragging = False
|
||||
cls.active_operator_id = None
|
||||
return {"CANCELLED"}
|
||||
|
||||
if self.asset_data.get("assetType") == "brush":
|
||||
if not (context.sculpt_object or context.image_paint_object):
|
||||
# either switch to sculpt mode and layout automatically or show a popup message
|
||||
if context.active_object and context.active_object.type == "MESH":
|
||||
bpy.ops.object.mode_set(mode="SCULPT")
|
||||
self.mouse_release(context) # does the main job with assets
|
||||
if self.asset_data.get("assetType") == "brush" and not (
|
||||
context.sculpt_object or context.image_paint_object
|
||||
):
|
||||
# either switch to sculpt mode and layout automatically or show a popup message
|
||||
if context.active_object and context.active_object.type == "MESH":
|
||||
bpy.ops.object.mode_set(mode="SCULPT")
|
||||
self.mouse_release(context) # does the main job with assets
|
||||
|
||||
if bpy.data.workspaces.get("Sculpting") is not None:
|
||||
bpy.context.window.workspace = bpy.data.workspaces["Sculpting"]
|
||||
reports.add_report(
|
||||
"Automatically switched to sculpt mode to use brushes."
|
||||
)
|
||||
else:
|
||||
message = "Select a mesh and switch to sculpt or image paint modes to use the brushes."
|
||||
bpy.ops.wm.blenderkit_popup_dialog(
|
||||
"INVOKE_REGION_WIN", message=message, width=500
|
||||
)
|
||||
return {"CANCELLED"}
|
||||
if bpy.data.workspaces.get("Sculpting") is not None:
|
||||
bpy.context.window.workspace = bpy.data.workspaces["Sculpting"]
|
||||
reports.add_report(
|
||||
"Automatically switched to sculpt mode to use brushes."
|
||||
)
|
||||
else:
|
||||
message = "Select a mesh and switch to sculpt or image paint modes to use the brushes."
|
||||
bpy.ops.wm.blenderkit_popup_dialog(
|
||||
"INVOKE_REGION_WIN", message=message, width=500
|
||||
)
|
||||
ui_props.dragging = False
|
||||
cls.active_operator_id = None
|
||||
return {"CANCELLED"}
|
||||
|
||||
# the arguments we pass the the callback
|
||||
args = (self, context)
|
||||
@@ -2044,48 +2023,25 @@ class AssetDragOperator(bpy.types.Operator):
|
||||
# but if RNA Struct fails we are not longer able to remove it, so we log an error and store None
|
||||
self._handlers_universal[space_type] = handler
|
||||
except (AttributeError, TypeError) as e:
|
||||
bk_logger.error(f"Could not register handler for {space_type}: {e}")
|
||||
bk_logger.error("Could not register handler for %s: %s", space_type, e)
|
||||
self._handlers_universal[space_type] = None
|
||||
|
||||
self.mouse_x = 0
|
||||
self.mouse_y = 0
|
||||
self.mouse_screen_x = 0
|
||||
self.mouse_screen_y = 0
|
||||
self.steps = 0
|
||||
self.mouse_screen_x = self.start_mouse_x
|
||||
self.mouse_screen_y = self.start_mouse_y
|
||||
# Store the initial active region pointer
|
||||
self.active_region_pointer = context.region.as_pointer()
|
||||
|
||||
# Initialize outliner tracking variables
|
||||
self.hovered_outliner_element = None
|
||||
self.outliner_area = None
|
||||
self.outliner_region = None
|
||||
self.orig_selected_objects = None
|
||||
self.orig_active_object = None
|
||||
self.orig_active_collection = None
|
||||
self.prev_area_type = context.area.type # Track previous area type
|
||||
|
||||
# Initialize node editor tracking
|
||||
self.in_node_editor = False
|
||||
self.node_editor_type = None
|
||||
|
||||
self.shift_pressed = False
|
||||
|
||||
# Initialize has_hit to False, and set other 3D properties
|
||||
# We'll only use these in 3D views, not in outliner
|
||||
self.has_hit = False
|
||||
self.snapped_location = (0, 0, 0)
|
||||
self.snapped_normal = (0, 0, 1)
|
||||
self.snapped_rotation = (0, 0, 0)
|
||||
self.face_index = 0
|
||||
self.matrix = None
|
||||
|
||||
self.iname = f".{self.asset_data['thumbnail_small']}"
|
||||
self.iname = (self.iname[:63]) if len(self.iname) > 63 else self.iname
|
||||
|
||||
bpy.context.window.cursor_modal_set("NONE")
|
||||
bpy.context.window.cursor_modal_restore()
|
||||
ui_props = bpy.context.window_manager.blenderkitUI
|
||||
ui_props.dragging = True
|
||||
self.drag = False
|
||||
self.steps = 0
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
@@ -2245,7 +2201,7 @@ class DownloadGizmoOperator(BL_UI_OT_draw_operator):
|
||||
self.button_close.set_image_size((button_size, button_size))
|
||||
self.button_close.set_image_position((0, 0))
|
||||
|
||||
directory = paths.get_temp_dir("%s_search" % self.asset_data["assetType"])
|
||||
directory = paths.get_temp_dir(f"{self.asset_data['assetType']}_search")
|
||||
thumbnail_path = os.path.join(directory, self.asset_data["thumbnail_small"])
|
||||
|
||||
self.image.set_image(thumbnail_path)
|
||||
@@ -2296,7 +2252,10 @@ class DownloadGizmoOperator(BL_UI_OT_draw_operator):
|
||||
bk_logger.debug("unregistering class %s", cls)
|
||||
instances_copy = cls.instances.copy()
|
||||
for instance in instances_copy:
|
||||
bk_logger.debug("- class instance %s", instance)
|
||||
try:
|
||||
bk_logger.debug("- class instance %s", instance)
|
||||
except ReferenceError:
|
||||
bk_logger.debug("- class instance <deleted>")
|
||||
try:
|
||||
instance.unregister_handlers(instance.context)
|
||||
except Exception as e:
|
||||
@@ -2407,37 +2366,6 @@ def create_material_mapping(obj, temp_mesh):
|
||||
return mapping
|
||||
|
||||
|
||||
def add_set_material_node(tree):
|
||||
"""Add a Set Material node at the end of the node tree"""
|
||||
# Find output node
|
||||
output_node = None
|
||||
for node in tree.nodes:
|
||||
if node.type == "GROUP_OUTPUT":
|
||||
output_node = node
|
||||
break
|
||||
|
||||
if output_node:
|
||||
# Create Set Material node
|
||||
set_mat_node = tree.nodes.new("GeometryNodeSetMaterial")
|
||||
# Position it before output
|
||||
set_mat_node.location = (output_node.location.x - 200, output_node.location.y)
|
||||
|
||||
# Connect nodes
|
||||
last_geometry_socket = None
|
||||
for source in output_node.inputs:
|
||||
if source.type == "GEOMETRY":
|
||||
if source.is_linked:
|
||||
last_geometry_socket = source.links[0].from_socket
|
||||
break
|
||||
|
||||
if last_geometry_socket:
|
||||
tree.links.new(last_geometry_socket, set_mat_node.inputs["Geometry"])
|
||||
tree.links.new(set_mat_node.outputs["Geometry"], output_node.inputs[0])
|
||||
|
||||
return set_mat_node
|
||||
return None
|
||||
|
||||
|
||||
classes = (
|
||||
AssetDragOperator,
|
||||
DownloadGizmoOperator,
|
||||
|
||||
Reference in New Issue
Block a user