From d1701786f237df9cbcd7b12b5383a283d4f12e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vil=C3=A9m=20Duha?= Date: Thu, 9 Jan 2020 13:46:21 +0100 Subject: BlenderKit: search field on top - a dialog box telling the user why an asset is locked -verification status change now in thread - Search UI small changes, getting rid of show assetbar button (now a small eye) --- blenderkit/__init__.py | 30 +++++++--- blenderkit/download.py | 4 +- blenderkit/search.py | 6 +- blenderkit/ui.py | 23 ++++++-- blenderkit/ui_panels.py | 150 ++++++++++++++++++++++++++++++++++++------------ blenderkit/upload.py | 17 +++--- 6 files changed, 169 insertions(+), 61 deletions(-) (limited to 'blenderkit') diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index af323336..2734ad69 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -244,6 +244,26 @@ 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 + if self.down_up == 'SEARCH': + items = ( + ('MODEL', 'Search Models', 'Browse models', 'OBJECT_DATAMODE', 0), + # ('SCENE', 'SCENE', 'Browse scenes', 'SCENE_DATA', 1), + ('MATERIAL', 'Search Materials', 'Browse materials', 'MATERIAL', 2), + # ('TEXTURE', 'Texture', 'Browse textures', 'TEXTURE', 3), + ('BRUSH', 'Search Brushes', 'Browse brushes', 'BRUSH_DATA', 3) + ) + else: + items = ( + ('MODEL', 'Upload Model', 'Browse models', 'OBJECT_DATAMODE', 0), + # ('SCENE', 'SCENE', 'Browse scenes', 'SCENE_DATA', 1), + ('MATERIAL', 'Uplaod Material', 'Browse materials', 'MATERIAL', 2), + # ('TEXTURE', 'Texture', 'Browse textures', 'TEXTURE', 3), + ('BRUSH', 'Upload Brush', 'Browse brushes', 'BRUSH_DATA', 3) + ) + return items class BlenderKitUIProps(PropertyGroup): down_up: EnumProperty( @@ -258,15 +278,9 @@ class BlenderKitUIProps(PropertyGroup): ) asset_type: EnumProperty( name="Active Asset Type", - items=( - ('MODEL', 'Model', 'Browse models', 'OBJECT_DATAMODE', 0), - # ('SCENE', 'SCENE', 'Browse scenes', 'SCENE_DATA', 1), - ('MATERIAL', 'Material', 'Browse models', 'MATERIAL', 2), - # ('TEXTURE', 'Texture', 'Browse textures', 'TEXTURE', 3), - ('BRUSH', 'Brush', 'Browse brushes', 'BRUSH_DATA', 3) - ), + items=asset_type_callback, description="Activate asset in UI", - default="MATERIAL", + default=None, update=switch_search_results ) # these aren't actually used ( by now, seems to better use globals in UI module: diff --git a/blenderkit/download.py b/blenderkit/download.py index 296a7639..d652807e 100644 --- a/blenderkit/download.py +++ b/blenderkit/download.py @@ -762,8 +762,8 @@ def get_download_url(asset_data, scene_id, api_key, tcom=None): if r.status_code == 403: r = 'You need Full plan to get this item.' - r1 = 'All materials and brushes are available for free. Only users registered to Standard plan can use all models.' - tasks_queue.add_task((ui.add_report, (r1, 5, colors.RED))) + # r1 = 'All materials and brushes are available for free. Only users registered to Standard plan can use all models.' + # tasks_queue.add_task((ui.add_report, (r1, 5, colors.RED))) if tcom is not None: tcom.report = r tcom.error = True diff --git a/blenderkit/search.py b/blenderkit/search.py index 56c1d0cb..b4459167 100644 --- a/blenderkit/search.py +++ b/blenderkit/search.py @@ -95,8 +95,6 @@ def refresh_token_timer(): def scene_load(context): wm = bpy.context.window_manager fetch_server_data() - # following doesn't necessarily happen if version isn't checked yet or similar, first run. - # wm['bkit_update'] = version_checker.compare_versions(blenderkit) categories.load_categories() if not bpy.app.timers.is_registered(refresh_token_timer): bpy.app.timers.register(refresh_token_timer, persistent=True, first_interval=36000) @@ -1118,6 +1116,10 @@ def search(category='', get_next=False, author_id=''): def search_update(self, context): utils.p('search updater') #if self.search_keywords != '': + ui_props = bpy.context.scene.blenderkitUI + if ui_props.down_up != 'SEARCH': + ui_props.down_up = 'SEARCH' + search() diff --git a/blenderkit/ui.py b/blenderkit/ui.py index b29e24af..0e8b0744 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -1161,7 +1161,7 @@ def get_largest_3dview(): for a in screen.areas: if a.type == 'VIEW_3D': asurf = a.width * a.height - if asurf>maxsurf: + if asurf > maxsurf: maxa = a maxw = w maxsurf = asurf @@ -1171,7 +1171,6 @@ def get_largest_3dview(): region = r return maxw, maxa, region - class AssetBarOperator(bpy.types.Operator): '''runs search and displays the asset bar at the same time''' bl_idname = "view3d.blenderkit_asset_bar" @@ -1459,6 +1458,17 @@ class AssetBarOperator(bpy.types.Operator): ui_props = context.scene.blenderkitUI if event.value == 'PRESS' and ui_props.active_index > -1: if ui_props.asset_type == 'MODEL' or ui_props.asset_type == 'MATERIAL': + # check if asset is locked and let the user know in that case + asset_search_index = ui_props.active_index + asset_data = sr[asset_search_index] + 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'] + bpy.ops.wm.blenderkit_url_dialog('INVOKE_REGION_WIN', url=url, message=message, + link_text=link_text) + return {'RUNNING_MODAL'} + # go on with drag init ui_props.drag_init = True bpy.context.window.cursor_set("NONE") ui_props.draw_tooltip = False @@ -1720,12 +1730,13 @@ class TransferBlenderkitData(bpy.types.Operator): source_ob.property_unset('blenderkit') return {'FINISHED'} + class RunAssetBarWithContext(bpy.types.Operator): """Regenerate cobweb""" bl_idname = "object.run_assetbar_fix_context" bl_label = "BlnenderKit assetbar with fixed context" bl_description = "Run assetbar with fixed context" - bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} # def modal(self, context, event): # return {'RUNNING_MODAL'} @@ -1772,9 +1783,9 @@ def register_ui(): kmi.properties.keep_running = False kmi.properties.do_search = False addon_keymapitems.append(kmi) - #auto open after searching: - kmi = km.keymap_items.new(RunAssetBarWithContext.bl_idname, 'SEMI_COLON', 'PRESS',\ - ctrl=True, shift=True, alt = True) + # auto open after searching: + kmi = km.keymap_items.new(RunAssetBarWithContext.bl_idname, 'SEMI_COLON', 'PRESS', \ + ctrl=True, shift=True, alt=True) addon_keymapitems.append(kmi) diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index fb3f944b..24d64cb3 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -108,7 +108,6 @@ def draw_upload_common(layout, props, asset_type, context): # if props.upload_state.find('Error') > -1: # layout.label(text = props.upload_state) - if props.asset_base_id == '': optext = 'Upload %s' % asset_type.lower() op = layout.operator("object.blenderkit_upload", text=optext, icon='EXPORT') @@ -263,12 +262,28 @@ 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 + + if ui_props.assetbar_on: + icon = 'HIDE_OFF' + else: + icon = 'HIDE_ON' + op = layout.operator('view3d.blenderkit_asset_bar', text='', icon=icon) + op.keep_running = False + op.do_search = False + def draw_panel_model_search(self, context): s = context.scene + props = s.blenderkit_models layout = self.layout - layout.prop(props, "search_keywords", text="", icon='VIEWZOOM') + + row = layout.row() + row.prop(props, "search_keywords", text="", icon='VIEWZOOM') + draw_assetbar_show_hide(row, props) icon = 'NONE' if props.report == 'You need Full plan to get this item.': @@ -342,7 +357,9 @@ def draw_panel_scene_search(self, context): props = s.blenderkit_scene layout = self.layout # layout.label(text = "common search properties:") - layout.prop(props, "search_keywords", text="", icon='VIEWZOOM') + row = layout.row() + row.prop(props, "search_keywords", text="", icon='VIEWZOOM') + draw_assetbar_show_hide(row, props) label_multiline(layout, text=props.report) @@ -381,12 +398,12 @@ class VIEW3D_PT_blenderkit_model_properties(Panel): # if 'rig' in ad['tags']: # # layout.label(text = 'can make proxy') # layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy') - #fast upload, blocked by now + # fast upload, blocked by now # else: # op = layout.operator("object.blenderkit_upload", text='Store as private', icon='EXPORT') # op.asset_type = 'MODEL' # op.fast = True - #fun override project, not finished + # fun override project, not finished # layout.operator('object.blenderkit_color_corrector') @@ -500,7 +517,9 @@ def draw_panel_material_search(self, context): props = wm.blenderkit_mat layout = self.layout - layout.prop(props, "search_keywords", text="", icon='VIEWZOOM') + row = layout.row() + row.prop(props, "search_keywords", text="", icon='VIEWZOOM') + draw_assetbar_show_hide(row, props) label_multiline(layout, text=props.report) @@ -540,7 +559,11 @@ def draw_panel_brush_search(self, context): props = wm.blenderkit_brush layout = self.layout - layout.prop(props, "search_keywords", text="", icon='VIEWZOOM') + row = layout.row() + row.prop(props, "search_keywords", text="", icon='VIEWZOOM') + draw_assetbar_show_hide(row, props) + + label_multiline(layout, text=props.report) draw_panel_categories(self, context) @@ -595,11 +618,11 @@ class VIEW3D_PT_blenderkit_unified(Panel): row.scale_x = 1.6 row.scale_y = 1.6 # - row.prop(ui_props, 'down_up', expand=True, icon_only=True) + row.prop(ui_props, 'down_up', expand=True, icon_only=False) # row.label(text='') - row = row.split().row() + #row = row.split().row() - row.prop(ui_props, 'asset_type', expand=True, icon_only=True) + layout.prop(ui_props, 'asset_type', expand=False, text = '', icon_only=False) w = context.region.width if user_preferences.login_attempt: @@ -619,31 +642,8 @@ class VIEW3D_PT_blenderkit_unified(Panel): if bpy.data.filepath == '': label_multiline(layout, text="It's better to save the file first.", width=w) layout.separator() - if wm.get('bkit_update'): - label_multiline(layout, text="New version available!", icon='INFO', width=w) - layout.operator("wm.url_open", text="Get new version", - icon='URL').url = paths.BLENDERKIT_ADDON_FILE_URL - layout.separator() - layout.separator() - layout.separator() - if ui_props.down_up == 'SEARCH': - # global assetbar_on - if not ui_props.assetbar_on: - icon = 'EXPORT' - text = 'Show AssetBar - ;' - row = layout.row() - sr = bpy.context.scene.get('search results') - if sr != None: - icon = 'RESTRICT_VIEW_OFF' - row.scale_y = 1 - text = 'Show Assetbar to see %i results - ;' % len(sr) - op = row.operator('view3d.blenderkit_asset_bar', text=text, icon=icon) - else: - - op = layout.operator('view3d.blenderkit_asset_bar', text='Hide AssetBar - ;', icon='EXPORT') - op.keep_running = False - op.do_search = False + if ui_props.down_up == 'SEARCH': if ui_props.asset_type == 'MODEL': # noinspection PyCallByClass @@ -705,7 +705,8 @@ class VIEW3D_PT_blenderkit_unified(Panel): if ui_props.asset_type == 'MODEL': # TODO improve poll here to parenting structures - if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.get('asset_data') != None: + if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.get( + 'asset_data') != None: ad = bpy.context.active_object.get('asset_data') layout.label(text=ad['name']) draw_panel_model_rating(self, context) @@ -727,6 +728,7 @@ 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" @@ -781,6 +783,10 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu): op = layout.operator('object.blenderkit_change_status', text='Put on Hold') op.asset_id = asset_data['id'] op.state = 'on_hold' + if asset_data['verificationStatus'] != 'rejected': + op = layout.operator('object.blenderkit_change_status', text='Reject') + op.asset_id = asset_data['id'] + op.state = 'rejected' if author_id == str(profile['user']['id']): layout.label(text='Management tools:') @@ -825,6 +831,49 @@ class SetCategoryOperator(bpy.types.Operator): return {'FINISHED'} +class UrlPopupDialog(bpy.types.Operator): + """Generate Cycles thumbnail for model assets""" + bl_idname = "wm.blenderkit_url_dialog" + bl_label = "BlenderKit message:" + bl_options = {'REGISTER', 'INTERNAL'} + + url: bpy.props.StringProperty( + name="Url", + description="url", + default="") + + link_text: bpy.props.StringProperty( + name="Url", + description="url", + default="Go to website") + + message: bpy.props.StringProperty( + name="Text", + description="text", + default="") + + # @classmethod + # def poll(cls, context): + # return bpy.context.view_layer.objects.active is not None + + def draw(self, context): + layout = self.layout + label_multiline(layout, text=self.message) + + op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION') + op.url = self.url + + def execute(self, context): + #start_thumbnailer(self, context) + return {'FINISHED'} + + def invoke(self, context, event): + self.bl_label = 'ahoj' + wm = context.window_manager + + return wm.invoke_props_dialog(self) + + def draw_panel_categories(self, context): s = context.scene ui_props = s.blenderkitUI @@ -908,6 +957,33 @@ class VIEW3D_PT_blenderkit_downloads(Panel): layout.separator() +def header_search_draw(self, context): + '''Top bar menu in 3d view.''' + layout = self.layout + s = bpy.context.scene + ui_props = s.blenderkitUI + if ui_props.asset_type == 'MODEL': + props = s.blenderkit_models + if ui_props.asset_type == 'MATERIAL': + props = s.blenderkit_mat + if ui_props.asset_type == 'BRUSH': + props = s.blenderkit_brush + + layout.separator_spacer() + layout.prop(ui_props, "asset_type", text='', icon='URL') + layout.prop(props, "search_keywords", text="", icon='VIEWZOOM') + if ui_props.assetbar_on: + icon = 'HIDE_OFF' + else: + icon = 'HIDE_ON' + op = layout.operator('view3d.blenderkit_asset_bar', text='', icon=icon) + op.keep_running = False + op.do_search = False + + +# We can store multiple preview collections here, +# however in this example we only store "main" +preview_collections = {} classess = ( SetCategoryOperator, @@ -915,13 +991,15 @@ classess = ( VIEW3D_PT_blenderkit_model_properties, VIEW3D_PT_blenderkit_downloads, VIEW3D_PT_blenderkit_profile, - OBJECT_MT_blenderkit_asset_menu + OBJECT_MT_blenderkit_asset_menu, + UrlPopupDialog ) def register_ui_panels(): for c in classess: bpy.utils.register_class(c) + bpy.types.VIEW3D_MT_editor_menus.append(header_search_draw) def unregister_ui_panels(): diff --git a/blenderkit/upload.py b/blenderkit/upload.py index 3d46c106..b1c4b25c 100644 --- a/blenderkit/upload.py +++ b/blenderkit/upload.py @@ -40,6 +40,7 @@ import tempfile, os, subprocess, json, re import bpy import requests +import threading BLENDERKIT_EXPORT_DATA_FILE = "data.json" @@ -465,13 +466,12 @@ def get_upload_data(self, context, asset_type): return export_data, upload_data, eval_path_computing, eval_path_state, eval_path, props -def verification_status_change(asset_id, state): - user_preferences = bpy.context.preferences.addons['blenderkit'].preferences +def verification_status_change_thread(asset_id, state, api_key): upload_data = { "verificationStatus": state } url = paths.get_api_url() + 'assets/' + str(asset_id) + '/' - headers = utils.get_headers(user_preferences.api_key) + headers = utils.get_headers(api_key) try: r = rerequests.patch(url, json=upload_data, headers=headers, verify=True) # files = files, except requests.exceptions.RequestException as e: @@ -783,7 +783,7 @@ class UploadOperator(Operator): if props.is_private == 'PUBLIC': ui_panels.label_multiline(layout, text='public assets are validated several hours' - ' or days after upload. ', width = 300) + ' or days after upload. ', width=300) def invoke(self, context, event): props = utils.get_upload_props() @@ -794,7 +794,6 @@ class UploadOperator(Operator): return self.execute(context) - class AssetVerificationStatusChange(Operator): """Change verification status""" bl_idname = "object.blenderkit_change_status" @@ -823,8 +822,12 @@ class AssetVerificationStatusChange(Operator): # layout.prop(self, 'state') def execute(self, context): - result = verification_status_change(self.asset_id, self.state) - return result + preferences = bpy.context.preferences.addons['blenderkit'].preferences + + thread = threading.Thread(target=verification_status_change_thread, + args=(self.asset_id, self.state, preferences.api_key)) + thread.start() + return {'FINISHED'} def invoke(self, context, event): print(self.state) -- cgit v1.2.3