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.
This commit is contained in:
parent
0d6b2e8767
commit
69ad4c43d0
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 not os.path.exists(imgpath):
|
||||
thumb_sml_download_threads.put((url, imgpath))
|
||||
|
||||
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 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)
|
||||
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.9 KiB |
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"]
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue