BlenderKit:

-icons module
-clipboard monitoring
-fix link to website when people want to see asset online
-advanced search parameters
This commit is contained in:
Vilém Duha 2020-01-24 19:43:06 +01:00
parent 7c3d8127da
commit 7410d631ce
9 changed files with 288 additions and 145 deletions

View File

@ -39,6 +39,7 @@ if "bpy" in locals():
ratings = reload(ratings)
autothumb = reload(autothumb)
ui = reload(ui)
icons = reload(icons)
bg_blender = reload(bg_blender)
paths = reload(paths)
utils = reload(utils)
@ -48,7 +49,8 @@ if "bpy" in locals():
bkit_oauth = reload(bkit_oauth)
tasks_queue = reload(tasks_queue)
else:
from blenderkit import asset_inspector, search, download, upload, ratings, autothumb, ui, bg_blender, paths, utils, \
from blenderkit import asset_inspector, search, download, upload, ratings, autothumb, ui, icons, bg_blender, paths, \
utils, \
overrides, ui_panels, categories, bkit_oauth, tasks_queue
import os
@ -91,6 +93,7 @@ def scene_load(context):
preferences = bpy.context.preferences.addons['blenderkit'].preferences
preferences.login_attempt = False
def check_timers_timer():
''' checks if all timers are registered regularly. Prevents possible bugs from stopping the addon.'''
if not bpy.app.timers.is_registered(search.timer_update):
@ -103,6 +106,7 @@ def check_timers_timer():
bpy.app.timers.register(bg_blender.bg_update)
return 5.0
licenses = (
('royalty_free', 'Royalty Free', 'royalty free commercial license'),
('cc_zero', 'Creative Commons Zero', 'Creative Commons Zero'),
@ -191,6 +195,7 @@ thumbnail_resolutions = (
('2048', '2048', ''),
)
def get_upload_asset_type(self):
typemapper = {
BlenderKitModelUploadProps: 'model',
@ -244,9 +249,10 @@ def switch_search_results(self, context):
s['search results orig'] = s.get('bkit brush search orig')
search.load_previews()
def asset_type_callback(self, context):
#s = bpy.context.scene
#ui_props = s.blenderkitUI
# s = bpy.context.scene
# ui_props = s.blenderkitUI
if self.down_up == 'SEARCH':
items = (
('MODEL', 'Find Models', 'Find models in the BlenderKit online database', 'OBJECT_DATAMODE', 0),
@ -265,6 +271,7 @@ def asset_type_callback(self, context):
)
return items
class BlenderKitUIProps(PropertyGroup):
down_up: EnumProperty(
name="Download vs Upload",
@ -387,13 +394,35 @@ class BlenderKitCommonSearchProps(object):
search_done: BoolProperty(name="Search Completed", description="at least one search did run (internal)",
default=False)
own_only: BoolProperty(name="My Assets", description="Search only for your assets",
default=False)
default=False)
search_error: BoolProperty(name="Search Error", description="last search had an error", default=False)
report: StringProperty(
name="Report",
description="errors and messages",
default="")
# TEXTURE RESOLUTION
search_texture_resolution: BoolProperty(name="Texture Resolution",
description="Span of the texture resolutions",
default=False,
update=search.search_update,
)
search_texture_resolution_min: IntProperty(name="Min Texture Resolution",
description="Minimum texture resolution",
default=256,
min=0,
max=32768,
update=search.search_update,
)
search_texture_resolution_max: IntProperty(name="Max Texture Resolution",
description="Maximum texture resolution",
default=4096,
min=0,
max=32768,
update=search.search_update,
)
def name_update(self, context):
''' checks for name change, because it decides if whole asset has to be re-uploaded. Name is stored in the blend file
@ -401,7 +430,6 @@ def name_update(self, context):
utils.name_update()
def update_tags(self, context):
props = utils.get_upload_props()
@ -426,6 +454,7 @@ def update_tags(self, context):
if props.tags != ns:
props.tags = ns
def update_free(self, context):
if self.is_free == False:
self.is_free = True
@ -440,6 +469,7 @@ def update_free(self, context):
bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO')
class BlenderKitCommonUploadProps(object):
id: StringProperty(
name="Asset Version Id",
@ -506,9 +536,9 @@ class BlenderKitCommonUploadProps(object):
)
is_procedural: BoolProperty(name="Procedural",
description="Asset is procedural - has no texture.",
default=True
)
description="Asset is procedural - has no texture.",
default=True
)
node_count: IntProperty(name="Node count", description="Total nodes in the asset", default=0)
texture_count: IntProperty(name="Texture count", description="Total texture count in asset", default=0)
total_megapixels: IntProperty(name="Megapixels", description="Total megapixels of texture", default=0)
@ -593,22 +623,26 @@ class BlenderKitMaterialSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
items=search_material_styles,
description="Style of material",
default="ANY",
update=search.search_update,
)
search_style_other: StringProperty(
name="Style Other",
description="Style not in the list",
default="",
update=search.search_update,
)
search_engine: EnumProperty(
name='Engine',
items=engines,
default='NONE',
description='Output engine',
update=search.search_update,
)
search_engine_other: StringProperty(
name="Engine",
description="engine not specified by addon",
default="",
update=search.search_update,
)
automap: BoolProperty(name="Auto-Map",
description="reset object texture space and also add automatically a cube mapped UV "
@ -1147,10 +1181,10 @@ class BlenderKitModelSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
)
free_only: BoolProperty(name="Free only", description="Show only free models",
default=False)
default=False,update=search.search_update)
search_advanced: BoolProperty(name="Advanced Search Options", description="use advanced search properties",
default=False)
default=False,update=search.search_update)
# CONDITION
search_condition: EnumProperty(
@ -1169,9 +1203,9 @@ class BlenderKitModelSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
search_procedural: EnumProperty(
items=(
('BOTH', 'Both',''),
('PROCEDURAL', 'Procedural',''),
('TEXTURE_BASED', 'Texture based',''),
('BOTH', 'Both', ''),
('PROCEDURAL', 'Procedural', ''),
('TEXTURE_BASED', 'Texture based', ''),
),
default='BOTH',
@ -1182,51 +1216,47 @@ class BlenderKitModelSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
# DESIGN YEAR
search_design_year: BoolProperty(name="Sesigned in Year",
description="when the object was approximately designed",
default=False)
default=False,
update=search.search_update,
)
search_design_year_min: IntProperty(name="Min Age",
description="when the object was approximately designed",
default=1950, min=-100000000, max=1000000000)
default=1950, min=-100000000, max=1000000000,
update=search.search_update,
)
search_design_year_max: IntProperty(name="Max Age",
description="when the object was approximately designed",
default=2017,
min=0,
max=10000000)
max=10000000,
update=search.search_update,
)
# TEXTURE RESOLUTION
search_texture_resolution: BoolProperty(name="Texture Resolution",
description="Span of the texture resolutions",
default=False)
search_texture_resolution_min: IntProperty(name="Min Texture Resolution",
description="when the object was approximately designed",
default=256,
min=0,
max=32768)
search_texture_resolution_max: IntProperty(name="Max Texture Resolution",
description="when the object was approximately designed",
default=4096,
min=0,
max=32768)
# POLYCOUNT
search_polycount: BoolProperty(name="Use Polycount",
description="use polycount of object search tag",
default=False)
default=False,
update=search.search_update,)
search_polycount_min: IntProperty(name="Min Polycount",
description="polycount of the asset minimum",
default=0,
min=0,
max=100000000)
max=100000000,
update=search.search_update,)
search_polycount_max: IntProperty(name="Max Polycount",
description="polycount of the asset maximum",
default=100000000,
min=0,
max=100000000)
max=100000000,
update=search.search_update,
)
append_method: EnumProperty(
name="Import Method",
@ -1313,6 +1343,7 @@ class BlenderKitSceneSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
)
class BlenderKitAddonPreferences(AddonPreferences):
# this must match the addon name, use '__package__'
# when defining this in a submodule of a python package.
@ -1338,9 +1369,9 @@ class BlenderKitAddonPreferences(AddonPreferences):
)
api_key_timeout: IntProperty(
name = 'api key timeout',
description = 'time where the api key will need to be refreshed',
default = 0,
name='api key timeout',
description='time where the api key will need to be refreshed',
default=0,
)
api_key_life: IntProperty(
@ -1370,7 +1401,7 @@ class BlenderKitAddonPreferences(AddonPreferences):
tips_on_start: BoolProperty(
name="Show tips when starting blender",
description="Show tips when starting blender",
default=True
default=False
)
search_in_header: BoolProperty(
@ -1439,10 +1470,8 @@ class BlenderKitAddonPreferences(AddonPreferences):
min=0,
max=20)
thumb_size: IntProperty(name="Assetbar thumbnail Size", default=96, min=-1, max=256)
asset_counter: IntProperty(name="Usage Counter",
description="Counts usages so it asks for registration only after reaching a limit",
default=0,
@ -1473,7 +1502,7 @@ class BlenderKitAddonPreferences(AddonPreferences):
layout.operator("wm.blenderkit_logout", text="Logout",
icon='URL')
#if not self.enable_oauth:
# if not self.enable_oauth:
layout.prop(self, "api_key", text='Your API Key')
# layout.label(text='After you paste API Key, categories are downloaded, so blender will freeze for a few seconds.')
layout.prop(self, "global_dir")
@ -1489,7 +1518,6 @@ class BlenderKitAddonPreferences(AddonPreferences):
layout.prop(self, "search_in_header")
# registration
classes = (
@ -1560,6 +1588,7 @@ def register():
ratings.register_ratings()
autothumb.register_thumbnailer()
ui.register_ui()
icons.register_icons()
ui_panels.register_ui_panels()
bg_blender.register()
utils.load_prefs()
@ -1573,10 +1602,10 @@ def register():
def unregister():
bpy.app.timers.unregister(check_timers_timer)
ui.unregister_ui()
icons.unregister_icons()
search.unregister_search()
asset_inspector.unregister_asset_inspector()
download.unregister_download()

53
blenderkit/icons.py Normal file
View File

@ -0,0 +1,53 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import os
import bpy
# We can store multiple preview collections here,
# however in this example we only store "main"
icon_collections = {}
icons_read = {
'fp.png': 'free',
'flp.png': 'full',
}
def register_icons():
# Note that preview collections returned by bpy.utils.previews
# are regular py objects - you can use them to store custom data.
import bpy.utils.previews
pcoll = bpy.utils.previews.new()
# path to the folder where the icon is
# the path is calculated relative to this py file inside the addon folder
icons_dir = os.path.join(os.path.dirname(__file__), "thumbnails")
# load a preview thumbnail of a file and store in the previews collection
for ir in icons_read.keys():
pcoll.load(icons_read[ir], os.path.join(icons_dir, ir), 'IMAGE')
icon_collections["main"] = pcoll
def unregister_icons():
for pcoll in icon_collections.values():
bpy.utils.previews.remove(pcoll)
icon_collections.clear()

View File

@ -33,7 +33,6 @@ BLENDERKIT_BRUSH_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uplo
BLENDERKIT_LOGIN_URL = "https://www.blenderkit.com/accounts/login"
BLENDERKIT_OAUTH_LANDING_URL = "/oauth-landing/"
BLENDERKIT_SIGNUP_URL = "https://www.blenderkit.com/accounts/register"
BLENDERKIT_ADDON_FILE_URL = "https://www.blenderkit.com/get-blenderkit/"
BLENDERKIT_SETTINGS_FILENAME = os.path.join(_presets, "bkit.json")

View File

@ -154,7 +154,7 @@ asset_types = (
class UploadRatingOperator(bpy.types.Operator):
"""Upload rating to the web db"""
bl_idname = "object.blenderkit_rating_upload"
bl_label = "Upload the Rating"
bl_label = "Send Rating"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
# type of upload - model, material, textures, e.t.c.

View File

@ -86,10 +86,11 @@ rtips = ['Click or drag model or material in scene to link/append ',
"Please rate responsively and plentifully. This helps us distribute rewards to the authors.",
"Click on brushes to link them into scene.",
"All materials and brushes are free.",
"Storage for public assets is unlimited.",
"Locked models are available if you subscribe to Full plan.",
"Login to upload your own models, materials or brushes.",
"Use 'A' key to search assets by same author.",
"Use 'W' key to open Authors webpage.", ]
"Use 'A' key over asset bar to search assets by same author.",
"Use 'W' key over asset bar to open Authors webpage.", ]
def refresh_token_timer():
''' this timer gets run every time the token needs refresh. It refreshes tokens and also categories.'''
@ -127,7 +128,7 @@ def fetch_server_data():
first_time = True
last_clipboard = ''
@bpy.app.handlers.persistent
def timer_update(): # TODO might get moved to handle all blenderkit stuff.
#this makes a first search after opening blender. showing latest assets.
@ -142,6 +143,22 @@ def timer_update(): # TODO might get moved to handle all blenderkit stuff.
ui.update_ui_size(ui.active_area, ui.active_region)
ui.add_report(text='BlenderKit Tip:' + random.choice(rtips), timeout=12, color=colors.GREEN)
# clipboard monitoring to search assets from web
global last_clipboard
if bpy.context.window_manager.clipboard != last_clipboard:
last_clipboard = bpy.context.window_manager.clipboard
instr = 'asset_base_id:'
if last_clipboard[:len(instr)] == instr:
atstr = 'asset_type:'
ati = last_clipboard.find(atstr)
if ati>-1:
at = last_clipboard[ati:]
search_props = utils.get_search_props()
search_props.search_keywords = last_clipboard
search()
global search_threads
# don't do anything while dragging - this could switch asset type during drag, and make results list length different,
# causing a lot of throuble literally.
@ -700,6 +717,9 @@ def profile_is_validator():
return True
return False
class Searcher(threading.Thread):
query = None
@ -715,6 +735,43 @@ class Searcher(threading.Thread):
def stopped(self):
return self._stop_event.is_set()
def query_to_url(self):
query = self.query
params = self.params
# build a new request
url = paths.get_api_url() + 'search/'
# build request manually
# TODO use real queries
requeststring = '?query='
#
if query.get('query') not in ('', None):
requeststring += query['query'].lower()
for i, q in enumerate(query):
if q != 'query':
requeststring += '+'
requeststring += q + ':' + str(query[q]).lower()
# result ordering: _score - relevance, score - BlenderKit score
# first condition assumes no keywords and no category, thus an empty search that is triggered on start.
if query.get('query') is None and query.get('category_subtree') == None:
requeststring += '+order:-created'
elif query.get('author_id') is not None and profile_is_validator():
requeststring += '+order:-created'
else:
if query.get('category_subtree') is not None:
requeststring += '+order:-score,_score'
else:
requeststring += '+order:_score'
requeststring += '&addon_version=%s' % params['addon_version']
if params.get('scene_uuid') is not None:
requeststring += '&scene_uuid=%s' % params['scene_uuid']
print('params', params)
urlquery = url + requeststring
return urlquery
def run(self):
maxthreads = 50
query = self.query
@ -736,45 +793,23 @@ class Searcher(threading.Thread):
try:
origdata = json.load(infile)
urlquery = origdata['next']
#rparameters = {}
if urlquery == None:
return;
except:
# in case no search results found on drive we don't do next page loading.
params['get_next'] = False
if not params['get_next']:
# build a new request
url = paths.get_api_url() + 'search/'
# build request manually
# TODO use real queries
requeststring = '?query=' + query['keywords'].lower() + '+'
#
for i, q in enumerate(query):
if q != 'keywords':
requeststring += q + ':' + str(query[q]).lower()
if i < len(query) - 1:
requeststring += '+'
urlquery = url
# result ordering: _score - relevance, score - BlenderKit score
#first condition assumes no keywords and no category, thus an empty search that is triggered on start.
if query['keywords'] == '' and query.get('category_subtree') == None:
requeststring += '+order:-created'
elif query.get('author_id') is not None and profile_is_validator():
requeststring += '+order:-created'
else:
if query.get('category_subtree') is not None:
requeststring += '+order:-score,_score'
else:
requeststring += '+order:_score'
requeststring += '&addon_version=%s' % params['addon_version']
if params.get('scene_uuid') is not None:
requeststring += '&scene_uuid=%s' % params['scene_uuid']
urlquery = url + requeststring
#rparameters = query
urlquery = self.query_to_url()
try:
utils.p(urlquery)
r = rerequests.get(urlquery, headers=headers)
r = rerequests.get(urlquery, headers=headers)#, params = rparameters)
print(r.url)
reports = ''
# utils.p(r.text)
except requests.exceptions.RequestException as e:
@ -808,7 +843,7 @@ class Searcher(threading.Thread):
# print('number of results: ', len(rdata.get('results', [])))
if self.stopped():
utils.p('stopping search : ' + query['keywords'])
utils.p('stopping search : ' + str(query))
return
mt('search finished')
@ -867,7 +902,7 @@ class Searcher(threading.Thread):
# TODO do the killing/ stopping here! remember threads might have finished inbetween!
if self.stopped():
utils.p('stopping search : ' + query['keywords'])
utils.p('stopping search : ' + str(query))
return
# this loop handles downloading of small thumbnails
@ -891,7 +926,7 @@ class Searcher(threading.Thread):
# utils.p('fetched thumbnail ', i)
i += 1
if self.stopped():
utils.p('stopping search : ' + query['keywords'])
utils.p('stopping search : ' + str(query))
return
idx = 0
while len(thumb_sml_download_threads) > 0:
@ -903,7 +938,7 @@ class Searcher(threading.Thread):
i += 1
if self.stopped():
utils.p('stopping search : ' + query['keywords'])
utils.p('stopping search : ' + str(query))
return
# start downloading full thumbs in the end
@ -918,10 +953,11 @@ class Searcher(threading.Thread):
def build_query_common(query, props):
query_common = {
"keywords": props.search_keywords
}
query.update(query_common)
if props.search_keywords != '':
query_common = {
"query": props.search_keywords
}
query.update(query_common)
# def query_add_range(query, name, rmin, rmax):
@ -948,19 +984,19 @@ def build_query_model():
if props.search_condition != 'UNSPECIFIED':
query["condition"] = props.search_condition
if props.search_design_year:
query["designYearMin"] = props.search_design_year_min
query["designYearMax"] = props.search_design_year_max
query["designYear_gte"] = props.search_design_year_min
query["designYear_lte"] = props.search_design_year_max
if props.search_polycount:
query["polyCountMin"] = props.search_polycount_min
query["polyCountMax"] = props.search_polycount_max
query["faceCount_gte"] = props.search_polycount_min
query["faceCount_lte"] = props.search_polycount_max
if props.search_texture_resolution:
query["textureResolutionMin"] = props.search_texture_resolution_min
query["textureResolutionMax"] = props.search_texture_resolution_max
query["textureResolutionMax_gte"] = props.search_texture_resolution_min
query["textureResolutionMax_lte"] = props.search_texture_resolution_max
if props.search_procedural == "PROCEDURAL":
query["procedural"] = True
elif props.search_procedural == 'TEXTURE_BASED':
query["procedural"] = False
if props.search_procedural == "PROCEDURAL":
query["procedural"] = True
elif props.search_procedural == 'TEXTURE_BASED':
query["procedural"] = False
build_query_common(query, props)
@ -997,6 +1033,11 @@ def build_query_material():
query["style"] = props.search_style
else:
query["style"] = props.search_style_other
if props.search_texture_resolution:
query["textureResolutionMax_gte"] = props.search_texture_resolution_min
query["textureResolutionMax_lte"] = props.search_texture_resolution_max
build_query_common(query, props)
return query

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

View File

@ -1428,7 +1428,6 @@ class AssetBarOperator(bpy.types.Operator):
ui_props.draw_tooltip = True
ui_props.tooltip = asset_data['tooltip']
# bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
else:
@ -1490,7 +1489,7 @@ class AssetBarOperator(bpy.types.Operator):
if not asset_data['can_download']:
message = 'Asset locked. Find out how to unlock Everything and ...'
link_text = 'support all BlenderKit artists.'
url = paths.get_bkit_url() + '/get-blenderkit/' + asset_data['id']
url = paths.get_bkit_url() + '/get-blenderkit/' + asset_data['id'] + '/?from_addon'
bpy.ops.wm.blenderkit_url_dialog('INVOKE_REGION_WIN', url=url, message=message,
link_text=link_text)
return {'RUNNING_MODAL'}

View File

@ -24,8 +24,9 @@ if "bpy" in locals():
utils = importlib.reload(utils)
download = importlib.reload(download)
categories = importlib.reload(categories)
icons = importlib.reload(icons)
else:
from blenderkit import paths, ratings, utils, download, categories
from blenderkit import paths, ratings, utils, download, categories, icons
from bpy.types import (
Panel
@ -75,10 +76,10 @@ def draw_ratings(layout, context):
layout.prop(bkit_ratings, 'rating_work_hours')
w = context.region.width
layout.label(text='problems')
layout.prop(bkit_ratings, 'rating_problems', text='')
layout.label(text='compliments')
layout.prop(bkit_ratings, 'rating_compliments', text='')
# layout.label(text='problems')
# layout.prop(bkit_ratings, 'rating_problems', text='')
# layout.label(text='compliments')
# layout.prop(bkit_ratings, 'rating_compliments', text='')
row = layout.row()
op = row.operator("object.blenderkit_rating_upload", text="Send rating", icon='URL')
@ -151,7 +152,7 @@ def prop_needed(layout, props, name, value, is_not_filled=''):
# row.label(text='', icon = 'ERROR')
icon = 'ERROR'
row.alert = True
row.prop(props, name)#, icon=icon)
row.prop(props, name) # , icon=icon)
row.alert = False
else:
# row.label(text='', icon = 'FILE_TICK')
@ -264,6 +265,7 @@ def draw_panel_scene_upload(self, context):
row.prop(props, 'work_hours')
layout.prop(props, 'adult')
def draw_assetbar_show_hide(layout, props):
s = bpy.context.scene
ui_props = s.blenderkitUI
@ -301,7 +303,7 @@ def draw_panel_model_search(self, context):
layout.prop(props, "search_style")
layout.prop(props, "own_only")
layout.prop(props, "free_only")
#layout.prop(props, "search_procedural", expand = True)
# layout.prop(props, "search_procedural", expand = True)
# if props.search_style == 'OTHER':
# layout.prop(props, "search_style_other")
# layout.prop(props, "search_engine")
@ -309,7 +311,7 @@ def draw_panel_model_search(self, context):
# layout.prop(props, 'append_link', expand=True, icon_only=False)
# layout.prop(props, 'import_as', expand=True, icon_only=False)
# layout.prop(props, "search_advanced")
layout.prop(props, "search_advanced")
if props.search_advanced:
layout.separator()
@ -320,34 +322,31 @@ def draw_panel_model_search(self, context):
# layout.prop(props, "search_engine_keyword")
# AGE
layout.prop(props, "search_condition") # , text ='condition of object new/old e.t.c.')
layout.prop(props, "search_condition", text = 'Condition') # , text ='condition of object new/old e.t.c.')
# DESIGN YEAR
layout.prop(props, "search_design_year", text='designed in ( min - max )')
row = layout.row(align=True)
if not props.search_design_year_min:
row.active = False
row.prop(props, "search_design_year_min", text='min')
row.prop(props, "search_design_year_max", text='max')
if props.search_design_year:
row = layout.row(align=True)
row.prop(props, "search_design_year_min", text='min')
row.prop(props, "search_design_year_max", text='max')
# POLYCOUNT
layout.prop(props, "search_polycount", text='polycount in ( min - max )')
row = layout.row(align=True)
if not props.search_polycount:
row.active = False
row.prop(props, "search_polycount_min", text='min')
row.prop(props, "search_polycount_max", text='max')
layout.prop(props, "search_polycount", text='Poly count in ( min - max )')
if props.search_polycount:
row = layout.row(align=True)
row.prop(props, "search_polycount_min", text='min')
row.prop(props, "search_polycount_max", text='max')
# TEXTURE RESOLUTION
layout.prop(props, "search_texture_resolution", text='texture resolution ( min - max )')
row = layout.row(align=True)
if not props.search_texture_resolution:
row.active = False
row.prop(props, "search_texture_resolution_min", text='min')
row.prop(props, "search_texture_resolution_max", text='max')
if props.search_texture_resolution:
row = layout.row(align=True)
row.prop(props, "search_texture_resolution_min", text='min')
row.prop(props, "search_texture_resolution_max", text='max')
# ADULT
layout.prop(props, "search_adult") # , text ='condition of object new/old e.t.c.')
#layout.prop(props, "search_adult") # , text ='condition of object new/old e.t.c.')
draw_panel_categories(self, context)
@ -403,6 +402,8 @@ class VIEW3D_PT_blenderkit_model_properties(Panel):
if o.instance_type == 'COLLECTION' and o.instance_collection is not None:
layout.operator('object.blenderkit_bring_to_scene', text='Bring to scene')
draw_panel_model_rating(self, context)
# if 'rig' in ad['tags']:
# # layout.label(text = 'can make proxy')
# layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy')
@ -442,19 +443,31 @@ class VIEW3D_PT_blenderkit_profile(Panel):
draw_login_progress(layout)
return
if user_preferences.api_key != '':
me = bpy.context.window_manager.get('bkit profile')
if me is not None:
me = me['user']
layout.label(text='User: %s %s' % (me['firstName'], me['lastName']))
layout.label(text='Email: %s' % (me['email']))
if me.get('sumAssetFilesSize') is not None: # TODO remove this when production server has these too.
layout.label(text='Public assets: %i MiB' % (me['sumAssetFilesSize']))
if me.get('sumPrivateAssetFilesSize') is not None:
layout.label(text='Private assets: %i MiB' % (me['sumPrivateAssetFilesSize']))
#user name
layout.label(text='Me: %s %s' % (me['firstName'], me['lastName']))
# layout.label(text='Email: %s' % (me['email']))
# plan information
# pcoll = icons.icon_collections["main"]
# my_icon = pcoll['free']
# row = layout.row()
# row.label(text='My plan:')
# row.label(text='Free plan', icon_value=my_icon.icon_id)
# layout.operator("wm.url_open", text="Change plan",
# icon='URL').url = paths.get_bkit_url() + paths.BLENDERKIT_PLANS
#storage statistics
# if me.get('sumAssetFilesSize') is not None: # TODO remove this when production server has these too.
# layout.label(text='My public assets: %i MiB' % (me['sumAssetFilesSize']))
# if me.get('sumPrivateAssetFilesSize') is not None:
# layout.label(text='My private assets: %i MiB' % (me['sumPrivateAssetFilesSize']))
if me.get('remainingPrivateQuota') is not None:
layout.label(text='Remaining private storage: %i MiB' % (me['remainingPrivateQuota']))
layout.label(text='My free storage: %i MiB' % (me['remainingPrivateQuota']))
layout.operator("wm.url_open", text="See my uploads",
icon='URL').url = paths.get_bkit_url() + paths.BLENDERKIT_USER_ASSETS
@ -482,6 +495,7 @@ class VIEW3D_PT_blenderkit_login(Panel):
if user_preferences.enable_oauth:
draw_login_buttons(layout)
def draw_panel_model_rating(self, context):
o = bpy.context.active_object
op = draw_ratings(self.layout, context) # , props)
@ -558,10 +572,18 @@ def draw_panel_material_search(self, context):
# if props.search_engine == 'OTHER':
# layout.prop(props, 'search_engine_other')
layout.prop(props, 'automap')
# TEXTURE RESOLUTION
layout.prop(props, "search_texture_resolution", text='texture resolution ( min - max )')
if props.search_texture_resolution:
row = layout.row(align=True)
row.prop(props, "search_texture_resolution_min", text='min')
row.prop(props, "search_texture_resolution_max", text='max')
draw_panel_categories(self, context)
layout.prop(props, 'automap')
def draw_panel_material_ratings(self, context):
op = draw_ratings(self.layout, context) # , props)
@ -644,19 +666,19 @@ class VIEW3D_PT_blenderkit_unified(Panel):
# layout.prop_tabs_enum(ui_props, "asset_type", icon_only = True)
row = layout.row()
#row.scale_x = 1.6
#row.scale_y = 1.6
# row.scale_x = 1.6
# row.scale_y = 1.6
#
row.prop(ui_props, 'down_up', expand=True, icon_only=False)
# row.label(text='')
#row = row.split().row()
#layout.alert = True
#layout.alignment = 'CENTER'
#row = layout.row(align = True)
#split = row.split(factor=.5)
#row.prop(ui_props, 'asset_type', expand=True, icon_only=True)
#row = layout.column(align = False)
layout.prop(ui_props, 'asset_type', expand=False, text = '')
# row = row.split().row()
# layout.alert = True
# layout.alignment = 'CENTER'
# row = layout.row(align = True)
# split = row.split(factor=.5)
# row.prop(ui_props, 'asset_type', expand=True, icon_only=True)
# row = layout.column(align = False)
layout.prop(ui_props, 'asset_type', expand=False, text='')
w = context.region.width
if user_preferences.login_attempt:
@ -766,7 +788,6 @@ class VIEW3D_PT_blenderkit_unified(Panel):
layout.label(text='not yet implemented')
class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu):
bl_label = "Asset options:"
bl_idname = "OBJECT_MT_blenderkit_asset_menu"
@ -907,7 +928,7 @@ class UrlPopupDialog(bpy.types.Operator):
op.url = self.url
def execute(self, context):
#start_thumbnailer(self, context)
# start_thumbnailer(self, context)
return {'FINISHED'}
def invoke(self, context, event):
@ -1014,8 +1035,9 @@ def header_search_draw(self, context):
if ui_props.asset_type == 'BRUSH':
props = s.blenderkit_brush
if context.space_data.show_region_tool_header == True:
layout.separator_spacer()
# the center snap menu is in edit and object mode if tool settings are off.
if context.space_data.show_region_tool_header == True or context.mode[:4] not in ('EDIT', 'OBJE'):
layout.separator_spacer()
layout.prop(ui_props, "asset_type", text='', icon='URL')
layout.prop(props, "search_keywords", text="", icon='VIEWZOOM')
draw_assetbar_show_hide(layout, props)
@ -1046,4 +1068,4 @@ def register_ui_panels():
def unregister_ui_panels():
for c in classess:
bpy.utils.unregister_class(c)
bpy.types.VIEW3D_MT_editor_menus.remove(header_search_draw)
bpy.types.VIEW3D_MT_editor_menus.remove(header_search_draw)