Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVilém Duha <vilda.novak@gmail.com>2021-04-29 13:13:40 +0300
committerVilém Duha <vilda.novak@gmail.com>2021-04-29 13:13:59 +0300
commite670cee07525af65395a13f30f57ca5e656771a1 (patch)
tree6b5433dd9521bb63770ea82849db190be9f1f1d6
parent452996ae951478853af3c1bcac3e0e1a26a6cab4 (diff)
BlenderKit: improve right click menu
-basically a complete revamp of the code, enables to display asset information in a much cleaner way with more tooltips e.t.c. -simplified floating asset preview - name needs to be fixed still, and tooltip generation cleaned -added several new icons, deleted one unused -improve a lot of tooltips -fix rerender of thumbnails in unsaved files (would save assets into addon directory) -reorganize some rating functions into ratings_utils.py -new 'wrap' operator for web links, allows to have custom tooltips for each link
-rw-r--r--blenderkit/__init__.py10
-rw-r--r--blenderkit/asset_bar_op.py11
-rw-r--r--blenderkit/autothumb.py15
-rw-r--r--blenderkit/autothumb_material_bg.py6
-rw-r--r--blenderkit/autothumb_model_bg.py8
-rw-r--r--blenderkit/icons.py16
-rw-r--r--blenderkit/ratings.py217
-rw-r--r--blenderkit/ratings_utils.py121
-rw-r--r--blenderkit/search.py212
-rw-r--r--blenderkit/thumbnails/cc0.pngbin0 -> 5419 bytes
-rw-r--r--blenderkit/thumbnails/locked_large.pngbin3170 -> 0 bytes
-rw-r--r--blenderkit/thumbnails/private.pngbin0 -> 540 bytes
-rw-r--r--blenderkit/thumbnails/royalty_free.pngbin0 -> 4755 bytes
-rw-r--r--blenderkit/thumbnails/trophy.pngbin0 -> 3078 bytes
-rw-r--r--blenderkit/thumbnails/vs_validated.pngbin0 -> 2393 bytes
-rw-r--r--blenderkit/ui.py32
-rw-r--r--blenderkit/ui_panels.py483
-rw-r--r--blenderkit/upload.py7
-rw-r--r--blenderkit/utils.py13
19 files changed, 859 insertions, 292 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py
index 9633ae50..02d17f0b 100644
--- a/blenderkit/__init__.py
+++ b/blenderkit/__init__.py
@@ -49,6 +49,7 @@ if "bpy" in locals():
overrides = reload(overrides)
paths = reload(paths)
ratings = reload(ratings)
+ ratings_utils = reload(ratings_utils)
resolutions = reload(resolutions)
search = reload(search)
tasks_queue = reload(tasks_queue)
@@ -84,6 +85,7 @@ else:
from blenderkit import overrides
from blenderkit import paths
from blenderkit import ratings
+ from blenderkit import ratings_utils
from blenderkit import resolutions
from blenderkit import search
from blenderkit import tasks_queue
@@ -731,20 +733,20 @@ class BlenderKitRatingProps(PropertyGroup):
description="quality of the material",
default=0,
min=-1, max=10,
- update=ratings.update_ratings_quality)
+ update=ratings_utils.update_ratings_quality)
# the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily.
rating_quality_ui: EnumProperty(name='rating_quality_ui',
- items=ratings.stars_enum_callback,
+ items=ratings_utils.stars_enum_callback,
description='Rating stars 0 - 10',
default=None,
- update=ratings.update_quality_ui,
+ update=ratings_utils.update_quality_ui,
)
rating_work_hours: FloatProperty(name="Work Hours",
description="How many hours did this work take?",
default=0.00,
- min=0.0, max=150, update=ratings.update_ratings_work_hours
+ min=0.0, max=150, update=ratings_utils.update_ratings_work_hours
)
# rating_complexity: IntProperty(name="Complexity",
diff --git a/blenderkit/asset_bar_op.py b/blenderkit/asset_bar_op.py
index acb9cf94..30d94e27 100644
--- a/blenderkit/asset_bar_op.py
+++ b/blenderkit/asset_bar_op.py
@@ -225,9 +225,9 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
self.asset_name = name_label
self.tooltip_widgets.append(name_label)
offset_y = 16 + self.margin
- label = self.new_text('Left click or drag to append/link. Right click for more options.', self.assetbar_margin*2, labels_start + offset_y,
- text_size=14)
- self.tooltip_widgets.append(label)
+ # label = self.new_text('Left click or drag to append/link. Right click for more options.', self.assetbar_margin*2, labels_start + offset_y,
+ # text_size=14)
+ # self.tooltip_widgets.append(label)
self.hide_tooltip()
@@ -505,6 +505,9 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
# handlers
def enter_button(self, widget):
+ # context.window.cursor_warp(event.mouse_x, event.mouse_y - 20);
+
+
self.show_tooltip()
if self.active_index != widget.search_index:
@@ -532,6 +535,8 @@ class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
self.tooltip_panel.update(tooltip_x, widget.y_screen + widget.height)
self.tooltip_panel.layout_widgets()
+ # bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
+
def exit_button(self, widget):
# this condition checks if there wasn't another button already entered, which can happen with small button gaps
diff --git a/blenderkit/autothumb.py b/blenderkit/autothumb.py
index 26697d74..baf1a2ca 100644
--- a/blenderkit/autothumb.py
+++ b/blenderkit/autothumb.py
@@ -156,7 +156,7 @@ def start_thumbnailer(self=None, json_args=None, props=None, wait=False, add_bg_
eval_path_state = "bpy.data.objects['%s'].blenderkit.thumbnail_generating_state" % json_args['asset_name']
eval_path = "bpy.data.objects['%s']" % json_args['asset_name']
- bg_blender.add_bg_process(eval_path_computing=eval_path_computing, eval_path_state=eval_path_state,
+ bg_blender.add_bg_process(name = f"{json_args['asset_name']} thumbnailer" ,eval_path_computing=eval_path_computing, eval_path_state=eval_path_state,
eval_path=eval_path, process_type='THUMBNAILER', process=proc)
@@ -206,7 +206,7 @@ def start_material_thumbnailer(self=None, json_args=None, props=None, wait=False
eval_path_state = "bpy.data.materials['%s'].blenderkit.thumbnail_generating_state" % json_args['asset_name']
eval_path = "bpy.data.materials['%s']" % json_args['asset_name']
- bg_blender.add_bg_process(name=json_args['asset_name'], eval_path_computing=eval_path_computing,
+ bg_blender.add_bg_process(name=f"{json_args['asset_name']} thumbnailer", eval_path_computing=eval_path_computing,
eval_path_state=eval_path_state,
eval_path=eval_path, process_type='THUMBNAILER', process=proc)
if props:
@@ -328,7 +328,10 @@ class GenerateThumbnailOperator(bpy.types.Operator):
class ReGenerateThumbnailOperator(bpy.types.Operator):
- """Generate Cycles thumbnail for model assets"""
+ """
+ Generate default thumbnail with Cycles renderer and upload it.
+ Works also for assets from search results, without being downloaded before.
+ """
bl_idname = "object.blenderkit_regenerate_thumbnail"
bl_label = "BlenderKit Thumbnail Re-generate"
bl_options = {'REGISTER', 'INTERNAL'}
@@ -371,11 +374,9 @@ class ReGenerateThumbnailOperator(bpy.types.Operator):
return True # bpy.context.view_layer.objects.active is not None
def draw(self, context):
- ob = bpy.context.active_object
- while ob.parent is not None:
- ob = ob.parent
props = self
layout = self.layout
+ # layout.label('This will re-generate thumbnail and directly upload it to server. You should see your updated thumbnail online depending ')
layout.label(text='thumbnailer settings')
layout.prop(props, 'thumbnail_background_lightness')
layout.prop(props, 'thumbnail_angle')
@@ -521,7 +522,7 @@ class GenerateMaterialThumbnailOperator(bpy.types.Operator):
class ReGenerateMaterialThumbnailOperator(bpy.types.Operator):
"""
- Generate default thumbnail with Cycles renderer.
+ Generate default thumbnail with Cycles renderer and upload it.
Works also for assets from search results, without being downloaded before.
"""
bl_idname = "object.blenderkit_regenerate_material_thumbnail"
diff --git a/blenderkit/autothumb_material_bg.py b/blenderkit/autothumb_material_bg.py
index 0a0ce5db..3ae0d5dd 100644
--- a/blenderkit/autothumb_material_bg.py
+++ b/blenderkit/autothumb_material_bg.py
@@ -20,7 +20,7 @@
from blenderkit import utils, append_link, bg_blender, upload_bg, download
-import sys, json, math
+import sys, json, math, os
import bpy
from pathlib import Path
@@ -48,6 +48,10 @@ if __name__ == "__main__":
data = json.load(s)
# append_material(file_name, matname = None, link = False, fake_user = True)
if data.get('do_download'):
+ #need to save the file, so that asset doesn't get downloaded into addon directory
+ temp_blend_path = os.path.join(data['tempdir'], 'temp.blend')
+ bpy.ops.wm.save_as_mainfile(filepath=temp_blend_path)
+
asset_data = data['asset_data']
has_url = download.get_download_url(asset_data, download.get_scene_id(), user_preferences.api_key, tcom=None,
resolution='blend')
diff --git a/blenderkit/autothumb_model_bg.py b/blenderkit/autothumb_model_bg.py
index 9be56d9f..d8e529fd 100644
--- a/blenderkit/autothumb_model_bg.py
+++ b/blenderkit/autothumb_model_bg.py
@@ -20,8 +20,7 @@
from blenderkit import utils, append_link, bg_blender, download, upload_bg
-import sys, json, math
-from pathlib import Path
+import sys, json, math, os
import bpy
import mathutils
@@ -86,8 +85,11 @@ if __name__ == "__main__":
if data.get('do_download'):
- bg_blender.progress('Downloading asset')
+ #need to save the file, so that asset doesn't get downloaded into addon directory
+ temp_blend_path = os.path.join(data['tempdir'], 'temp.blend')
+ bpy.ops.wm.save_as_mainfile(filepath = temp_blend_path)
+ bg_blender.progress('Downloading asset')
asset_data = data['asset_data']
has_url = download.get_download_url(asset_data, download.get_scene_id(), user_preferences.api_key, tcom=None,
resolution='blend')
diff --git a/blenderkit/icons.py b/blenderkit/icons.py
index 45c729df..ab17efcf 100644
--- a/blenderkit/icons.py
+++ b/blenderkit/icons.py
@@ -27,9 +27,23 @@ icon_collections = {}
icons_read = {
'fp.png': 'free',
'flp.png': 'full',
- 'test.jpg': 'test',
+ 'trophy.png': 'trophy',
+ 'cc0.png': 'cc0',
+ 'royalty_free.png': 'royalty_free',
}
+verification_icons = {
+ 'vs_ready.png':'ready',
+ 'vs_deleted.png':'deleted' ,
+ 'vs_uploaded.png': 'uploaded',
+ 'vs_uploading.png': 'uploading',
+ 'vs_on_hold.png': 'on_hold',
+ 'vs_validated.png': 'validated',
+ 'vs_rejected.png': 'rejected'
+
+}
+
+icons_read.update(verification_icons)
def register_icons():
# Note that preview collections returned by bpy.utils.previews
diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py
index c7055905..118cc3ae 100644
--- a/blenderkit/ratings.py
+++ b/blenderkit/ratings.py
@@ -16,7 +16,7 @@
#
# ##### END GPL LICENSE BLOCK #####
-from blenderkit import paths, utils, rerequests, tasks_queue
+from blenderkit import paths, utils, rerequests, tasks_queue, ratings_utils
import bpy
import requests, threading
@@ -103,42 +103,6 @@ def get_rating(asset_id):
print(r.text)
-def update_ratings_quality(self, context):
- user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- api_key = user_preferences.api_key
-
- headers = utils.get_headers(api_key)
- asset = self.id_data
- if asset:
- bkit_ratings = asset.bkit_ratings
- url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/rating/'
- else:
- # this part is for operator rating:
- bkit_ratings = self
- url = paths.get_api_url() + f'assets/{self.asset_id}/rating/'
-
- if bkit_ratings.rating_quality > 0.1:
- ratings = [('quality', bkit_ratings.rating_quality)]
- tasks_queue.add_task((send_rating_to_thread_quality, (url, ratings, headers)), wait=2.5, only_last=True)
-
-
-def update_ratings_work_hours(self, context):
- user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- api_key = user_preferences.api_key
- headers = utils.get_headers(api_key)
- asset = self.id_data
- if asset:
- bkit_ratings = asset.bkit_ratings
- url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/rating/'
- else:
- # this part is for operator rating:
- bkit_ratings = self
- url = paths.get_api_url() + f'assets/{self.asset_id}/rating/'
-
- if bkit_ratings.rating_work_hours > 0.45:
- ratings = [('working_hours', round(bkit_ratings.rating_work_hours, 1))]
- tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5, only_last=True)
-
def upload_rating(asset):
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
@@ -242,69 +206,40 @@ class UploadRatingOperator(bpy.types.Operator):
return wm.invoke_props_dialog(self)
-def stars_enum_callback(self, context):
- '''regenerates the enum property used to display rating stars, so that there are filled/empty stars correctly.'''
- items = []
- for a in range(0, 10):
- if self.rating_quality < a + 1:
- icon = 'SOLO_OFF'
- else:
- icon = 'SOLO_ON'
- # has to have something before the number in the value, otherwise fails on registration.
- items.append((f'{a + 1}', f'{a + 1}', '', icon, a + 1))
- return items
-
-
-def update_quality_ui(self, context):
- '''Converts the _ui the enum into actual quality number.'''
- user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- if user_preferences.api_key == '':
- # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
- # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
- # return
- bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
- message='Please login/signup to rate assets. Clicking OK takes you to web login.')
- # self.rating_quality_ui = '0'
- self.rating_quality = int(self.rating_quality_ui)
-
-def update_ratings_work_hours_ui(self, context):
- user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- if user_preferences.api_key == '':
- # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
- # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
- # return
- bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
- message='Please login/signup to rate assets. Clicking OK takes you to web login.')
- # self.rating_work_hours_ui = '0'
- self.rating_work_hours = float(self.rating_work_hours_ui)
+def draw_ratings_menu(self, context, layout):
+ col = layout.column()
+ # layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0)
+ row = col.row()
+ row.prop(self, 'rating_quality_ui', expand=True, icon_only=True, emboss=False)
+ # row.label(text=str(self.rating_quality))
+ col.separator()
+ row = layout.row()
+ row.label(text=f"How many hours did this {self.asset_type} save you?")
-def update_ratings_work_hours_ui_1_5(self, context):
- user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- if user_preferences.api_key == '':
- # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
- # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
- # return
- bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
- message='Please login/signup to rate assets. Clicking OK takes you to web login.')
- # self.rating_work_hours_ui_1_5 = '0'
- # print('updating 1-5')
- # print(float(self.rating_work_hours_ui_1_5))
- self.rating_work_hours = float(self.rating_work_hours_ui_1_5)
-
-def update_ratings_work_hours_ui_1_10(self, context):
- user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
- if user_preferences.api_key == '':
- # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
- # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
- # return
- bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
- message='Please login/signup to rate assets. Clicking OK takes you to web login.')
- # self.rating_work_hours_ui_1_5 = '0'
- # print('updating 1-5')
- # print(float(self.rating_work_hours_ui_1_5))
- self.rating_work_hours = float(self.rating_work_hours_ui_1_10)
+ if self.asset_type in ('model', 'scene'):
+ row = layout.row()
+ if utils.profile_is_validator():
+ col.prop(self, 'rating_work_hours')
+ row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True)
+ if float(self.rating_work_hours_ui) > 100:
+ utils.label_multiline(layout,
+ text=f"\nThat's huge! please be sure to give such rating only to godly {self.asset_type}s.\n",
+ width=500)
+ elif float(self.rating_work_hours_ui) > 18:
+ layout.separator()
+
+ utils.label_multiline(layout,
+ text=f"\nThat's a lot! please be sure to give such rating only to amazing {self.asset_type}s.\n",
+ width=500)
+
+ elif self.asset_type == 'hdr':
+ row = layout.row()
+ row.prop(self, 'rating_work_hours_ui_1_10', expand=True, icon_only=False, emboss=True)
+ else:
+ row = layout.row()
+ row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True)
class FastRateMenu(Operator):
@@ -341,22 +276,22 @@ class FastRateMenu(Operator):
description="quality of the material",
default=0,
min=-1, max=10,
- # update=update_ratings_quality,
+ # update=ratings_utils.update_ratings_quality,
options={'SKIP_SAVE'})
# the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily.
rating_quality_ui: EnumProperty(name='rating_quality_ui',
- items=stars_enum_callback,
+ items=ratings_utils.stars_enum_callback,
description='Rating stars 0 - 10',
default=0,
- update=update_quality_ui,
+ update=ratings_utils.update_quality_ui,
options={'SKIP_SAVE'})
rating_work_hours: FloatProperty(name="Work Hours",
description="How many hours did this work take?",
default=0.00,
min=0.0, max=300,
- # update=update_ratings_work_hours,
+ # update=ratings_utils.update_ratings_work_hours,
options={'SKIP_SAVE'}
)
@@ -383,8 +318,8 @@ class FastRateMenu(Operator):
('200', '200', high_rating_warning),
('250', '250', high_rating_warning),
],
- default='0', update=update_ratings_work_hours_ui,
- options = {'SKIP_SAVE'}
+ default='0', update=ratings_utils.update_ratings_work_hours_ui,
+ options={'SKIP_SAVE'}
)
rating_work_hours_ui_1_5: EnumProperty(name="Work Hours",
@@ -399,28 +334,28 @@ class FastRateMenu(Operator):
('5', '5', '')
],
default='0',
- update=update_ratings_work_hours_ui_1_5,
- options = {'SKIP_SAVE'}
+ update=ratings_utils.update_ratings_work_hours_ui_1_5,
+ options={'SKIP_SAVE'}
)
rating_work_hours_ui_1_10: EnumProperty(name="Work Hours",
- description="How many hours did this work take?",
- items=[('0', '0', ''),
- ('1', '1', ''),
- ('2', '2', ''),
- ('3', '3', ''),
- ('4', '4', ''),
- ('5', '5', ''),
- ('6', '6', ''),
- ('7', '7', ''),
- ('8', '8', ''),
- ('9', '9', ''),
- ('10', '10', '')
- ],
- default='0',
- update=update_ratings_work_hours_ui_1_10,
- options={'SKIP_SAVE'}
- )
+ description="How many hours did this work take?",
+ items=[('0', '0', ''),
+ ('1', '1', ''),
+ ('2', '2', ''),
+ ('3', '3', ''),
+ ('4', '4', ''),
+ ('5', '5', ''),
+ ('6', '6', ''),
+ ('7', '7', ''),
+ ('8', '8', ''),
+ ('9', '9', ''),
+ ('10', '10', '')
+ ],
+ default='0',
+ update=ratings_utils.update_ratings_work_hours_ui_1_10,
+ options={'SKIP_SAVE'}
+ )
@classmethod
def poll(cls, context):
@@ -430,41 +365,9 @@ class FastRateMenu(Operator):
def draw(self, context):
layout = self.layout
- col = layout.column()
-
- # layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0)
- col.label(text=self.message)
- row = col.row()
- row.prop(self, 'rating_quality_ui', expand=True, icon_only=True, emboss=False)
- # row.label(text=str(self.rating_quality))
- col.separator()
-
- row = layout.row()
- row.label(text=f"How many hours did this {self.asset_type} save you?")
-
- if self.asset_type in ('model', 'scene'):
- row = layout.row()
- if utils.profile_is_validator():
- col.prop(self, 'rating_work_hours')
- row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True)
- if float(self.rating_work_hours_ui) > 100:
- utils.label_multiline(layout,
- text=f"\nThat's huge! please be sure to give such rating only to godly {self.asset_type}s.\n",
- width=500)
- elif float(self.rating_work_hours_ui) > 18:
- layout.separator()
-
- utils.label_multiline(layout,
- text=f"\nThat's a lot! please be sure to give such rating only to amazing {self.asset_type}s.\n",
- width=500)
-
- elif self.asset_type == 'hdr':
- row = layout.row()
- row.prop(self, 'rating_work_hours_ui_1_10', expand=True, icon_only=False, emboss=True)
- else:
- row = layout.row()
- row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True)
+ layout.label(text=self.message)
+ draw_ratings_menu(self, context, layout)
def execute(self, context):
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
@@ -505,7 +408,7 @@ class FastRateMenu(Operator):
self.message = f"Rate asset {self.asset_name}"
wm = context.window_manager
- if self.asset_type in ('model','scene'):
+ if self.asset_type in ('model', 'scene'):
# spawn a wider one for validators for the enum buttons
return wm.invoke_props_dialog(self, width=500)
else:
diff --git a/blenderkit/ratings_utils.py b/blenderkit/ratings_utils.py
new file mode 100644
index 00000000..9dc02e55
--- /dev/null
+++ b/blenderkit/ratings_utils.py
@@ -0,0 +1,121 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+#mainly update functions and callbacks for ratings properties, here to avoid circular imports.
+import bpy
+
+def update_ratings_quality(self, context):
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ api_key = user_preferences.api_key
+
+ headers = utils.get_headers(api_key)
+ asset = self.id_data
+ if asset:
+ bkit_ratings = asset.bkit_ratings
+ url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/rating/'
+ else:
+ # this part is for operator rating:
+ bkit_ratings = self
+ url = paths.get_api_url() + f'assets/{self.asset_id}/rating/'
+
+ if bkit_ratings.rating_quality > 0.1:
+ ratings = [('quality', bkit_ratings.rating_quality)]
+ tasks_queue.add_task((send_rating_to_thread_quality, (url, ratings, headers)), wait=2.5, only_last=True)
+
+
+def update_ratings_work_hours(self, context):
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ api_key = user_preferences.api_key
+ headers = utils.get_headers(api_key)
+ asset = self.id_data
+ if asset:
+ bkit_ratings = asset.bkit_ratings
+ url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/rating/'
+ else:
+ # this part is for operator rating:
+ bkit_ratings = self
+ url = paths.get_api_url() + f'assets/{self.asset_id}/rating/'
+
+ if bkit_ratings.rating_work_hours > 0.45:
+ ratings = [('working_hours', round(bkit_ratings.rating_work_hours, 1))]
+ tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5, only_last=True)
+
+def update_quality_ui(self, context):
+ '''Converts the _ui the enum into actual quality number.'''
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ if user_preferences.api_key == '':
+ # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
+ # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
+ # return
+ bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
+ message='Please login/signup to rate assets. Clicking OK takes you to web login.')
+ # self.rating_quality_ui = '0'
+ self.rating_quality = int(self.rating_quality_ui)
+
+
+def update_ratings_work_hours_ui(self, context):
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ if user_preferences.api_key == '':
+ # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
+ # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
+ # return
+ bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
+ message='Please login/signup to rate assets. Clicking OK takes you to web login.')
+ # self.rating_work_hours_ui = '0'
+ self.rating_work_hours = float(self.rating_work_hours_ui)
+
+
+def update_ratings_work_hours_ui_1_5(self, context):
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ if user_preferences.api_key == '':
+ # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
+ # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
+ # return
+ bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
+ message='Please login/signup to rate assets. Clicking OK takes you to web login.')
+ # self.rating_work_hours_ui_1_5 = '0'
+ # print('updating 1-5')
+ # print(float(self.rating_work_hours_ui_1_5))
+ self.rating_work_hours = float(self.rating_work_hours_ui_1_5)
+
+
+def update_ratings_work_hours_ui_1_10(self, context):
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ if user_preferences.api_key == '':
+ # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
+ # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
+ # return
+ bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
+ message='Please login/signup to rate assets. Clicking OK takes you to web login.')
+ # self.rating_work_hours_ui_1_5 = '0'
+ # print('updating 1-5')
+ # print(float(self.rating_work_hours_ui_1_5))
+ self.rating_work_hours = float(self.rating_work_hours_ui_1_10)
+
+
+def stars_enum_callback(self, context):
+ '''regenerates the enum property used to display rating stars, so that there are filled/empty stars correctly.'''
+ items = []
+ for a in range(0, 10):
+ if self.rating_quality < a + 1:
+ icon = 'SOLO_OFF'
+ else:
+ icon = 'SOLO_ON'
+ # has to have something before the number in the value, otherwise fails on registration.
+ items.append((f'{a + 1}', f'{a + 1}', '', icon, a + 1))
+ return items \ No newline at end of file
diff --git a/blenderkit/search.py b/blenderkit/search.py
index 1465d103..3f0532b5 100644
--- a/blenderkit/search.py
+++ b/blenderkit/search.py
@@ -572,10 +572,6 @@ def writeblockm(tooltip, mdata, key='', pretext=None, width=40): # for longer t
return tooltip
-def fmt_length(prop):
- prop = str(round(prop, 2))
- return prop
-
def has(mdata, prop):
if mdata.get(prop) is not None and mdata[prop] is not None and mdata[prop] is not False:
@@ -583,7 +579,6 @@ def has(mdata, prop):
else:
return False
-
def generate_tooltip(mdata):
col_w = 40
if type(mdata['parameters']) == list:
@@ -591,6 +586,151 @@ def generate_tooltip(mdata):
else:
mparams = mdata['parameters']
t = ''
+ # t = writeblock(t, mdata['displayName'], width=col_w)
+ # t += '\n'
+
+ t = writeblockm(t, mdata, key='description', pretext='', width=col_w)
+ if mdata['description'] != '':
+ t += '\n'
+
+ bools = (('rig', None), ('animated', None), ('manifold', 'non-manifold'), ('scene', None), ('simulation', None),
+ ('uv', None))
+ for b in bools:
+ if mparams.get(b[0]):
+ mdata['tags'].append(b[0])
+ elif b[1] != None:
+ mdata['tags'].append(b[1])
+
+ bools_data = ('adult',)
+ for b in bools_data:
+ if mdata.get(b) and mdata[b]:
+ mdata['tags'].append(b)
+ t = writeblockm(t, mparams, key='designer', pretext='Designer', width=col_w)
+ t = writeblockm(t, mparams, key='manufacturer', pretext='Manufacturer', width=col_w)
+ t = writeblockm(t, mparams, key='designCollection', pretext='Design collection', width=col_w)
+
+ # t = writeblockm(t, mparams, key='engines', pretext='engine', width = col_w)
+ # t = writeblockm(t, mparams, key='model_style', pretext='style', width = col_w)
+ # t = writeblockm(t, mparams, key='material_style', pretext='style', width = col_w)
+ # t = writeblockm(t, mdata, key='tags', width = col_w)
+ # t = writeblockm(t, mparams, key='condition', pretext='condition', width = col_w)
+ # t = writeblockm(t, mparams, key='productionLevel', pretext='production level', width = col_w)
+ if has(mdata, 'purePbr'):
+ t = writeblockm(t, mparams, key='pbrType', pretext='Pbr', width=col_w)
+
+ t = writeblockm(t, mparams, key='designYear', pretext='Design year', width=col_w)
+
+ if has(mparams, 'dimensionX'):
+ t += 'Size: %s × %s × %s m\n' % (utils.fmt_length(mparams['dimensionX']),
+ utils.fmt_length(mparams['dimensionY']),
+ utils.fmt_length(mparams['dimensionZ']))
+ if has(mparams, 'faceCount') and mdata['assetType'] == 'model':
+ t += 'Face count: %s\n' % (mparams['faceCount'])
+ # t += 'face count: %s, render: %s\n' % (mparams['faceCount'], mparams['faceCountRender'])
+
+ # write files size - this doesn't reflect true file size, since files size is computed from all asset files, including resolutions.
+ # if mdata.get('filesSize'):
+ # fs = utils.files_size_to_text(mdata['filesSize'])
+ # t += f'files size: {fs}\n'
+
+ # t = writeblockm(t, mparams, key='meshPolyType', pretext='mesh type', width = col_w)
+ # t = writeblockm(t, mparams, key='objectCount', pretext='nubmber of objects', width = col_w)
+
+ # t = writeblockm(t, mparams, key='materials', width = col_w)
+ # t = writeblockm(t, mparams, key='modifiers', width = col_w)
+ # t = writeblockm(t, mparams, key='shaders', width = col_w)
+
+ # if has(mparams, 'textureSizeMeters'):
+ # t += 'Texture size: %s m\n' % utils.fmt_length(mparams['textureSizeMeters'])
+
+ if has(mparams, 'textureResolutionMax') and mparams['textureResolutionMax'] > 0:
+ if not mparams.get('textureResolutionMin'): # for HDR's
+ t = writeblockm(t, mparams, key='textureResolutionMax', pretext='Resolution', width=col_w)
+ elif mparams.get('textureResolutionMin') == mparams['textureResolutionMax']:
+ t = writeblockm(t, mparams, key='textureResolutionMin', pretext='Texture resolution', width=col_w)
+ else:
+ t += 'Tex resolution: %i - %i\n' % (mparams.get('textureResolutionMin'), mparams['textureResolutionMax'])
+
+ if has(mparams, 'thumbnailScale'):
+ t = writeblockm(t, mparams, key='thumbnailScale', pretext='Preview scale', width=col_w)
+
+ # t += 'uv: %s\n' % mdata['uv']
+ # t += '\n'
+ if mdata.get('license') == 'cc_zero':
+ t+= 'license: CC Zero\n'
+ else:
+ t+= 'license: Royalty free\n'
+ # t = writeblockm(t, mdata, key='license', width=col_w)
+
+ fs = mdata.get('files')
+
+ if utils.profile_is_validator():
+ if fs and len(fs) > 2:
+ resolutions = 'Resolutions:'
+ list.sort(fs, key=lambda f: f['fileType'])
+ for f in fs:
+ if f['fileType'].find('resolution') > -1:
+ resolutions += f['fileType'][11:] + ' '
+ resolutions += '\n'
+ t += resolutions.replace('_', '.')
+
+ # if mdata['isFree']:
+ # t += 'Free plan\n'
+ # else:
+ # t += 'Full plan\n'
+ else:
+ if fs:
+ for f in fs:
+ if f['fileType'].find('resolution') > -1:
+ t += 'Asset has lower resolutions available\n'
+ break;
+
+ # generator is for both upload preview and search, this is only after search
+ # if mdata.get('versionNumber'):
+ # # t = writeblockm(t, mdata, key='versionNumber', pretext='version', width = col_w)
+ # a_id = mdata['author'].get('id')
+ # if a_id != None:
+ # adata = bpy.context.window_manager['bkit authors'].get(str(a_id))
+ # if adata != None:
+ # t += generate_author_textblock(adata)
+
+
+ # t += '\n'
+ # rc = mdata.get('ratingsCount')
+ # if rc:
+ # t+='\n'
+ # if rc:
+ # rcount = min(rc['quality'], rc['workingHours'])
+ # else:
+ # rcount = 0
+ #
+ # show_rating_threshold = 5
+ #
+ # if rcount < show_rating_threshold and mdata['assetType'] != 'hdr':
+ # t += f"Only assets with enough ratings \nshow the rating value. Please rate.\n"
+ # if rc['quality'] >= show_rating_threshold:
+ # # t += f"{int(mdata['ratingsAverage']['quality']) * '*'}\n"
+ # t += f"* {round(mdata['ratingsAverage']['quality'],1)}\n"
+ # if rc['workingHours'] >= show_rating_threshold:
+ # t += f"Hours saved: {int(mdata['ratingsAverage']['workingHours'])}\n"
+ # if utils.profile_is_validator():
+ # t += f"Score: {int(mdata['score'])}\n"
+ #
+ # t += f"Ratings count {rc['quality']}*/{rc['workingHours']}wh value " \
+ # f"{(mdata['ratingsAverage']['quality'],1)}*/{(mdata['ratingsAverage']['workingHours'],1)}wh\n"
+ # if len(t.split('\n')) < 11:
+ # t += '\n'
+ # t += get_random_tip(mdata)
+ # t += '\n'
+ return t
+
+def generate_tooltip_old(mdata):
+ col_w = 40
+ if type(mdata['parameters']) == list:
+ mparams = utils.params_to_dict(mdata['parameters'])
+ else:
+ mparams = mdata['parameters']
+ t = ''
t = writeblock(t, mdata['displayName'], width=col_w)
t += '\n'
@@ -626,9 +766,9 @@ def generate_tooltip(mdata):
t = writeblockm(t, mparams, key='designYear', pretext='Design year', width=col_w)
if has(mparams, 'dimensionX'):
- t += 'Size: %s x %s x %sm\n' % (fmt_length(mparams['dimensionX']),
- fmt_length(mparams['dimensionY']),
- fmt_length(mparams['dimensionZ']))
+ t += 'Size: %s x %s x %sm\n' % (utils.fmt_length(mparams['dimensionX']),
+ utils.fmt_length(mparams['dimensionY']),
+ utils.fmt_length(mparams['dimensionZ']))
if has(mparams, 'faceCount') and mdata['assetType'] == 'model':
t += 'Face count: %s\n' % (mparams['faceCount'])
# t += 'face count: %s, render: %s\n' % (mparams['faceCount'], mparams['faceCountRender'])
@@ -646,7 +786,7 @@ def generate_tooltip(mdata):
# t = writeblockm(t, mparams, key='shaders', width = col_w)
# if has(mparams, 'textureSizeMeters'):
- # t += 'Texture size: %s m\n' % fmt_length(mparams['textureSizeMeters'])
+ # t += 'Texture size: %s m\n' % utils.fmt_length(mparams['textureSizeMeters'])
if has(mparams, 'textureResolutionMax') and mparams['textureResolutionMax'] > 0:
if not mparams.get('textureResolutionMin'): # for HDR's
@@ -729,37 +869,24 @@ def generate_tooltip(mdata):
return t
-def get_random_tip(mdata):
+def get_random_tip():
t = ''
-
tip = 'Tip: ' + random.choice(rtips)
t = writeblock(t, tip)
return t
- # at = mdata['assetType']
- # if at == 'brush' or at == 'texture':
- # t += 'click to link %s' % mdata['assetType']
- # if at == 'model' or at == 'material':
- # tips = ['Click or drag in scene to link/append %s' % mdata['assetType'],
- # "'A' key to search assets by same author",
- # "'W' key to open Authors webpage",
- # ]
- # tip = 'Tip: ' + random.choice(tips)
- # t = writeblock(t, tip)
- return t
def generate_author_textblock(adata):
- t = '\n\n\n'
+ t = ''
if adata not in (None, ''):
- col_w = 40
+ col_w = 2000
if len(adata['firstName'] + adata['lastName']) > 0:
- t = 'Author:\n'
- t += '%s %s\n' % (adata['firstName'], adata['lastName'])
+ t = 'Author: %s %s\n' % (adata['firstName'], adata['lastName'])
t += '\n'
- if adata.get('aboutMeUrl') is not None:
- t = writeblockm(t, adata, key='aboutMeUrl', pretext='', width=col_w)
- t += '\n'
+ # if adata.get('aboutMeUrl') is not None:
+ # t = writeblockm(t, adata, key='aboutMeUrl', pretext='', width=col_w)
+ # t += '\n'
if adata.get('aboutMe') is not None:
t = writeblockm(t, adata, key='aboutMe', pretext='', width=col_w)
t += '\n'
@@ -1528,6 +1655,7 @@ class SearchOperator(Operator):
bl_label = "BlenderKit asset search"
bl_description = "Search online for assets"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
+
own: BoolProperty(name="own assets only",
description="Find all own assets",
default=False)
@@ -1559,6 +1687,12 @@ class SearchOperator(Operator):
options={'SKIP_SAVE'}
)
+ tooltip: bpy.props.StringProperty(default='Runs search and displays the asset bar at the same time')
+
+ @classmethod
+ def description(cls, context, properties):
+ return properties.tooltip
+
@classmethod
def poll(cls, context):
return True
@@ -1577,9 +1711,27 @@ class SearchOperator(Operator):
return {'FINISHED'}
+class UrlOperator(Operator):
+ """"""
+ bl_idname = "wm.blenderkit_url"
+ bl_label = ""
+ bl_description = "Search online for assets"
+ bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
+
+ tooltip: bpy.props.StringProperty(default='Open a web page')
+ url: bpy.props.StringProperty(default='Runs search and displays the asset bar at the same time')
+
+ @classmethod
+ def description(cls, context, properties):
+ return properties.tooltip
+
+ def execute(self,context):
+ bpy.ops.wm.url_open(url=self.url)
+
classes = [
- SearchOperator
+ SearchOperator,
+ UrlOperator
]
diff --git a/blenderkit/thumbnails/cc0.png b/blenderkit/thumbnails/cc0.png
new file mode 100644
index 00000000..3f5450f8
--- /dev/null
+++ b/blenderkit/thumbnails/cc0.png
Binary files differ
diff --git a/blenderkit/thumbnails/locked_large.png b/blenderkit/thumbnails/locked_large.png
deleted file mode 100644
index eb2deb65..00000000
--- a/blenderkit/thumbnails/locked_large.png
+++ /dev/null
Binary files differ
diff --git a/blenderkit/thumbnails/private.png b/blenderkit/thumbnails/private.png
new file mode 100644
index 00000000..7ac3c3d7
--- /dev/null
+++ b/blenderkit/thumbnails/private.png
Binary files differ
diff --git a/blenderkit/thumbnails/royalty_free.png b/blenderkit/thumbnails/royalty_free.png
new file mode 100644
index 00000000..b85fa910
--- /dev/null
+++ b/blenderkit/thumbnails/royalty_free.png
Binary files differ
diff --git a/blenderkit/thumbnails/trophy.png b/blenderkit/thumbnails/trophy.png
new file mode 100644
index 00000000..01d77a22
--- /dev/null
+++ b/blenderkit/thumbnails/trophy.png
Binary files differ
diff --git a/blenderkit/thumbnails/vs_validated.png b/blenderkit/thumbnails/vs_validated.png
new file mode 100644
index 00000000..b2d8fdd2
--- /dev/null
+++ b/blenderkit/thumbnails/vs_validated.png
Binary files differ
diff --git a/blenderkit/ui.py b/blenderkit/ui.py
index 7117055f..7ef5092a 100644
--- a/blenderkit/ui.py
+++ b/blenderkit/ui.py
@@ -360,8 +360,10 @@ def draw_tooltip(x, y, text='', author='', img=None, gravatar=None):
if gravatar is not None:
# ui_bgl.draw_image(x + isizex - gsize - textmargin, y - isizey + texth - gsize - nameline_height - textmargin,
# gsize, gsize, gravatar, 1)
- ui_bgl.draw_image(x + isizex / 2 + textmargin, y - isizey + texth - gsize - nameline_height - textmargin,
- gsize, gsize, gravatar, 1)
+ # ui_bgl.draw_image(x + isizex / 2 + textmargin, y - isizey + texth - gsize - nameline_height - textmargin,
+ # gsize, gsize, gravatar, 1)
+ ui_bgl.draw_image(x + isizex / 2 + textmargin, y - isizey + texth - gsize - textmargin,
+ gsize, gsize, gravatar, 1)
i = 0
column_lines = -1 # start minus one for the name
@@ -399,13 +401,14 @@ def draw_tooltip(x, y, text='', author='', img=None, gravatar=None):
xtext -= gsize + textmargin
ytext = y - column_lines * line_height - nameline_height - ttipmargin - textmargin - isizey + texth
- if False: # i == 0:
+ if i == 0:
+ fsize = name_height-4
ytext = y - name_height + 5 - isizey + texth - textmargin
elif i == len(lines) - 1:
ytext = y - (nlines - 1) * line_height - nameline_height - ttipmargin * 2 - isizey + texth
tcol = textcol
tsize = font_height
- if (i > 0 and alines[i - 1][:7] == 'Author:'):
+ elif (i > 0 and alines[i - 1][:7] == 'Author:'):
tcol = textcol_strong
fsize = font_height + 2
else:
@@ -455,9 +458,16 @@ def draw_tooltip_with_author(asset_data, x, y):
gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash'])
atip = a['tooltip']
+
+ tooltip = f"{asset_data['displayName']}\n\n" \
+ f"Left click to drag to append/link.\nRight click for more."
+
# scene = bpy.context.scene
# ui_props = scene.blenderkitUI
- draw_tooltip(x, y, text=asset_data['tooltip'], author=atip, img=img,
+ author_s = ''
+ if not gimg:
+ author_s = 'Author: '
+ draw_tooltip(x, y, text=asset_data['displayName']+'\n\n', author=f"{author_s}{a['firstName']} {a['lastName']}", img=img,
gravatar=gimg)
@@ -851,6 +861,8 @@ def draw_asset_bar(self, context):
img = utils.get_thumbnail('locked.png')
ui_bgl.draw_image(x + 2, y + 2, 24, 24, img, 1)
+ # pcoll = icons.icon_collections["main"]
+ # v_icon = pcoll['rejected']
v_icon = verification_icons[result.get('verificationStatus', 'validated')]
if v_icon is not None:
img = utils.get_thumbnail(v_icon)
@@ -1575,8 +1587,12 @@ class AssetBarOperator(bpy.types.Operator):
my = event.mouse_y - r.y
if event.value == 'PRESS' and mouse_in_asset_bar(mx, my):
- # bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
- bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
+ context.window.cursor_warp(event.mouse_x-500, event.mouse_y-45);
+
+ bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
+ context.window.cursor_warp(event.mouse_x, event.mouse_y);
+
+ # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
return {'RUNNING_MODAL'}
if event.type == 'LEFTMOUSE':
@@ -1960,7 +1976,7 @@ def find_and_activate_instancers(object):
class AssetDragOperator(bpy.types.Operator):
- """Draw a line with the mouse"""
+ """Drag & drop assets into scene."""
bl_idname = "view3d.asset_drag_drop"
bl_label = "BlenderKit asset drag drop"
diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py
index 6bacc895..4f703ba3 100644
--- a/blenderkit/ui_panels.py
+++ b/blenderkit/ui_panels.py
@@ -17,8 +17,9 @@
# ##### END GPL LICENSE BLOCK #####
-from blenderkit import paths, ratings, utils, download, categories, icons, search, resolutions, ui, tasks_queue, \
- autothumb
+from blenderkit import paths, ratings, ratings_utils, utils, download, categories, icons, search, resolutions, ui, \
+ tasks_queue, \
+ autothumb, upload
from bpy.types import (
Panel
@@ -35,9 +36,7 @@ from bpy.props import (
import bpy
import os
-import random
import logging
-import blenderkit
bk_logger = logging.getLogger('blenderkit')
@@ -207,7 +206,6 @@ def draw_panel_hdr_search(self, context):
utils.label_multiline(layout, text=props.report)
-
def draw_thumbnail_upload_panel(layout, props):
update = False
tex = autothumb.get_texture_ui(props.thumbnail, '.upload_preview')
@@ -216,6 +214,7 @@ def draw_thumbnail_upload_panel(layout, props):
box = layout.box()
box.template_icon(icon_value=tex.image.preview.icon_id, scale=6.0)
+
def draw_panel_model_upload(self, context):
ob = bpy.context.active_object
while ob.parent is not None:
@@ -646,7 +645,8 @@ def draw_panel_material_upload(self, context):
prop_needed(row, props, 'thumbnail', props.has_thumbnail, False)
if bpy.context.scene.render.engine in ('CYCLES', 'BLENDER_EEVEE'):
- layout.operator("object.blenderkit_generate_material_thumbnail", text='Render thumbnail with Cycles', icon='EXPORT')
+ layout.operator("object.blenderkit_generate_material_thumbnail", text='Render thumbnail with Cycles',
+ icon='EXPORT')
if props.is_generating_thumbnail:
row = layout.row(align=True)
row.label(text=props.thumbnail_generating_state, icon='RENDER_STILL')
@@ -1153,12 +1153,13 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
layout.operator_context = 'INVOKE_DEFAULT'
- op = layout.operator('wm.blenderkit_menu_rating_upload', text='Rate')
- op.asset_name = asset_data['name']
- op.asset_id = asset_data['id']
- op.asset_type = asset_data['assetType']
+ if from_panel:
+ op = layout.operator('wm.blenderkit_menu_rating_upload', text='Rate')
+ op.asset_name = asset_data['name']
+ op.asset_id = asset_data['id']
+ op.asset_type = asset_data['assetType']
- if wm.get('bkit authors') is not None and author_id is not None:
+ if from_panel and wm.get('bkit authors') is not None and author_id is not None:
a = bpy.context.window_manager['bkit authors'].get(author_id)
if a is not None:
# utils.p('author:', a)
@@ -1172,6 +1173,7 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
op.author_id = author_id
op = layout.operator('view3d.blenderkit_search', text='Search Similar')
+ op.tooltip = 'Search for similar assets in the library'
# build search string from description and tags:
op.keywords = asset_data['name']
if asset_data.get('description'):
@@ -1263,7 +1265,6 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
op.model_rotation = (0, 0, 0)
op.max_resolution = asset_data.get('max_resolution',
0) # str(utils.get_param(asset_data, 'textureResolutionMax'))
- print('should be drawn!')
# print('operator res ', resolution)
# op.resolution = resolution
@@ -1297,7 +1298,7 @@ def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
row = layout.row()
row.operator_context = 'INVOKE_DEFAULT'
- op = layout.operator('wm.blenderkit_fast_metadata', text='Fast Edit Metadata')
+ op = layout.operator('wm.blenderkit_fast_metadata', text='Edit Metadata')
op.asset_id = asset_data['id']
op.asset_type = asset_data['assetType']
@@ -1377,97 +1378,429 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu):
asset_data = sr[ui_props.active_index]
draw_asset_context_menu(self.layout, context, asset_data, from_panel=False)
- # ui_props = context.scene.blenderkitUI
- #
- # sr = bpy.context.window_manager['search results']
- # asset_data = sr[ui_props.active_index]
- # layout = self.layout
- # row = layout.row()
- # split = row.split(factor=0.2)
- # col = split.column()
- # op = col.operator('view3d.asset_drag_drop')
- # op.asset_search_index=ui_props.active_index
- #
- # draw_asset_context_menu(col, context, asset_data, from_panel=False)
- # split = split.split(factor=0.3)
- # col1 = split.column()
- # box = col1.box()
- # utils.label_multiline(box, asset_data['tooltip'])
- # col2 = split.column()
- #
- # pcoll = icons.icon_collections["main"]
- # my_icon = pcoll['test']
- # row = col2.row()
- # row.scale_y = 4
- # row.template_icon(icon_value=my_icon.icon_id, scale=2.0)
- # # col2.template_icon(icon_value=self.img.preview.icon_id, scale=10.0)
- # box2 = col2.box()
- #
- # box2.label(text='and heere goes the rating')
- # box2.label(text='************')
- # box2.label(text='dadydadadada')
-
class AssetPopupCard(bpy.types.Operator):
"""Generate Cycles thumbnail for model assets"""
bl_idname = "wm.blenderkit_asset_popup"
bl_label = "BlenderKit asset popup"
- # bl_options = {'REGISTER', 'INTERNAL'}
- bl_options = {'REGISTER', }
+
+ width = 700
+
+ message: StringProperty(
+ name="message",
+ description="message",
+ default="Rating asset",
+ options={'SKIP_SAVE'})
+
+ asset_id: StringProperty(
+ name="Asset Base Id",
+ description="Unique id of the asset (hidden)",
+ default="",
+ options={'SKIP_SAVE'})
+
+ asset_name: StringProperty(
+ name="Asset Name",
+ description="Name of the asset (hidden)",
+ default="",
+ options={'SKIP_SAVE'})
+
+ asset_type: StringProperty(
+ name="Asset type",
+ description="asset type",
+ default="",
+ options={'SKIP_SAVE'})
+
+ rating_quality: IntProperty(name="Quality",
+ description="quality of the material",
+ default=0,
+ min=-1, max=10,
+ # update=update_ratings_quality,
+ options={'SKIP_SAVE'})
+
+ # the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily.
+ rating_quality_ui: EnumProperty(name='rating_quality_ui',
+ items=ratings_utils.stars_enum_callback,
+ description='Rating stars 0 - 10',
+ default=0,
+ update=ratings_utils.update_quality_ui,
+ options={'SKIP_SAVE'})
+
+ rating_work_hours: FloatProperty(name="Work Hours",
+ description="How many hours did this work take?",
+ default=0.00,
+ min=0.0, max=300,
+ # update=update_ratings_work_hours,
+ options={'SKIP_SAVE'}
+ )
+
+ high_rating_warning = "This is a high rating, please be sure to give such rating only to amazing assets"
+
+ rating_work_hours_ui: EnumProperty(name="Work Hours",
+ description="How many hours did this work take?",
+ items=[('0', '0', ''),
+ ('.5', '0.5', ''),
+ ('1', '1', ''),
+ ('2', '2', ''),
+ ('3', '3', ''),
+ ('4', '4', ''),
+ ('5', '5', ''),
+ ('6', '6', ''),
+ ('8', '8', ''),
+ ('10', '10', ''),
+ ('15', '15', ''),
+ ('20', '20', ''),
+ ('30', '30', high_rating_warning),
+ ('50', '50', high_rating_warning),
+ ('100', '100', high_rating_warning),
+ ('150', '150', high_rating_warning),
+ ('200', '200', high_rating_warning),
+ ('250', '250', high_rating_warning),
+ ],
+ default='0', update=ratings_utils.update_ratings_work_hours_ui,
+ options={'SKIP_SAVE'}
+ )
+
+ rating_work_hours_ui_1_5: EnumProperty(name="Work Hours",
+ description="How many hours did this work take?",
+ items=[('0', '0', ''),
+ ('.2', '0.2', ''),
+ ('.5', '0.5', ''),
+ ('1', '1', ''),
+ ('2', '2', ''),
+ ('3', '3', ''),
+ ('4', '4', ''),
+ ('5', '5', '')
+ ],
+ default='0',
+ update=ratings_utils.update_ratings_work_hours_ui_1_5,
+ options={'SKIP_SAVE'}
+ )
+
+ rating_work_hours_ui_1_10: EnumProperty(name="Work Hours",
+ description="How many hours did this work take?",
+ items=[('0', '0', ''),
+ ('1', '1', ''),
+ ('2', '2', ''),
+ ('3', '3', ''),
+ ('4', '4', ''),
+ ('5', '5', ''),
+ ('6', '6', ''),
+ ('7', '7', ''),
+ ('8', '8', ''),
+ ('9', '9', ''),
+ ('10', '10', '')
+ ],
+ default='0',
+ update=ratings_utils.update_ratings_work_hours_ui_1_10,
+ options={'SKIP_SAVE'}
+ )
@classmethod
def poll(cls, context):
return True
+ def draw_menu(self, context, layout):
+ ui_props = context.scene.blenderkitUI
+
+ col_left = layout.column()
+ # row_button = col_left.row()
+ # row_button.scale_y = 3
+ # op = row_button.operator('view3d.asset_drag_drop', text='Drag & Drop')
+ # op.asset_search_index = ui_props.active_index
+ draw_asset_context_menu(col_left, context, self.asset_data, from_panel=False)
+ # layout = col_left
+ # op = layout.operator('view3d.blenderkit_search', text='Search Similar')
+ # # build search string from description and tags:
+ # op.keywords = self.asset_data['name']
+ # if self.asset_data.get('description'):
+ # op.keywords += ' ' + self.asset_data.get('description') + ' '
+ # op.keywords += ' '.join(self.asset_data.get('tags'))
+
+ def draw_property(self, layout, left, right, icon=None, icon_value=None, url=None, 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 = split.split()
+ op = split.operator('wm.blenderkit_url', text='', icon='QUESTION')
+ op.url = url
+ op.tooltip = tooltip
+
+ def draw_asset_parameter(self, layout, key='', pretext=''):
+ parameter = utils.get_param(self.asset_data, key)
+ if parameter == None:
+ return
+ self.draw_property(layout, pretext, parameter)
+
+ def draw_tooltip(self, layout):
+ if type(self.asset_data['parameters']) == list:
+ mparams = utils.params_to_dict(self.asset_data['parameters'])
+ else:
+ mparams = self.asset_data['parameters']
+
+ layout = layout.column()
+ if len(self.asset_data['description']) > 0:
+ box = layout.box()
+ box.scale_y = 0.8
+ box.label(text='Description:')
+ utils.label_multiline(box, self.asset_data['description'], width=200)
+
+ pcoll = icons.icon_collections["main"]
+
+ box = layout.box()
+ box.scale_y = 0.8
+
+ if self.asset_data.get('license') == 'cc_zero':
+ t = 'CC Zero'
+ icon = pcoll['cc0']
+
+ else:
+ t = 'Royalty free'
+ icon = pcoll['royalty_free']
+
+ self.draw_property(box,
+ 'license:', t,
+ 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'
+ )
+
+ if upload.can_edit_asset(asset_data=self.asset_data):
+ icon = pcoll[self.asset_data['verificationStatus']]
+ verification_status_tooltips = {
+ 'uploading': "Your asset got stuck during upload. Probably, your file was too large "
+ "or your connection too slow or interrupting. If you have repeated issues, "
+ "please contact us and let us know, it might be a bug",
+ 'uploaded': "Your asset uploaded successfully. Yay! If it's public, "
+ "it's awaiting validation. If it's private, use it",
+ 'on_hold': "Your asset needs some (usually smaller) fixes, "
+ "so we can make it public for everybody."
+ " Please check your email to see the feedback "
+ "that we send to every creator personally",
+ 'rejected': "The asset has serious quality issues, " \
+ "and it's probable that it might be good to start " \
+ "all over again or try with something simpler. " \
+ "You also get personal feedback into your e-mail, " \
+ "since we believe that together, we can all learn " \
+ "to become awesome 3D artists",
+ 'deleted': "You deleted this asset",
+ 'validated': "Your asset passed our validation process, "
+ "and is now available to BlenderKit users"
+
+ }
+ self.draw_property(box,
+ 'Verification:',
+ self.asset_data['verificationStatus'],
+ icon_value=icon.icon_id,
+ url="https://www.blenderkit.com/docs/validation-status/",
+ tooltip=verification_status_tooltips[self.asset_data['verificationStatus']]
+
+ )
+
+ self.draw_asset_parameter(box, key='textureResolutionMax', pretext='Resolution:')
+
+ self.draw_asset_parameter(box, key='designer', pretext='Designer:')
+ self.draw_asset_parameter(box, key='manufacturer', pretext='Manufacturer:')
+ self.draw_asset_parameter(box, key='collection', pretext='Collection:')
+ self.draw_asset_parameter(box, key='designYear', pretext='Design year:')
+ self.draw_asset_parameter(box, key='faceCount', pretext='Face count:')
+ self.draw_asset_parameter(box, key='thumbnailScale', pretext='Preview scale:')
+
+ if utils.get_param(self.asset_data, 'dimensionX'):
+ t = '%s × %s × %s m' % (utils.fmt_length(mparams['dimensionX']),
+ utils.fmt_length(mparams['dimensionY']),
+ utils.fmt_length(mparams['dimensionZ']))
+ self.draw_property(box, 'Size:', t)
+
+ #Free/Full plan or private Access
+ 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)
+ else:
+ t = 'Full plan'
+ icon = pcoll['full']
+ self.draw_property(box, 'Access:', t, icon_value=icon.icon_id)
+
+ def draw_author(self, layout, width=330):
+ image_split = 0.25
+ text_width = width
+ authors = bpy.context.window_manager['bkit authors']
+ a = authors.get(self.asset_data['author']['id'])
+ if a is not None: # or a is '' or (a.get('gravatarHash') is not None and a.get('gravatarImg') is None):
+ row = layout.row()
+ author_box = row.box()
+ author_box.scale_y = 0.6 # get text lines closer to each other
+ if hasattr(self, 'gimg'):
+
+ author_left = author_box.split(factor=0.25)
+ author_left.template_icon(icon_value=self.gimg.preview.icon_id, scale=6.0)
+ text_area = author_left.split()
+ text_width = int(text_width * (1 - image_split))
+ else:
+ text_area = author_box
+
+ author_right = text_area.column()
+ row = author_right.row()
+ col = row.column()
+
+ utils.label_multiline(col, text=a['tooltip'], width=text_width)
+ if upload.can_edit_asset(asset_data=self.asset_data) and a.get('aboutMe') is not None and len(
+ a.get('aboutMe', '')) == 0:
+ col.label(text='Please write something about yourself!')
+ op = col.operator('wm.blenderkit_url', text='Edit your profile')
+ op.url = 'https://www.blenderkit.com/profile'
+ op.tooltip = 'Edit your profile on BlenderKit webpage'
+
+ button_row = author_box.row()
+ button_row.scale_y = 2.0
+
+ if a.get('aboutMeUrl') is not None:
+ url = a['aboutMeUrl']
+ text = url
+ if len(url) > 25:
+ text = url[:25] + '...'
+ else:
+ url = paths.get_author_gallery_url(a['id'])
+ text = "Open Author's Profile"
+
+ 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.keywords = ''
+ op.author_id = self.asset_data['author']['id']
+
+ def draw_thumbnail_box(self, layout):
+ 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.template_icon(icon_value=self.img.preview.icon_id, scale=34.0)
+ # row = box_thumbnail.row()
+ # row.scale_y = 4
+ # op = row.operator('view3d.asset_drag_drop', text='Drag & Drop from here', depress=True)
+
+ row = box_thumbnail.row()
+ row.alignment = 'EXPAND'
+ rc = self.asset_data.get('ratingsCount')
+ show_rating_threshold = 3
+
+ if rc:
+ rcount = min(rc['quality'], rc['workingHours'])
+ else:
+ rcount = 0
+ if rcount >= show_rating_threshold or upload.can_edit_asset(asset_data=self.asset_data):
+ pcoll = icons.icon_collections["main"]
+ my_icon = pcoll['trophy']
+ s = self.asset_data['score']
+ if s:
+ row.label(text=str(round(s)), icon_value=my_icon.icon_id)
+ q = self.asset_data['ratingsAverage'].get('quality')
+ if q:
+ row.label(text=str(round(q)), icon='SOLO_ON')
+ c = self.asset_data['ratingsAverage'].get('workingHours')
+ if c:
+ row.label(text=str(round(c)), icon='SORTTIME')
+ else:
+ box_thumbnail.label(text=f"This asset needs more ratings ( {rcount} of {show_rating_threshold} ).")
+ # box_thumbnail.label(text=f"Please rate this asset.")
+
+ def draw_menu_desc_author(self, context, layout):
+ box = layout.column()
+
+ box.emboss = 'NORMAL'
+ # left - tooltip & params
+ row = box.row()
+ split_left_left = row.split(factor=0.7)
+ self.draw_tooltip(split_left_left)
+
+ # right - menu
+ col1 = split_left_left.split()
+ self.draw_menu(context, col1)
+
+ # author
+ self.draw_author(box)
+
def draw(self, context):
ui_props = context.scene.blenderkitUI
sr = bpy.context.window_manager['search results']
asset_data = sr[ui_props.active_index]
+ self.asset_data = asset_data
layout = self.layout
- row = layout.row()
- split = row.split(factor=0.2)
- col = split.column()
- op = col.operator('view3d.asset_drag_drop')
- op.asset_search_index = ui_props.active_index
- draw_asset_context_menu(col, context, asset_data, from_panel=False)
- split = split.split(factor=0.5)
- col1 = split.column()
- box = col1.box()
- utils.label_multiline(box, asset_data['tooltip'], width=300)
-
- col2 = split.column()
+ # top draggabe bar with name of the asset
+ top_row = layout.row()
+ top_drag_bar = top_row.box()
+ top_drag_bar.alignment = 'CENTER'
- pcoll = icons.icon_collections["main"]
- my_icon = pcoll['test']
- col2.template_icon(icon_value=my_icon.icon_id, scale=20.0)
- # col2.template_icon(icon_value=self.img.preview.icon_id, scale=10.0)
- box2 = col2.box()
-
- # draw_ratings(box2, context, asset_data)
- box2.label(text='Ratings')
- # print(tp, dir(tp))
- # if not hasattr(self, 'first_draw'):# try to redraw because of template preview which needs update
- # for region in context.area.regions:
- # region.tag_redraw()
- # self.first_draw = True
+ top_drag_bar.label(text=asset_data['displayName'])
+ # left side
+ row = layout.row(align=True)
+ split_left = row.split(factor=0.5)
+ self.draw_thumbnail_box(split_left)
- def execute(self, context):
- print('execute')
- return {'FINISHED'}
+ # right split
+ split_right = split_left.split()
+ self.draw_menu_desc_author(context, split_right)
- def invoke(self, context, event):
+ ratings_box = layout.box()
+ ratings_box.label(text='Rate asset quality:')
+ ratings.draw_ratings_menu(self, context, ratings_box)
+ tip_box = layout.box()
+ tip_box.label(text=self.tip)
+
+ def execute(self, context):
wm = context.window_manager
ui_props = context.scene.blenderkitUI
ui_props.draw_tooltip = False
sr = bpy.context.window_manager['search results']
asset_data = sr[ui_props.active_index]
self.img = ui.get_large_thumbnail_image(asset_data)
+ self.asset_type = asset_data['assetType']
# self.tex = utils.get_hidden_texture(self.img)
# self.tex.update_tag()
+ authors = bpy.context.window_manager['bkit authors']
+ a = authors.get(asset_data['author']['id'])
+ if a.get('gravatarImg') is not None:
+ self.gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash'])
+
bl_label = asset_data['name']
- return wm.invoke_props_dialog(self, width=700)
+ self.tip = search.get_random_tip()
+ self.tip = self.tip.replace('\n', '')
+ return wm.invoke_popup(self, width=self.width)
class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu):
diff --git a/blenderkit/upload.py b/blenderkit/upload.py
index cc72b92a..b1d20f94 100644
--- a/blenderkit/upload.py
+++ b/blenderkit/upload.py
@@ -580,13 +580,13 @@ def can_edit_asset(active_index=-1, asset_data=None):
sr = bpy.context.window_manager['search results']
asset_data = dict(sr[active_index])
# print(profile, asset_data)
- if asset_data['author']['id'] == profile['user']['id']:
+ if int(asset_data['author']['id']) == int(profile['user']['id']):
return True
return False
class FastMetadata(bpy.types.Operator):
- """Fast change of the category of object directly in asset bar."""
+ """Edit metadata of the asset"""
bl_idname = "wm.blenderkit_fast_metadata"
bl_label = "Update metadata"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
@@ -731,6 +731,7 @@ class FastMetadata(bpy.types.Operator):
active_asset = utils.get_active_asset_by_type(asset_type = self.asset_type)
asset_data = active_asset.get('asset_data')
+ print('can edit asset?', can_edit_asset(asset_data=asset_data))
if not can_edit_asset(asset_data=asset_data):
return {'CANCELLED'}
self.asset_id = asset_data['id']
@@ -1298,7 +1299,7 @@ class AssetDebugPrint(Operator):
class AssetVerificationStatusChange(Operator):
"""Change verification status"""
bl_idname = "object.blenderkit_change_status"
- bl_description = "Change asset ststus"
+ bl_description = "Change asset status"
bl_label = "Change verification status"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
diff --git a/blenderkit/utils.py b/blenderkit/utils.py
index 953ded5e..f4302ac0 100644
--- a/blenderkit/utils.py
+++ b/blenderkit/utils.py
@@ -337,6 +337,12 @@ def get_hidden_texture(name, force_reload=False):
return t
+def img_to_preview(img):
+ img.preview.image_size = (img.size[0], img.size[1])
+ img.preview.image_pixels_float = img.pixels[:]
+ # img.preview.icon_size = (img.size[0], img.size[1])
+ # img.preview.icon_pixels_float = img.pixels[:]
+
def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace='sRGB'):
if bdata_name[0] == '.':
hidden_name = bdata_name
@@ -355,6 +361,7 @@ def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace='sRGB'):
if img is None:
img = bpy.data.images.load(tpath)
+ img_to_preview(img)
img.name = hidden_name
else:
if img.filepath != tpath:
@@ -363,13 +370,16 @@ def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace='sRGB'):
img.filepath = tpath
img.reload()
+ img_to_preview(img)
image_utils.set_colorspace(img, colorspace)
elif force_reload:
if img.packed_file is not None:
img.unpack(method='USE_ORIGINAL')
img.reload()
+ img_to_preview(img)
image_utils.set_colorspace(img, colorspace)
+
return img
@@ -690,6 +700,9 @@ def name_update(props):
# Here we actually rename assets datablocks, but don't do that with HDR's and possibly with others
asset.name = fname
+def fmt_length(prop):
+ prop = str(round(prop, 2))
+ return prop
def get_param(asset_data, parameter_name, default = None):
if not asset_data.get('parameters'):