Newer
Older
# layout.prop(ui_props, 'asset_type', expand=False, text='')
Vilem Duha
committed
if user_preferences.login_attempt:
draw_login_progress(layout)
Vilem Duha
committed
return
if len(user_preferences.api_key) < 20 and user_preferences.asset_counter > 20:
if user_preferences.enable_oauth:
else:
op = layout.operator("wm.url_open", text="Get your API Key",
icon='QUESTION')
op.url = paths.BLENDERKIT_SIGNUP_URL
layout.label(text='Paste your API Key:')
layout.prop(user_preferences, 'api_key', text='')
# utils.label_multiline(layout, text="It's better to save your file first.", width=w)
if utils.profile_is_validator():
search_props = utils.get_search_props()
layout.prop(search_props, 'search_verification_status')
layout.prop(search_props, "unrated_only")
if ui_props.asset_type == 'MODEL':
# noinspection PyCallByClass
draw_panel_model_search(self, context)
if ui_props.asset_type == 'SCENE':
# noinspection PyCallByClass
draw_panel_scene_search(self, context)
if ui_props.asset_type == 'HDR':
# noinspection PyCallByClass
draw_panel_hdr_search(self, context)
elif ui_props.asset_type == 'MATERIAL':
draw_panel_material_search(self, context)
elif ui_props.asset_type == 'BRUSH':
if context.sculpt_object or context.image_paint_object:
# noinspection PyCallByClass
draw_panel_brush_search(self, context)
else:
utils.label_multiline(layout, text='Switch to paint or sculpt mode.', width=context.region.width)
elif ui_props.down_up == 'UPLOAD':
if not ui_props.assetbar_on:
text = 'Show asset preview - ;'
else:
text = 'Hide asset preview - ;'
op = layout.operator('view3d.blenderkit_asset_bar', text=text, icon='EXPORT')
op.keep_running = False
op.do_search = False
op.tooltip = 'Show/Hide asset preview'
e = s.render.engine
if e not in ('CYCLES', 'BLENDER_EEVEE'):
rtext = 'Only Cycles and EEVEE render engines are currently supported. ' \
'Please use Cycles for all assets you upload to BlenderKit.'
utils.label_multiline(layout, rtext, icon='ERROR', width=w)
return;
if ui_props.asset_type == 'MODEL':
# utils.label_multiline(layout, "Uploaded models won't be available in b2.79", icon='ERROR')
if bpy.context.view_layer.objects.active is not None:
draw_panel_model_upload(self, context)
else:
layout.label(text='selet object to upload')
elif ui_props.asset_type == 'SCENE':
draw_panel_scene_upload(self, context)
elif ui_props.asset_type == 'HDR':
draw_panel_hdr_upload(self, context)
# utils.label_multiline(layout, "Uploaded materials won't be available in b2.79", icon='ERROR')
if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
draw_panel_material_upload(self, context)
else:
utils.label_multiline(layout, text='select object with material to upload materials', width=w)
elif ui_props.asset_type == 'BRUSH':
if context.sculpt_object or context.image_paint_object:
draw_panel_brush_upload(self, context)
else:
layout.label(text='Switch to paint or sculpt mode.')
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
class BlenderKitWelcomeOperator(bpy.types.Operator):
"""Login online on BlenderKit webpage"""
bl_idname = "wm.blenderkit_welcome"
bl_label = "Welcome to BlenderKit!"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
step: IntProperty(
name="step",
description="Tutorial Step",
default=0,
options={'SKIP_SAVE'}
)
@classmethod
def poll(cls, context):
return True
def draw(self, context):
layout = self.layout
if self.step == 0:
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
message = "BlenderKit connects from Blender to an online, " \
"community built shared library of models, " \
"materials, and brushes. " \
"Use addon preferences to set up where files will be saved in the Global directory setting."
utils.label_multiline(layout, text=message, width=300)
utils.label_multiline(layout, text="\n Let's start by searching for some cool materials?", width=300)
message = "Operator Tutorial called with invalid step"
def execute(self, context):
if self.step == 0:
# move mouse:
# bpy.context.window_manager.windows[0].cursor_warp(1000, 1000)
# show n-key sidebar (spaces[index] has to be found for view3d too:
# bpy.context.window_manager.windows[0].screen.areas[5].spaces[0].show_region_ui = False
print('running search no')
ui_props = bpy.context.scene.blenderkitUI
ui_props.asset_type = 'MATERIAL'
bpy.context.scene.blenderkit_mat.search_keywords = 'ice'
# search.search()
return {'FINISHED'}
def invoke(self, context, event):
wm = bpy.context.window_manager
return wm.invoke_props_dialog(self)
def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
ui_props = context.scene.blenderkitUI
wm = bpy.context.window_manager
layout.operator_context = 'INVOKE_DEFAULT'
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 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)
op = layout.operator('wm.url_open', text="Open Author's Website")
if a.get('aboutMeUrl') is not None:
op.url = a['aboutMeUrl']
else:
op.url = paths.get_author_gallery_url(a['id'])
op = layout.operator('view3d.blenderkit_search', text="Show Assets By Author")
op.keywords = ''
op.author_id = author_id
op = layout.operator('view3d.blenderkit_search', text='Search Similar')
op.tooltip = 'Search for similar assets in the library'
op.keywords = asset_data['name']
if asset_data.get('description'):
op.keywords += ' '.join(asset_data.get('tags'))
if asset_data.get('canDownload') != 0:
if len(bpy.context.selected_objects) > 0 and ui_props.asset_type == 'MODEL':
aob = bpy.context.active_object
if aob is None:
aob = bpy.context.selected_objects[0]
op = layout.operator('scene.blenderkit_download', text='Replace Active Models')
# this checks if the menu got called from right-click in assetbar(then index is 0 - x) or
# from a panel(then replacement happens from the active model)
else:
op.asset_index = ui_props.active_index
op.model_location = aob.location
op.model_rotation = aob.rotation_euler
op.target_object = aob.name
op.material_target_slot = aob.active_material_index
op.replace = True
op.replace_resolution = False
# resolution replacement operator
# if asset_data['downloaded'] == 100: # only show for downloaded/used assets
# if ui_props.asset_type in ('MODEL', 'MATERIAL'):
# layout.menu(OBJECT_MT_blenderkit_resolution_menu.bl_idname)
if ui_props.asset_type in ('MODEL', 'MATERIAL', 'HDR') and \
utils.get_param(asset_data, 'textureResolutionMax') is not None and \
utils.get_param(asset_data, 'textureResolutionMax') > 512:
s = bpy.context.scene
col = layout.column()
col.operator_context = 'INVOKE_DEFAULT'
if from_panel:
# Called from addon panel
if asset_data.get('resolution'):
op = col.operator('scene.blenderkit_download', text='Replace asset resolution')
op.asset_base_id = asset_data['assetBaseId']
if asset_data['assetType'] == 'MODEL':
o = utils.get_active_model()
op.model_location = o.location
op.model_rotation = o.rotation_euler
op.target_object = o.name
op.material_target_slot = o.active_material_index
elif asset_data['assetType'] == 'MATERIAL':
aob = bpy.context.active_object
op.model_location = aob.location
op.model_rotation = aob.rotation_euler
op.target_object = aob.name
op.material_target_slot = aob.active_material_index
op.invoke_resolution = True
op.max_resolution = asset_data.get('max_resolution',
0) # str(utils.get_param(asset_data, 'textureResolutionMax'))
elif asset_data['assetBaseId'] in s['assets used'].keys() and asset_data['assetType'] != 'hdr':
# HDRs are excluded from replacement, since they are always replaced.
# called from asset bar:
op = col.operator('scene.blenderkit_download', text='Replace asset resolution')
op.asset_index = ui_props.active_index
# op.asset_type = ui_props.asset_type
op.replace_resolution = True
op.invoke_resolution = True
o = utils.get_active_model()
if o and o.get('asset_data'):
if o['asset_data']['assetBaseId'] == bpy.context.window_manager['search results'][
ui_props.active_index]:
op.model_location = o.location
op.model_rotation = o.rotation_euler
op.model_location = (0, 0, 0)
op.model_rotation = (0, 0, 0)
op.max_resolution = asset_data.get('max_resolution',
0) # str(utils.get_param(asset_data, 'textureResolutionMax'))
# print('operator res ', resolution)
# op.resolution = resolution
wm = bpy.context.window_manager
profile = wm.get('bkit profile')
if profile is not None:
# validation
if author_id == str(profile['user']['id']) or utils.profile_is_validator():
layout.label(text='Management tools:')
row = layout.row()
row.operator_context = 'INVOKE_DEFAULT'
op = layout.operator('wm.blenderkit_fast_metadata', text='Edit Metadata')
op.asset_type = asset_data['assetType']
if asset_data['assetType'] == 'model':
op = layout.operator('object.blenderkit_regenerate_thumbnail', text='Regenerate thumbnail')
op.asset_index = ui_props.active_index
if asset_data['assetType'] == 'material':
op = layout.operator('object.blenderkit_regenerate_material_thumbnail', text='Regenerate thumbnail')
op.asset_index = ui_props.active_index
# op.asset_id = asset_data['id']
# op.asset_type = asset_data['assetType']
if author_id == str(profile['user']['id']):
row = layout.row()
row.operator_context = 'INVOKE_DEFAULT'
op = row.operator('object.blenderkit_change_status', text='Delete')
op.asset_id = asset_data['id']
op.state = 'deleted'
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
op = layout.operator('object.blenderkit_print_asset_debug', text='Print asset debug')
op.asset_id = asset_data['id']
# def draw_asset_resolution_replace(self, context, resolution):
# layout = self.layout
# ui_props = bpy.context.scene.blenderkitUI
#
# op = layout.operator('scene.blenderkit_download', text=resolution)
# if ui_props.active_index == -3:
# # This happens if the command is called from addon panel
# o = utils.get_active_model()
# op.asset_base_id = o['asset_data']['assetBaseId']
#
# else:
# op.asset_index = ui_props.active_index
#
# op.asset_type = ui_props.asset_type
# if len(bpy.context.selected_objects) > 0: # and ui_props.asset_type == 'MODEL':
# aob = bpy.context.active_object
# op.model_location = aob.location
# op.model_rotation = aob.rotation_euler
# op.target_object = aob.name
# op.material_target_slot = aob.active_material_index
# op.replace_resolution = True
# print('operator res ', resolution)
# op.resolution = resolution
# class OBJECT_MT_blenderkit_resolution_menu(bpy.types.Menu):
# bl_label = "Replace Asset Resolution"
# bl_idname = "OBJECT_MT_blenderkit_resolution_menu"
#
# def draw(self, context):
# ui_props = context.scene.blenderkitUI
#
# # sr = bpy.context.window_manager['search results']
# # sr = bpy.context.window_manager['search results']
# # asset_data = sr[ui_props.active_index]
#
# for k in resolutions.resolution_props_to_server.keys():
# draw_asset_resolution_replace(self, context, k)
class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu):
bl_label = "Asset options:"
bl_idname = "OBJECT_MT_blenderkit_asset_menu"
def draw(self, context):
ui_props = context.scene.blenderkitUI
sr = bpy.context.window_manager['search results']
asset_data = sr[ui_props.active_index]
draw_asset_context_menu(self.layout, context, asset_data, from_panel=False)
def numeric_to_str(s):
if s:
s = str(round(s))
else:
s = '-'
return s
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
def label_or_url(layout, text='', tooltip='', url='', icon_value=None, icon=None):
'''automatically switch between different layout options for linking or tooltips'''
layout.emboss = 'NONE'
if url != '':
if icon:
op = layout.operator('wm.blenderkit_url', text=text, icon=icon)
elif icon_value:
op = layout.operator('wm.blenderkit_url', text=text, icon_value=icon_value)
else:
op = layout.operator('wm.blenderkit_url', text=text)
op.url = url
op.tooltip = tooltip
layout.label(text='')
layout.label(text='')
return
if tooltip != '':
if icon:
op = layout.operator('wm.blenderkit_tooltip', text=text, icon=icon)
elif icon_value:
op = layout.operator('wm.blenderkit_tooltip', text=text, icon_value=icon_value)
else:
op = layout.operator('wm.blenderkit_tooltip', text=text)
op.tooltip = tooltip
# these are here to move the text to left, since operators can only center text by default
layout.label(text='')
layout.label(text='')
return
if icon:
layout.label(text=text, icon=icon)
elif icon_value:
layout.label(text=text, icon_value=icon_value)
else:
layout.label(text=text)
class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
"""Generate Cycles thumbnail for model assets"""
bl_idname = "wm.blenderkit_asset_popup"
bl_label = "BlenderKit asset popup"
@classmethod
def poll(cls, context):
return True
def draw_menu(self, context, layout):
col = layout.column()
draw_asset_context_menu(col, context, self.asset_data, from_panel=False)
def draw_property(self, layout, left, right, icon=None, icon_value=None, url='', tooltip=''):
right = str(right)
row = layout.row()
split = row.split(factor=0.4)
split.alignment = 'RIGHT'
split.label(text=left)
split = split.split()
# split for questionmark:
if url != '':
split = split.split(factor=0.7)
label_or_url(split, text=right, tooltip=tooltip, url=url, icon_value=icon_value, icon=icon)
# additional questionmark icon where it's important?
if url != '':
split = split.split()
op = split.operator('wm.blenderkit_url', text='', icon='QUESTION')
op.url = url
op.tooltip = tooltip
def draw_asset_parameter(self, layout, key='', pretext=''):
parameter = utils.get_param(self.asset_data, key)
if parameter == None:
return
if type(parameter) == int:
parameter = f"{parameter:,d}"
elif type(parameter) == float:
parameter = f"{parameter:,.1f}"
self.draw_property(layout, pretext, parameter)
def draw_properties(self, layout, width=250):
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=width)
pcoll = icons.icon_collections["main"]
box = layout.box()
box.label(text='Properties')
if self.asset_data.get('license') == 'cc_zero':
icon = pcoll['cc0']
else:
t = 'Royalty free'
icon = pcoll['royalty_free']
self.draw_property(box,
url="https://www.blenderkit.com/docs/licenses/",
tooltip='All BlenderKit assets are available for commercial use. \n' \
'Click to read more about BlenderKit licenses on the website'
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
)
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']]
)
resolution = utils.get_param(self.asset_data, 'textureResolutionMax')
ress = f"{int(round(resolution / 1024, 0))}K"
self.draw_property(box, 'Resolution', ress,
tooltip='Maximal resolution of textures in this asset.\n' \
'Most texture asset have also lower resolutions generated.\n' \
'Go to BlenderKit add-on import settings to set default resolution')
if fs and len(fs) > 2 and utils.profile_is_validator():
resolutions = ''
list.sort(fs, key=lambda f: f['fileType'])
for f in fs:
if f['fileType'].find('resolution') > -1:
resolutions += f['fileType'][11:] + ' '
resolutions = resolutions.replace('_', '.')
self.draw_property(box, 'Generated:', resolutions)
self.draw_asset_parameter(box, key='designer', pretext='Designer')
self.draw_asset_parameter(box, key='manufacturer', pretext='Manufacturer') # TODO make them clickable!
self.draw_asset_parameter(box, key='designCollection', pretext='Collection')
self.draw_asset_parameter(box, key='designVariant', pretext='Variant')
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')
# self.draw_asset_parameter(box, key='purePbr', pretext='Pure PBR')
# self.draw_asset_parameter(box, key='productionLevel', pretext='Readiness')
# self.draw_asset_parameter(box, key='condition', pretext='Condition')
self.draw_asset_parameter(box, key='material_style', pretext='Style')
self.draw_asset_parameter(box, key='model_style', pretext='Style')
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']))
if self.asset_data.get('filesSize'):
fs = self.asset_data['filesSize']
fsmb = fs // (1024 * 1024)
fskb = fs % 1024
if fsmb == 0:
self.draw_property(box, 'Original size:', f'{fskb}KB')
else:
self.draw_property(box, 'Original size:', f'{fsmb}MB')
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
# Tags section
# row = box.row()
# letters_on_row = 0
# max_on_row = width / 10
# for tag in self.asset_data['tags']:
# if tag in ('manifold', 'uv', 'non-manifold'):
# # these are sometimes accidentally stored in the lib
# continue
#
# # row.emboss='NONE'
# # we need to split wisely
# remaining_row = (max_on_row - letters_on_row) / max_on_row
# split_factor = (len(tag) / max_on_row) / remaining_row
# row = row.split(factor=split_factor)
# letters_on_row += len(tag)
# if letters_on_row > max_on_row:
# letters_on_row = len(tag)
# row = box.row()
# remaining_row = (max_on_row - letters_on_row) / max_on_row
# split_factor = (len(tag) / max_on_row) / remaining_row
# row = row.split(factor=split_factor)
#
# op = row.operator('wm')
# op = row.operator('view3d.blenderkit_search', text=tag)
# op.tooltip = f'Search items with tag {tag}'
# # build search string from description and tags:
# op.keywords = f'+tags:{tag}'
# self.draw_property(box, 'Tags', self.asset_data['tags']) #TODO make them clickable!
# Free/Full plan or private Access
plans_tooltip = 'BlenderKit has 2 plans:\n' \
' * Free plan - more than 50% of all assets\n' \
' * Full plan - unlimited access to everything\n' \
'Click to go to subscriptions page'
plans_link = 'https://www.blenderkit.com/plans/pricing/'
if self.asset_data['isPrivate']:
t = 'Private'
self.draw_property(box, 'Access:', t, icon='LOCKED')
elif self.asset_data['isFree']:
t = 'Free plan'
icon = pcoll['free']
self.draw_property(box, 'Access:', t,
icon_value=icon.icon_id,
tooltip=plans_tooltip,
url=plans_link)
else:
t = 'Full plan'
icon = pcoll['full']
self.draw_property(box, 'Access:', t,
icon_value=icon.icon_id,
tooltip=plans_tooltip,
url=plans_link)
if utils.profile_is_validator():
date = self.asset_data['created'][:10]
date = f"{date[8:10]}. {date[5:7]}. {date[:4]}"
def draw_author_area(self, context, layout, width=330):
self.draw_author(context, layout, width=width)
def draw_author(self, context, 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
author_box.label(text='Author') # just one extra line to give spacing
if hasattr(self, 'gimg'):
author_left = author_box.split(factor=0.25)
author_left.template_icon(icon_value=self.gimg.preview.icon_id, scale=7)
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)
# check if author didn't fill any data about himself and prompt him if that's the case
if upload.user_is_owner(asset_data=self.asset_data) and a.get('aboutMe') is not None and len(
row = col.row()
row.enabled = False
row.label(text='Please introduce yourself to the community!')
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="Find 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()
box_thumbnail.template_icon(icon_value=self.img.preview.icon_id, scale=34.0)
# row = box_thumbnail.row()
# row.scale_y = 3
# op = row.operator('view3d.asset_drag_drop', text='Drag & Drop from here', depress=True)
row = box_thumbnail.row()
row.alignment = 'EXPAND'
# display_ratings = can_display_ratings(self.asset_data)
rc = self.asset_data.get('ratingsCount')
show_rating_threshold = 0
show_rating_prompt_threshold = 5
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):
s = numeric_to_str(self.asset_data['score'])
q = numeric_to_str(self.asset_data['ratingsAverage'].get('quality'))
c = numeric_to_str(self.asset_data['ratingsAverage'].get('workingHours'))
s = '-'
q = '-'
c = '-'
pcoll = icons.icon_collections["main"]
row.emboss = 'NONE'
op = row.operator('wm.blenderkit_tooltip', text=str(s), icon_value=pcoll['trophy'].icon_id)
op.tooltip = 'Asset score calculated from averaged user ratings. \n\n' \
'Score = quality × complexity × 10*\n\n *Happiness multiplier'
row.label(text=' ')
tooltip_extension = f'.\n\nRatings results are shown for assets with more than {show_rating_threshold} ratings'
op = row.operator('wm.blenderkit_tooltip', text=str(q), icon='SOLO_ON')
op.tooltip = f"Quality, average from {rc['quality']} ratings" \
f"{tooltip_extension if rcount <= show_rating_threshold else ''}"
row.label(text=' ')
op = row.operator('wm.blenderkit_tooltip', text=str(c), icon_value=pcoll['dumbbell'].icon_id)
op.tooltip = f"Complexity, average from {rc['workingHours']} ratings" \
f"{tooltip_extension if rcount <= show_rating_threshold else ''}"
if rcount <= show_rating_prompt_threshold:
box_thumbnail.alert = True
box_thumbnail.label(text=f"")
box_thumbnail.label(text=f"This asset has only {rcount} rating{'' if rcount == 1 else 's'} , please rate.")
# box_thumbnail.label(text=f"Please rate this asset.")
def draw_menu_desc_author(self, context, layout, width=330):
box = layout.column()
box.emboss = 'NORMAL'
# left - tooltip & params
row = box.row()
split_factor = 0.7
split_left_left = row.split(factor=split_factor)
self.draw_properties(split_left_left, width=int(width * split_factor))
# right - menu
col1 = split_left_left.split()
self.draw_menu(context, col1)
# author
self.draw_author_area(context, box, width=width)
def draw(self, context):
ui_props = context.scene.blenderkitUI
sr = bpy.context.window_manager['search results']
# top draggabe bar with name of the asset
top_row = layout.row()
top_drag_bar = top_row.box()
aname = asset_data['displayName']
top_drag_bar.label(text=aname)
# left side
row = layout.row(align=True)
split_left = row.split(factor=0.5)
self.draw_thumbnail_box(split_left)
# right split
split_right = split_left.split()
self.draw_menu_desc_author(context, split_right, width=int(self.width * split_ratio))
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']
self.tip = search.get_random_tip()
self.tip = self.tip.replace('\n', '')
# pre-fill ratings
self.prefill_ratings()
return wm.invoke_popup(self, width=self.width)
class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu):
bl_label = "BlenderKit login/signup:"
bl_idname = "OBJECT_MT_blenderkit_login_menu"
def draw(self, context):
layout = self.layout
# utils.label_multiline(layout, text=message)
draw_login_buttons(layout)
class SetCategoryOperator(bpy.types.Operator):
"""Visit subcategory"""
bl_idname = "view3d.blenderkit_set_category"
bl_label = "BlenderKit Set Active Category"
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
category: bpy.props.StringProperty(
name="Category",
description="set this category active",
default="")
asset_type: bpy.props.StringProperty(
name="Asset Type",
description="asset type",
default="")
@classmethod
def poll(cls, context):
return True
def execute(self, context):
acat = bpy.context.window_manager['active_category'][self.asset_type]
if self.category == '':
acat.remove(acat[-1])
else:
acat.append(self.category)
# we have to write back to wm. Thought this should happen with original list.
bpy.context.window_manager['active_category'][self.asset_type] = acat
return {'FINISHED'}
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
class UrlPopupDialog(bpy.types.Operator):
"""Generate Cycles thumbnail for model assets"""
bl_idname = "wm.blenderkit_url_dialog"
bl_label = "BlenderKit message:"
bl_options = {'REGISTER', 'INTERNAL'}
url: bpy.props.StringProperty(
name="Url",
description="url",
default="")
link_text: bpy.props.StringProperty(
name="Url",
description="url",
default="Go to website")
message: bpy.props.StringProperty(
name="Text",
description="text",
default="")
# @classmethod
# def poll(cls, context):
# return bpy.context.view_layer.objects.active is not None
def draw(self, context):
layout = self.layout
utils.label_multiline(layout, text=self.message, width=300)
layout.active_default = True
op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION')
if not utils.user_logged_in():
utils.label_multiline(layout,
text='Already subscribed? You need to login to access your Full Plan.',
layout.operator_context = 'EXEC_DEFAULT'
layout.operator("wm.blenderkit_login", text="Login",
icon='URL').signup = False
op.url = self.url
def execute(self, context):
# start_thumbnailer(self, context)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self, width=300)
class LoginPopupDialog(bpy.types.Operator):
"""Popup a dialog which enables the user to log in after being logged out automatically."""
bl_idname = "wm.blenderkit_login_dialog"
bl_label = "BlenderKit login"
bl_options = {'REGISTER', 'INTERNAL'}
message: bpy.props.StringProperty(
name="Message",
description="",
default="Your were logged out from BlenderKit. Please login again. ")
# @classmethod
# def poll(cls, context):
# return bpy.context.view_layer.objects.active is not None
def draw(self, context):
layout = self.layout
utils.label_multiline(layout, text=self.message)
op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION')
op.url = self.url
def execute(self, context):
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self)
def draw_panel_categories(self, context):
s = context.scene
ui_props = s.blenderkitUI
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
layout = self.layout
# row = layout.row()
# row.prop(ui_props, 'asset_type', expand=True, icon_only=True)
wm = bpy.context.window_manager
col = layout.column(align=True)
if wm.get('active_category') is not None:
acat = wm['active_category'][ui_props.asset_type]
if len(acat) > 1:
# we are in subcategory, so draw the parent button
op = col.operator('view3d.blenderkit_set_category', text='...', icon='FILE_PARENT')
op.asset_type = ui_props.asset_type
op.category = ''
cats = categories.get_category(wm['bkit_categories'], cat_path=acat)
# draw freebies only in models parent category
Vilem Duha
committed
# if ui_props.asset_type == 'MODEL' and len(acat) == 1:
# op = col.operator('view3d.blenderkit_asset_bar', text='freebies')
# op.free_only = True
if c['assetCount'] > 0 or (utils.profile_is_validator() and user_preferences.categories_fix):
if len(c['children']) > 0 and c['assetCount'] > 15 or (
utils.profile_is_validator() and user_preferences.categories_fix):
row = row.split(factor=.8, align=True)
# row = split.split()
ctext = '%s (%i)' % (c['name'], c['assetCount'])
preferences = bpy.context.preferences.addons['blenderkit'].preferences
if preferences.experimental_features:
op = row.operator('view3d.blenderkit_asset_bar_widget', text=ctext)
else:
op = row.operator('view3d.blenderkit_asset_bar', text=ctext)
op.do_search = True
op.keep_running = True
if len(c['children']) > 0 and c['assetCount'] > 15 or (
utils.profile_is_validator() and user_preferences.categories_fix):
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
# row = row.split()
op = row.operator('view3d.blenderkit_set_category', text='>>')
op.asset_type = ui_props.asset_type
op.category = c['slug']
# for c1 in c['children']:
# if c1['assetCount']>0:
# row = col.row()
# split = row.split(percentage=.2)
# row = split.split()
# row = split.split()
# ctext = '%s (%i)' % (c1['name'], c1['assetCount'])
# op = row.operator('view3d.blenderkit_search', text=ctext)
# op.category = c1['slug']
class VIEW3D_PT_blenderkit_downloads(Panel):
bl_category = "BlenderKit"
bl_idname = "VIEW3D_PT_blenderkit_downloads"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Downloads"