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
This commit is contained in:
Vilém Duha 2021-04-29 12:13:40 +02:00
parent 452996ae95
commit e670cee075
19 changed files with 855 additions and 288 deletions

View File

@ -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",

View File

@ -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

View File

@ -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"

View File

@ -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')

View File

@ -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')

View File

@ -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

View File

@ -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 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()
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)
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()
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)
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)
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)
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:

121
blenderkit/ratings_utils.py Normal file
View File

@ -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

View File

@ -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,8 +579,152 @@ def has(mdata, prop):
else:
return False
def generate_tooltip(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'
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'])
@ -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
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -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"

View File

@ -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)
# top draggabe bar with name of the asset
top_row = layout.row()
top_drag_bar = top_row.box()
top_drag_bar.alignment = 'CENTER'
col2 = split.column()
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)
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()
# right split
split_right = split_left.split()
self.draw_menu_desc_author(context, split_right)
# 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
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):
print('execute')
return {'FINISHED'}
def invoke(self, context, event):
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):

View File

@ -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'}

View File

@ -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'):