2025-07-01
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
# #### 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 #####
|
||||
|
||||
from bpy.types import Operator
|
||||
from bpy.props import StringProperty
|
||||
import bpy.utils.previews
|
||||
import bmesh
|
||||
|
||||
from ..modules.poliigon_core.multilingual import _t
|
||||
from ..toolbox import get_context
|
||||
from .. import reporting
|
||||
|
||||
|
||||
class POLIIGON_OT_select(Operator):
|
||||
bl_idname = "poliigon.poliigon_select"
|
||||
bl_label = ""
|
||||
bl_description = _t("Select Model")
|
||||
bl_options = {"REGISTER", "INTERNAL", "UNDO"}
|
||||
|
||||
tooltip: StringProperty(options={"HIDDEN"}) # noqa: F821
|
||||
mode: StringProperty(options={"HIDDEN"}) # noqa: F821
|
||||
data: StringProperty(options={"HIDDEN"}) # noqa: F821
|
||||
|
||||
@staticmethod
|
||||
def init_context(addon_version: str) -> None:
|
||||
"""Called from operators.py to init global addon context."""
|
||||
|
||||
global cTB
|
||||
cTB = get_context(addon_version)
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, properties):
|
||||
return properties.tooltip
|
||||
|
||||
def select_faces(self, context) -> None:
|
||||
"""Selects all faces which have imported material assigned."""
|
||||
|
||||
self.deselect(context)
|
||||
|
||||
obj = context.active_object
|
||||
idx_mat = int(self.data)
|
||||
# #### vMat = obj.material_slots[i].material
|
||||
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
|
||||
mesh = obj.data
|
||||
bm = bmesh.from_edit_mesh(mesh)
|
||||
for _face in bm.faces:
|
||||
_face.select = 0
|
||||
|
||||
obj.active_material_index = idx_mat
|
||||
bpy.ops.object.material_slot_select()
|
||||
|
||||
def select_object(self, context) -> None:
|
||||
"""Selects an object by name."""
|
||||
|
||||
self.deselect(context)
|
||||
obj = context.scene.objects[self.data]
|
||||
try:
|
||||
obj.select_set(True)
|
||||
except RuntimeError:
|
||||
pass # Might not be in view layer
|
||||
|
||||
def select_sets(self, context) -> None:
|
||||
"""TODO(Andreas): Really not sure what this is.
|
||||
What does it do? And for what purpose?
|
||||
"""
|
||||
|
||||
parts_data = self.data.split("@")
|
||||
self.deselect(context)
|
||||
try:
|
||||
context.scene.objects[parts_data[1]].select_set(1)
|
||||
except RuntimeError:
|
||||
pass # Might not be in view layer
|
||||
|
||||
def select_model(self, context) -> None:
|
||||
"""Selects all objects belonging to an imported Model asset."""
|
||||
|
||||
if not context.mode == "OBJECT":
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
|
||||
self.deselect(context)
|
||||
objs_to_select = []
|
||||
|
||||
key = self.data
|
||||
for obj in context.scene.objects:
|
||||
split = obj.name.rsplit("_")[0]
|
||||
|
||||
# For instance collections
|
||||
if split == key and obj.instance_type == "COLLECTION":
|
||||
objs_to_select.append(obj)
|
||||
# For empty parents
|
||||
ref_key = key + "_empty"
|
||||
if obj.name.lower().startswith(ref_key.lower()):
|
||||
objs_to_select.append(obj)
|
||||
# For the objects within the empty tree
|
||||
if key in obj.poliigon.split(";")[-1]:
|
||||
objs_to_select.append(obj)
|
||||
|
||||
for _obj in objs_to_select:
|
||||
try:
|
||||
_obj.select_set(True)
|
||||
except RuntimeError:
|
||||
pass # Might not be in view layer
|
||||
|
||||
def select_objects_by_texture(self, context) -> None:
|
||||
"""Selects all objects which have a given Texture asset assigned."""
|
||||
|
||||
mat = bpy.data.materials[self.data]
|
||||
objs = [_obj
|
||||
for _obj in context.scene.objects
|
||||
if _obj.active_material == mat]
|
||||
|
||||
if len(objs) == 1:
|
||||
self.deselect(context)
|
||||
try:
|
||||
objs[0].select_set(True)
|
||||
except RuntimeError:
|
||||
pass # Might not be in view layer
|
||||
|
||||
else:
|
||||
# TODO(Andreas): Looks like this branch is never used.
|
||||
# This operator seems to be only used in "model"
|
||||
# mode.
|
||||
# For sure the name access on our object list is a
|
||||
# bug.
|
||||
reporting.capture_message(
|
||||
"reached_legacy_f_DropdownSelect", objs.name)
|
||||
return {"FINISHED"}
|
||||
|
||||
@reporting.handle_operator()
|
||||
def execute(self, context):
|
||||
# TODO(Andreas): addon seems to use "mode == model", only
|
||||
if self.mode == "faces":
|
||||
self.select_faces(context)
|
||||
elif self.mode == "object":
|
||||
self.select_object(context)
|
||||
# TODO(Andreas): Seems odd to have this one data comparison in between
|
||||
# the mode ones...
|
||||
elif "@" in self.data:
|
||||
self.select_sets(context)
|
||||
elif self.mode == "model":
|
||||
self.select_model(context)
|
||||
elif self.mode == "mat_objs":
|
||||
self.select_objects_by_texture(context)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
def deselect(self, context):
|
||||
"""Deselects objects in a lower api, faster, context-invaraint way."""
|
||||
for obj in context.scene.collection.all_objects:
|
||||
try:
|
||||
obj.select_set(False)
|
||||
except RuntimeError:
|
||||
pass # Might not be in view layer
|
||||
Reference in New Issue
Block a user