Newer
Older
# split = row
# split = layout.row()
else:
split = split.column()
split.prop(ui_props, 'asset_type', expand=True, icon_only=ui_props.asset_type_fold)
# 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.')
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
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)
layout.template_icon(icon_value=self.img.preview.icon_id, scale=18)
# utils.label_multiline(layout, text="\n Let's start by searching for some cool materials?", width=300)
op = layout.operator("wm.url_open", text='Watch Video Tutorial', icon='QUESTION')
op.url = paths.BLENDERKIT_MANUAL
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
random_searches = [
('MATERIAL','ice'),
('MODEL','car'),
('MODEL','vase'),
('MODEL','grass'),
('MODEL','plant'),
('MODEL','man'),
('MATERIAL','metal'),
('MATERIAL','wood'),
('MATERIAL','floor'),
('MATERIAL','bricks'),
]
random_search = random.choice(random_searches)
ui_props.asset_type = random_search[0]
bpy.context.scene.blenderkit_mat.search_keywords = ''#random_search[1]
bpy.context.scene.blenderkit_mat.search_keywords = '+is_free:true+score_gte:1000+order:-created'#random_search[1]
return {'FINISHED'}
def invoke(self, context, event):
wm = bpy.context.window_manager
img = utils.get_thumbnail('intro.jpg')
utils.img_to_preview(img, copy_original = True)
self.img = img
w, a, r = utils.get_largest_area(area_type='VIEW_3D')
if a is not None:
a.spaces.active.show_region_ui = True
return wm.invoke_props_dialog(self, width = 500)
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'
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
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
def push_op_left(layout):
for a in range(0, 5):
layout.label(text='')
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
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
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):
# layout = layout.column()
draw_asset_context_menu(layout, 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.alignment = 'RIGHT'
split.label(text=left)
split = split.split()
# split for questionmark:
if url != '':
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)
if len(self.asset_data['description']) > 0:
box = layout.box()
utils.label_multiline(box, self.asset_data['description'], width=width)
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']
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'
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
)
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,
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_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')
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
# 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'
elif self.asset_data['isFree']:
t = 'Free plan'
icon = pcoll['free']
tooltip=plans_tooltip,
url=plans_link)
else:
t = 'Full plan'
icon = pcoll['full']
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]}"
self.draw_property(box, 'Created', date)
box.separator()
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
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 utils.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']
layout.emboss = 'NORMAL'
box_thumbnail = layout.box()
box_thumbnail.template_icon(icon_value=self.img.preview.icon_id, scale=width * .12)
# 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"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_left = row.split(factor=split_factor)
col = split_left.column()
width_left = int(width * split_factor)
self.draw_description(col, width=width_left)
self.draw_properties(col, width=width_left)
split_right = split_left.split()
col = split_right.column()
self.draw_menu(context, col)
self.draw_author_area(context, box, width=width)
# self.draw_author_area(context, box, width=width)
#
# col = box.column_flow(columns=2)
# self.draw_menu(context, col)
#
#
# # self.draw_description(box, width=int(width))
# self.draw_properties(box, width=int(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()
bcats = bpy.context.window_manager['bkit_categories']
cat_path = categories.get_category_path(bcats,
self.asset_data['category'])[1:]
for i,c in enumerate(cat_path):
cat_path[i] = c.capitalize()
cat_path = ' > '.join(cat_path)
# box.label(text=cat_path)
aname = asset_data['displayName']
top_drag_bar.label(text=f'{cat_path} > {aname}')
# left side
row = layout.row(align=True)
split_ratio = 0.45
split_left = row.split(factor=split_ratio)
left_column = split_left.column()
self.draw_thumbnail_box(left_column, width=int(self.width * split_ratio))
# self.draw_description(left_column, width = int(self.width*split_ratio))
# right split
split_right = split_left.split()
self.draw_menu_desc_author(context, split_right, width=int(self.width * (1 - split_ratio)))
if not utils.user_is_owner(asset_data=asset_data):
# Draw ratings, but not for owners of assets - doesn't make sense.
ratings_box = layout.box()
ratings.draw_ratings_menu(self, context, ratings_box)
# else:
# ratings_box.label('Here you should find ratings, but you can not rate your own assets ;)')
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)
utils.img_to_preview(self.img, copy_original = True)
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"
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
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'}
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
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):