diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index 3726a3c2a0a83234d4ca9df9266c62e81550368f..d38f185b57dd0134e2d04d8c3e2dd81d892ade87 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -199,37 +199,7 @@ thumbnail_resolutions = ( ) -def get_upload_asset_type(self): - typemapper = { - BlenderKitModelUploadProps: 'model', - BlenderKitSceneUploadProps: 'scene', - BlenderKitMaterialUploadProps: 'material', - BlenderKitBrushUploadProps: 'brush' - } - asset_type = typemapper[type(self)] - return asset_type - - -def get_subcategory_enums(self, context): - wm = bpy.context.window_manager - asset_type = get_upload_asset_type(self) - items = [] - if self.category != '': - asset_categories = categories.get_category(wm['bkit_categories'], cat_path=(asset_type, self.category,)) - for c in asset_categories['children']: - items.append((c['slug'], c['name'], c['description'])) - return items - - -def get_category_enums(self, context): - wm = bpy.context.window_manager - asset_type = get_upload_asset_type(self) - asset_categories = categories.get_category(wm['bkit_categories'], cat_path=(asset_type,)) - items = [] - for c in asset_categories['children']: - items.append((c['slug'], c['name'], c['description'])) - return items def switch_search_results(self, context): @@ -278,6 +248,8 @@ def asset_type_callback(self, context): return items + + class BlenderKitUIProps(PropertyGroup): down_up: EnumProperty( name="Download vs Upload", @@ -490,7 +462,7 @@ class BlenderKitCommonSearchProps(object): update=search.search_update, ) - #resolution download/import settings + # resolution download/import settings resolution: EnumProperty( name="Max resolution", description="Cap texture sizes in the file to this resolution", @@ -509,9 +481,9 @@ class BlenderKitCommonSearchProps(object): ) unpack_files: BoolProperty(name="Unpack Files", - description="Unpack files after download", - default=True - ) + description="Unpack files after download", + default=True + ) def name_update(self, context): @@ -667,12 +639,12 @@ class BlenderKitCommonUploadProps(object): category: EnumProperty( name="Category", description="main category to put into", - items=get_category_enums + items=categories.get_category_enums ) subcategory: EnumProperty( name="Subcategory", description="main category to put into", - items=get_subcategory_enums + items=categories.get_subcategory_enums ) diff --git a/blenderkit/categories.py b/blenderkit/categories.py index 8983e3add3df053d482faac06cece43bf77ff307..6983d4d6b2953b25e5abaf44cdd7ed5ff7d26ab9 100644 --- a/blenderkit/categories.py +++ b/blenderkit/categories.py @@ -65,6 +65,32 @@ def filter_categories(categories): filter_category(category) +def get_category_path(categories, category): + '''finds the category in all possible subcategories and returns the path to it''' + category_path = [] + check_categories = categories[:] + parents = {} + while len(check_categories) > 0: + ccheck = check_categories.pop() + # print(ccheck['name']) + if not ccheck.get('children'): + continue + + for ch in ccheck['children']: + # print(ch['name']) + parents[ch['slug']] = ccheck['slug'] + + if ch['slug'] == category: + category_path = [ch['slug']] + slug = ch['slug'] + while parents.get(slug): + slug = parents.get(slug) + + category_path.insert(0, slug) + return category_path + check_categories.append(ch) + + def get_category(categories, cat_path=()): for category in cat_path: for c in categories: @@ -74,6 +100,43 @@ def get_category(categories, cat_path=()): return (c) break; +def get_upload_asset_type(self): + typemapper = { + bpy.types.Object.blenderkit: 'model', + bpy.types.Scene.blenderkit: 'scene', + bpy.types.Material.blenderkit: 'material', + bpy.types.Brush.blenderkit: 'brush' + } + asset_type = typemapper[type(self)] + return asset_type + + + + +def get_category_enums(self, context): + wm = bpy.context.window_manager + props = bpy.context.scene.blenderkitUI + asset_type = props.asset_type.lower() + # asset_type = self.asset_type#get_upload_asset_type(self) + asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type,)) + items = [] + for c in asset_categories['children']: + items.append((c['slug'], c['name'], c['description'])) + return items + +def get_subcategory_enums(self, context): + wm = bpy.context.window_manager + props = bpy.context.scene.blenderkitUI + asset_type = props.asset_type.lower() +# asset_type = self.asset_type#get_upload_asset_type(self) + # asset_type = get_upload_asset_type(self) + items = [] + if self.category != '': + asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type, self.category,)) + for c in asset_categories['children']: + items.append((c['slug'], c['name'], c['description'])) + + return items def copy_categories(): # this creates the categories system on only diff --git a/blenderkit/ui.py b/blenderkit/ui.py index 38aa46ac1a883a09ff97feca5678cd4dedf6e6d2..71e4b06f0e2564f97abb46953a65210d856c87e1 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -30,8 +30,9 @@ if "bpy" in locals(): bg_blender = importlib.reload(bg_blender) colors = importlib.reload(colors) tasks_queue = importlib.reload(tasks_queue) + tasks_queue = importlib.reload(ui_panels) else: - from blenderkit import paths, ratings, utils, search, upload, ui_bgl, download, bg_blender, colors, tasks_queue + from blenderkit import paths, ratings, utils, search, upload, ui_bgl, download, bg_blender, colors, tasks_queue, ui_panels import bpy @@ -1920,6 +1921,7 @@ def register_ui(): wm = bpy.context.window_manager km = wm.keyconfigs.addon.keymaps['Window'] kmi = km.keymap_items.new(ratings.FastRateMenu.bl_idname, 'F', 'PRESS', ctrl=False, shift=False) + kmi = km.keymap_items.new(upload.FastCategory.bl_idname, 'F', 'PRESS', ctrl=True, shift=False) addon_keymapitems.append(kmi) diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index a1f990cb22e78de44e1fefe9a933dce4b720795b..b7c9884c331390833072e8b4428cae2db59a7f72 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -46,6 +46,7 @@ from bpy.props import ( import bpy import os import random +import blenderkit # this was moved to separate interface: @@ -415,7 +416,7 @@ class NODE_PT_blenderkit_material_properties(Panel): draw_panel_material_ratings(self, context) layout.label(text='Asset tools:') - draw_asset_context_menu(self, context, ad, from_panel = True) + draw_asset_context_menu(self, context, ad, from_panel=True) # if 'rig' in ad['tags']: # # layout.label(text = 'can make proxy') # layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy') @@ -1147,7 +1148,6 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False): if from_panel: # Called from addon panel - if asset_data.get('resolution'): op = col.operator('scene.blenderkit_download', text='Replace asset resolution') op.asset_base_id = asset_data['assetBaseId'] @@ -1162,7 +1162,7 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False): op.model_location = aob.location op.model_rotation = aob.rotation_euler op.target_object = aob.name - op.material_target_slot = aob.active_material_index + op.material_target_slot = aob.active_material_index op.replace_resolution = True op.invoke_resolution = True op.max_resolution = asset_data.get('max_resolution', @@ -1182,8 +1182,8 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False): op.model_location = o.location op.model_rotation = o.rotation_euler else: - op.model_location = (0,0,0) - op.model_rotation = (0,0,0) + op.model_location = (0, 0, 0) + op.model_rotation = (0, 0, 0) op.max_resolution = asset_data.get('max_resolution', 0) # str(utils.get_param(asset_data, 'textureResolutionMax')) @@ -1235,6 +1235,9 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False): op.asset_id = asset_data['id'] + + + # def draw_asset_resolution_replace(self, context, resolution): # layout = self.layout # ui_props = bpy.context.scene.blenderkitUI @@ -1286,7 +1289,7 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu): # sr = bpy.context.scene['search results'] sr = bpy.context.scene['search results'] asset_data = sr[ui_props.active_index] - draw_asset_context_menu(self, context, asset_data, from_panel = False) + draw_asset_context_menu(self, context, asset_data, from_panel=False) class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu): diff --git a/blenderkit/upload.py b/blenderkit/upload.py index c789313d44a130fd4078b83070f24942ba03c0d1..f7d4be4879411939a181e820805f785e2dcfb3f5 100644 --- a/blenderkit/upload.py +++ b/blenderkit/upload.py @@ -32,9 +32,10 @@ if "bpy" in locals(): overrides = reload(overrides) colors = reload(colors) rerequests = reload(rerequests) + categories = reload(categories) else: from blenderkit import asset_inspector, paths, utils, bg_blender, autothumb, version_checker, search, ui_panels, ui, \ - overrides, colors, rerequests + overrides, colors, rerequests, categories import tempfile, os, subprocess, json, re @@ -449,6 +450,118 @@ def get_upload_data(self, context, asset_type): return export_data, upload_data, eval_path_computing, eval_path_state, eval_path, props +def category_change_thread(asset_id, category, api_key): + upload_data = { + "category": category + } + url = paths.get_api_url() + 'assets/' + str(asset_id) + '/' + headers = utils.get_headers(api_key) + try: + r = rerequests.patch(url, json=upload_data, headers=headers, verify=True) # files = files, + except requests.exceptions.RequestException as e: + print(e) + return {'CANCELLED'} + return {'FINISHED'} + + + +# class OBJECT_MT_blenderkit_fast_category_menu(bpy.types.Menu): +# bl_label = "Fast category change" +# bl_idname = "OBJECT_MT_blenderkit_fast_category_menu" +# +# def draw(self, context): +# layout = self.layout +# ui_props = context.scene.blenderkitUI +# +# # sr = bpy.context.scene['search results'] +# sr = bpy.context.scene['search results'] +# asset_data = sr[ui_props.active_index] +# categories = bpy.context.window_manager['bkit_categories'] +# wm = bpy.context.win +# for c in categories: +# if c['name'].lower() == asset_data['assetType']: +# for ch in c['children']: +# op = layout.operator('wm.blenderkit_fast_category', text = ch['name']) +# op = layout.operator('wm.blenderkit_fast_category', text = ch['name']) + + +class FastCategory(bpy.types.Operator): + """Fast change of the category of object directly in asset bar.""" + bl_idname = "wm.blenderkit_fast_category" + bl_label = "Update categories" + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + + category: EnumProperty( + name="Category", + description="main category to put into", + items=categories.get_category_enums + ) + subcategory: EnumProperty( + name="Subcategory", + description="main category to put into", + items=categories.get_subcategory_enums + ) + + asset_id: StringProperty( + name="Asset Base Id", + description="Unique name of the asset (hidden)", + default="") + + @classmethod + def poll(cls, context): + scene = bpy.context.scene + ui_props = scene.blenderkitUI + return ui_props.active_index > -1 + + def draw(self, context): + layout = self.layout + # col = layout.column() + layout.label(text=self.message) + row = layout.row() + # col = row.column() + # layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0) + # col.prop(self, 'category') + + layout.prop(self, 'category')#, expand = True) + props = bpy.context.scene.blenderkitUI + if props.asset_type == 'MODEL': # by now block this for other asset types. + # col = row.column() + layout.prop(self, 'subcategory') + # layout.prop(self, 'subcategory', expand = True) + + def execute(self, context): + user_preferences = bpy.context.preferences.addons['blenderkit'].preferences + props = bpy.context.scene.blenderkitUI + if props.asset_type == 'MODEL': + category = self.subcategory + else: + category = self.category + thread = threading.Thread(target=category_change_thread, + args=(self.asset_id, category, user_preferences.api_key)) + thread.start() + return {'FINISHED'} + + def invoke(self, context, event): + scene = bpy.context.scene + ui_props = scene.blenderkitUI + if ui_props.active_index > -1: + sr = bpy.context.scene['search results'] + asset_data = dict(sr[ui_props.active_index]) + self.asset_id = asset_data['id'] + self.asset_type = asset_data['assetType'] + cat_path = categories.get_category_path(bpy.context.window_manager['bkit_categories'], + asset_data['category']) + try: + if len(cat_path) > 1: + self.category = cat_path[1] + if len(cat_path) > 2: + self.subcategory = cat_path[2] + except Exception as e: + print(e) + self.message = f"Recategorize asset {asset_data['name']}" + wm = context.window_manager + return wm.invoke_props_dialog(self) + def verification_status_change_thread(asset_id, state, api_key): upload_data = { "verificationStatus": state @@ -890,11 +1003,15 @@ class AssetVerificationStatusChange(Operator): def register_upload(): bpy.utils.register_class(UploadOperator) + # bpy.utils.register_class(FastCategoryMenu) + bpy.utils.register_class(FastCategory) bpy.utils.register_class(AssetDebugPrint) bpy.utils.register_class(AssetVerificationStatusChange) def unregister_upload(): bpy.utils.unregister_class(UploadOperator) + # bpy.utils.unregister_class(FastCategoryMenu) + bpy.utils.unregister_class(FastCategory) bpy.utils.unregister_class(AssetDebugPrint) bpy.utils.unregister_class(AssetVerificationStatusChange) diff --git a/blenderkit/utils.py b/blenderkit/utils.py index d24272f91730bac57deb2adc09545e60842c5f4e..96b547b12392ea2c3b5adef6562037bde2d78f17 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -408,7 +408,6 @@ def delete_hierarchy(ob): obs = get_hierarchy(ob) bpy.ops.object.delete({"selected_objects": obs}) - def get_bounds_snappable(obs, use_modifiers=False): # progress('getting bounds of object(s)') parent = obs[0]