1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 from blenderkit
import paths
, ratings
, utils
, download
, categories
, icons
, search
, resolutions
, ui
22 from bpy
.types
import (
25 from bpy
.props
import (
41 # this was moved to separate interface:
43 def draw_ratings(layout
, context
, asset
):
44 # layout.operator("wm.url_open", text="Read rating instructions", icon='QUESTION').url = 'https://support.google.com/?hl=en'
45 # the following shouldn't happen at all in an optimal case,
46 # this function should run only when asset was already checked to be existing
51 bkit_ratings
= asset
.bkit_ratings
53 # layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0)
56 row
.prop(bkit_ratings
, 'rating_quality_ui', expand
=True, icon_only
=True, emboss
=False)
57 if bkit_ratings
.rating_quality
> 0:
59 col
.prop(bkit_ratings
, 'rating_work_hours')
60 # w = context.region.width
62 # layout.label(text='problems')
63 # layout.prop(bkit_ratings, 'rating_problems', text='')
64 # layout.label(text='compliments')
65 # layout.prop(bkit_ratings, 'rating_compliments', text='')
68 # op = row.operator("object.blenderkit_rating_upload", text="Send rating", icon='URL')
70 # re-enable layout if included in longer panel
73 def draw_not_logged_in(source
, message
='Please Login/Signup to use this feature'):
74 title
= "You aren't logged in"
76 def draw_message(source
, context
):
77 layout
= source
.layout
78 utils
.label_multiline(layout
, text
=message
)
79 draw_login_buttons(layout
)
81 bpy
.context
.window_manager
.popup_menu(draw_message
, title
=title
, icon
='INFO')
84 def draw_upload_common(layout
, props
, asset_type
, context
):
85 op
= layout
.operator("wm.url_open", text
=f
"Read {asset_type.lower()} upload instructions",
87 if asset_type
== 'MODEL':
88 op
.url
= paths
.BLENDERKIT_MODEL_UPLOAD_INSTRUCTIONS_URL
89 if asset_type
== 'MATERIAL':
90 op
.url
= paths
.BLENDERKIT_MATERIAL_UPLOAD_INSTRUCTIONS_URL
91 if asset_type
== 'BRUSH':
92 op
.url
= paths
.BLENDERKIT_BRUSH_UPLOAD_INSTRUCTIONS_URL
93 if asset_type
== 'SCENE':
94 op
.url
= paths
.BLENDERKIT_SCENE_UPLOAD_INSTRUCTIONS_URL
95 if asset_type
== 'HDR':
96 op
.url
= paths
.BLENDERKIT_HDR_UPLOAD_INSTRUCTIONS_URL
98 row
= layout
.row(align
=True)
99 if props
.upload_state
!= '':
100 utils
.label_multiline(layout
, text
=props
.upload_state
, width
=context
.region
.width
)
102 op
= layout
.operator('object.kill_bg_process', text
="", icon
='CANCEL')
103 op
.process_source
= asset_type
104 op
.process_type
= 'UPLOAD'
105 layout
= layout
.column()
106 layout
.enabled
= False
107 # if props.upload_state.find('Error') > -1:
108 # layout.label(text = props.upload_state)
110 if props
.asset_base_id
== '':
111 optext
= 'Upload %s' % asset_type
.lower()
112 op
= layout
.operator("object.blenderkit_upload", text
=optext
, icon
='EXPORT')
113 op
.asset_type
= asset_type
115 #make sure everything gets uploaded.
120 if props
.asset_base_id
!= '':
121 op
= layout
.operator("object.blenderkit_upload", text
='Reupload asset', icon
='EXPORT')
122 op
.asset_type
= asset_type
125 op
= layout
.operator("object.blenderkit_upload", text
='Upload as new asset', icon
='EXPORT')
126 op
.asset_type
= asset_type
129 # layout.label(text = 'asset id, overwrite only for reuploading')
130 layout
.label(text
='asset has a version online.')
132 # row.enabled = False
133 # row.prop(props, 'asset_base_id', icon='FILE_TICK')
135 # row.enabled = False
136 # row.prop(props, 'id', icon='FILE_TICK')
137 layout
.prop(props
, 'category')
138 if props
.category
!= 'NONE' and props
.subcategory
!= 'NONE':
139 layout
.prop(props
, 'subcategory')
140 if props
.subcategory
!= 'NONE' and props
.subcategory1
!= 'NONE':
141 layout
.prop(props
, 'subcategory1')
143 layout
.prop(props
, 'is_private', expand
=True)
144 if props
.is_private
== 'PUBLIC':
145 layout
.prop(props
, 'license')
148 def poll_local_panels():
149 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
150 return user_preferences
.panel_behaviour
== 'BOTH' or user_preferences
.panel_behaviour
== 'LOCAL'
153 def prop_needed(layout
, props
, name
, value
, is_not_filled
=''):
155 if value
== is_not_filled
:
156 # row.label(text='', icon = 'ERROR')
159 row
.prop(props
, name
) # , icon=icon)
162 # row.label(text='', icon = 'FILE_TICK')
164 row
.prop(props
, name
)
166 def draw_panel_hdr_upload(self
, context
):
168 ui_props
= bpy
.context
.scene
.blenderkitUI
170 # layout.prop_search(ui_props, "hdr_upload_image", bpy.data, "images")
171 layout
.prop(ui_props
, "hdr_upload_image")
173 hdr
= utils
.get_active_HDR()
177 props
= hdr
.blenderkit
181 draw_upload_common(layout
, props
, 'HDR', context
)
183 layout
.prop(props
, 'name')
184 layout
.prop(props
, 'description')
185 layout
.prop(props
, 'tags')
187 def draw_panel_hdr_search(self
, context
):
189 props
= s
.blenderkit_HDR
193 row
.prop(props
, "search_keywords", text
="", icon
='VIEWZOOM')
194 draw_assetbar_show_hide(row
, props
)
195 layout
.prop(props
, "own_only")
197 utils
.label_multiline(layout
, text
=props
.report
)
199 def draw_panel_model_upload(self
, context
):
200 ob
= bpy
.context
.active_object
201 while ob
.parent
is not None:
203 props
= ob
.blenderkit
207 draw_upload_common(layout
, props
, 'MODEL', context
)
209 prop_needed(layout
, props
, 'name', props
.name
)
211 col
= layout
.column()
212 if props
.is_generating_thumbnail
:
214 prop_needed(col
, props
, 'thumbnail', props
.has_thumbnail
, False)
215 if bpy
.context
.scene
.render
.engine
in ('CYCLES', 'BLENDER_EEVEE'):
216 col
.operator("object.blenderkit_generate_thumbnail", text
='Generate thumbnail', icon
='IMAGE')
218 # row = layout.row(align=True)
219 if props
.is_generating_thumbnail
:
220 row
= layout
.row(align
=True)
221 row
.label(text
=props
.thumbnail_generating_state
)
222 op
= row
.operator('object.kill_bg_process', text
="", icon
='CANCEL')
223 op
.process_source
= 'MODEL'
224 op
.process_type
= 'THUMBNAILER'
225 elif props
.thumbnail_generating_state
!= '':
226 utils
.label_multiline(layout
, text
=props
.thumbnail_generating_state
)
228 layout
.prop(props
, 'description')
229 layout
.prop(props
, 'tags')
230 # prop_needed(layout, props, 'style', props.style)
231 # prop_needed(layout, props, 'production_level', props.production_level)
232 layout
.prop(props
, 'style')
233 layout
.prop(props
, 'production_level')
235 layout
.prop(props
, 'condition')
236 layout
.prop(props
, 'is_free')
237 layout
.prop(props
, 'pbr')
238 layout
.label(text
='design props:')
239 layout
.prop(props
, 'manufacturer')
240 layout
.prop(props
, 'designer')
241 layout
.prop(props
, 'design_collection')
242 layout
.prop(props
, 'design_variant')
243 layout
.prop(props
, 'use_design_year')
244 if props
.use_design_year
:
245 layout
.prop(props
, 'design_year')
248 row
.prop(props
, 'work_hours')
250 layout
.prop(props
, 'adult')
253 def draw_panel_scene_upload(self
, context
):
254 s
= bpy
.context
.scene
258 # if bpy.app.debug_value != -1:
259 # layout.label(text='Scene upload not Implemented')
261 draw_upload_common(layout
, props
, 'SCENE', context
)
263 # layout = layout.column()
267 # if props.dimensions[0] + props.dimensions[1] == 0 and props.face_count == 0:
269 # layout.operator("object.blenderkit_auto_tags", text='Auto fill tags', icon=icon)
271 # layout.operator("object.blenderkit_auto_tags", text='Auto fill tags')
273 prop_needed(layout
, props
, 'name', props
.name
)
275 col
= layout
.column()
276 # if props.is_generating_thumbnail:
277 # col.enabled = False
278 prop_needed(col
, props
, 'thumbnail', props
.has_thumbnail
, False)
279 # if bpy.context.scene.render.engine == 'CYCLES':
280 # col.operator("object.blenderkit_generate_thumbnail", text='Generate thumbnail', icon='IMAGE_COL')
282 # row = layout.row(align=True)
283 # if props.is_generating_thumbnail:
284 # row = layout.row(align=True)
285 # row.label(text = props.thumbnail_generating_state)
286 # op = row.operator('object.kill_bg_process', text="", icon='CANCEL')
287 # op.process_source = 'MODEL'
288 # op.process_type = 'THUMBNAILER'
289 # elif props.thumbnail_generating_state != '':
290 # utils.label_multiline(layout, text = props.thumbnail_generating_state)
292 layout
.prop(props
, 'is_free')
293 layout
.prop(props
, 'description')
294 layout
.prop(props
, 'tags')
295 layout
.prop(props
, 'style')
296 layout
.prop(props
, 'production_level')
297 layout
.prop(props
, 'use_design_year')
298 if props
.use_design_year
:
299 layout
.prop(props
, 'design_year')
300 layout
.prop(props
, 'condition')
302 row
.prop(props
, 'work_hours')
303 layout
.prop(props
, 'adult')
306 def draw_assetbar_show_hide(layout
, props
):
307 s
= bpy
.context
.scene
308 ui_props
= s
.blenderkitUI
310 if ui_props
.assetbar_on
:
312 ttip
= 'Click to Hide Asset Bar'
315 ttip
= 'Click to Show Asset Bar'
317 preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
318 if preferences
.experimental_features
:
319 op
= layout
.operator('view3d.blenderkit_asset_bar_widget', text
= '', icon
= icon
)
320 op
.keep_running
= False
324 op
= layout
.operator('view3d.blenderkit_asset_bar', text
='', icon
=icon
)
325 op
.keep_running
= False
331 def draw_panel_model_search(self
, context
):
334 props
= s
.blenderkit_models
338 row
.prop(props
, "search_keywords", text
="", icon
='VIEWZOOM')
339 draw_assetbar_show_hide(row
, props
)
342 if props
.report
== 'You need Full plan to get this item.':
344 utils
.label_multiline(layout
, text
=props
.report
, icon
=icon
)
345 if props
.report
== 'You need Full plan to get this item.':
346 layout
.operator("wm.url_open", text
="Get Full plan", icon
='URL').url
= paths
.BLENDERKIT_PLANS
348 layout
.prop(props
, "search_style")
349 layout
.prop(props
, "own_only")
350 layout
.prop(props
, "free_only")
352 # if props.search_style == 'OTHER':
353 # layout.prop(props, "search_style_other")
354 # layout.prop(props, "search_engine")
355 # col = layout.column()
356 # layout.prop(props, 'append_link', expand=True, icon_only=False)
357 # layout.prop(props, 'import_as', expand=True, icon_only=False)
359 # draw_panel_categories(self, context)
362 def draw_panel_scene_search(self
, context
):
364 props
= s
.blenderkit_scene
366 # layout.label(text = "common search properties:")
368 row
.prop(props
, "search_keywords", text
="", icon
='VIEWZOOM')
369 draw_assetbar_show_hide(row
, props
)
370 layout
.prop(props
, "own_only")
371 utils
.label_multiline(layout
, text
=props
.report
)
373 # layout.prop(props, "search_style")
374 # if props.search_style == 'OTHER':
375 # layout.prop(props, "search_style_other")
376 # layout.prop(props, "search_engine")
378 # draw_panel_categories(self, context)
381 class VIEW3D_PT_blenderkit_model_properties(Panel
):
382 bl_category
= "BlenderKit"
383 bl_idname
= "VIEW3D_PT_blenderkit_model_properties"
384 bl_space_type
= 'VIEW_3D'
385 bl_region_type
= 'UI'
386 bl_label
= "Selected Model"
387 bl_context
= "objectmode"
390 def poll(cls
, context
):
391 p
= bpy
.context
.view_layer
.objects
.active
is not None
394 def draw(self
, context
):
395 # draw asset properties here
398 o
= utils
.get_active_model()
399 # o = bpy.context.active_object
400 if o
.get('asset_data') is None:
401 utils
.label_multiline(layout
,
402 text
='To upload this asset to BlenderKit, go to the Find and Upload Assets panel.')
403 layout
.prop(o
, 'name')
405 if o
.get('asset_data') is not None:
407 layout
.label(text
=str(ad
['name']))
408 if o
.instance_type
== 'COLLECTION' and o
.instance_collection
is not None:
409 layout
.operator('object.blenderkit_bring_to_scene', text
='Bring to scene')
410 layout
.label(text
='Ratings:')
411 draw_panel_model_rating(self
, context
)
413 layout
.label(text
='Asset tools:')
414 draw_asset_context_menu(self
.layout
, context
, ad
, from_panel
=True)
415 # if 'rig' in ad['tags']:
416 # # layout.label(text = 'can make proxy')
417 # layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy')
418 # fast upload, blocked by now
420 # op = layout.operator("object.blenderkit_upload", text='Store as private', icon='EXPORT')
421 # op.asset_type = 'MODEL'
423 # fun override project, not finished
424 # layout.operator('object.blenderkit_color_corrector')
427 class NODE_PT_blenderkit_material_properties(Panel
):
428 bl_category
= "BlenderKit"
429 bl_idname
= "NODE_PT_blenderkit_material_properties"
430 bl_space_type
= 'NODE_EDITOR'
431 bl_region_type
= 'UI'
432 bl_label
= "Selected Material"
433 bl_context
= "objectmode"
436 def poll(cls
, context
):
437 p
= bpy
.context
.view_layer
.objects
.active
is not None and bpy
.context
.active_object
.active_material
is not None
440 def draw(self
, context
):
441 # draw asset properties here
444 m
= bpy
.context
.active_object
.active_material
445 # o = bpy.context.active_object
446 if m
.get('asset_data') is None and m
.blenderkit
.id == '':
447 utils
.label_multiline(layout
,
448 text
='To upload this asset to BlenderKit, go to the Find and Upload Assets panel.')
449 layout
.prop(m
, 'name')
451 if m
.get('asset_data') is not None:
453 layout
.label(text
=str(ad
['name']))
454 layout
.label(text
='Ratings:')
455 draw_panel_material_ratings(self
, context
)
457 layout
.label(text
='Asset tools:')
458 draw_asset_context_menu(self
.layout
, context
, ad
, from_panel
=True)
459 # if 'rig' in ad['tags']:
460 # # layout.label(text = 'can make proxy')
461 # layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy')
462 # fast upload, blocked by now
464 # op = layout.operator("object.blenderkit_upload", text='Store as private', icon='EXPORT')
465 # op.asset_type = 'MODEL'
467 # fun override project, not finished
468 # layout.operator('object.blenderkit_color_corrector')
471 def draw_rating_asset(self
, context
, asset
):
474 # split = layout.split(factor=0.5)
475 # col1 = split.column()
476 # col2 = split.column()
477 # print('%s_search' % asset['asset_data']['assetType'])
478 directory
= paths
.get_temp_dir('%s_search' % asset
['asset_data']['assetType'])
479 tpath
= os
.path
.join(directory
, asset
['asset_data']['thumbnail_small'])
480 for image
in bpy
.data
.images
:
481 if image
.filepath
== tpath
:
482 # split = row.split(factor=1.0, align=False)
483 col
.template_icon(icon_value
=image
.preview
.icon_id
, scale
=6.0)
485 # layout.label(text = '', icon_value=image.preview.icon_id, scale = 10)
486 col
.label(text
=asset
.name
)
487 draw_ratings(col
, context
, asset
=asset
)
490 class VIEW3D_PT_blenderkit_ratings(Panel
):
491 bl_category
= "BlenderKit"
492 bl_idname
= "VIEW3D_PT_blenderkit_ratings"
493 bl_space_type
= 'VIEW_3D'
494 bl_region_type
= 'UI'
495 bl_label
= "Please rate"
496 bl_context
= "objectmode"
499 def poll(cls
, context
):
501 p
= bpy
.context
.view_layer
.objects
.active
is not None
504 def draw(self
, context
):
505 # TODO make a list of assets inside asset appending code, to happen only when assets are added to the scene.
506 # draw asset properties here
508 assets
= ratings
.get_assets_for_rating()
510 utils
.label_multiline(layout
, text
='Please help BlenderKit community by rating these assets:')
513 if a
.bkit_ratings
.rating_work_hours
==0:
514 draw_rating_asset(self
, context
, asset
=a
)
517 def draw_login_progress(layout
):
518 layout
.label(text
='Login through browser')
519 layout
.label(text
='in progress.')
520 layout
.operator("wm.blenderkit_login_cancel", text
="Cancel", icon
='CANCEL')
523 class VIEW3D_PT_blenderkit_profile(Panel
):
524 bl_category
= "BlenderKit"
525 bl_idname
= "VIEW3D_PT_blenderkit_profile"
526 bl_space_type
= 'VIEW_3D'
527 bl_region_type
= 'UI'
528 bl_label
= "BlenderKit Profile"
531 def poll(cls
, context
):
535 def draw(self
, context
):
536 # draw asset properties here
538 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
540 if user_preferences
.login_attempt
:
541 draw_login_progress(layout
)
544 if user_preferences
.api_key
!= '':
545 me
= bpy
.context
.window_manager
.get('bkit profile')
549 layout
.label(text
='Me: %s %s' % (me
['firstName'], me
['lastName']))
550 # layout.label(text='Email: %s' % (me['email']))
554 if me
.get('currentPlanName') is not None:
555 pn
= me
['currentPlanName']
556 pcoll
= icons
.icon_collections
["main"]
558 my_icon
= pcoll
['free']
560 my_icon
= pcoll
['full']
563 row
.label(text
='My plan:')
564 row
.label(text
='%s plan' % pn
, icon_value
=my_icon
.icon_id
)
566 layout
.operator("wm.url_open", text
="Change plan",
567 icon
='URL').url
= paths
.get_bkit_url() + paths
.BLENDERKIT_PLANS
570 # if me.get('sumAssetFilesSize') is not None: # TODO remove this when production server has these too.
571 # layout.label(text='My public assets: %i MiB' % (me['sumAssetFilesSize']))
572 # if me.get('sumPrivateAssetFilesSize') is not None:
573 # layout.label(text='My private assets: %i MiB' % (me['sumPrivateAssetFilesSize']))
574 if me
.get('remainingPrivateQuota') is not None:
575 layout
.label(text
='My free storage: %i MiB' % (me
['remainingPrivateQuota']))
577 layout
.operator("wm.url_open", text
="See my uploads",
578 icon
='URL').url
= paths
.get_bkit_url() + paths
.BLENDERKIT_USER_ASSETS
581 class VIEW3D_PT_blenderkit_login(Panel
):
582 bl_category
= "BlenderKit"
583 bl_idname
= "VIEW3D_PT_blenderkit_login"
584 bl_space_type
= 'VIEW_3D'
585 bl_region_type
= 'UI'
586 bl_label
= "BlenderKit Login"
589 def poll(cls
, context
):
592 def draw(self
, context
):
594 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
596 if user_preferences
.login_attempt
:
597 draw_login_progress(layout
)
600 if user_preferences
.enable_oauth
:
601 draw_login_buttons(layout
)
604 def draw_panel_model_rating(self
, context
):
605 # o = bpy.context.active_object
606 o
= utils
.get_active_model()
607 # print('ratings active',o)
608 draw_ratings(self
.layout
, context
, asset
=o
) # , props)
609 # op.asset_type = 'MODEL'
612 def draw_panel_material_upload(self
, context
):
613 o
= bpy
.context
.active_object
614 mat
= bpy
.context
.active_object
.active_material
616 props
= mat
.blenderkit
619 draw_upload_common(layout
, props
, 'MATERIAL', context
)
621 prop_needed(layout
, props
, 'name', props
.name
)
622 layout
.prop(props
, 'description')
623 layout
.prop(props
, 'style')
624 # if props.style == 'OTHER':
625 # layout.prop(props, 'style_other')
626 # layout.prop(props, 'engine')
627 # if props.engine == 'OTHER':
628 # layout.prop(props, 'engine_other')
629 layout
.prop(props
, 'tags')
630 # layout.prop(props,'shaders')#TODO autofill on upload
632 layout
.prop(props
, 'is_free')
634 layout
.prop(props
, 'pbr')
635 layout
.prop(props
, 'uv')
636 layout
.prop(props
, 'animated')
637 layout
.prop(props
, 'texture_size_meters')
641 if props
.is_generating_thumbnail
:
643 prop_needed(row
, props
, 'thumbnail', props
.has_thumbnail
, False)
645 if props
.is_generating_thumbnail
:
646 row
= layout
.row(align
=True)
647 row
.label(text
=props
.thumbnail_generating_state
, icon
='RENDER_STILL')
648 op
= row
.operator('object.kill_bg_process', text
="", icon
='CANCEL')
649 op
.process_source
= 'MATERIAL'
650 op
.process_type
= 'THUMBNAILER'
651 elif props
.thumbnail_generating_state
!= '':
652 utils
.label_multiline(layout
, text
=props
.thumbnail_generating_state
)
654 if bpy
.context
.scene
.render
.engine
in ('CYCLES', 'BLENDER_EEVEE'):
655 layout
.operator("object.blenderkit_material_thumbnail", text
='Render thumbnail with Cycles', icon
='EXPORT')
657 # tname = "." + bpy.context.active_object.active_material.name + "_thumbnail"
658 # if props.has_thumbnail and bpy.data.textures.get(tname) is not None:
660 # # row.scale_y = 1.5
661 # row.template_preview(bpy.data.textures[tname], preview_id='test')
664 def draw_panel_material_search(self
, context
):
666 props
= wm
.blenderkit_mat
670 row
.prop(props
, "search_keywords", text
="", icon
='VIEWZOOM')
671 draw_assetbar_show_hide(row
, props
)
672 layout
.prop(props
, "own_only")
673 utils
.label_multiline(layout
, text
=props
.report
)
675 # layout.prop(props, 'search_style')F
676 # if props.search_style == 'OTHER':
677 # layout.prop(props, 'search_style_other')
678 # layout.prop(props, 'search_engine')
679 # if props.search_engine == 'OTHER':
680 # layout.prop(props, 'search_engine_other')
682 # draw_panel_categories(self, context)
685 def draw_panel_material_ratings(self
, context
):
686 asset
= bpy
.context
.active_object
.active_material
687 draw_ratings(self
.layout
, context
, asset
) # , props)
688 # op.asset_type = 'MATERIAL'
691 def draw_panel_brush_upload(self
, context
):
692 brush
= utils
.get_active_brush()
693 if brush
is not None:
694 props
= brush
.blenderkit
698 draw_upload_common(layout
, props
, 'BRUSH', context
)
700 layout
.prop(props
, 'name')
701 layout
.prop(props
, 'description')
702 layout
.prop(props
, 'tags')
705 def draw_panel_brush_search(self
, context
):
707 props
= s
.blenderkit_brush
711 row
.prop(props
, "search_keywords", text
="", icon
='VIEWZOOM')
712 draw_assetbar_show_hide(row
, props
)
713 layout
.prop(props
, "own_only")
715 utils
.label_multiline(layout
, text
=props
.report
)
716 # draw_panel_categories(self, context)
719 def draw_panel_brush_ratings(self
, context
):
720 # props = utils.get_brush_props(context)
721 brush
= utils
.get_active_brush()
722 draw_ratings(self
.layout
, context
, asset
=brush
) # , props)
724 # op.asset_type = 'BRUSH'
727 def draw_login_buttons(layout
, invoke
=False):
728 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
730 if user_preferences
.login_attempt
:
731 draw_login_progress(layout
)
734 layout
.operator_context
= 'INVOKE_DEFAULT'
736 layout
.operator_context
= 'EXEC_DEFAULT'
737 if user_preferences
.api_key
== '':
738 layout
.operator("wm.blenderkit_login", text
="Login",
739 icon
='URL').signup
= False
740 layout
.operator("wm.blenderkit_login", text
="Sign up",
741 icon
='URL').signup
= True
744 layout
.operator("wm.blenderkit_login", text
="Login as someone else",
745 icon
='URL').signup
= False
746 layout
.operator("wm.blenderkit_logout", text
="Logout",
750 class VIEW3D_PT_blenderkit_advanced_model_search(Panel
):
751 bl_category
= "BlenderKit"
752 bl_idname
= "VIEW3D_PT_blenderkit_advanced_model_search"
753 bl_parent_id
= "VIEW3D_PT_blenderkit_unified"
754 bl_space_type
= 'VIEW_3D'
755 bl_region_type
= 'UI'
756 bl_label
= "Search filters"
757 bl_options
= {'DEFAULT_CLOSED'}
760 def poll(cls
, context
):
762 ui_props
= s
.blenderkitUI
763 return ui_props
.down_up
== 'SEARCH' and ui_props
.asset_type
== 'MODEL'
765 def draw(self
, context
):
768 props
= s
.blenderkit_models
772 # layout.label(text = "common searches keywords:")
773 # layout.prop(props, "search_global_keywords", text = "")
774 # layout.prop(props, "search_modifier_keywords")
775 # if props.search_engine == 'OTHER':
776 # layout.prop(props, "search_engine_keyword")
779 layout
.prop(props
, "search_condition", text
='Condition') # , text ='condition of object new/old e.t.c.')
782 layout
.prop(props
, "search_design_year", text
='designed in ( min - max )')
783 if props
.search_design_year
:
784 row
= layout
.row(align
=True)
785 row
.prop(props
, "search_design_year_min", text
='min')
786 row
.prop(props
, "search_design_year_max", text
='max')
789 layout
.prop(props
, "search_polycount", text
='Poly count in ( min - max )')
790 if props
.search_polycount
:
791 row
= layout
.row(align
=True)
792 row
.prop(props
, "search_polycount_min", text
='min')
793 row
.prop(props
, "search_polycount_max", text
='max')
796 layout
.prop(props
, "search_texture_resolution", text
='texture resolution ( min - max )')
797 if props
.search_texture_resolution
:
798 row
= layout
.row(align
=True)
799 row
.prop(props
, "search_texture_resolution_min", text
='min')
800 row
.prop(props
, "search_texture_resolution_max", text
='max')
803 layout
.prop(props
, "search_file_size", text
='File size ( min - max MB)')
804 if props
.search_file_size
:
805 row
= layout
.row(align
=True)
806 row
.prop(props
, "search_file_size_min", text
='min')
807 row
.prop(props
, "search_file_size_max", text
='max')
809 # layout.prop(props, "search_procedural", expand=True)
811 # layout.prop(props, "search_adult") # , text ='condition of object new/old e.t.c.')
814 class VIEW3D_PT_blenderkit_advanced_material_search(Panel
):
815 bl_category
= "BlenderKit"
816 bl_idname
= "VIEW3D_PT_blenderkit_advanced_material_search"
817 bl_parent_id
= "VIEW3D_PT_blenderkit_unified"
818 bl_space_type
= 'VIEW_3D'
819 bl_region_type
= 'UI'
820 bl_label
= "Search filters"
821 bl_options
= {'DEFAULT_CLOSED'}
824 def poll(cls
, context
):
826 ui_props
= s
.blenderkitUI
827 return ui_props
.down_up
== 'SEARCH' and ui_props
.asset_type
== 'MATERIAL'
829 def draw(self
, context
):
832 props
= s
.blenderkit_mat
836 layout
.label(text
='texture types')
837 col
= layout
.column()
838 col
.prop(props
, "search_procedural", expand
=True)
840 if props
.search_procedural
== 'TEXTURE_BASED':
842 layout
.prop(props
, "search_texture_resolution", text
='texture resolution ( min - max )')
843 if props
.search_texture_resolution
:
844 row
= layout
.row(align
=True)
845 row
.prop(props
, "search_texture_resolution_min", text
='min')
846 row
.prop(props
, "search_texture_resolution_max", text
='max')
849 layout
.prop(props
, "search_file_size", text
='File size ( min - max MB)')
850 if props
.search_file_size
:
851 row
= layout
.row(align
=True)
852 row
.prop(props
, "search_file_size_min", text
='min')
853 row
.prop(props
, "search_file_size_max", text
='max')
856 class VIEW3D_PT_blenderkit_categories(Panel
):
857 bl_category
= "BlenderKit"
858 bl_idname
= "VIEW3D_PT_blenderkit_categories"
859 bl_space_type
= 'VIEW_3D'
860 bl_region_type
= 'UI'
861 bl_label
= "Categories"
862 bl_parent_id
= "VIEW3D_PT_blenderkit_unified"
863 bl_options
= {'DEFAULT_CLOSED'}
866 def poll(cls
, context
):
868 ui_props
= s
.blenderkitUI
870 if ui_props
.asset_type
== 'BRUSH' and not (context
.sculpt_object
or context
.image_paint_object
):
872 return ui_props
.down_up
== 'SEARCH' and mode
874 def draw(self
, context
):
875 draw_panel_categories(self
, context
)
878 class VIEW3D_PT_blenderkit_import_settings(Panel
):
879 bl_category
= "BlenderKit"
880 bl_idname
= "VIEW3D_PT_blenderkit_import_settings"
881 bl_space_type
= 'VIEW_3D'
882 bl_region_type
= 'UI'
883 bl_label
= "Import settings"
884 bl_parent_id
= "VIEW3D_PT_blenderkit_unified"
885 bl_options
= {'DEFAULT_CLOSED'}
888 def poll(cls
, context
):
890 ui_props
= s
.blenderkitUI
891 return ui_props
.down_up
== 'SEARCH' and ui_props
.asset_type
in ['MATERIAL', 'MODEL', 'HDR']
893 def draw(self
, context
):
897 ui_props
= s
.blenderkitUI
899 if ui_props
.asset_type
== 'MODEL':
900 # noinspection PyCallByClass
901 props
= s
.blenderkit_models
902 layout
.prop(props
, 'randomize_rotation')
903 if props
.randomize_rotation
:
904 layout
.prop(props
, 'randomize_rotation_amount')
905 layout
.prop(props
, 'perpendicular_snap')
906 # if props.perpendicular_snap:
907 # layout.prop(props,'perpendicular_snap_threshold')
909 layout
.label(text
='Import method:')
911 row
.prop(props
, 'append_method', expand
=True, icon_only
=False)
913 if ui_props
.asset_type
== 'MATERIAL':
914 props
= s
.blenderkit_mat
915 layout
.prop(props
, 'automap')
916 layout
.label(text
='Import method:')
919 row
.prop(props
, 'append_method', expand
=True, icon_only
=False)
920 if ui_props
.asset_type
== 'HDR':
921 props
= s
.blenderkit_HDR
923 layout
.prop(props
, 'resolution')
924 # layout.prop(props, 'unpack_files')
927 class VIEW3D_PT_blenderkit_unified(Panel
):
928 bl_category
= "BlenderKit"
929 bl_idname
= "VIEW3D_PT_blenderkit_unified"
930 bl_space_type
= 'VIEW_3D'
931 bl_region_type
= 'UI'
932 bl_label
= "Find and Upload Assets"
935 def poll(cls
, context
):
936 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
937 return user_preferences
.panel_behaviour
== 'BOTH' or user_preferences
.panel_behaviour
== 'UNIFIED'
939 def draw(self
, context
):
941 ui_props
= s
.blenderkitUI
942 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
943 wm
= bpy
.context
.window_manager
945 # layout.prop_tabs_enum(ui_props, "asset_type", icon_only = True)
951 row
.prop(ui_props
, 'down_up', expand
=True, icon_only
=False)
953 # row = row.split().row()
954 # layout.alert = True
955 # layout.alignment = 'CENTER'
956 row
= layout
.row(align
=True)
959 # split = row.split(factor=.
960 col
= layout
.column()
961 col
.prop(ui_props
, 'asset_type', expand
=True, icon_only
=False)
962 # row = layout.column(align = False)
963 # layout.prop(ui_props, 'asset_type', expand=False, text='')
965 w
= context
.region
.width
966 if user_preferences
.login_attempt
:
967 draw_login_progress(layout
)
970 if len(user_preferences
.api_key
) < 20 and user_preferences
.asset_counter
> 20:
971 if user_preferences
.enable_oauth
:
972 draw_login_buttons(layout
)
974 op
= layout
.operator("wm.url_open", text
="Get your API Key",
976 op
.url
= paths
.BLENDERKIT_SIGNUP_URL
977 layout
.label(text
='Paste your API Key:')
978 layout
.prop(user_preferences
, 'api_key', text
='')
980 # if bpy.data.filepath == '':
981 # layout.alert = True
982 # utils.label_multiline(layout, text="It's better to save your file first.", width=w)
983 # layout.alert = False
986 if ui_props
.down_up
== 'SEARCH':
987 if utils
.profile_is_validator():
988 search_props
= utils
.get_search_props()
989 layout
.prop(search_props
, 'search_verification_status')
990 layout
.prop(search_props
, "unrated_only")
992 if ui_props
.asset_type
== 'MODEL':
993 # noinspection PyCallByClass
994 draw_panel_model_search(self
, context
)
995 if ui_props
.asset_type
== 'SCENE':
996 # noinspection PyCallByClass
997 draw_panel_scene_search(self
, context
)
998 if ui_props
.asset_type
== 'HDR':
999 # noinspection PyCallByClass
1000 draw_panel_hdr_search(self
, context
)
1001 elif ui_props
.asset_type
== 'MATERIAL':
1002 draw_panel_material_search(self
, context
)
1003 elif ui_props
.asset_type
== 'BRUSH':
1004 if context
.sculpt_object
or context
.image_paint_object
:
1005 # noinspection PyCallByClass
1006 draw_panel_brush_search(self
, context
)
1008 utils
.label_multiline(layout
, text
='Switch to paint or sculpt mode.', width
=context
.region
.width
)
1012 elif ui_props
.down_up
== 'UPLOAD':
1013 if not ui_props
.assetbar_on
:
1014 text
= 'Show asset preview - ;'
1016 text
= 'Hide asset preview - ;'
1017 op
= layout
.operator('view3d.blenderkit_asset_bar', text
=text
, icon
='EXPORT')
1018 op
.keep_running
= False
1019 op
.do_search
= False
1020 op
.tooltip
= 'Show/Hide asset preview'
1023 if e
not in ('CYCLES', 'BLENDER_EEVEE'):
1024 rtext
= 'Only Cycles and EEVEE render engines are currently supported. ' \
1025 'Please use Cycles for all assets you upload to BlenderKit.'
1026 utils
.label_multiline(layout
, rtext
, icon
='ERROR', width
=w
)
1029 if ui_props
.asset_type
== 'MODEL':
1030 # utils.label_multiline(layout, "Uploaded models won't be available in b2.79", icon='ERROR')
1031 if bpy
.context
.view_layer
.objects
.active
is not None:
1032 draw_panel_model_upload(self
, context
)
1034 layout
.label(text
='selet object to upload')
1035 elif ui_props
.asset_type
== 'SCENE':
1036 draw_panel_scene_upload(self
, context
)
1037 elif ui_props
.asset_type
== 'HDR':
1038 draw_panel_hdr_upload(self
, context
)
1040 elif ui_props
.asset_type
== 'MATERIAL':
1041 # utils.label_multiline(layout, "Uploaded materials won't be available in b2.79", icon='ERROR')
1043 if bpy
.context
.view_layer
.objects
.active
is not None and bpy
.context
.active_object
.active_material
is not None:
1044 draw_panel_material_upload(self
, context
)
1046 utils
.label_multiline(layout
, text
='select object with material to upload materials', width
=w
)
1048 elif ui_props
.asset_type
== 'BRUSH':
1049 if context
.sculpt_object
or context
.image_paint_object
:
1050 draw_panel_brush_upload(self
, context
)
1052 layout
.label(text
='Switch to paint or sculpt mode.')
1054 elif ui_props
.down_up
== 'RATING': # the poll functions didn't work here, don't know why.
1056 if ui_props
.asset_type
== 'MODEL':
1057 # TODO improve poll here to parenting structures
1058 if bpy
.context
.view_layer
.objects
.active
is not None and bpy
.context
.active_object
.get(
1059 'asset_data') != None:
1060 ad
= bpy
.context
.active_object
.get('asset_data')
1061 layout
.label(text
=ad
['name'])
1062 draw_panel_model_rating(self
, context
)
1063 if ui_props
.asset_type
== 'MATERIAL':
1064 if bpy
.context
.view_layer
.objects
.active
is not None and \
1065 bpy
.context
.active_object
.active_material
is not None and \
1066 bpy
.context
.active_object
.active_material
.blenderkit
.asset_base_id
!= '':
1067 layout
.label(text
=bpy
.context
.active_object
.active_material
.blenderkit
.name
+ ' :')
1068 # noinspection PyCallByClass
1069 draw_panel_material_ratings(self
, context
)
1070 if ui_props
.asset_type
== 'BRUSH':
1071 if context
.sculpt_object
or context
.image_paint_object
:
1072 props
= utils
.get_brush_props(context
)
1073 if props
.asset_base_id
!= '':
1074 layout
.label(text
=props
.name
+ ' :')
1075 # noinspection PyCallByClass
1076 draw_panel_brush_ratings(self
, context
)
1077 if ui_props
.asset_type
== 'TEXTURE':
1078 layout
.label(text
='not yet implemented')
1081 class BlenderKitWelcomeOperator(bpy
.types
.Operator
):
1082 """Login online on BlenderKit webpage"""
1084 bl_idname
= "wm.blenderkit_welcome"
1085 bl_label
= "Welcome to BlenderKit!"
1086 bl_options
= {'REGISTER', 'UNDO', 'INTERNAL'}
1090 description
="Tutorial Step",
1092 options
={'SKIP_SAVE'}
1096 def poll(cls
, context
):
1099 def draw(self
, context
):
1100 layout
= self
.layout
1102 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
1104 message
= "BlenderKit connects from Blender to an online, " \
1105 "community built shared library of models, " \
1106 "materials, and brushes. " \
1107 "Use addon preferences to set up where files will be saved in the Global directory setting."
1109 utils
.label_multiline(layout
, text
=message
, width
=300)
1110 utils
.label_multiline(layout
, text
="\n Let's start by searching for some cool materials?", width
=300)
1112 message
= "Operator Tutorial called with invalid step"
1114 def execute(self
, context
):
1117 # bpy.context.window_manager.windows[0].cursor_warp(1000, 1000)
1118 # show n-key sidebar (spaces[index] has to be found for view3d too:
1119 # bpy.context.window_manager.windows[0].screen.areas[5].spaces[0].show_region_ui = False
1120 print('running search no')
1121 ui_props
= bpy
.context
.scene
.blenderkitUI
1122 ui_props
.asset_type
= 'MATERIAL'
1123 bpy
.context
.scene
.blenderkit_mat
.search_keywords
= 'ice'
1127 def invoke(self
, context
, event
):
1128 wm
= bpy
.context
.window_manager
1129 return wm
.invoke_props_dialog(self
)
1132 def draw_asset_context_menu(layout
, context
, asset_data
, from_panel
=False):
1133 ui_props
= context
.scene
.blenderkitUI
1135 author_id
= str(asset_data
['author'].get('id'))
1136 wm
= bpy
.context
.window_manager
1138 layout
.operator_context
= 'INVOKE_DEFAULT'
1140 op
= layout
.operator('wm.blenderkit_menu_rating_upload', text
='Rate')
1141 op
.asset_name
= asset_data
['name']
1142 op
.asset_id
= asset_data
['id']
1143 op
.asset_type
= asset_data
['assetType']
1145 if wm
.get('bkit authors') is not None and author_id
is not None:
1146 a
= bpy
.context
.window_manager
['bkit authors'].get(author_id
)
1148 # utils.p('author:', a)
1149 op
= layout
.operator('wm.url_open', text
="Open Author's Website")
1150 if a
.get('aboutMeUrl') is not None:
1151 op
.url
= a
['aboutMeUrl']
1153 op
.url
= paths
.get_author_gallery_url(a
['id'])
1154 op
= layout
.operator('view3d.blenderkit_search', text
="Show Assets By Author")
1156 op
.author_id
= author_id
1158 op
= layout
.operator('view3d.blenderkit_search', text
='Search Similar')
1159 # build search string from description and tags:
1160 op
.keywords
= asset_data
['name']
1161 if asset_data
.get('description'):
1162 op
.keywords
+= ' ' + asset_data
.get('description')
1163 op
.keywords
+= ' '.join(asset_data
.get('tags'))
1165 if asset_data
.get('canDownload') != 0:
1166 if len(bpy
.context
.selected_objects
) > 0 and ui_props
.asset_type
== 'MODEL':
1167 aob
= bpy
.context
.active_object
1169 aob
= bpy
.context
.selected_objects
[0]
1170 op
= layout
.operator('scene.blenderkit_download', text
='Replace Active Models')
1172 # this checks if the menu got called from right-click in assetbar(then index is 0 - x) or
1173 # from a panel(then replacement happens from the active model)
1175 # called from addon panel
1176 op
.asset_base_id
= asset_data
['assetBaseId']
1178 op
.asset_index
= ui_props
.active_index
1180 # op.asset_type = ui_props.asset_type
1181 op
.model_location
= aob
.location
1182 op
.model_rotation
= aob
.rotation_euler
1183 op
.target_object
= aob
.name
1184 op
.material_target_slot
= aob
.active_material_index
1186 op
.replace_resolution
= False
1188 # resolution replacement operator
1189 # if asset_data['downloaded'] == 100: # only show for downloaded/used assets
1190 # if ui_props.asset_type in ('MODEL', 'MATERIAL'):
1191 # layout.menu(OBJECT_MT_blenderkit_resolution_menu.bl_idname)
1194 if ui_props
.asset_type
in ('MODEL', 'MATERIAL', 'HDR') and \
1195 utils
.get_param(asset_data
, 'textureResolutionMax') is not None and \
1196 utils
.get_param(asset_data
, 'textureResolutionMax') > 512:
1198 s
= bpy
.context
.scene
1200 col
= layout
.column()
1201 col
.operator_context
= 'INVOKE_DEFAULT'
1204 # Called from addon panel
1206 if asset_data
.get('resolution'):
1207 op
= col
.operator('scene.blenderkit_download', text
='Replace asset resolution')
1208 op
.asset_base_id
= asset_data
['assetBaseId']
1209 if asset_data
['assetType'] == 'MODEL':
1210 o
= utils
.get_active_model()
1211 op
.model_location
= o
.location
1212 op
.model_rotation
= o
.rotation_euler
1213 op
.target_object
= o
.name
1214 op
.material_target_slot
= o
.active_material_index
1216 elif asset_data
['assetType'] == 'MATERIAL':
1217 aob
= bpy
.context
.active_object
1218 op
.model_location
= aob
.location
1219 op
.model_rotation
= aob
.rotation_euler
1220 op
.target_object
= aob
.name
1221 op
.material_target_slot
= aob
.active_material_index
1222 op
.replace_resolution
= True
1225 op
.invoke_resolution
= True
1226 op
.max_resolution
= asset_data
.get('max_resolution',
1227 0) # str(utils.get_param(asset_data, 'textureResolutionMax'))
1229 elif asset_data
['assetBaseId'] in s
['assets used'].keys():
1230 # called from asset bar:
1231 print('context menu')
1232 op
= col
.operator('scene.blenderkit_download', text
='Replace asset resolution')
1234 op
.asset_index
= ui_props
.active_index
1235 # op.asset_type = ui_props.asset_type
1236 op
.replace_resolution
= True
1238 op
.invoke_resolution
= True
1239 o
= utils
.get_active_model()
1240 if o
and o
.get('asset_data'):
1241 if o
['asset_data']['assetBaseId'] == bpy
.context
.scene
['search results'][ui_props
.active_index
]:
1242 op
.model_location
= o
.location
1243 op
.model_rotation
= o
.rotation_euler
1245 op
.model_location
= (0, 0, 0)
1246 op
.model_rotation
= (0, 0, 0)
1247 op
.max_resolution
= asset_data
.get('max_resolution',
1248 0) # str(utils.get_param(asset_data, 'textureResolutionMax'))
1249 print('should be drawn!')
1250 # print('operator res ', resolution)
1251 # op.resolution = resolution
1253 wm
= bpy
.context
.window_manager
1254 profile
= wm
.get('bkit profile')
1255 if profile
is not None:
1257 if utils
.profile_is_validator():
1258 layout
.label(text
='Validation tools:')
1259 layout
.operator_context
= 'EXEC_DEFAULT'
1261 if asset_data
['verificationStatus'] != 'uploaded':
1262 op
= layout
.operator('object.blenderkit_change_status', text
='set Uploaded')
1263 op
.asset_id
= asset_data
['id']
1264 op
.state
= 'uploaded'
1265 if asset_data
['verificationStatus'] != 'validated':
1266 op
= layout
.operator('object.blenderkit_change_status', text
='Validate')
1267 op
.asset_id
= asset_data
['id']
1268 op
.state
= 'validated'
1269 if asset_data
['verificationStatus'] != 'on_hold':
1270 op
= layout
.operator('object.blenderkit_change_status', text
='Put on Hold')
1271 op
.asset_id
= asset_data
['id']
1272 op
.state
= 'on_hold'
1273 if asset_data
['verificationStatus'] != 'rejected':
1274 op
= layout
.operator('object.blenderkit_change_status', text
='Reject')
1275 op
.asset_id
= asset_data
['id']
1276 op
.state
= 'rejected'
1278 if author_id
== str(profile
['user']['id']) or utils
.profile_is_validator():
1279 layout
.label(text
='Management tools:')
1282 row
.operator_context
= 'INVOKE_DEFAULT'
1283 op
= layout
.operator('wm.blenderkit_fast_metadata', text
='Fast Edit Metadata')
1284 op
.asset_id
= asset_data
['id']
1286 if author_id
== str(profile
['user']['id']):
1288 row
.operator_context
= 'INVOKE_DEFAULT'
1289 op
= row
.operator('object.blenderkit_change_status', text
='Delete')
1290 op
.asset_id
= asset_data
['id']
1291 op
.state
= 'deleted'
1293 if utils
.profile_is_validator():
1294 layout
.label(text
='Admin Tools:')
1297 op
= layout
.operator('object.blenderkit_print_asset_debug', text
='Print asset debug')
1298 op
.asset_id
= asset_data
['id']
1304 # def draw_asset_resolution_replace(self, context, resolution):
1305 # layout = self.layout
1306 # ui_props = bpy.context.scene.blenderkitUI
1308 # op = layout.operator('scene.blenderkit_download', text=resolution)
1309 # if ui_props.active_index == -3:
1310 # # This happens if the command is called from addon panel
1311 # o = utils.get_active_model()
1312 # op.asset_base_id = o['asset_data']['assetBaseId']
1315 # op.asset_index = ui_props.active_index
1317 # op.asset_type = ui_props.asset_type
1318 # if len(bpy.context.selected_objects) > 0: # and ui_props.asset_type == 'MODEL':
1319 # aob = bpy.context.active_object
1320 # op.model_location = aob.location
1321 # op.model_rotation = aob.rotation_euler
1322 # op.target_object = aob.name
1323 # op.material_target_slot = aob.active_material_index
1324 # op.replace_resolution = True
1325 # print('operator res ', resolution)
1326 # op.resolution = resolution
1329 # class OBJECT_MT_blenderkit_resolution_menu(bpy.types.Menu):
1330 # bl_label = "Replace Asset Resolution"
1331 # bl_idname = "OBJECT_MT_blenderkit_resolution_menu"
1333 # def draw(self, context):
1334 # ui_props = context.scene.blenderkitUI
1336 # # sr = bpy.context.scene['search results']
1338 # # sr = bpy.context.scene['search results']
1339 # # asset_data = sr[ui_props.active_index]
1341 # for k in resolutions.resolution_props_to_server.keys():
1342 # draw_asset_resolution_replace(self, context, k)
1345 class OBJECT_MT_blenderkit_asset_menu(bpy
.types
.Menu
):
1346 bl_label
= "Asset options:"
1347 bl_idname
= "OBJECT_MT_blenderkit_asset_menu"
1349 def draw(self
, context
):
1350 ui_props
= context
.scene
.blenderkitUI
1352 sr
= bpy
.context
.scene
['search results']
1353 asset_data
= sr
[ui_props
.active_index
]
1354 draw_asset_context_menu(self
.layout
, context
, asset_data
, from_panel
=False)
1356 # ui_props = context.scene.blenderkitUI
1358 # sr = bpy.context.scene['search results']
1359 # asset_data = sr[ui_props.active_index]
1360 # layout = self.layout
1361 # row = layout.row()
1362 # split = row.split(factor=0.2)
1363 # col = split.column()
1364 # op = col.operator('view3d.asset_drag_drop')
1365 # op.asset_search_index=ui_props.active_index
1367 # draw_asset_context_menu(col, context, asset_data, from_panel=False)
1368 # split = split.split(factor=0.3)
1369 # col1 = split.column()
1371 # utils.label_multiline(box, asset_data['tooltip'])
1372 # col2 = split.column()
1374 # pcoll = icons.icon_collections["main"]
1375 # my_icon = pcoll['test']
1378 # row.template_icon(icon_value=my_icon.icon_id, scale=2.0)
1379 # # col2.template_icon(icon_value=self.img.preview.icon_id, scale=10.0)
1382 # box2.label(text='and heere goes the rating')
1383 # box2.label(text='************')
1384 # box2.label(text='dadydadadada')
1386 class AssetPopupCard(bpy
.types
.Operator
):
1387 """Generate Cycles thumbnail for model assets"""
1388 bl_idname
= "wm.blenderkit_asset_popup"
1389 bl_label
= "BlenderKit asset popup"
1390 # bl_options = {'REGISTER', 'INTERNAL'}
1391 bl_options
= {'REGISTER',}
1394 def poll(cls
, context
):
1397 def draw(self
, context
):
1398 ui_props
= context
.scene
.blenderkitUI
1400 sr
= bpy
.context
.scene
['search results']
1401 asset_data
= sr
[ui_props
.active_index
]
1402 layout
= self
.layout
1404 split
= row
.split(factor
=0.2)
1405 col
= split
.column()
1406 op
= col
.operator('view3d.asset_drag_drop')
1407 op
.asset_search_index
= ui_props
.active_index
1408 draw_asset_context_menu(col
, context
, asset_data
, from_panel
=False)
1409 split
= split
.split(factor
=0.5)
1410 col1
= split
.column()
1412 utils
.label_multiline(box
,asset_data
['tooltip'], width
= 300)
1414 col2
= split
.column()
1417 pcoll
= icons
.icon_collections
["main"]
1418 my_icon
= pcoll
['test']
1419 col2
.template_icon(icon_value
=my_icon
.icon_id
, scale
=20.0)
1420 # col2.template_icon(icon_value=self.img.preview.icon_id, scale=10.0)
1423 # draw_ratings(box2, context, asset_data)
1424 box2
.label(text
= 'Ratings')
1425 # print(tp, dir(tp))
1426 # if not hasattr(self, 'first_draw'):# try to redraw because of template preview which needs update
1427 # for region in context.area.regions:
1428 # region.tag_redraw()
1429 # self.first_draw = True
1431 def execute(self
, context
):
1435 def invoke(self
, context
, event
):
1436 wm
= context
.window_manager
1437 ui_props
= context
.scene
.blenderkitUI
1438 ui_props
.draw_tooltip
= False
1439 sr
= bpy
.context
.scene
['search results']
1440 asset_data
= sr
[ui_props
.active_index
]
1441 self
.img
= ui
.get_large_thumbnail_image(asset_data
)
1442 # self.tex = utils.get_hidden_texture(self.img)
1443 # self.tex.update_tag()
1445 bl_label
= asset_data
['name']
1446 return wm
.invoke_props_dialog(self
, width
= 700)
1448 class OBJECT_MT_blenderkit_login_menu(bpy
.types
.Menu
):
1449 bl_label
= "BlenderKit login/signup:"
1450 bl_idname
= "OBJECT_MT_blenderkit_login_menu"
1452 def draw(self
, context
):
1453 layout
= self
.layout
1455 # utils.label_multiline(layout, text=message)
1456 draw_login_buttons(layout
)
1459 class SetCategoryOperator(bpy
.types
.Operator
):
1460 """Visit subcategory"""
1461 bl_idname
= "view3d.blenderkit_set_category"
1462 bl_label
= "BlenderKit Set Active Category"
1463 bl_options
= {'REGISTER', 'UNDO', 'INTERNAL'}
1465 category
: bpy
.props
.StringProperty(
1467 description
="set this category active",
1470 asset_type
: bpy
.props
.StringProperty(
1472 description
="asset type",
1476 def poll(cls
, context
):
1479 def execute(self
, context
):
1480 acat
= bpy
.context
.window_manager
['active_category'][self
.asset_type
]
1481 if self
.category
== '':
1482 acat
.remove(acat
[-1])
1484 acat
.append(self
.category
)
1485 # we have to write back to wm. Thought this should happen with original list.
1486 bpy
.context
.window_manager
['active_category'][self
.asset_type
] = acat
1490 class UrlPopupDialog(bpy
.types
.Operator
):
1491 """Generate Cycles thumbnail for model assets"""
1492 bl_idname
= "wm.blenderkit_url_dialog"
1493 bl_label
= "BlenderKit message:"
1494 bl_options
= {'REGISTER', 'INTERNAL'}
1496 url
: bpy
.props
.StringProperty(
1501 link_text
: bpy
.props
.StringProperty(
1504 default
="Go to website")
1506 message
: bpy
.props
.StringProperty(
1512 # def poll(cls, context):
1513 # return bpy.context.view_layer.objects.active is not None
1515 def draw(self
, context
):
1516 layout
= self
.layout
1517 utils
.label_multiline(layout
, text
=self
.message
)
1519 layout
.active_default
= True
1520 op
= layout
.operator("wm.url_open", text
=self
.link_text
, icon
='QUESTION')
1523 def execute(self
, context
):
1524 # start_thumbnailer(self, context)
1527 def invoke(self
, context
, event
):
1528 wm
= context
.window_manager
1530 return wm
.invoke_props_dialog(self
)
1533 class LoginPopupDialog(bpy
.types
.Operator
):
1534 """Popup a dialog which enables the user to log in after being logged out automatically."""
1535 bl_idname
= "wm.blenderkit_login_dialog"
1536 bl_label
= "BlenderKit login"
1537 bl_options
= {'REGISTER', 'INTERNAL'}
1539 message
: bpy
.props
.StringProperty(
1542 default
="Your were logged out from BlenderKit. Please login again. ")
1545 # def poll(cls, context):
1546 # return bpy.context.view_layer.objects.active is not None
1548 def draw(self
, context
):
1549 layout
= self
.layout
1550 utils
.label_multiline(layout
, text
=self
.message
)
1552 layout
.active_default
= True
1553 op
= layout
.operator
1554 op
= layout
.operator("wm.url_open", text
=self
.link_text
, icon
='QUESTION')
1557 def execute(self
, context
):
1558 # start_thumbnailer(self, context)
1561 def invoke(self
, context
, event
):
1562 wm
= context
.window_manager
1564 return wm
.invoke_props_dialog(self
)
1567 def draw_panel_categories(self
, context
):
1569 ui_props
= s
.blenderkitUI
1570 user_preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
1571 layout
= self
.layout
1572 # row = layout.row()
1573 # row.prop(ui_props, 'asset_type', expand=True, icon_only=True)
1576 layout
.label(text
='Categories')
1577 wm
= bpy
.context
.window_manager
1578 if wm
.get('bkit_categories') == None:
1580 col
= layout
.column(align
=True)
1581 if wm
.get('active_category') is not None:
1582 acat
= wm
['active_category'][ui_props
.asset_type
]
1584 # we are in subcategory, so draw the parent button
1585 op
= col
.operator('view3d.blenderkit_set_category', text
='...', icon
='FILE_PARENT')
1586 op
.asset_type
= ui_props
.asset_type
1588 cats
= categories
.get_category(wm
['bkit_categories'], cat_path
=acat
)
1589 # draw freebies only in models parent category
1590 # if ui_props.asset_type == 'MODEL' and len(acat) == 1:
1591 # op = col.operator('view3d.blenderkit_asset_bar', text='freebies')
1592 # op.free_only = True
1594 for c
in cats
['children']:
1595 if c
['assetCount'] > 0:
1596 row
= col
.row(align
=True)
1597 if len(c
['children']) > 0 and c
['assetCount'] > 15:
1598 row
= row
.split(factor
=.8, align
=True)
1599 # row = split.split()
1600 ctext
= '%s (%i)' % (c
['name'], c
['assetCount'])
1602 preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
1603 if preferences
.experimental_features
:
1604 op
= row
.operator('view3d.blenderkit_asset_bar_widget', text
=ctext
)
1606 op
= row
.operator('view3d.blenderkit_asset_bar', text
=ctext
)
1608 op
.keep_running
= True
1609 op
.category
= c
['slug']
1610 # TODO enable subcategories, now not working due to some bug on server probably
1611 if len(c
['children']) > 0 and c
['assetCount'] > 15:
1613 op
= row
.operator('view3d.blenderkit_set_category', text
='>>')
1614 op
.asset_type
= ui_props
.asset_type
1615 op
.category
= c
['slug']
1616 # for c1 in c['children']:
1617 # if c1['assetCount']>0:
1619 # split = row.split(percentage=.2)
1620 # row = split.split()
1621 # row = split.split()
1622 # ctext = '%s (%i)' % (c1['name'], c1['assetCount'])
1623 # op = row.operator('view3d.blenderkit_search', text=ctext)
1624 # op.category = c1['slug']
1627 class VIEW3D_PT_blenderkit_downloads(Panel
):
1628 bl_category
= "BlenderKit"
1629 bl_idname
= "VIEW3D_PT_blenderkit_downloads"
1630 bl_space_type
= 'VIEW_3D'
1631 bl_region_type
= 'UI'
1632 bl_label
= "Downloads"
1635 def poll(cls
, context
):
1636 return len(download
.download_threads
) > 0
1638 def draw(self
, context
):
1639 layout
= self
.layout
1640 for i
, threaddata
in enumerate(download
.download_threads
):
1641 tcom
= threaddata
[2]
1642 asset_data
= threaddata
[1]
1644 row
.label(text
=asset_data
['name'])
1645 row
.label(text
=str(int(tcom
.progress
)) + ' %')
1646 op
= row
.operator('scene.blenderkit_download_kill', text
='', icon
='CANCEL')
1648 if tcom
.passargs
.get('retry_counter', 0) > 0:
1650 row
.label(text
='failed. retrying ... ', icon
='ERROR')
1651 row
.label(text
=str(tcom
.passargs
["retry_counter"]))
1656 def header_search_draw(self
, context
):
1657 '''Top bar menu in 3D view'''
1659 if not utils
.guard_from_crash():
1662 preferences
= bpy
.context
.preferences
.addons
['blenderkit'].preferences
1663 if preferences
.search_in_header
:
1664 layout
= self
.layout
1665 s
= bpy
.context
.scene
1666 ui_props
= s
.blenderkitUI
1667 if ui_props
.asset_type
== 'MODEL':
1668 props
= s
.blenderkit_models
1669 if ui_props
.asset_type
== 'MATERIAL':
1670 props
= s
.blenderkit_mat
1671 if ui_props
.asset_type
== 'BRUSH':
1672 props
= s
.blenderkit_brush
1673 if ui_props
.asset_type
== 'HDR':
1674 props
= s
.blenderkit_HDR
1675 if ui_props
.asset_type
== 'SCENE':
1676 props
= s
.blenderkit_scene
1678 # the center snap menu is in edit and object mode if tool settings are off.
1679 if context
.space_data
.show_region_tool_header
== True or context
.mode
[:4] not in ('EDIT', 'OBJE'):
1680 layout
.separator_spacer()
1681 layout
.prop(ui_props
, "asset_type", expand
= True, icon_only
= True, text
='', icon
='URL')
1682 layout
.prop(props
, "search_keywords", text
="", icon
='VIEWZOOM')
1683 draw_assetbar_show_hide(layout
, props
)
1686 # We can store multiple preview collections here,
1687 # however in this example we only store "main"
1688 preview_collections
= {}
1691 SetCategoryOperator
,
1692 VIEW3D_PT_blenderkit_profile
,
1693 VIEW3D_PT_blenderkit_login
,
1694 VIEW3D_PT_blenderkit_unified
,
1695 VIEW3D_PT_blenderkit_advanced_model_search
,
1696 VIEW3D_PT_blenderkit_advanced_material_search
,
1697 VIEW3D_PT_blenderkit_categories
,
1698 VIEW3D_PT_blenderkit_import_settings
,
1699 VIEW3D_PT_blenderkit_model_properties
,
1700 NODE_PT_blenderkit_material_properties
,
1701 # VIEW3D_PT_blenderkit_ratings,
1702 VIEW3D_PT_blenderkit_downloads
,
1703 # OBJECT_MT_blenderkit_resolution_menu,
1704 OBJECT_MT_blenderkit_asset_menu
,
1705 OBJECT_MT_blenderkit_login_menu
,
1708 BlenderKitWelcomeOperator
,
1712 def register_ui_panels():
1714 bpy
.utils
.register_class(c
)
1715 bpy
.types
.VIEW3D_MT_editor_menus
.append(header_search_draw
)
1718 def unregister_ui_panels():
1719 bpy
.types
.VIEW3D_MT_editor_menus
.remove(header_search_draw
)
1721 # print('unregister', c)
1722 bpy
.utils
.unregister_class(c
)