From 7410d631ce4ac4f3e53c1d634eb6b70499398371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vil=C3=A9m=20Duha?= Date: Fri, 24 Jan 2020 19:43:06 +0100 Subject: BlenderKit: -icons module -clipboard monitoring -fix link to website when people want to see asset online -advanced search parameters --- blenderkit/__init__.py | 113 +++++++++++++++++++++------------- blenderkit/icons.py | 53 ++++++++++++++++ blenderkit/paths.py | 1 - blenderkit/ratings.py | 2 +- blenderkit/search.py | 139 +++++++++++++++++++++++++++--------------- blenderkit/thumbnails/flp.png | Bin 0 -> 540 bytes blenderkit/thumbnails/fp.png | Bin 0 -> 561 bytes blenderkit/ui.py | 3 +- blenderkit/ui_panels.py | 122 +++++++++++++++++++++--------------- 9 files changed, 288 insertions(+), 145 deletions(-) create mode 100644 blenderkit/icons.py create mode 100644 blenderkit/thumbnails/flp.png create mode 100644 blenderkit/thumbnails/fp.png (limited to 'blenderkit') diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index f8b31fec..fc2599a2 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -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() diff --git a/blenderkit/icons.py b/blenderkit/icons.py new file mode 100644 index 00000000..3c6cea4b --- /dev/null +++ b/blenderkit/icons.py @@ -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() diff --git a/blenderkit/paths.py b/blenderkit/paths.py index 3b0f22f9..112e2465 100644 --- a/blenderkit/paths.py +++ b/blenderkit/paths.py @@ -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") diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py index 7684d017..fd6bb2e8 100644 --- a/blenderkit/ratings.py +++ b/blenderkit/ratings.py @@ -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. diff --git a/blenderkit/search.py b/blenderkit/search.py index 96c1e63e..fd92a87f 100644 --- a/blenderkit/search.py +++ b/blenderkit/search.py @@ -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 += '+' - - # 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' + urlquery = url - 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 diff --git a/blenderkit/thumbnails/flp.png b/blenderkit/thumbnails/flp.png new file mode 100644 index 00000000..7ac3c3d7 Binary files /dev/null and b/blenderkit/thumbnails/flp.png differ diff --git a/blenderkit/thumbnails/fp.png b/blenderkit/thumbnails/fp.png new file mode 100644 index 00000000..4e356ab1 Binary files /dev/null and b/blenderkit/thumbnails/fp.png differ diff --git a/blenderkit/ui.py b/blenderkit/ui.py index be4bd451..f4b64a1f 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -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'} diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index ede93587..50ea8e5d 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -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) \ No newline at end of file + bpy.types.VIEW3D_MT_editor_menus.remove(header_search_draw) -- cgit v1.2.3