diff options
author | Vilem Duha <vilem.duha@gmail.com> | 2021-07-27 00:08:13 +0300 |
---|---|---|
committer | Vilem Duha <vilem.duha@gmail.com> | 2021-07-27 00:08:13 +0300 |
commit | 69ad4c43d004c9788ba98e75ade02097284a25f9 (patch) | |
tree | bc054237f00dc627d40aef9f03b125cce3cba464 | |
parent | 0d6b2e8767fdec2cb77e1a9ae92003a496b01837 (diff) |
BlenderKit: optimize search
quite a large overhaul of how search results are loaded.
this saves time due to not closing the session and enabling small previews to be first.
Also use the dict_param paraameter so that the results responses are a bit smaller.
-rw-r--r-- | blenderkit/__init__.py | 2 | ||||
-rw-r--r-- | blenderkit/asset_bar_op.py | 2 | ||||
-rw-r--r-- | blenderkit/search.py | 220 | ||||
-rw-r--r-- | blenderkit/thumbnails/thumbnail_notready.jpg | bin | 3663 -> 2999 bytes | |||
-rw-r--r-- | blenderkit/ui.py | 69 | ||||
-rw-r--r-- | blenderkit/ui_bgl.py | 12 | ||||
-rw-r--r-- | blenderkit/ui_panels.py | 9 | ||||
-rw-r--r-- | blenderkit/utils.py | 12 |
8 files changed, 174 insertions, 152 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index 574349b1..ec2268dc 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -1704,7 +1704,7 @@ class BlenderKitAddonPreferences(AddonPreferences): max_assetbar_rows: IntProperty(name="Max Assetbar Rows", description="max rows of assetbar in the 3D view", default=1, - min=0, + min=1, max=20) thumb_size: IntProperty(name="Assetbar thumbnail Size", default=96, min=-1, max=256) diff --git a/blenderkit/asset_bar_op.py b/blenderkit/asset_bar_op.py index 19f51682..8727698d 100644 --- a/blenderkit/asset_bar_op.py +++ b/blenderkit/asset_bar_op.py @@ -518,7 +518,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator): self.active_index = widget.search_index self.draw_tooltip = True - self.tooltip = asset_data['tooltip'] + # self.tooltip = asset_data['tooltip'] ui_props = scene.blenderkitUI ui_props.active_index = widget.search_index +self.scroll_offset diff --git a/blenderkit/search.py b/blenderkit/search.py index ed295e79..6bbbac7f 100644 --- a/blenderkit/search.py +++ b/blenderkit/search.py @@ -52,7 +52,6 @@ import urllib import queue import logging - bk_logger = logging.getLogger('blenderkit') search_start_time = 0 @@ -77,9 +76,12 @@ def check_errors(rdata): search_threads = [] -thumb_sml_download_threads = {} -thumb_full_download_threads = {} +thumb_workers_sml = [] +thumb_workers_full = [] +thumb_sml_download_threads = queue.Queue() +thumb_full_download_threads = queue.Queue() reports_queue = queue.Queue() +all_thumbs_loaded = True rtips = ['Click or drag model or material in scene to link/append ', "Please rate responsively and plentifully. This helps us distribute rewards to the authors.", @@ -282,7 +284,7 @@ def parse_result(r): if r['available_resolutions']: # should check only for non-empty sequences r['max_resolution'] = max(r['available_resolutions']) - tooltip = generate_tooltip(r) + # tooltip = generate_tooltip(r) # for some reason, the id was still int on some occurances. investigate this. r['author']['id'] = str(r['author']['id']) @@ -290,13 +292,13 @@ def parse_result(r): # so blender's data is same as on server. asset_data = {'thumbnail': tname, 'thumbnail_small': small_tname, - 'tooltip': tooltip, + # 'tooltip': tooltip, } asset_data['downloaded'] = 0 # parse extra params needed for blender here - params = utils.params_to_dict(r['parameters']) + params = r['dictParameters']#utils.params_to_dict(r['parameters']) if asset_type == 'model': if params.get('boundBoxMinX') != None: @@ -343,7 +345,6 @@ def parse_result(r): # @bpy.app.handlers.persistent def search_timer(): - # this makes a first search after opening blender. showing latest assets. # utils.p('timer search') # utils.p('start search timer') @@ -371,6 +372,19 @@ def search_timer(): # check_clipboard() + # finish loading thumbs from queues + global all_thumbs_loaded + if not all_thumbs_loaded: + ui_props = bpy.context.scene.blenderkitUI + search_name = f'bkit {ui_props.asset_type.lower()} search' + wm = bpy.context.window_manager + if wm.get(search_name) is not None: + all_loaded = True + for ri, r in enumerate(wm[search_name]): + if not r.get('thumb_small_loaded'): + all_loaded = all_loaded and load_preview(r, ri) + all_thumbs_loaded = all_loaded + global search_threads if len(search_threads) == 0: # utils.p('end search timer') @@ -384,6 +398,8 @@ def search_timer(): return 0.5 + + for thread in search_threads: # TODO this doesn't check all processes when one gets removed, # but most of the time only one is running anyway @@ -417,18 +433,16 @@ def search_timer(): rdata = thread[0].result - - ok, error = check_errors(rdata) if ok: ui_props = bpy.context.scene.blenderkitUI - orig_len = len(result_field) + for ri, r in enumerate(rdata['results']): asset_data = parse_result(r) if asset_data != None: result_field.append(asset_data) - load_preview(asset_data,ri + orig_len) + all_thumbs_loaded = all_thumbs_loaded and load_preview(asset_data, ri + orig_len) # Get ratings from BlenderKit server user_preferences = bpy.context.preferences.addons['blenderkit'].preferences @@ -437,13 +451,14 @@ def search_timer(): if utils.profile_is_validator(): for r in rdata['results']: if ratings_utils.get_rating_local(asset_data['id']) is None: - rating_thread = threading.Thread(target=ratings_utils.get_rating, args=([r['id'], headers]), daemon=True) + rating_thread = threading.Thread(target=ratings_utils.get_rating, args=([r['id'], headers]), + daemon=True) rating_thread.start() wm[search_name] = result_field wm['search results'] = result_field - #rdata=['results']=[] + # rdata=['results']=[] wm[search_name + ' orig'] = rdata wm['search results orig'] = rdata @@ -456,7 +471,7 @@ def search_timer(): tasks_queue.add_task((ui.add_report, ('No matching results found.',))) # undo push # bpy.ops.wm.undo_push_context(message='Get BlenderKit search') - #show asset bar automatically, but only on first page - others are loaded also when asset bar is hidden. + # show asset bar automatically, but only on first page - others are loaded also when asset bar is hidden. if not ui_props.assetbar_on and not thread[0].params.get('get_next'): bpy.ops.object.run_assetbar_fix_context() @@ -469,9 +484,11 @@ def search_timer(): # print('finished search thread') mt('preview loading finished') # utils.p('end search timer') - + if not all_thumbs_loaded: + return .1 return .3 + def load_preview(asset, index): scene = bpy.context.scene # FIRST START SEARCH @@ -479,11 +496,13 @@ def load_preview(asset, index): directory = paths.get_temp_dir('%s_search' % props.asset_type.lower()) s = bpy.context.scene results = bpy.context.window_manager.get('search results') - + loaded = True tpath = os.path.join(directory, asset['thumbnail_small']) - if not asset['thumbnail_small']: - tpath = paths.get_addon_thumbnail_path('thumbnail_not_available.jpg') + if not asset['thumbnail_small'] or not os.path.exists(tpath): + # tpath = paths.get_addon_thumbnail_path('thumbnail_notready.jpg') + asset['thumb_small_loaded'] = False + loaded = False iname = utils.previmg_name(index) @@ -492,14 +511,16 @@ def load_preview(asset, index): if img is None: if not os.path.exists(tpath): - return + return False img = bpy.data.images.load(tpath) img.name = iname elif img.filepath != tpath: if not os.path.exists(tpath): - return + #unload loaded previews from previous results + bpy.data.images.remove(img) + return False # had to add this check for autopacking files... - if img.packed_file is not None: + if bpy.data.use_autopack and img.packed_file is not None: img.unpack(method='USE_ORIGINAL') img.filepath = tpath img.reload() @@ -508,6 +529,8 @@ def load_preview(asset, index): image_utils.set_colorspace(img, 'Non-Color') else: image_utils.set_colorspace(img, 'sRGB') + asset['thumb_small_loaded'] = True + return loaded def load_previews(): @@ -521,7 +544,7 @@ def load_previews(): if results is not None: i = 0 for r in results: - load_preview(r,i) + load_preview(r, i) i += 1 @@ -635,14 +658,47 @@ def generate_author_textblock(adata): t = writeblockm(t, adata, key='aboutMe', pretext='', width=col_w) return t +def download_image(session, url, filepath): + r = None + try: + r = session.get(url, stream=False) + except Exception as e: + bk_logger.error('Thumbnail download failed') + bk_logger.error(str(e)) + if r and r.status_code == 200: + with open(filepath, 'wb') as f: + f.write(r.content) + +def thumb_download_worker(queue_sml, queue_full): + # print('thumb downloader', self.url) + # utils.p('start thumbdownloader thread') + while 1: + session = None + #start a session only for single search usually. + if not queue_sml.empty() or not queue_full.empty(): + session = requests.Session() + + while not queue_sml.empty(): + url, filepath = queue_sml.get() + download_image(session,url, filepath) + exit_full = False + # download full resolution image, but only if no small thumbs are waiting. + while not queue_full.empty() and queue_sml.empty(): + url, filepath = queue_full.get() + download_image(session,url, filepath) + + if queue_sml.empty() and queue_full.empty(): + if session is not None: + session.close() + time.sleep(.5) class ThumbDownloader(threading.Thread): - query = None - def __init__(self, url, path): + def __init__(self, url, path, session): super(ThumbDownloader, self).__init__() self.url = url self.path = path + self.session = session self._stop_event = threading.Event() def stop(self): @@ -656,7 +712,7 @@ class ThumbDownloader(threading.Thread): # utils.p('start thumbdownloader thread') r = None try: - r = requests.get(self.url, stream=False) + r = self.session.get(self.url, stream=False) except Exception as e: bk_logger.error('Thumbnail download failed') bk_logger.error(str(e)) @@ -670,7 +726,6 @@ class ThumbDownloader(threading.Thread): # utils.p('end thumbdownloader thread') - def write_gravatar(a_id, gravatar_path): ''' Write down gravatar path, as a result of thread-based gravatar image download. @@ -693,14 +748,14 @@ def fetch_gravatar(adata): ''' # utils.p('fetch gravatar') - #fetch new avatars if available already + # fetch new avatars if available already if adata.get('avatar128') is not None: - avatar_path = paths.get_temp_dir(subdir='bkit_g/') + adata['id']+ '.jpg' + avatar_path = paths.get_temp_dir(subdir='bkit_g/') + adata['id'] + '.jpg' if os.path.exists(avatar_path): tasks_queue.add_task((write_gravatar, (adata['id'], avatar_path))) return; - url= paths.get_bkit_url() + adata['avatar128'] + url = paths.get_bkit_url() + adata['avatar128'] r = rerequests.get(url, stream=False) # print(r.body) if r.status_code == 200: @@ -714,7 +769,7 @@ def fetch_gravatar(adata): utils.p('avatar for author not available.') return - #older gravatar code + # older gravatar code if adata.get('gravatarHash') is not None: gravatar_path = paths.get_temp_dir(subdir='bkit_g/') + adata['gravatarHash'] + '.jpg' @@ -824,6 +879,7 @@ def query_to_url(query={}, params={}): requeststring += '+' requeststring += q + ':' + str(query[q]).lower() + # add dict_parameters to make results smaller # result ordering: _score - relevance, score - BlenderKit score order = [] if params['free_first']: @@ -844,8 +900,9 @@ def query_to_url(query={}, params={}): order.append('-score,_score') else: order.append('_score') - if requeststring.find('+order:')==-1: + if requeststring.find('+order:') == -1: requeststring += '+order:' + ','.join(order) + requeststring += '&dict_parameters=1' requeststring += '&page_size=' + str(params['page_size']) requeststring += '&addon_version=%s' % params['addon_version'] @@ -882,7 +939,7 @@ class Searcher(threading.Thread): return self._stop_event.is_set() def run(self): - global reports_queue + global reports_queue, thumb_sml_download_threads, thumb_full_download_threads maxthreads = 50 query = self.query @@ -912,7 +969,7 @@ class Searcher(threading.Thread): try: rdata = r.json() except Exception as e: - if hasattr(r,'text'): + if hasattr(r, 'text'): error_description = parse_html_formated_error(r.text) reports_queue.put(error_description) tasks_queue.add_task((ui.add_report, (error_description, 10, colors.RED))) @@ -987,62 +1044,21 @@ class Searcher(threading.Thread): # we can also prepend previous results. These have downloaded thumbnails already... self.result = rdata - # with open(json_filepath, 'w', encoding = 'utf-8') as outfile: - # json.dump(rdata, outfile, ensure_ascii=False, indent=4) - - killthreads_sml = [] - for k in thumb_sml_download_threads.keys(): - if k not in thumb_small_filepaths: - killthreads_sml.append(k) # do actual killing here? - - killthreads_full = [] - for k in thumb_full_download_threads.keys(): - if k not in thumb_full_filepaths: - killthreads_full.append(k) # do actual killing here? - # TODO do the killing/ stopping here. remember threads might have finished inbetween. if self.stopped(): utils.p('stopping search : ' + str(query)) # utils.p('end search thread') - return # this loop handles downloading of small thumbnails for imgpath, url in sml_thbs: - if imgpath not in thumb_sml_download_threads and not os.path.exists(imgpath): - thread = ThumbDownloader(url, imgpath) - # thread = threading.Thread(target=download_thumbnail, args=([url, imgpath]), - # daemon=True) - thread.start() - thumb_sml_download_threads[imgpath] = thread - # threads.append(thread) - - if len(thumb_sml_download_threads) > maxthreads: - while len(thumb_sml_download_threads) > maxthreads: - threads_copy = thumb_sml_download_threads.copy() # because for loop can erase some of the items. - for tk, thread in threads_copy.items(): - if not thread.is_alive(): - thread.join() - # utils.p(x) - del (thumb_sml_download_threads[tk]) - # utils.p('fetched thumbnail ', i) - i += 1 + if not os.path.exists(imgpath): + thumb_sml_download_threads.put((url, imgpath)) + if self.stopped(): utils.p('stopping search : ' + str(query)) # utils.p('end search thread') - return - idx = 0 - while len(thumb_sml_download_threads) > 0: - threads_copy = thumb_sml_download_threads.copy() # because for loop can erase some of the items. - for tk, thread in threads_copy.items(): - if not thread.is_alive(): - thread.join() - try: - del (thumb_sml_download_threads[tk]) - except Exception as e: - print(e) - i += 1 if self.stopped(): # utils.p('end search thread') @@ -1051,13 +1067,11 @@ class Searcher(threading.Thread): return # start downloading full thumbs in the end + tsession = requests.Session() + for imgpath, url in full_thbs: - if imgpath not in thumb_full_download_threads and not os.path.exists(imgpath): - thread = ThumbDownloader(url, imgpath) - # thread = threading.Thread(target=download_thumbnail, args=([url, imgpath]), - # daemon=True) - thread.start() - thumb_full_download_threads[imgpath] = thread + if not os.path.exists(imgpath): + thumb_full_download_threads.put((url, imgpath)) # utils.p('end search thread') mt('thumbnails finished') @@ -1067,7 +1081,7 @@ def build_query_common(query, props): query_common = {} if props.search_keywords != '': # keywords = urllib.parse.urlencode(props.search_keywords) - keywords = props.search_keywords.replace('&','%26') + keywords = props.search_keywords.replace('&', '%26') query_common["query"] = keywords if props.search_verification_status != 'ALL' and utils.profile_is_validator(): @@ -1234,7 +1248,7 @@ def mt(text): def add_search_process(query, params): - global search_threads + global search_threads, thumb_workers_sml, thumb_workers_full, all_thumbs_loaded while (len(search_threads) > 0): old_thread = search_threads.pop(0) @@ -1249,6 +1263,16 @@ def add_search_process(query, params): else: urlquery = query_to_url(query, params) + if thumb_workers_sml == []: + for a in range(0, 8): + # worker = ThumbDownloadWorker(thumb_sml_download_threads, thumb_full_download_threads) + thread = threading.Thread(target=thumb_download_worker, args=(thumb_sml_download_threads, thumb_full_download_threads), + daemon=True) + thread.start() + thumb_workers_sml.append(thread) + + all_thumbs_loaded = False + thread = Searcher(query, params, tempdir=tempdir, headers=headers, urlquery=urlquery) thread.start() @@ -1405,22 +1429,23 @@ def search(category='', get_next=False, author_id=''): props.report = 'BlenderKit searching....' + def update_filters(): sprops = utils.get_search_props() ui_props = bpy.context.scene.blenderkitUI fcommon = sprops.own_only or \ - sprops.search_texture_resolution or\ - sprops.search_file_size or \ - sprops.search_procedural != 'BOTH' or \ - sprops.free_only or \ - sprops.quality_limit>0 + sprops.search_texture_resolution or \ + sprops.search_file_size or \ + sprops.search_procedural != 'BOTH' or \ + sprops.free_only or \ + sprops.quality_limit > 0 - if ui_props.asset_type =='MODEL': + if ui_props.asset_type == 'MODEL': sprops.use_filters = fcommon or \ sprops.search_style != 'ANY' or \ - sprops.search_condition != 'UNSPECIFIED' or \ - sprops.search_design_year or \ - sprops.search_polycount + sprops.search_condition != 'UNSPECIFIED' or \ + sprops.search_design_year or \ + sprops.search_polycount elif ui_props.asset_type == 'MATERIAL': sprops.use_filters = fcommon @@ -1522,7 +1547,6 @@ class SearchOperator(Operator): # description='Try to close the window below mouse before download', # default=False) - tooltip: bpy.props.StringProperty(default='Runs search and displays the asset bar at the same time') @classmethod @@ -1556,6 +1580,7 @@ class SearchOperator(Operator): # context.window.cursor_warp(event.mouse_x, event.mouse_y); # return self. execute(context) + class UrlOperator(Operator): """""" bl_idname = "wm.blenderkit_url" @@ -1574,6 +1599,7 @@ class UrlOperator(Operator): bpy.ops.wm.url_open(url=self.url) return {'FINISHED'} + class TooltipLabelOperator(Operator): """""" bl_idname = "wm.blenderkit_tooltip" @@ -1590,6 +1616,7 @@ class TooltipLabelOperator(Operator): def execute(self, context): return {'FINISHED'} + classes = [ SearchOperator, UrlOperator, @@ -1605,7 +1632,6 @@ def register_search(): user_preferences = bpy.context.preferences.addons['blenderkit'].preferences if user_preferences.use_timers: - bpy.app.timers.register(search_timer) categories.load_categories() @@ -1619,5 +1645,3 @@ def unregister_search(): if bpy.app.timers.is_registered(search_timer): bpy.app.timers.unregister(search_timer) - - diff --git a/blenderkit/thumbnails/thumbnail_notready.jpg b/blenderkit/thumbnails/thumbnail_notready.jpg Binary files differindex a32cb096..5be976b9 100644 --- a/blenderkit/thumbnails/thumbnail_notready.jpg +++ b/blenderkit/thumbnails/thumbnail_notready.jpg diff --git a/blenderkit/ui.py b/blenderkit/ui.py index a21cff91..138f4a89 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -40,7 +40,6 @@ import os import logging - draw_time = 0 eval_time = 0 @@ -361,7 +360,7 @@ def draw_tooltip(x, y, name='', author='', quality='-', img=None, gravatar=None) # draw author's name author_text_size = int(name_height * .7) - ui_bgl.draw_text(author, author_x_text, gravatar_y, author_text_size, textcol, ralign=True) + ui_bgl.draw_text(author, author_x_text, gravatar_y, author_text_size, textcol, halign='RIGHT') # draw quality quality_text_size = int(name_height * 1) @@ -385,7 +384,7 @@ def draw_tooltip_with_author(asset_data, x, y): if a.get('gravatarImg') is not None: gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash']).name - if len(a['firstName'])>0 or len(a['lastName'])>0: + if len(a['firstName']) > 0 or len(a['lastName']) > 0: author_text = f"by {a['firstName']} {a['lastName']}" aname = asset_data['displayName'] @@ -398,13 +397,13 @@ def draw_tooltip_with_author(asset_data, x, y): rcount = 0 quality = '-' if rc: - rcount = min(rc.get('quality',0), rc.get('workingHours',0)) + rcount = min(rc.get('quality', 0), rc.get('workingHours', 0)) if rcount > show_rating_threshold: quality = round(asset_data['ratingsAverage'].get('quality')) - tooltip_data={ + tooltip_data = { 'aname': aname, 'author_text': author_text, - 'quality':quality, + 'quality': quality, 'gimg': gimg } asset_data['tooltip_data'] = tooltip_data @@ -419,7 +418,6 @@ def draw_tooltip_with_author(asset_data, x, y): gravatar=gimg) - def draw_callback_2d(self, context): if not utils.guard_from_crash(): return @@ -699,7 +697,9 @@ def draw_asset_bar(self, context): # w + 2*highlight_margin, h + 2*highlight_margin , highlight) else: - ui_bgl.draw_rect(x, y, ui_props.thumb_size, ui_props.thumb_size, white) + ui_bgl.draw_rect(x, y, ui_props.thumb_size, ui_props.thumb_size, grey2) + ui_bgl.draw_text('loading', x + ui_props.thumb_size // 2, y + ui_props.thumb_size // 2, + ui_props.thumb_size // 6, white, halign='CENTER', valign='CENTER') result = search_results[index] # code to inform validators that the validation is waiting too long and should be done asap @@ -744,7 +744,7 @@ def draw_asset_bar(self, context): # report = 'BlenderKit - No matching results found.' # ui_bgl.draw_text(report, ui_props.bar_x + ui_props.margin, # ui_props.bar_y - 25 - ui_props.margin, 15) - if ui_props.draw_tooltip and len(search_results)>ui_props.active_index: + if ui_props.draw_tooltip and len(search_results) > ui_props.active_index: r = search_results[ui_props.active_index] draw_tooltip_with_author(r, ui_props.mouse_x, ui_props.mouse_y) s = bpy.context.scene @@ -1193,7 +1193,6 @@ class AssetBarOperator(bpy.types.Operator): ui_props.has_hit = False ui_props.assetbar_on = False - def modal(self, context, event): # This is for case of closing the area or changing type: @@ -1256,7 +1255,6 @@ class AssetBarOperator(bpy.types.Operator): self.area.tag_redraw() s = context.scene - if ui_props.turn_off: ui_props.turn_off = False self.exit_modal() @@ -1432,7 +1430,6 @@ class AssetBarOperator(bpy.types.Operator): ui_props.scrolloffset = max(0, ui_props.scrolloffset - ui_props.wcount * ui_props.hcount) return {'RUNNING_MODAL'} - if ui_props.active_index == -3: return {'RUNNING_MODAL'} else: @@ -1529,7 +1526,6 @@ class AssetBarOperator(bpy.types.Operator): update_ui_size(self.area, self.region) - self._handle_2d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_2d, args, 'WINDOW', 'POST_PIXEL') ui_props.assetbar_on = True @@ -1592,10 +1588,10 @@ def draw_callback_dragging(self, context): try: img = bpy.data.images.get(self.iname) except: - # self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_dragging, args, 'WINDOW', 'POST_PIXEL') - # self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d_dragging, args, 'WINDOW', - # bpy.types.SpaceView3D.draw_handler_remove(self._handle, - # bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW') + # self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_dragging, args, 'WINDOW', 'POST_PIXEL') + # self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d_dragging, args, 'WINDOW', + # bpy.types.SpaceView3D.draw_handler_remove(self._handle, + # bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW') return linelength = 35 @@ -1646,7 +1642,7 @@ class AssetDragOperator(bpy.types.Operator): if ui_props.asset_type == 'MODEL': if not self.drag: self.snapped_location = scene.cursor.location - self.snapped_rotation = (0,0,0) + self.snapped_rotation = (0, 0, 0) target_object = '' if self.object_name is not None: @@ -1671,7 +1667,7 @@ class AssetDragOperator(bpy.types.Operator): target_object = '' target_slot = '' if not self.drag: - #click interaction + # click interaction object = bpy.context.active_object if object is None: ui_panels.ui_message(title='Nothing selected', @@ -1725,7 +1721,6 @@ class AssetDragOperator(bpy.types.Operator): message=f"Can't assign materials to {object.type.lower()} object.") return - if target_object != '': # position is for downloader: loc = self.snapped_location @@ -1741,16 +1736,13 @@ class AssetDragOperator(bpy.types.Operator): target_object=target_object, material_target_slot=target_slot) - - if ui_props.asset_type == 'HDR': bpy.ops.scene.blenderkit_download('INVOKE_DEFAULT', - asset_index=self.asset_search_index, - # replace_resolution=True, - invoke_resolution=True, - max_resolution=self.asset_data.get('max_resolution', 0) - ) - + asset_index=self.asset_search_index, + # replace_resolution=True, + invoke_resolution=True, + max_resolution=self.asset_data.get('max_resolution', 0) + ) if ui_props.asset_type == 'SCENE': bpy.ops.scene.blenderkit_download('INVOKE_DEFAULT', @@ -1778,18 +1770,18 @@ class AssetDragOperator(bpy.types.Operator): self.mouse_x = event.mouse_region_x self.mouse_y = event.mouse_region_y - #are we dragging already? + # are we dragging already? drag_threshold = 10 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): + abs(self.start_mouse_y - self.mouse_y) > drag_threshold): self.drag = True - #turn off asset bar here, shout start again after finishing drag drop. + # turn off asset bar here, shout start again after finishing drag drop. ui_props.turn_off = True if (event.type == 'ESC' or \ - not mouse_in_region(context.region, self.mouse_x, self.mouse_y))and \ - (not self.drag or self.steps<5): + not 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'} @@ -1808,8 +1800,7 @@ class AssetDragOperator(bpy.types.Operator): sprops.offset_rotation_amount -= sprops.offset_rotation_step return {'RUNNING_MODAL'} - - if event.type =='MOUSEMOVE': + if event.type == 'MOUSEMOVE': #### TODO - this snapping code below is 3x in this file.... refactor it. self.has_hit, self.snapped_location, self.snapped_normal, self.snapped_rotation, self.face_index, object, self.matrix = mouse_raycast( @@ -1831,14 +1822,14 @@ class AssetDragOperator(bpy.types.Operator): return {'RUNNING_MODAL'} if event.type == 'LEFTMOUSE' and event.value == 'RELEASE': - self.mouse_release()# does the main job with assets + self.mouse_release() # does the main job with assets self.handlers_remove() bpy.context.window.cursor_set("DEFAULT") - bpy.ops.object.run_assetbar_fix_context(keep_running = True, do_search = False) + bpy.ops.object.run_assetbar_fix_context(keep_running=True, do_search=False) ui_props.dragging = False return {'FINISHED'} - self.steps +=1 + self.steps += 1 return {'RUNNING_MODAL'} @@ -1850,8 +1841,6 @@ class AssetDragOperator(bpy.types.Operator): # draw in view space with 'POST_VIEW' and 'PRE_VIEW' self.iname = utils.previmg_name(self.asset_search_index) - - self.mouse_x = 0 self.mouse_y = 0 self.steps = 0 diff --git a/blenderkit/ui_bgl.py b/blenderkit/ui_bgl.py index 95c454fe..339f5983 100644 --- a/blenderkit/ui_bgl.py +++ b/blenderkit/ui_bgl.py @@ -134,14 +134,20 @@ def draw_image(x, y, width, height, image, transparency, crop=(0, 0, 1, 1), batc return batch -def draw_text(text, x, y, size, color=(1, 1, 1, 0.5), ralign = False): +def draw_text(text, x, y, size, color=(1, 1, 1, 0.5), halign = 'LEFT', valign = 'TOP'): font_id = 1 # bgl.glColor4f(*color) blf.color(font_id, color[0], color[1], color[2], color[3]) blf.size(font_id, size, 72) - if ralign: + if halign != 'LEFT': width,height = blf.dimensions(font_id, text) - x-=width + if halign == 'RIGHT': + x-=width + elif halign == 'CENTER': + x-=width//2 + if valign=='CENTER': + y-=height//2 + #bottom could be here but there's no reason for it blf.position(font_id, x, y, 0) blf.draw(font_id, text) diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index de4a5f9b..67f42148 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -1506,10 +1506,11 @@ class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties): def draw_properties(self, layout, width=250): - if type(self.asset_data['parameters']) == list: - mparams = utils.params_to_dict(self.asset_data['parameters']) - else: - mparams = self.asset_data['parameters'] + # if type(self.asset_data['parameters']) == list: + # mparams = utils.params_to_dict(self.asset_data['parameters']) + # else: + # mparams = self.asset_data['parameters'] + mparams = self.asset_data['dictParameters'] pcoll = icons.icon_collections["main"] diff --git a/blenderkit/utils.py b/blenderkit/utils.py index d5affc7e..113dc130 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -721,14 +721,16 @@ def fmt_length(prop): def get_param(asset_data, parameter_name, default=None): - if not asset_data.get('parameters'): + if not asset_data.get('dictParameters'): # this can appear in older version files. return default - for p in asset_data['parameters']: - if p.get('parameterType') == parameter_name: - return p['value'] - return default + return asset_data['dictParameters'].get(parameter_name, default) + + # for p in asset_data['parameters']: + # if p.get('parameterType') == parameter_name: + # return p['value'] + # return default def params_to_dict(params): |