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