From c12dc2b19968b3e222e5b0c41ea918a8a15c4ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vil=C3=A9m=20Duha?= <vilda.novak@gmail.com> Date: Sat, 1 May 2021 19:09:09 +0200 Subject: [PATCH] BlenderKit: minor tweaks to asset card layout - some code cleanup - labels with tooltips (an empty operator that enables this, drawing it non-emobssed) --- blenderkit/autothumb.py | 2 +- blenderkit/search.py | 22 ++++- blenderkit/thumbnails/star_grey.png | Bin 0 -> 1733 bytes blenderkit/ui.py | 43 +++++---- blenderkit/ui_panels.py | 143 +++++++++++++++++----------- blenderkit/utils.py | 7 +- 6 files changed, 139 insertions(+), 78 deletions(-) create mode 100644 blenderkit/thumbnails/star_grey.png diff --git a/blenderkit/autothumb.py b/blenderkit/autothumb.py index baf1a2caa..9be9039e0 100644 --- a/blenderkit/autothumb.py +++ b/blenderkit/autothumb.py @@ -523,7 +523,7 @@ class GenerateMaterialThumbnailOperator(bpy.types.Operator): class ReGenerateMaterialThumbnailOperator(bpy.types.Operator): """ Generate default thumbnail with Cycles renderer and upload it. - Works also for assets from search results, without being downloaded before. + Works also for assets from search results, without being downloaded before """ bl_idname = "object.blenderkit_regenerate_material_thumbnail" bl_label = "BlenderKit Material Thumbnail Re-Generator" diff --git a/blenderkit/search.py b/blenderkit/search.py index 67a353ac0..858f676bd 100644 --- a/blenderkit/search.py +++ b/blenderkit/search.py @@ -990,10 +990,10 @@ def build_query_common(query, props): if props.search_keywords != '': query_common["query"] = props.search_keywords - if props.search_verification_status != 'ALL': + if props.search_verification_status != 'ALL' and utils.profile_is_validator(): query_common['verification_status'] = props.search_verification_status.lower() - if props.unrated_only: + if props.unrated_only and utils.profile_is_validator(): query["quality_count"] = 0 if props.search_file_size: @@ -1447,10 +1447,26 @@ class UrlOperator(Operator): bpy.ops.wm.url_open(url=self.url) return {'FINISHED'} +class TooltipLabelOperator(Operator): + """""" + bl_idname = "wm.blenderkit_tooltip" + bl_label = "" + bl_description = "Empty operator to be able to create tooltips on labels in UI" + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + + tooltip: bpy.props.StringProperty(default='Open a web page') + + @classmethod + def description(cls, context, properties): + return properties.tooltip + + def execute(self, context): + return {'FINISHED'} classes = [ SearchOperator, - UrlOperator + UrlOperator, + TooltipLabelOperator ] diff --git a/blenderkit/thumbnails/star_grey.png b/blenderkit/thumbnails/star_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..53c5bd05a66ba6a2709a802240500100d89f5875 GIT binary patch literal 1733 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 a`{QePX5X8`63@WEz~JfX=d#Wzp$Py2cHq_k literal 0 HcmV?d00001 diff --git a/blenderkit/ui.py b/blenderkit/ui.py index ba5855f7d..644980de6 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -231,11 +231,6 @@ def draw_ratings_bgl(): if rating_possible: # (not rated or ui_props.rating_menu_on): # print('rating is pssible', asset_data['name']) bkit_ratings = asset.bkit_ratings - bgcol = bpy.context.preferences.themes[0].user_interface.wcol_tooltip.inner - textcol = (1, 1, 1, 1) - - r = bpy.context.region - font_size = int(ui.rating_ui_scale * 20) if ui.rating_button_on: # print('should draw button') @@ -261,7 +256,6 @@ def draw_ratings_bgl(): ui.rating_button_width, ui.rating_button_width, img, 1) - # ui_bgl.draw_text( 'rate asset %s' % asset_data['name'],r.width - rating_button_width + margin, margin, font_size) return @@ -278,7 +272,7 @@ def draw_text_block(x=0, y=0, width=40, font_size=10, line_height=15, text='', c ui_bgl.draw_text(l, x, ytext, font_size, color) -def draw_tooltip(x, y, name='', author='', img=None, gravatar=None): +def draw_tooltip(x, y, name='', author='', quality = '-', img=None, gravatar=None): region = bpy.context.region scale = bpy.context.preferences.view.ui_scale t = time.time() @@ -308,7 +302,7 @@ def draw_tooltip(x, y, name='', author='', img=None, gravatar=None): if gravatar is not None: overlay_height_base = 90 else: - overlay_height_base = 50 + overlay_height_base = 70 overlay_height = overlay_height_base * scale @@ -347,6 +341,12 @@ def draw_tooltip(x, y, name='', author='', img=None, gravatar=None): ttipmargin + overlay_height , background_overlay) + #draw name + name_x = x + textmargin + name_y = y - isizey + overlay_height - textmargin - name_height + ui_bgl.draw_text(name, name_x, name_y, name_height, textcol) + + # draw gravatar author_x_text = x + isizex - textmargin gravatar_size = overlay_height - 2 * textmargin @@ -357,13 +357,17 @@ def draw_tooltip(x, y, name='', author='', img=None, gravatar=None): gravatar_y, # + textmargin, gravatar_size, gravatar_size, gravatar, 1) - name_x = x + textmargin - name_y = y - isizey + overlay_height - textmargin - name_height - ui_bgl.draw_text(name, name_x, name_y, name_height, textcol) - + #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) + # draw quality + quality_text_size = int(name_height * 1) + img = utils.get_thumbnail('star_grey.png') + ui_bgl.draw_image(name_x, gravatar_y, quality_text_size, quality_text_size, img, .6) + ui_bgl.draw_text(str(quality), name_x + quality_text_size + 5, gravatar_y, quality_text_size, textcol) + + def draw_tooltip_with_author(asset_data, x, y): # TODO move this lazy loading into a function and don't duplicate through the code @@ -377,13 +381,20 @@ 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']) - # author_s = '' - # if not gimg: - # author_s = 'Author: ' aname = asset_data['displayName'] if len(aname)>36: aname = f"{aname[:33]}..." - draw_tooltip(x, y, name=aname, author=f"by {a['firstName']} {a['lastName']}", img=img, + + rc = asset_data.get('ratingsCount') + show_rating_threshold = 0 + rcount = 0 + quality = '-' + if rc: + rcount = min(rc['quality'], rc['workingHours']) + if rcount>show_rating_threshold: + quality = round(asset_data['ratingsAverage'].get('quality')) + + draw_tooltip(x, y, name=aname, author=f"by {a['firstName']} {a['lastName']}", quality= quality, img=img, gravatar=gimg) diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index 8d880fddd..daa374c12 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -1271,26 +1271,7 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False): profile = wm.get('bkit profile') if profile is not None: # validation - if utils.profile_is_validator(): - layout.label(text='Validation tools:') - layout.operator_context = 'EXEC_DEFAULT' - if asset_data['verificationStatus'] != 'uploaded': - op = layout.operator('object.blenderkit_change_status', text='set Uploaded') - op.asset_id = asset_data['id'] - op.state = 'uploaded' - if asset_data['verificationStatus'] != 'validated': - op = layout.operator('object.blenderkit_change_status', text='Validate') - op.asset_id = asset_data['id'] - op.state = 'validated' - if asset_data['verificationStatus'] != 'on_hold': - op = layout.operator('object.blenderkit_change_status', text='Put on Hold') - op.asset_id = asset_data['id'] - op.state = 'on_hold' - if asset_data['verificationStatus'] != 'rejected': - op = layout.operator('object.blenderkit_change_status', text='Reject') - op.asset_id = asset_data['id'] - op.state = 'rejected' if author_id == str(profile['user']['id']) or utils.profile_is_validator(): layout.label(text='Management tools:') @@ -1386,6 +1367,41 @@ def numeric_to_str(s): return s +def label_or_url(layout, text='', tooltip='', url='', icon_value=None, icon=None): + '''automatically switch between different layout options for linking or tooltips''' + layout.emboss = 'NONE' + if url != '': + if icon: + op = layout.operator('wm.blenderkit_url', text=text, icon=icon) + elif icon_value: + op = layout.operator('wm.blenderkit_url', text=text, icon_value=icon_value) + else: + op = layout.operator('wm.blenderkit_url', text=text) + op.url = url + op.tooltip = tooltip + layout.label(text='') + layout.label(text='') + + return + if tooltip != '': + if icon: + op = layout.operator('wm.blenderkit_tooltip', text=text, icon=icon) + elif icon_value: + op = layout.operator('wm.blenderkit_tooltip', text=text, icon_value=icon_value) + else: + op = layout.operator('wm.blenderkit_tooltip', text=text) + op.tooltip = tooltip + layout.label(text='') + layout.label(text='') + return + if icon: + layout.label(text=text, icon=icon) + elif icon_value: + layout.label(text=text, icon_value=icon_value) + else: + layout.label(text=text) + + class AssetPopupCard(bpy.types.Operator): """Generate Cycles thumbnail for model assets""" bl_idname = "wm.blenderkit_asset_popup" @@ -1510,32 +1526,20 @@ class AssetPopupCard(bpy.types.Operator): col = layout.column() draw_asset_context_menu(col, context, self.asset_data, from_panel=False) - def draw_property(self, layout, left, right, icon=None, icon_value=None, url=None, tooltip=''): + def draw_property(self, layout, left, right, icon=None, icon_value=None, url='', tooltip=''): right = str(right) row = layout.row() split = row.split(factor=0.4) split.alignment = 'RIGHT' split.label(text=left) split = split.split() - # if url: - # if icon_value: - # op = split.operator('wm.url_open', text=right, icon_value=icon_value) - # elif icon: - # op = split.operator('wm.url_open', text=right, icon=icon) - # else: - # op = split.operator('wm.url_open', text=right) - # op.url = url - # return - if url: - split = split.split(factor=0.9) - if icon_value: - split.label(text=right, icon_value=icon_value) - elif icon: - split.label(text=right, icon=icon) - - else: - split.label(text=right) - if url: + split.alignment = 'LEFT' + #split for questionmark: + if url!='': + split = split.split(factor=0.7) + label_or_url(split,text=right,tooltip=tooltip, url=url, icon_value=icon_value, icon=icon) + #additional questionmark icon where it's important? + if url!='': split = split.split() op = split.operator('wm.blenderkit_url', text='', icon='QUESTION') op.url = url @@ -1576,10 +1580,10 @@ class AssetPopupCard(bpy.types.Operator): self.draw_property(box, 'License:', t, - icon_value=icon.icon_id, + # icon_value=icon.icon_id, url="https://www.blenderkit.com/docs/licenses/", - tooltip='All BlenderKit assets are available for commercial use. ' - 'Click to read more about BlenderKit licenses online' + tooltip='All BlenderKit assets are available for commercial use. \n'\ + 'Click to read more about BlenderKit licenses on the website' ) if upload.can_edit_asset(asset_data=self.asset_data): @@ -1627,7 +1631,10 @@ class AssetPopupCard(bpy.types.Operator): resolution = utils.get_param(self.asset_data, 'textureResolutionMax') if resolution is not None: ress = f"{int(round(resolution / 1024, 0))}K" - self.draw_property(box, 'Resolution', ress) + self.draw_property(box, 'Resolution', ress, + tooltip='Maximal resolution of textures in this asset.\n'\ + 'Most texture asset have also lower resolutions generated.\n'\ + 'Go to BlenderKit add-on import settings to set default resolution') self.draw_asset_parameter(box, key='designer', pretext='Designer') self.draw_asset_parameter(box, key='manufacturer', pretext='Manufacturer') # TODO make them clickable! @@ -1650,17 +1657,28 @@ class AssetPopupCard(bpy.types.Operator): self.draw_property(box, 'Size:', t) # Free/Full plan or private Access + plans_tooltip = 'BlenderKit has 2 plans:\n'\ + ' * Free plan - more than 50% of all assets\n'\ + ' * Full plan - unlimited access to everything'\ + 'Click to go to subscriptions page.' + plans_link = 'https://www.blenderkit.com/plans/pricing/' if self.asset_data['isPrivate']: t = 'Private' self.draw_property(box, 'Access:', t, icon='LOCKED') elif self.asset_data['isFree']: t = 'Free plan' icon = pcoll['free'] - self.draw_property(box, 'Access:', t, icon_value=icon.icon_id) + self.draw_property(box, 'Access:', t, + icon_value=icon.icon_id, + tooltip = plans_tooltip, + url= plans_link) else: t = 'Full plan' icon = pcoll['full'] - self.draw_property(box, 'Access:', t, icon_value=icon.icon_id) + self.draw_property(box, 'Access:', t, + icon_value=icon.icon_id, + tooltip=plans_tooltip, + url=plans_link) def draw_author_area(self, context, layout, width=330): self.draw_author(context, layout, width=330) @@ -1716,7 +1734,7 @@ class AssetPopupCard(bpy.types.Operator): op = button_row.operator('wm.url_open', text=text) op.url = url - op = button_row.operator('view3d.blenderkit_search', text="Show Assets By Author") + op = button_row.operator('view3d.blenderkit_search', text="Find Assets By Author") op.keywords = '' op.author_id = self.asset_data['author']['id'] @@ -1724,12 +1742,8 @@ class AssetPopupCard(bpy.types.Operator): layout.emboss = 'NORMAL' box_thumbnail = layout.box() - # row = split_right.row() - # column_right = row.column() - box_thumbnail.scale_y = 0.5 - # row = box_thumbnail.row() - # row.scale_y = 20 + box_thumbnail.scale_y = .4 box_thumbnail.template_icon(icon_value=self.img.preview.icon_id, scale=34.0) # row = box_thumbnail.row() @@ -1738,8 +1752,11 @@ class AssetPopupCard(bpy.types.Operator): row = box_thumbnail.row() row.alignment = 'EXPAND' + + # display_ratings = can_display_ratings(self.asset_data) rc = self.asset_data.get('ratingsCount') - show_rating_threshold = 5 + show_rating_threshold = 0 + show_rating_prompt_threshold = 5 if rc: rcount = min(rc['quality'], rc['workingHours']) @@ -1755,13 +1772,25 @@ class AssetPopupCard(bpy.types.Operator): c = '-' pcoll = icons.icon_collections["main"] - row.label(text=str(s), icon_value=pcoll['trophy'].icon_id) - row.label(text=str(q), icon='SOLO_ON') - row.label(text=str(c), icon_value=pcoll['dumbbell'].icon_id) - if rcount <= show_rating_threshold: - box_thumbnail.alert = True + row.emboss = 'NONE' + op = row.operator('wm.blenderkit_tooltip', text=str(s), icon_value=pcoll['trophy'].icon_id) + op.tooltip = 'Asset score calculated from averaged user ratings. \n\n' \ + 'Score = quality × complexity × 10*\n\n *Happiness multiplier' + row.label(text=' ') + + tooltip_extension = f'.\n\nRatings results are shown for assets with more than {show_rating_threshold} ratings' + op = row.operator('wm.blenderkit_tooltip', text=str(q), icon='SOLO_ON') + op.tooltip = f"Quality, average from {rc['quality']} ratings" \ + f"{tooltip_extension if rcount <= show_rating_threshold else ''}" + row.label(text=' ') + op = row.operator('wm.blenderkit_tooltip', text=str(c), icon_value=pcoll['dumbbell'].icon_id) + op.tooltip = f"Complexity, average from {rc['workingHours']} ratings" \ + f"{tooltip_extension if rcount <= show_rating_threshold else ''}" + + if rcount <= show_rating_prompt_threshold: + box_thumbnail.alert = True box_thumbnail.label(text=f"") box_thumbnail.label(text=f"This asset has only {rcount} rating{'' if rcount == 1 else 's'} , please rate.") # box_thumbnail.label(text=f"Please rate this asset.") diff --git a/blenderkit/utils.py b/blenderkit/utils.py index f4302ac0b..d0f52cb2f 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -786,7 +786,12 @@ def profile_is_validator(): def guard_from_crash(): - '''Blender tends to crash when trying to run some functions with the addon going through unregistration process.''' + ''' + Blender tends to crash when trying to run some functions + with the addon going through unregistration process. + This function is used in these functions (like draw callbacks) + so these don't run during unregistration. + ''' if bpy.context.preferences.addons.get('blenderkit') is None: return False; if bpy.context.preferences.addons['blenderkit'].preferences is None: -- GitLab