BlenderKit: fix asset bar thumbnail refresh

also sevearal small UI tweaks and fix of the asset-bar scaling when switching on toolbar/properties in 3d view
remove debug prints
This commit is contained in:
Vilem Duha 2021-10-22 15:10:00 +02:00
parent 259ab9a873
commit be3f162ef7
7 changed files with 161 additions and 127 deletions

View File

@ -365,8 +365,8 @@ class BlenderKitUIProps(PropertyGroup):
highlight_margin: IntProperty(name="Highlight Margin", default=int(margin_def / 2), min=-10, max=256)
bar_height: IntProperty(name="Bar Height", default=thumb_size_def + 2 * margin_def, min=-1, max=2048)
bar_x_offset: IntProperty(name="Bar X Offset", default=0, min=0, max=5000)
bar_y_offset: IntProperty(name="Bar Y Offset", default=60, min=0, max=5000)
bar_x_offset: IntProperty(name="Bar X Offset", default=40, min=0, max=5000)
bar_y_offset: IntProperty(name="Bar Y Offset", default=80, min=0, max=5000)
bar_x: IntProperty(name="Bar X", default=100, min=0, max=5000)
bar_y: IntProperty(name="Bar Y", default=100, min=50, max=5000)

View File

@ -13,6 +13,7 @@ from blenderkit.bl_ui_widgets.bl_ui_draw_op import *
# from blenderkit.bl_ui_widgets.bl_ui_textbox import *
import random
import math
import time
import blenderkit
from blenderkit import ui, paths, utils, search, comments_utils
@ -47,7 +48,8 @@ def get_area_height(self):
BL_UI_Widget.get_area_height = get_area_height
def modal_inside(self,context,event):
def modal_inside(self, context, event):
ui_props = bpy.context.window_manager.blenderkitUI
if ui_props.turn_off:
ui_props.turn_off = False
@ -62,20 +64,27 @@ def modal_inside(self,context,event):
self.finish()
return {'FINISHED'}
# progress bar
# Todo: put this into a timer?
sr = bpy.context.window_manager.get('search results')
ui_scale = bpy.context.preferences.view.ui_scale
for asset_button in self.asset_buttons:
self.update_timer +=1
if self.update_timer > self.update_timer_limit:
self.update_timer = 0
# print('timer', time.time())
self.update_images()
# progress bar
sr = bpy.context.window_manager.get('search results')
ui_scale = bpy.context.preferences.view.ui_scale
for asset_button in self.asset_buttons:
if sr is not None and len(sr) > asset_button.asset_index:
asset_data = sr[asset_button.asset_index]
if asset_data['downloaded'] > 0:
asset_button.progress_bar.width = int(self.button_size * ui_scale * asset_data['downloaded'] / 100)
asset_button.progress_bar.visible = True
else:
asset_button.progress_bar.visible = False
if sr is not None and len(sr) > asset_button.asset_index:
asset_data = sr[asset_button.asset_index]
if asset_data['downloaded'] > 0:
asset_button.progress_bar.width = int(self.button_size * ui_scale * asset_data['downloaded'] / 100)
asset_button.progress_bar.visible = True
else:
asset_button.progress_bar.visible = False
if self.handle_widget_events(event):
return {'RUNNING_MODAL'}
@ -85,12 +94,12 @@ def modal_inside(self,context,event):
self.mouse_x = event.mouse_region_x
self.mouse_y = event.mouse_region_y
if event.type == 'WHEELUPMOUSE' and self.panel.is_in_rect(self.mouse_x, self.mouse_y):
self.scroll_offset -= 5
self.scroll_offset -= 2
self.scroll_update()
return {'RUNNING_MODAL'}
elif event.type == 'WHEELDOWNMOUSE' and self.panel.is_in_rect(self.mouse_x, self.mouse_y):
self.scroll_offset += 5
self.scroll_offset += 2
self.scroll_update()
return {'RUNNING_MODAL'}
@ -101,8 +110,9 @@ def modal_inside(self,context,event):
return {"PASS_THROUGH"}
def asset_bar_modal(self, context, event):
return modal_inside(self,context,event)
return modal_inside(self, context, event)
def asset_bar_invoke(self, context, event):
@ -113,6 +123,11 @@ def asset_bar_invoke(self, context, event):
self.register_handlers(args, context)
self.update_timer_limit = 30
self.update_timer =0
# print('adding timer')
# self._timer = context.window_manager.event_timer_add(10.0, window=context.window)
context.window_manager.modal_handler_add(self)
return {"RUNNING_MODAL"}
@ -298,42 +313,34 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
return True
return False
def check_ui_resized(self, context):
# TODO this should only check if region was resized, not really care about the UI elements size.
def get_region_size(self, context):
# just check the size of region..
region = context.region
area = context.area
ui_props = bpy.context.window_manager.blenderkitUI
ui_scale = bpy.context.preferences.view.ui_scale
# just check the size of region..
if not hasattr(self, 'region_width'):
self.region_width = region.width
self.region_height = region.height
if region.height != self.region_height or region.width != self.region_width:
self.region_height = region.height
self.region_width = region.width
ui_width = 0
tools_width = 0
for r in area.regions:
if r.type == 'UI':
ui_width = r.width
if r.type == 'TOOLS':
tools_width = r.width
total_width = region.width - tools_width - ui_width
return total_width, region.height
def check_ui_resized(self, context):
# TODO this should only check if region was resized, not really care about the UI elements size.
region_width, region_height = self.get_region_size(context)
if not hasattr(self, 'total_width'):
self.total_width = region_width
self.region_height = region_height
if region_height != self.region_height or region_width != self.total_width:
self.region_height = region_height
self.total_width = region_width
return True
return False
# this actually calculated UI elements, which is unnecessary
reg_multiplier = 1
if not bpy.context.preferences.system.use_region_overlap:
reg_multiplier = 0
for r in area.regions:
if r.type == 'TOOLS':
self.bar_x = r.width * reg_multiplier + self.margin + ui_props.bar_x_offset * ui_scale
elif r.type == 'UI':
self.bar_end = r.width * reg_multiplier + 100 * ui_scale
bar_width = region.width - self.bar_x - self.bar_end
bar_y = ui_props.bar_y_offset * ui_scale
changed = False
if bar_width != self.bar_width:
changed = True
if bar_y != self.bar_y:
changed = True
return changed
def update_ui_size(self, context):
@ -364,12 +371,18 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
if not bpy.context.preferences.system.use_region_overlap:
reg_multiplier = 0
ui_width = 0
tools_width = 0
reg_multiplier = 1
if not bpy.context.preferences.system.use_region_overlap:
reg_multiplier = 0
for r in area.regions:
if r.type == 'UI' :
ui_width = r.width * reg_multiplier
if r.type == 'TOOLS':
self.bar_x = r.width * reg_multiplier + self.margin + ui_props.bar_x_offset * ui_scale
elif r.type == 'UI':
self.bar_end = r.width * reg_multiplier + 120 * ui_scale
tools_width = r.width * reg_multiplier
self.bar_x = tools_width + self.margin + ui_props.bar_x_offset * ui_scale
self.bar_end = ui_width + 180 * ui_scale + self.other_button_size
self.bar_width = region.width - self.bar_x - self.bar_end
self.wcount = math.floor((self.bar_width) / (self.button_size))
@ -402,13 +415,13 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
self.position_and_hide_buttons()
self.button_close.set_location(self.bar_width - self.other_button_size, -self.other_button_size)
if hasattr(self,'button_notifications'):
self.button_notifications.set_location(self.bar_width - self.other_button_size*2, -self.other_button_size)
if hasattr(self, 'button_notifications'):
self.button_notifications.set_location(self.bar_width - self.other_button_size * 2, -self.other_button_size)
self.button_scroll_up.set_location(self.bar_width, 0)
self.panel.width = self.bar_width
self.panel.height = self.bar_height
self.panel.set_location(self.panel.x, self.panel.y)
self.panel.set_location(self.bar_x, self.panel.y)
# to hide arrows accordingly
self.scroll_update()
@ -460,8 +473,6 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
new_button.progress_bar = progress_bar
self.progress_bars.append(progress_bar)
# if result['downloaded'] > 0:
# ui_bgl.draw_rect(x, y, int(ui_props.thumb_size * result['downloaded'] / 100.0), 2, green)
@ -498,7 +509,8 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
self.asset_buttons.append(new_button)
button_idx += 1
self.button_close = BL_UI_Button(self.bar_width - self.other_button_size, -self.other_button_size, self.other_button_size,
self.button_close = BL_UI_Button(self.bar_width - self.other_button_size, -self.other_button_size,
self.other_button_size,
self.other_button_size)
self.button_close.bg_color = button_bg_color
self.button_close.hover_bg_color = button_hover_color
@ -534,11 +546,11 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
self.widgets_panel.append(self.button_scroll_up)
#notifications
# notifications
if not comments_utils.check_notifications_read():
self.button_notifications = BL_UI_Button(self.bar_width - self.other_button_size*2, -self.other_button_size, self.other_button_size,
self.other_button_size)
self.button_notifications = BL_UI_Button(self.bar_width - self.other_button_size * 2,
-self.other_button_size, self.other_button_size,
self.other_button_size)
self.button_notifications.bg_color = button_bg_color
self.button_notifications.hover_bg_color = button_hover_color
self.button_notifications.text = ""
@ -562,7 +574,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
asset_y = self.assetbar_margin + y * (self.button_size)
button_idx = x + y * self.wcount
asset_idx = button_idx + self.scroll_offset
if len(self.asset_buttons)<=button_idx:
if len(self.asset_buttons) <= button_idx:
break
button = self.asset_buttons[button_idx]
button.set_location(asset_x, asset_y)
@ -681,6 +693,8 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
global asset_bar_operator
asset_bar_operator = None
# context.window_manager.event_timer_remove(self._timer)
scene = bpy.context.scene
ui_props = bpy.context.window_manager.blenderkitUI
ui_props.assetbar_on = False
@ -752,7 +766,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
ui_props.draw_tooltip = False
self.draw_tooltip = False
self.hide_tooltip()
#popup asset card on mouse down
# popup asset card on mouse down
# if utils.experimental_enabled():
# h = widget.get_area_height()
# print(h,h-self.mouse_y,self.panel.y_screen, self.panel.y,widget.y_screen, widget.y)
@ -818,6 +832,7 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
img_filepath = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
else:
img_filepath = img.filepath
# print(asset_button.button_index, img_filepath)
asset_button.set_image(img_filepath)
self.update_validation_icon(asset_button, asset_data)

View File

@ -67,12 +67,24 @@ class BL_UI_Button(BL_UI_Widget):
self.__image_position = image_position
def set_image(self, rel_filepath):
#first try to access the image, for cases where it can get removed
try:
self.__image
self.__image.filepath
self.__image.pixels
except:
self.__image = None
try:
if self.__image is None or self.__image.filepath != rel_filepath:
self.__image = bpy.data.images.load(rel_filepath, check_existing=True)
self.__image.gl_load()
except:
pass
if self.__image and len(self.__image.pixels) == 0:
self.__image.reload()
self.__image.gl_load()
except Exception as e:
self.__image = None
def update(self, x, y):
super().update(x, y)

View File

@ -75,7 +75,7 @@ def check_missing():
def check_unused():
'''find assets that have been deleted from scene but their library is still present.'''
# this is obviously broken. Blender should take care of the extra data automaticlaly
#first clean up collections
# first clean up collections
for c in bpy.data.collections:
if len(c.all_objects) == 0 and c.get('is_blenderkit_asset'):
bpy.data.collections.remove(c)
@ -331,7 +331,6 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None,
props = hdr.blenderkit
asset_main = hdr
if asset_data['assetType'] == 'model':
downloaders = kwargs.get('downloaders')
sprops = wm.blenderkit_models
@ -498,8 +497,6 @@ def append_asset(asset_data, **kwargs): # downloaders=[], location=None,
asset_main.blenderkit.asset_base_id = asset_data['assetBaseId']
asset_main.blenderkit.id = asset_data['id']
bpy.ops.wm.undo_push_context(message='add %s to scene' % asset_data['name'])
# moving reporting to on save.
# report_use_success(asset_data['id'])
@ -599,7 +596,7 @@ def download_timer():
if sr is not None:
for r in sr:
if asset_data['id'] == r['id']:
r['downloaded'] = 0.5#tcom.progress
r['downloaded'] = 0.5 # tcom.progress
if not t.is_alive():
if tcom.error:
sprops = utils.get_search_props()
@ -698,7 +695,7 @@ def delete_unfinished_file(file_name):
return
def download_asset_file(asset_data, resolution='blend', api_key = ''):
def download_asset_file(asset_data, resolution='blend', api_key=''):
# this is a simple non-threaded way to download files for background resolution genenration tool
file_names = paths.get_download_filepaths(asset_data, resolution) # prefer global dir if possible.
if len(file_names) == 0:
@ -854,7 +851,6 @@ class Downloader(threading.Thread):
# utils.p('end downloader thread')
class ThreadCom: # object passed to threads to read background process stdout info
def __init__(self):
self.file_size = 1000000000000000 # property that gets written to.
@ -1279,7 +1275,7 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
invoke_resolution: BoolProperty(name='Replace resolution popup',
description='pop up to ask which resolution to download', default=False)
invoke_scene_settings: BoolProperty(name='Scene import settings popup',
description='pop up scene import settings', default=False)
description='pop up scene import settings', default=False)
resolution: EnumProperty(
items=available_resolutions_callback,
@ -1287,7 +1283,7 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
description='Replace resolution'
)
#needs to be passed to the operator to not show all resolution possibilities
# needs to be passed to the operator to not show all resolution possibilities
max_resolution: IntProperty(
name="Max resolution",
description="",
@ -1306,6 +1302,13 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
# @classmethod
# def poll(cls, context):
# return bpy.context.window_manager.BlenderKitModelThumbnails is not ''
tooltip: bpy.props.StringProperty(
default='Download and link asset to scene. Only link if asset already available locally')
@classmethod
def description(cls, context, properties):
return properties.tooltip
def get_asset_data(self, context):
# get asset data - it can come from scene, or from search results.
s = bpy.context.scene
@ -1327,14 +1330,14 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
# already used assets have already download link and especially file link.
asset_data = s['assets used'][asset_base_id].to_dict()
else:
#when not in scene nor in search results, we need to get it from the server
# when not in scene nor in search results, we need to get it from the server
params = {
'asset_base_id': self.asset_base_id
}
preferences = bpy.context.preferences.addons['blenderkit'].preferences
results = search.get_search_simple(params, page_size=1, max_results=1,
api_key=preferences.api_key)
results = search.get_search_simple(params, page_size=1, max_results=1,
api_key=preferences.api_key)
asset_data = search.parse_result(results[0])
return asset_data
@ -1426,7 +1429,7 @@ class BlenderkitDownloadOperator(bpy.types.Operator):
self.asset_data = self.get_asset_data(context)
sprops = utils.get_search_props()
#set initial resolutions enum activation
# set initial resolutions enum activation
if sprops.resolution != 'ORIGINAL' and int(sprops.resolution) <= int(self.max_resolution):
self.resolution = sprops.resolution
elif int(self.max_resolution) > 0:

View File

@ -278,7 +278,7 @@ def rating_menu_draw(self, context):
layout.label(text='Admin rating Tools:')
col.operator_context = 'INVOKE_DEFAULT'
op = col.operator('wm.blenderkit_menu_rating_upload', text='Rate')
op = col.operator('wm.blenderkit_menu_rating_upload', text='Add Rating')
op.asset_id = asset_data['id']
op.asset_name = asset_data['name']
op.asset_type = asset_data['assetType']

View File

@ -391,13 +391,11 @@ def search_timer():
ui_props = bpy.context.window_manager.blenderkitUI
search_name = f'bkit {ui_props.asset_type.lower()} search'
wm = bpy.context.window_manager
print('finishing reading thumbs')
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'):
preview_loaded = load_preview(r, ri)
print(ri, preview_loaded, all_thumbs_loaded)
all_loaded = all_loaded and preview_loaded
all_thumbs_loaded = all_loaded
@ -452,7 +450,6 @@ def search_timer():
if ok:
ui_props = bpy.context.window_manager.blenderkitUI
orig_len = len(result_field)
print('reading from thread')
for ri, r in enumerate(rdata['results']):
asset_data = parse_result(r)
@ -526,9 +523,13 @@ def load_preview(asset, index):
# wrap into try statement since sometimes
try:
img = bpy.data.images.load(tpath)
img.name = iname
if len(img.pixels)>0:
return True
except:
return False
pass
return False
elif img.filepath != tpath:
if not os.path.exists(tpath):
# unload loaded previews from previous results

View File

@ -1310,7 +1310,7 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
layout.operator_context = 'INVOKE_DEFAULT'
if from_panel:
op = layout.operator('wm.blenderkit_menu_rating_upload', text='Rate')
op = layout.operator('wm.blenderkit_menu_rating_upload', text='Add Rating')
op.asset_name = asset_data['name']
op.asset_id = asset_data['id']
op.asset_type = asset_data['assetType']
@ -1343,6 +1343,7 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
if aob is None:
aob = bpy.context.selected_objects[0]
op = layout.operator('scene.blenderkit_download', text='Replace Active Models')
op.tooltip = "Replace all selected models with this one."
# this checks if the menu got called from right-click in assetbar(then index is 0 - x) or
# from a panel(then replacement happens from the active model)
@ -2391,53 +2392,55 @@ def header_search_draw(self, context):
return;
preferences = bpy.context.preferences.addons['blenderkit'].preferences
if preferences.search_in_header:
layout = self.layout
s = bpy.context.scene
wm = bpy.context.window_manager
ui_props = bpy.context.window_manager.blenderkitUI
if ui_props.asset_type == 'MODEL':
props = wm.blenderkit_models
if ui_props.asset_type == 'MATERIAL':
props = wm.blenderkit_mat
if ui_props.asset_type == 'BRUSH':
props = wm.blenderkit_brush
if ui_props.asset_type == 'HDR':
props = wm.blenderkit_HDR
if ui_props.asset_type == 'SCENE':
props = wm.blenderkit_scene
if not preferences.search_in_header:
return
# the center snap menu is in edit and object mode if tool settings are off.
if context.space_data.show_region_tool_header == True or context.mode[:4] not in ('EDIT', 'OBJE'):
layout.separator_spacer()
layout.prop(ui_props, "asset_type", expand=True, icon_only=True, text='', icon='URL')
layout.prop(props, "search_keywords", text="", icon='VIEWZOOM')
draw_assetbar_show_hide(layout, props)
layout.popover(panel="VIEW3D_PT_blenderkit_categories", text="", icon='OUTLINER')
layout = self.layout
s = bpy.context.scene
wm = bpy.context.window_manager
ui_props = bpy.context.window_manager.blenderkitUI
if ui_props.asset_type == 'MODEL':
props = wm.blenderkit_models
if ui_props.asset_type == 'MATERIAL':
props = wm.blenderkit_mat
if ui_props.asset_type == 'BRUSH':
props = wm.blenderkit_brush
if ui_props.asset_type == 'HDR':
props = wm.blenderkit_HDR
if ui_props.asset_type == 'SCENE':
props = wm.blenderkit_scene
pcoll = icons.icon_collections["main"]
# the center snap menu is in edit and object mode if tool settings are off.
if context.space_data.show_region_tool_header == True or context.mode[:4] not in ('EDIT', 'OBJE'):
layout.separator_spacer()
layout.prop(ui_props, "asset_type", expand=True, icon_only=True, text='', icon='URL')
layout.prop(props, "search_keywords", text="", icon='VIEWZOOM')
draw_assetbar_show_hide(layout, props)
layout.popover(panel="VIEW3D_PT_blenderkit_categories", text="", icon='OUTLINER')
if props.use_filters:
icon_id = pcoll['filter_active'].icon_id
else:
icon_id = pcoll['filter'].icon_id
pcoll = icons.icon_collections["main"]
if ui_props.asset_type == 'MODEL':
layout.popover(panel="VIEW3D_PT_blenderkit_advanced_model_search", text="", icon_value=icon_id)
if props.use_filters:
icon_id = pcoll['filter_active'].icon_id
else:
icon_id = pcoll['filter'].icon_id
elif ui_props.asset_type == 'MATERIAL':
layout.popover(panel="VIEW3D_PT_blenderkit_advanced_material_search", text="", icon_value=icon_id)
elif ui_props.asset_type == 'HDR':
layout.popover(panel="VIEW3D_PT_blenderkit_advanced_HDR_search", text="", icon_value=icon_id)
if ui_props.asset_type == 'MODEL':
layout.popover(panel="VIEW3D_PT_blenderkit_advanced_model_search", text="", icon_value=icon_id)
notifications = bpy.context.window_manager.get('bkit notifications')
if notifications is not None and len(notifications) > 0:
layout.operator('wm.show_notifications', text="", icon_value=pcoll['bell'].icon_id)
# layout.popover(panel="VIEW3D_PT_blenderkit_notifications", text="", icon_value=pcoll['bell'].icon_id)
elif ui_props.asset_type == 'MATERIAL':
layout.popover(panel="VIEW3D_PT_blenderkit_advanced_material_search", text="", icon_value=icon_id)
elif ui_props.asset_type == 'HDR':
layout.popover(panel="VIEW3D_PT_blenderkit_advanced_HDR_search", text="", icon_value=icon_id)
if utils.profile_is_validator():
search_props = utils.get_search_props()
layout.prop(search_props, 'search_verification_status', text='')
notifications = bpy.context.window_manager.get('bkit notifications')
if notifications is not None and len(notifications) > 0:
layout.operator('wm.show_notifications', text="", icon_value=pcoll['bell'].icon_id)
# layout.popover(panel="VIEW3D_PT_blenderkit_notifications", text="", icon_value=pcoll['bell'].icon_id)
if utils.profile_is_validator():
search_props = utils.get_search_props()
layout.prop(search_props, 'search_verification_status', text='')
def ui_message(title, message):