diff options
author | Vilém Duha <vilda.novak@gmail.com> | 2020-07-12 19:07:45 +0300 |
---|---|---|
committer | Vilém Duha <vilda.novak@gmail.com> | 2020-07-12 19:07:58 +0300 |
commit | 054ee2f41734049c9ba1386d9ec9eb3e85fc2e3f (patch) | |
tree | c0ca21ef9335b368b9785df3c7b9a86fb4200164 | |
parent | 6f7c4230af8e404d9fa9687b80ee8e7f3f8eac1d (diff) |
BlenderKit: fix rating interaction
-disabled layout didn't work(thanks to another blender layout bug that I reported)
-replaced it with an enum, and also a popup that informs the user instead.
-rw-r--r-- | blenderkit/__init__.py | 76 | ||||
-rw-r--r-- | blenderkit/bkit_oauth.py | 21 | ||||
-rw-r--r-- | blenderkit/ratings.py | 98 | ||||
-rw-r--r-- | blenderkit/rerequests.py | 2 | ||||
-rw-r--r-- | blenderkit/search.py | 2 | ||||
-rw-r--r-- | blenderkit/ui_panels.py | 195 | ||||
-rw-r--r-- | blenderkit/upload.py | 2 | ||||
-rw-r--r-- | blenderkit/utils.py | 38 |
8 files changed, 311 insertions, 123 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index 15dcaffb..a7e148ea 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -93,6 +93,7 @@ def scene_load(context): preferences = bpy.context.preferences.addons['blenderkit'].preferences preferences.login_attempt = False + @bpy.app.handlers.persistent def check_timers_timer(): ''' checks if all timers are registered regularly. Prevents possible bugs from stopping the addon.''' @@ -249,17 +250,12 @@ def switch_search_results(self, context): s['search results orig'] = s.get('bkit brush search orig') search.load_previews() -#define these static -# asset_type_ui_items = ( -# ('MODEL', 'Models', 'Find upload models in the BlenderKit online database', 'OBJECT_DATAMODE',0), -# # ('SCENE', 'SCENE', 'Browse scenes', 'SCENE_DATA', 1), -# ('MATERIAL', 'Materials', 'Find or upload models in the BlenderKit online database', 'MATERIAL',2), -# # ('TEXTURE', 'Texture', 'Browse textures', 'TEXTURE', 3), -# ('BRUSH', 'Brushes', 'Find or upload models in the BlenderKit online database', 'BRUSH_DATA',3) -# ) - -#same as above, but dynamic. def asset_type_callback(self, context): + ''' + Returns + items for Enum property, depending on the down_up property - BlenderKit is either in search or in upload mode. + + ''' if self.down_up == 'SEARCH': items = ( ('MODEL', 'Models', 'Find models in the BlenderKit online database', 'OBJECT_DATAMODE', 0), @@ -533,7 +529,7 @@ def update_free(self, context): "Part of subscription is sent to artists based on usage by paying users." def draw_message(self, context): - ui_panels.label_multiline(self.layout, text=message, icon='NONE', width=-1) + utils.label_multiline(self.layout, text=message, icon='NONE', width=-1) bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO') @@ -654,6 +650,29 @@ class BlenderKitCommonUploadProps(object): ) +def stars_enum_callback(self, context): + items = [] + for a in range(0, 10): + if self.rating_quality < a+1: + icon = 'SOLO_OFF' + else: + icon = 'SOLO_ON' + # has to have something before the number in the value, otherwise fails on registration. + items.append((f'{a+1}', f'{a+1}', '', icon, a+1)) + return items + + +def update_quality(self, context): + user_preferences = bpy.context.preferences.addons['blenderkit'].preferences + if user_preferences.api_key == '': + # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.') + # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu') + # return + bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT', message = 'Please login/signup to rate assets. Clicking OK takes you to web login.') + self.rating_quality_ui = '0' + self.rating_quality = int(self.rating_quality_ui) + + class BlenderKitRatingProps(PropertyGroup): rating_quality: IntProperty(name="Quality", description="quality of the material", @@ -661,17 +680,25 @@ class BlenderKitRatingProps(PropertyGroup): min=-1, max=10, update=ratings.update_ratings_quality) + #the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily. + rating_quality_ui: EnumProperty(name='rating_quality_ui', + items=stars_enum_callback, + description='Rating stars 0 - 10', + default=None, + update=update_quality, + ) + rating_work_hours: FloatProperty(name="Work Hours", description="How many hours did this work take?", default=0.00, min=0.0, max=1000, update=ratings.update_ratings_work_hours ) - rating_complexity: IntProperty(name="Complexity", - description="Complexity is a number estimating how much work was spent on the asset.aaa", - default=0, min=0, max=10) - rating_virtual_price: FloatProperty(name="Virtual Price", - description="How much would you pay for this object if buing it?", - default=0, min=0, max=10000) + # rating_complexity: IntProperty(name="Complexity", + # description="Complexity is a number estimating how much work was spent on the asset.aaa", + # default=0, min=0, max=10) + # rating_virtual_price: FloatProperty(name="Virtual Price", + # description="How much would you pay for this object if buing it?", + # default=0, min=0, max=10000) rating_problems: StringProperty( name="Problems", description="Problems found/ why did you take points down - this will be available for the author" @@ -1400,14 +1427,15 @@ class BlenderKitSceneSearchProps(PropertyGroup, BlenderKitCommonSearchProps): update=search.search_update ) + def fix_subdir(self, context): '''Fixes project subdicrectory settings if people input invalid path.''' # pp = pathlib.PurePath(self.project_subdir) pp = self.project_subdir[:] - pp = pp.replace('\\','') - pp = pp.replace('/','') - pp = pp.replace(':','') + pp = pp.replace('\\', '') + pp = pp.replace('/', '') + pp = pp.replace(':', '') pp = '//' + pp if self.project_subdir != pp: self.project_subdir = pp @@ -1418,10 +1446,11 @@ def fix_subdir(self, context): "and uses it for storing assets." def draw_message(self, context): - ui_panels.label_multiline(self.layout, text=message, icon='NONE', width=400) + utils.label_multiline(self.layout, text=message, icon='NONE', width=400) bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO') + class BlenderKitAddonPreferences(AddonPreferences): # this must match the addon name, use '__package__' # when defining this in a submodule of a python package. @@ -1501,7 +1530,7 @@ class BlenderKitAddonPreferences(AddonPreferences): description="where data will be stored for individual projects", # subtype='DIR_PATH', default="//assets", - update = fix_subdir + update=fix_subdir ) directory_behaviour: EnumProperty( @@ -1566,10 +1595,11 @@ class BlenderKitAddonPreferences(AddonPreferences): use_timers: BoolProperty( name="Use timers", - description="Use timers for bkit", + description="Use timers for BlenderKit. Usefull for debugging since timers seem to be unstable.", default=True, update=utils.save_prefs ) + # allow_proximity : BoolProperty( # name="allow proximity data reports", # description="This sends anonymized proximity data \n \ diff --git a/blenderkit/bkit_oauth.py b/blenderkit/bkit_oauth.py index 0bf20d4a..ae90b215 100644 --- a/blenderkit/bkit_oauth.py +++ b/blenderkit/bkit_oauth.py @@ -26,8 +26,9 @@ if "bpy" in locals(): categories = reload(categories) oauth = reload(oauth) ui = reload(ui) + ui = reload(ui_panels) else: - from blenderkit import tasks_queue, utils, paths, search, categories, oauth, ui + from blenderkit import tasks_queue, utils, paths, search, categories, oauth, ui, ui_panels import bpy @@ -102,7 +103,7 @@ class RegisterLoginOnline(bpy.types.Operator): """Login online on BlenderKit webpage""" bl_idname = "wm.blenderkit_login" - bl_label = "BlenderKit login or signup" + bl_label = "BlenderKit login/signup" bl_options = {'REGISTER', 'UNDO'} signup: BoolProperty( @@ -112,16 +113,32 @@ class RegisterLoginOnline(bpy.types.Operator): options={'SKIP_SAVE'} ) + message: bpy.props.StringProperty( + name="Message", + description="", + default="You were logged out from BlenderKit. Clicking OK takes you to web login. ") + @classmethod def poll(cls, context): return True + def draw(self, context): + layout = self.layout + utils.label_multiline(layout, text=self.message) + def execute(self, context): preferences = bpy.context.preferences.addons['blenderkit'].preferences preferences.login_attempt = True login_thread(self.signup) return {'FINISHED'} + def invoke(self, context, event): + wm = bpy.context.window_manager + preferences = bpy.context.preferences.addons['blenderkit'].preferences + preferences.api_key_refresh = '' + preferences.api_key = '' + return wm.invoke_props_dialog(self) + class Logout(bpy.types.Operator): """Logout from BlenderKit immediately""" diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py index dbe8b8eb..48c34a61 100644 --- a/blenderkit/ratings.py +++ b/blenderkit/ratings.py @@ -78,6 +78,7 @@ def send_rating_to_thread_quality(url, ratings, headers): thread = threading.Thread(target=upload_rating_thread, args=(url, ratings, headers)) thread.start() + def send_rating_to_thread_work_hours(url, ratings, headers): '''Sens rating into thread rating, main purpose is for tasks_queue. One function per property to avoid lost data due to stashing.''' @@ -93,6 +94,7 @@ def upload_review_thread(url, reviews, headers): def get_rating(asset_id): + #this function isn't used anywhere,should probably get removed. user_preferences = bpy.context.preferences.addons['blenderkit'].preferences api_key = user_preferences.api_key headers = utils.get_headers(api_key) @@ -133,6 +135,7 @@ def update_ratings_work_hours(self, context): tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=1, only_last=True) + def upload_rating(asset): user_preferences = bpy.context.preferences.addons['blenderkit'].preferences api_key = user_preferences.api_key @@ -170,26 +173,43 @@ def upload_rating(asset): if bkit_ratings.rating_quality > 0.1 and bkit_ratings.rating_work_hours > 0.1: s['assets rated'][asset['asset_data']['assetBaseId']] = True - -class StarRatingOperator(bpy.types.Operator): - """Tooltip""" - bl_idname = "object.blenderkit_rating" - bl_label = "Rate the Asset Quality" - bl_options = {'REGISTER', 'INTERNAL'} - - property_name: StringProperty( - name="Rating Property", - description="Property that is rated", - default="", - ) - - rating: IntProperty(name="Rating", description="rating value", default=1, min=1, max=10) - - def execute(self, context): - asset = utils.get_active_asset() - props = asset.bkit_ratings - props.rating_quality = self.rating - return {'FINISHED'} +def get_assets_for_rating(): + ''' + gets assets from scene that could/should be rated by the user. + TODO this is only a draft. + + ''' + assets = [] + for ob in bpy.context.scene.objects: + if ob.get('asset_data'): + assets.append(ob) + for m in bpy.data.materials: + if m.get('asset_data'): + assets.append(m) + for b in bpy.data.brushes: + if b.get('asset_data'): + assets.append(b) + return assets + +# class StarRatingOperator(bpy.types.Operator): +# """Tooltip""" +# bl_idname = "object.blenderkit_rating" +# bl_label = "Rate the Asset Quality" +# bl_options = {'REGISTER', 'INTERNAL'} +# +# property_name: StringProperty( +# name="Rating Property", +# description="Property that is rated", +# default="", +# ) +# +# rating: IntProperty(name="Rating", description="rating value", default=1, min=1, max=10) +# +# def execute(self, context): +# asset = utils.get_active_asset() +# props = asset.bkit_ratings +# props.rating_quality = self.rating +# return {'FINISHED'} asset_types = ( @@ -234,29 +254,43 @@ class UploadRatingOperator(bpy.types.Operator): return wm.invoke_props_dialog(self) + def draw_rating(layout, props, prop_name, name): # layout.label(name) row = layout.row(align=True) - - for a in range(0, 10): - if eval('props.' + prop_name) < a + 1: - icon = 'SOLO_OFF' - else: - icon = 'SOLO_ON' - - op = row.operator('object.blenderkit_rating', icon=icon, emboss=False, text='') - op.property_name = prop_name - op.rating = a + 1 + # test method - 10 booleans. + # propsx = bpy.context.active_object.bkit_ratings + # for a in range(0, 10): + # pn = f'rq{str(a+1).zfill(2)}' + # if eval('propsx.' + pn) == False: + # icon = 'SOLO_OFF' + # else: + # icon = 'SOLO_ON' + # row.prop(propsx, pn, icon=icon, icon_only=True) + # print(dir(props)) + # new best method - enum with an items callback. ('animates' the stars as item icons) + row.prop(props, 'rating_quality_ui', expand=True, icon_only=True, emboss = False) + # original (operator) method: + # row = layout.row(align=True) + # for a in range(0, 10): + # if eval('props.' + prop_name) < a + 1: + # icon = 'SOLO_OFF' + # else: + # icon = 'SOLO_ON' + # + # op = row.operator('object.blenderkit_rating', icon=icon, emboss=False, text='') + # op.property_name = prop_name + # op.rating = a + 1 def register_ratings(): pass; - bpy.utils.register_class(StarRatingOperator) + # bpy.utils.register_class(StarRatingOperator) bpy.utils.register_class(UploadRatingOperator) def unregister_ratings(): pass; - bpy.utils.unregister_class(StarRatingOperator) + # bpy.utils.unregister_class(StarRatingOperator) bpy.utils.unregister_class(UploadRatingOperator) diff --git a/blenderkit/rerequests.py b/blenderkit/rerequests.py index 587093e0..3d9a4d75 100644 --- a/blenderkit/rerequests.py +++ b/blenderkit/rerequests.py @@ -40,7 +40,7 @@ def rerequest(method, url, **kwargs): # first normal attempt response = requests.request(method, url, **kwargs) - utils.p(url) + utils.p(url, kwargs) utils.p(response.status_code) if response.status_code == 401: diff --git a/blenderkit/search.py b/blenderkit/search.py index bae25466..09dfeb65 100644 --- a/blenderkit/search.py +++ b/blenderkit/search.py @@ -134,7 +134,7 @@ def scene_load(context): def fetch_server_data(): - ''' download categories and addon version''' + ''' download categories , profile, and refresh token if needed.''' if not bpy.app.background: user_preferences = bpy.context.preferences.addons['blenderkit'].preferences api_key = user_preferences.api_key diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index 1083b6a6..b8d8ce73 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -33,58 +33,32 @@ from bpy.types import ( ) import bpy +import os +import random -def label_multiline(layout, text='', icon='NONE', width=-1): - ''' draw a ui label, but try to split it in multiple lines.''' - if text.strip() == '': - return - lines = text.split('\n') - if width > 0: - threshold = int(width / 5.5) - else: - threshold = 35 - maxlines = 8 - li = 0 - for l in lines: - while len(l) > threshold: - i = l.rfind(' ', 0, threshold) - if i < 1: - i = threshold - l1 = l[:i] - layout.label(text=l1, icon=icon) - icon = 'NONE' - l = l[i:].lstrip() - li += 1 - if li > maxlines: - break; - if li > maxlines: - break; - layout.label(text=l, icon=icon) - icon = 'NONE' - # this was moved to separate interface: -def draw_ratings(layout, context): +def draw_ratings(layout, context, asset): # layout.operator("wm.url_open", text="Read rating instructions", icon='QUESTION').url = 'https://support.google.com/?hl=en' - asset = utils.get_active_asset() # the following shouldn't happen at all in an optimal case, # this function should run only when asset was already checked to be existing if asset == None: return; col = layout.column() - if not utils.user_logged_in(): - label_multiline(layout, text='Please login or sign up ' - 'to rate assets.') - col.enabled = False bkit_ratings = asset.bkit_ratings - ratings.draw_rating(col, bkit_ratings, 'rating_quality', 'Quality') - col.separator() - col.prop(bkit_ratings, 'rating_work_hours') - w = context.region.width + # layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0) + + row = col.row() + row.prop(bkit_ratings , 'rating_quality_ui', expand=True, icon_only=True, emboss=False) + #ratings.draw_rating(col, bkit_ratings, 'rating_quality', 'Quality') + if bkit_ratings.rating_quality>0: + col.separator() + col.prop(bkit_ratings, 'rating_work_hours') + # w = context.region.width # layout.label(text='problems') # layout.prop(bkit_ratings, 'rating_problems', text='') @@ -97,13 +71,12 @@ def draw_ratings(layout, context): # re-enable layout if included in longer panel -def draw_not_logged_in(source): - title = "User not logged in" +def draw_not_logged_in(source, message = 'Please Login/Signup to use this feature' ): + title = "You aren't logged in" def draw_message(source, context): layout = source.layout - label_multiline(layout, text='Please login or sign up ' - 'to upload files.') + utils.label_multiline(layout, text=message) draw_login_buttons(layout) bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO') @@ -121,7 +94,7 @@ def draw_upload_common(layout, props, asset_type, context): row = layout.row(align=True) if props.upload_state != '': - label_multiline(layout, text=props.upload_state, width=context.region.width) + utils.label_multiline(layout, text=props.upload_state, width=context.region.width) if props.uploading: op = layout.operator('object.kill_bg_process', text="", icon='CANCEL') op.process_source = asset_type @@ -210,7 +183,7 @@ def draw_panel_model_upload(self, context): op.process_source = 'MODEL' op.process_type = 'THUMBNAILER' elif props.thumbnail_generating_state != '': - label_multiline(layout, text=props.thumbnail_generating_state) + utils.label_multiline(layout, text=props.thumbnail_generating_state) layout.prop(props, 'description') layout.prop(props, 'tags') @@ -274,7 +247,7 @@ def draw_panel_scene_upload(self, context): # op.process_source = 'MODEL' # op.process_type = 'THUMBNAILER' # elif props.thumbnail_generating_state != '': - # label_multiline(layout, text = props.thumbnail_generating_state) + # utils.label_multiline(layout, text = props.thumbnail_generating_state) layout.prop(props, 'description') layout.prop(props, 'tags') @@ -319,7 +292,7 @@ def draw_panel_model_search(self, context): icon = 'NONE' if props.report == 'You need Full plan to get this item.': icon = 'ERROR' - label_multiline(layout, text=props.report, icon=icon) + utils.label_multiline(layout, text=props.report, icon=icon) if props.report == 'You need Full plan to get this item.': layout.operator("wm.url_open", text="Get Full plan", icon='URL').url = paths.BLENDERKIT_PLANS @@ -346,7 +319,7 @@ def draw_panel_scene_search(self, context): row.prop(props, "search_keywords", text="", icon='VIEWZOOM') draw_assetbar_show_hide(row, props) layout.prop(props, "own_only") - label_multiline(layout, text=props.report) + utils.label_multiline(layout, text=props.report) # layout.prop(props, "search_style") # if props.search_style == 'OTHER': @@ -376,7 +349,7 @@ class VIEW3D_PT_blenderkit_model_properties(Panel): o = utils.get_active_model() # o = bpy.context.active_object if o.get('asset_data') is None: - label_multiline(layout, text='To upload this asset to BlenderKit, go to the Find and Upload Assets panel.') + utils.label_multiline(layout, text='To upload this asset to BlenderKit, go to the Find and Upload Assets panel.') layout.prop(o, 'name') if o.get('asset_data') is not None: @@ -400,6 +373,51 @@ class VIEW3D_PT_blenderkit_model_properties(Panel): # fun override project, not finished # layout.operator('object.blenderkit_color_corrector') +def draw_rating_asset(self,context,asset): + layout = self.layout + col = layout.box() + # split = layout.split(factor=0.5) + # col1 = split.column() + # col2 = split.column() + directory = paths.get_temp_dir('%s_search' % asset['asset_data']['assetType']) + tpath = os.path.join(directory, asset['asset_data']['thumbnail_small']) + for image in bpy.data.images: + if image.filepath == tpath: + # split = row.split(factor=1.0, align=False) + col.template_icon(icon_value=image.preview.icon_id, scale=6.0) + break; + # layout.label(text = '', icon_value=image.preview.icon_id, scale = 10) + col.label(text=asset.name) + draw_ratings(col, context, asset=asset) + + + + +class VIEW3D_PT_blenderkit_ratings(Panel): + bl_category = "BlenderKit" + bl_idname = "VIEW3D_PT_blenderkit_ratings" + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_label = "Please rate" + bl_context = "objectmode" + + @classmethod + def poll(cls, context): + # + p = bpy.context.view_layer.objects.active is not None + return p + + def draw(self, context): + #TODO make a list of assets inside asset appending code, to happen only when assets are added to the scene. + # draw asset properties here + layout = self.layout + assets = ratings.get_assets_for_rating() + if len(assets)>0: + layout.label(text = 'Help BlenderKit community') + layout.label(text = 'by rating these assets:') + + for a in assets: + draw_rating_asset(self, context, asset = a) def draw_login_progress(layout): layout.label(text='Login through browser') @@ -492,7 +510,7 @@ def draw_panel_model_rating(self, context): # o = bpy.context.active_object o = utils.get_active_model() # print('ratings active',o) - draw_ratings(self.layout, context) # , props) + draw_ratings(self.layout, context, asset = o) # , props) # op.asset_type = 'MODEL' @@ -536,7 +554,7 @@ def draw_panel_material_upload(self, context): op.process_source = 'MATERIAL' op.process_type = 'THUMBNAILER' elif props.thumbnail_generating_state != '': - label_multiline(layout, text=props.thumbnail_generating_state) + utils.label_multiline(layout, text=props.thumbnail_generating_state) if bpy.context.scene.render.engine in ('CYCLES', 'BLENDER_EEVEE'): layout.operator("object.blenderkit_material_thumbnail", text='Render thumbnail with Cycles', icon='EXPORT') @@ -557,9 +575,9 @@ def draw_panel_material_search(self, context): row.prop(props, "search_keywords", text="", icon='VIEWZOOM') draw_assetbar_show_hide(row, props) layout.prop(props, "own_only") - label_multiline(layout, text=props.report) + utils.label_multiline(layout, text=props.report) - # layout.prop(props, 'search_style') + # layout.prop(props, 'search_style')F # if props.search_style == 'OTHER': # layout.prop(props, 'search_style_other') # layout.prop(props, 'search_engine') @@ -570,7 +588,8 @@ def draw_panel_material_search(self, context): def draw_panel_material_ratings(self, context): - draw_ratings(self.layout, context) # , props) + asset = bpy.context.active_object.active_material + draw_ratings(self.layout, context, asset) # , props) # op.asset_type = 'MATERIAL' @@ -598,23 +617,28 @@ def draw_panel_brush_search(self, context): draw_assetbar_show_hide(row, props) layout.prop(props, "own_only") - label_multiline(layout, text=props.report) + utils.label_multiline(layout, text=props.report) # draw_panel_categories(self, context) def draw_panel_brush_ratings(self, context): # props = utils.get_brush_props(context) - draw_ratings(self.layout, context) # , props) + brush = utils.get_active_brush() + draw_ratings(self.layout, context, asset = brush) # , props) # # op.asset_type = 'BRUSH' -def draw_login_buttons(layout): +def draw_login_buttons(layout, invoke = False): user_preferences = bpy.context.preferences.addons['blenderkit'].preferences if user_preferences.login_attempt: draw_login_progress(layout) else: + if invoke: + layout.operator_context = 'INVOKE_DEFAULT' + else: + layout.operator_context = 'EXEC_DEFAULT' if user_preferences.api_key == '': layout.operator("wm.blenderkit_login", text="Login", icon='URL').signup = False @@ -846,7 +870,7 @@ class VIEW3D_PT_blenderkit_unified(Panel): layout.separator() # if bpy.data.filepath == '': # layout.alert = True - # label_multiline(layout, text="It's better to save your file first.", width=w) + # utils.label_multiline(layout, text="It's better to save your file first.", width=w) # layout.alert = False # layout.separator() @@ -868,7 +892,7 @@ class VIEW3D_PT_blenderkit_unified(Panel): # noinspection PyCallByClass draw_panel_brush_search(self, context) else: - label_multiline(layout, text='switch to paint or sculpt mode.', width=context.region.width) + utils.label_multiline(layout, text='switch to paint or sculpt mode.', width=context.region.width) return @@ -886,11 +910,11 @@ class VIEW3D_PT_blenderkit_unified(Panel): if e not in ('CYCLES', 'BLENDER_EEVEE'): rtext = 'Only Cycles and EEVEE render engines are currently supported. ' \ 'Please use Cycles for all assets you upload to BlenderKit.' - label_multiline(layout, rtext, icon='ERROR', width=w) + utils.label_multiline(layout, rtext, icon='ERROR', width=w) return; if ui_props.asset_type == 'MODEL': - # label_multiline(layout, "Uploaded models won't be available in b2.79", icon='ERROR') + #utils.label_multiline(layout, "Uploaded models won't be available in b2.79", icon='ERROR') if bpy.context.view_layer.objects.active is not None: draw_panel_model_upload(self, context) else: @@ -899,12 +923,12 @@ class VIEW3D_PT_blenderkit_unified(Panel): draw_panel_scene_upload(self, context) elif ui_props.asset_type == 'MATERIAL': - # label_multiline(layout, "Uploaded materials won't be available in b2.79", icon='ERROR') + #utils.label_multiline(layout, "Uploaded materials won't be available in b2.79", icon='ERROR') if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None: draw_panel_material_upload(self, context) else: - label_multiline(layout, text='select object with material to upload materials', width=w) + utils.label_multiline(layout, text='select object with material to upload materials', width=w) elif ui_props.asset_type == 'BRUSH': if context.sculpt_object or context.image_paint_object: @@ -1029,6 +1053,16 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu): asset_data = sr[ui_props.active_index] draw_asset_context_menu(self, context, asset_data) +class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu): + bl_label = "BlenderKit login/signup:" + bl_idname = "OBJECT_MT_blenderkit_login_menu" + + def draw(self, context): + layout = self.layout + + # utils.label_multiline(layout, text=message) + draw_login_buttons(layout) + class SetCategoryOperator(bpy.types.Operator): """Visit subcategory""" @@ -1088,9 +1122,42 @@ class UrlPopupDialog(bpy.types.Operator): def draw(self, context): layout = self.layout - label_multiline(layout, text=self.message) + utils.label_multiline(layout, text=self.message) + + layout.active_default = True + op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION') + op.url = self.url + + def execute(self, context): + # start_thumbnailer(self, context) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + + return wm.invoke_props_dialog(self) + +class LoginPopupDialog(bpy.types.Operator): + """Generate Cycles thumbnail for model assets""" + bl_idname = "wm.blenderkit_url_dialog" + bl_label = "BlenderKit login" + bl_options = {'REGISTER', 'INTERNAL'} + + message: bpy.props.StringProperty( + name="Message", + description="", + default="Your were logged out from BlenderKit. Please login again. ") + + # @classmethod + # def poll(cls, context): + # return bpy.context.view_layer.objects.active is not None + + def draw(self, context): + layout = self.layout + utils.label_multiline(layout, text=self.message) layout.active_default = True + op = layout.operator op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION') op.url = self.url @@ -1227,8 +1294,10 @@ classess = ( VIEW3D_PT_blenderkit_categories, VIEW3D_PT_blenderkit_import_settings, VIEW3D_PT_blenderkit_model_properties, + # VIEW3D_PT_blenderkit_ratings, VIEW3D_PT_blenderkit_downloads, OBJECT_MT_blenderkit_asset_menu, + OBJECT_MT_blenderkit_login_menu, UrlPopupDialog ) diff --git a/blenderkit/upload.py b/blenderkit/upload.py index 3afe9815..18e43b8a 100644 --- a/blenderkit/upload.py +++ b/blenderkit/upload.py @@ -777,7 +777,7 @@ class UploadOperator(Operator): props = utils.get_upload_props() if not utils.user_logged_in(): - ui_panels.draw_not_logged_in(self) + ui_panels.draw_not_logged_in(self, message = 'To upload assets you need to login/signup.') return {'CANCELLED'} if props.is_private == 'PUBLIC': diff --git a/blenderkit/utils.py b/blenderkit/utils.py index 503a93f2..2e59887c 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -263,6 +263,15 @@ def save_prefs(self, context): except Exception as e: print(e) +def get_hidden_texture(tpath, bdata_name, force_reload = False): + i = get_hidden_image(tpath, bdata_name, force_reload = force_reload) + bdata_name = f".{bdata_name}" + t = bpy.data.textures.get(bdata_name) + if t is None: + t = bpy.data.textures.new('.test', 'IMAGE') + if t.image!= i: + t.image = i + return t def get_hidden_image(tpath, bdata_name, force_reload=False): hidden_name = '.%s' % bdata_name @@ -603,3 +612,32 @@ def guard_from_crash(): if bpy.context.preferences.addons['blenderkit'].preferences is None: return False; return True + + +def label_multiline(layout, text='', icon='NONE', width=-1): + ''' draw a ui label, but try to split it in multiple lines.''' + if text.strip() == '': + return + lines = text.split('\n') + if width > 0: + threshold = int(width / 5.5) + else: + threshold = 35 + maxlines = 8 + li = 0 + for l in lines: + while len(l) > threshold: + i = l.rfind(' ', 0, threshold) + if i < 1: + i = threshold + l1 = l[:i] + layout.label(text=l1, icon=icon) + icon = 'NONE' + l = l[i:].lstrip() + li += 1 + if li > maxlines: + break; + if li > maxlines: + break; + layout.label(text=l, icon=icon) + icon = 'NONE'
\ No newline at end of file |