diff options
author | Vilém Duha <vilda.novak@gmail.com> | 2020-12-26 15:24:42 +0300 |
---|---|---|
committer | Vilém Duha <vilda.novak@gmail.com> | 2020-12-26 15:24:42 +0300 |
commit | fdf5ef26f695fb535c54af78c7f50969b632ddfc (patch) | |
tree | cfd649087be7f121147b901466774f5a89098227 | |
parent | 0cf887278e274324fddd70a1e2e9585ec00558db (diff) |
BlenderKit: improve ratings
Trash old BGL code and UI
Fix menu access and enable it for all users
Fix width of the fast rating operator for validators
Autotags for HDR's (only resolutions)
-rw-r--r-- | blenderkit/__init__.py | 11 | ||||
-rw-r--r-- | blenderkit/asset_inspector.py | 6 | ||||
-rw-r--r-- | blenderkit/categories.py | 20 | ||||
-rw-r--r-- | blenderkit/ratings.py | 43 | ||||
-rw-r--r-- | blenderkit/thumbnails/rating_ui.png | bin | 100234 -> 0 bytes | |||
-rw-r--r-- | blenderkit/thumbnails/rating_ui_empty.png | bin | 29345 -> 0 bytes | |||
-rw-r--r-- | blenderkit/ui.py | 184 | ||||
-rw-r--r-- | blenderkit/ui_panels.py | 14 |
8 files changed, 92 insertions, 186 deletions
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py index ceca7207..d5ad436d 100644 --- a/blenderkit/__init__.py +++ b/blenderkit/__init__.py @@ -198,6 +198,12 @@ thumbnail_resolutions = ( ('2048', '2048', ''), ) +def udate_down_up(self, context): + """Perform a search if results are empty.""" + s = context.scene + props = s.blenderkitUI + if s['search results'] == None and props.down_up == 'SEARCH': + search.search() def switch_search_results(self, context): s = bpy.context.scene @@ -225,8 +231,8 @@ def switch_search_results(self, context): 'Switch to paint or sculpt mode to search in BlenderKit brushes.') search.load_previews() - if s['search results'] == None: - search.search_update(self, context) + if s['search results'] == None and props.down_up == 'SEARCH': + search.search() @@ -287,6 +293,7 @@ class BlenderKitUIProps(PropertyGroup): ), description="BLenderKit", default="SEARCH", + update = udate_down_up ) asset_type: EnumProperty( name="BlenderKit Active Asset Type", diff --git a/blenderkit/asset_inspector.py b/blenderkit/asset_inspector.py index 0e26479f..0975acd8 100644 --- a/blenderkit/asset_inspector.py +++ b/blenderkit/asset_inspector.py @@ -363,6 +363,12 @@ def get_autotags(): props.texture_resolution_max = 0 props.texture_resolution_min = 0 check_material(props, mat) + elif ui.asset_type == 'HDR': + # reset some properties here, because they might not get re-filled at all when they aren't needed anymore. + + hdr = utils.get_active_asset() + props = hdr.blenderkit + props.texture_resolution_max = max(hdr.size[0],hdr.size[1]) class AutoFillTags(bpy.types.Operator): diff --git a/blenderkit/categories.py b/blenderkit/categories.py index abdfbe48..cb598709 100644 --- a/blenderkit/categories.py +++ b/blenderkit/categories.py @@ -100,16 +100,16 @@ def get_category(categories, cat_path=()): return (c) break; -def get_upload_asset_type(self): - typemapper = { - bpy.types.Object.blenderkit: 'model', - bpy.types.Scene.blenderkit: 'scene', - bpy.types.Image.blenderkit: 'hdr', - bpy.types.Material.blenderkit: 'material', - bpy.types.Brush.blenderkit: 'brush' - } - asset_type = typemapper[type(self)] - return asset_type +# def get_upload_asset_type(self): +# typemapper = { +# bpy.types.Object.blenderkit: 'model', +# bpy.types.Scene.blenderkit: 'scene', +# bpy.types.Image.blenderkit: 'hdr', +# bpy.types.Material.blenderkit: 'material', +# bpy.types.Brush.blenderkit: 'brush' +# } +# asset_type = typemapper[type(self)] +# return asset_type def get_category_enums(self, context): diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py index a2ade101..2ec1f462 100644 --- a/blenderkit/ratings.py +++ b/blenderkit/ratings.py @@ -162,10 +162,9 @@ def upload_rating(asset): ratings = (('quality', bkit_ratings.rating_quality),) tasks_queue.add_task((send_rating_to_thread_quality, (url, ratings, headers)), wait=2.5, only_last=True) if bkit_ratings.rating_work_hours > 0.1: - ratings=(('working_hours', round(bkit_ratings.rating_work_hours, 1)),) + ratings = (('working_hours', round(bkit_ratings.rating_work_hours, 1)),) tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5, only_last=True) - thread = threading.Thread(target=upload_rating_thread, args=(url, ratings, headers)) thread.start() @@ -285,6 +284,7 @@ def update_ratings_work_hours_ui(self, context): # self.rating_work_hours_ui = '0' self.rating_work_hours = float(self.rating_work_hours_ui) + def update_ratings_work_hours_ui_1_5(self, context): user_preferences = bpy.context.preferences.addons['blenderkit'].preferences if user_preferences.api_key == '': @@ -299,7 +299,6 @@ def update_ratings_work_hours_ui_1_5(self, context): self.rating_work_hours = float(self.rating_work_hours_ui_1_5) - class FastRateMenu(Operator): """Fast rating of the assets directly in the asset bar - without need to download assets.""" bl_idname = "wm.blenderkit_menu_rating_upload" @@ -313,7 +312,12 @@ class FastRateMenu(Operator): asset_id: StringProperty( name="Asset Base Id", - description="Unique name of the asset (hidden)", + description="Unique id of the asset (hidden)", + default="") + + asset_name: StringProperty( + name="Asset Name", + description="Name of the asset (hidden)", default="") asset_type: StringProperty( @@ -380,9 +384,9 @@ class FastRateMenu(Operator): @classmethod def poll(cls, context): - scene = bpy.context.scene - ui_props = scene.blenderkitUI - return ui_props.active_index > -1 + # scene = bpy.context.scene + # ui_props = scene.blenderkitUI + return True#ui_props.active_index > -1 def draw(self, context): layout = self.layout @@ -394,11 +398,13 @@ class FastRateMenu(Operator): row.prop(self, 'rating_quality_ui', expand=True, icon_only=True, emboss=False) col.separator() col.prop(self, 'rating_work_hours') - row = col.row() - if self.asset_type == 'model': - row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True) - else: - row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True) + if utils.profile_is_validator(): + row = layout.row() + print(self.asset_type, ' asset type for rating') + if self.asset_type == 'model': + row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True) + else: + row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True) def execute(self, context): user_preferences = bpy.context.preferences.addons['blenderkit'].preferences @@ -433,10 +439,15 @@ class FastRateMenu(Operator): asset_data = dict(sr[ui_props.active_index]) self.asset_id = asset_data['id'] self.asset_type = asset_data['assetType'] - self.message = f"Rate asset {asset_data['name']}" + + self.message = f"Rate asset {self.asset_name}" wm = context.window_manager - return wm.invoke_props_dialog(self) + if utils.profile_is_validator(): + #spawn a wider one for validators for the enum buttons + return wm.invoke_props_dialog(self, width = 500) + else: + return wm.invoke_props_dialog(self) def rating_menu_draw(self, context): layout = self.layout @@ -452,10 +463,12 @@ def rating_menu_draw(self, context): layout.label(text='Admin rating Tools:') col.operator_context = 'INVOKE_DEFAULT' - op = col.operator('wm.blenderkit_menu_rating_upload', text='Fast rate') + op = col.operator('wm.blenderkit_menu_rating_upload', text='Rate') op.asset_id = asset_data['id'] + op.asset_name = asset_data['name'] op.asset_type = asset_data['assetType'] + def register_ratings(): bpy.utils.register_class(UploadRatingOperator) bpy.utils.register_class(FastRateMenu) diff --git a/blenderkit/thumbnails/rating_ui.png b/blenderkit/thumbnails/rating_ui.png Binary files differdeleted file mode 100644 index 8d5bbdb5..00000000 --- a/blenderkit/thumbnails/rating_ui.png +++ /dev/null diff --git a/blenderkit/thumbnails/rating_ui_empty.png b/blenderkit/thumbnails/rating_ui_empty.png Binary files differdeleted file mode 100644 index f734d98c..00000000 --- a/blenderkit/thumbnails/rating_ui_empty.png +++ /dev/null diff --git a/blenderkit/ui.py b/blenderkit/ui.py index 91b8397a..c130a22e 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -32,7 +32,8 @@ if "bpy" in locals(): tasks_queue = importlib.reload(tasks_queue) tasks_queue = importlib.reload(ui_panels) else: - from blenderkit import paths, ratings, utils, search, upload, ui_bgl, download, bg_blender, colors, tasks_queue, ui_panels + from blenderkit import paths, ratings, utils, search, upload, ui_bgl, download, bg_blender, colors, tasks_queue, \ + ui_panels import bpy @@ -271,80 +272,6 @@ def draw_ratings_bgl(): # ui_bgl.draw_text( 'rate asset %s' % asset_data['name'],r.width - rating_button_width + margin, margin, font_size) return - ui_bgl.draw_rect(ui.rating_x, - ui.rating_y - ui.rating_ui_height - 2 * ui.margin - font_size, - ui.rating_ui_width + ui.margin, - ui.rating_ui_height + 2 * ui.margin + font_size, - bgcol) - if asset_data['assetType'] == 'model': - ui_img_name = 'rating_ui.png' - else: - ui_img_name = 'rating_ui_empty.png' - text = 'Try to estimate how many hours it would take for a professional artist to create this asset:' - tx = ui.rating_x + ui.workhours_bar_x - # draw_text_block(x=tx, y=ui.rating_y, width=80, font_size=20, line_height=15, text=text, color=colors.TEXT) - - img = utils.get_thumbnail(ui_img_name) - ui_bgl.draw_image(ui.rating_x, - ui.rating_y - ui.rating_ui_height - 2 * ui.margin, - ui.rating_ui_width, - ui.rating_ui_height, - img, 1) - img = utils.get_thumbnail('star_white.png') - - quality = bkit_ratings.rating_quality - work_hours = bkit_ratings.rating_work_hours - - for a in range(0, quality): - ui_bgl.draw_image(ui.rating_x + ui.quality_stars_x + a * ui.star_size, - ui.rating_y - ui.rating_ui_height + ui.quality_stars_y, - ui.star_size, - ui.star_size, - img, 1) - - img = utils.get_thumbnail('bar_slider.png') - # for a in range(0,11): - if work_hours > 0.2: - if asset_data['assetType'] == 'model': - complexity = math.log2(work_hours) + 2 # real complexity - complexity = (1. / 9.) * (complexity - 1) * ui.workhours_bar_x_max - else: - complexity = work_hours / 5 * ui.workhours_bar_x_max - ui_bgl.draw_image( - ui.rating_x + ui.workhours_bar_x + int( - complexity), - ui.rating_y - ui.rating_ui_height + ui.workhours_bar_y, - ui.workhours_bar_slider_size, - ui.workhours_bar_slider_size, img, 1) - ui_bgl.draw_text( - str(round(work_hours, 1)), - ui.rating_x + ui.workhours_bar_x - 50, - ui.rating_y - ui.rating_ui_height + ui.workhours_bar_y + 10, font_size) - # (0.5,1,2,4,8,16,32,64,128,256) - # ratings have to be different for models and brushes+materials. - - scalevalues, xs = get_rating_scalevalues(asset_data['assetType']) - for v, x in zip(scalevalues, xs): - ui_bgl.draw_rect(ui.rating_x + ui.workhours_bar_x + int( - x * ui.workhours_bar_x_max) - 1 + ui.workhours_bar_slider_size / 2, - ui.rating_y - ui.rating_ui_height + ui.workhours_bar_y, - 2, - 5, - textcol) - ui_bgl.draw_text(str(v), - ui.rating_x + ui.workhours_bar_x + int( - x * ui.workhours_bar_x_max), - ui.rating_y - ui.rating_ui_height + ui.workhours_bar_y - 30, - font_size) - if work_hours > 0.2 and quality > 0.2: - text = 'Thanks for rating asset %s' % asset_data['name'] - else: - text = 'Rate asset %s.' % asset_data['name'] - ui_bgl.draw_text(text, - ui.rating_x, - ui.rating_y - ui.margin - font_size, - font_size) - def draw_text_block(x=0, y=0, width=40, font_size=10, line_height=15, text='', color=colors.TEXT): lines = text.split('\n') @@ -633,7 +560,7 @@ def draw_callback_2d(self, context): draw_callback_2d_upload_preview(self, context) -def draw_downloader(x, y, percent=0, img=None, text= ''): +def draw_downloader(x, y, percent=0, img=None, text=''): if img is not None: ui_bgl.draw_image(x, y, 50, 50, img, .5) @@ -643,8 +570,8 @@ def draw_downloader(x, y, percent=0, img=None, text= ''): # ui_bgl.draw_text(asset_data['name'], x, y, colors.TEXT) # ui_bgl.draw_text(asset_data['filesSize']) if text: - ui_bgl.draw_text(text, x, y - 15,12, colors.TEXT) - #asset_data and asset_data.get('filesSize'): + ui_bgl.draw_text(text, x, y - 15, 12, colors.TEXT) + # asset_data and asset_data.get('filesSize'): # fs = asset_data['filesSize'] # fsmb = fs // (1024 * 1024) # fskb = fs % 1024 @@ -722,8 +649,8 @@ def draw_callback_2d_upload_preview(self, context): props = utils.get_upload_props() - #assets which don't need asset preview - if ui_props.asset_type =='HDR': + # assets which don't need asset preview + if ui_props.asset_type == 'HDR': return if props != None and ui_props.draw_tooltip: @@ -738,6 +665,7 @@ def draw_callback_2d_upload_preview(self, context): draw_tooltip(ui_props.bar_x, ui_props.bar_y, text=ui_props.tooltip, img=img) + def is_upload_old(asset_data): ''' estimates if the asset is far too long in the 'uploaded' state @@ -781,7 +709,7 @@ def draw_callback_2d_search(self, context): # 1, # img, # 1) - if not ui_props.dragging and ui_props.hcount > 0 and ui_props.wcount>0: + if not ui_props.dragging and ui_props.hcount > 0 and ui_props.wcount > 0: search_results = s.get('search results') search_results_orig = s.get('search results orig') if search_results == None: @@ -860,19 +788,18 @@ def draw_callback_2d_search(self, context): else: ui_bgl.draw_rect(x, y, ui_props.thumb_size, ui_props.thumb_size, white) - result = search_results[index] - #code to inform validators that the validation is waiting too long and should be done asap + # code to inform validators that the validation is waiting too long and should be done asap if result['verificationStatus'] == 'uploaded': if utils.profile_is_validator(): over_limit = is_upload_old(result) if over_limit: - redness = min(over_limit*.05,0.5) + redness = min(over_limit * .05, 0.5) red = (1, 0, 0, redness) ui_bgl.draw_rect(x, y, ui_props.thumb_size, ui_props.thumb_size, red) if result['downloaded'] > 0: - ui_bgl.draw_rect(x, y , int(ui_props.thumb_size * result['downloaded'] / 100.0), 2, green) + ui_bgl.draw_rect(x, y, int(ui_props.thumb_size * result['downloaded'] / 100.0), 2, green) # object type icons - just a test..., adds clutter/ not so userfull: # icons = ('type_finished.png', 'type_template.png', 'type_particle_system.png') @@ -1118,63 +1045,11 @@ def interact_rating(r, mx, my, event): ui.rating_y - ui.rating_button_width, ui.rating_button_width * 2, ui.rating_button_width): - ui.rating_menu_on = True - ui.rating_button_on = False + # ui.rating_menu_on = True + ctx = utils.get_fake_context(bpy.context, area_type='VIEW_3D') + bpy.ops.wm.blenderkit_menu_rating_upload(ctx,'INVOKE_DEFAULT',asset_name=asset_data['name'], asset_id=asset_data['id'], + asset_type=asset_data['assetType']) return True - if ui.rating_menu_on: - if mouse_in_area(mx, my, - ui.rating_x, - ui.rating_y - ui.rating_ui_height, - ui.rating_ui_width, - ui.rating_ui_height + 25): - rmx = mx - (ui.rating_x) - rmy = my - (ui.rating_y - ui.rating_ui_height) - - # quality - upload_rating = False - if (ui.quality_stars_x < rmx and rmx < ui.quality_stars_x + 10 * ui.star_size and \ - ui.quality_stars_y < rmy and rmy < ui.quality_stars_y + ui.star_size and event.type == 'LEFTMOUSE' and event.value == 'PRESS') or \ - ui.dragging_rating_quality: - - if event.type == 'LEFTMOUSE': - if event.value == 'PRESS': - ui.dragging_rating = True - ui.dragging_rating_quality = True - elif event.value == 'RELEASE': - ui.dragging_rating = False - ui.dragging_rating_quality = False - - if ui.dragging_rating_quality: - q = math.ceil((rmx - ui.quality_stars_x) / (float(ui.star_size))) - bkit_ratings.rating_quality = q - - # work hours - if ( - ui.workhours_bar_x < rmx and rmx < ui.workhours_bar_x + ui.workhours_bar_x_max + ui.workhours_bar_slider_size and \ - ui.workhours_bar_y < rmy and rmy < ui.workhours_bar_y + ui.workhours_bar_slider_size and event.type == 'LEFTMOUSE' and event.value == 'PRESS') \ - or (ui.dragging_rating_work_hours): - if event.value == 'PRESS': - ui.dragging_rating = True - ui.dragging_rating_work_hours = True - elif event.value == 'RELEASE': - ui.dragging_rating = False - ui.dragging_rating_work_hours = False - if ui.dragging_rating_work_hours: - xv = rmx - ui.workhours_bar_x - ui.workhours_bar_slider_size / 2 - ratio = xv / ui.workhours_bar_x_max - if asset_data['assetType'] == 'model': - wh_log2 = ratio * 9 - 1 - wh = 2 ** wh_log2 - else: - wh = 5 * ratio - bkit_ratings.rating_work_hours = wh - - if event.type == 'LEFTMOUSE' and event.value == 'RELEASE': - ui.last_rating_time = time.time() # this prop seems obsolete now? - return True - else: - ui.rating_button_on = True - ui.rating_menu_on = False return False @@ -1383,8 +1258,8 @@ class AssetBarOperator(bpy.types.Operator): ao = bpy.context.active_object if ui_props.asset_type == 'MODEL' and ao != None \ or ui_props.asset_type == 'MATERIAL' and ao != None and ao.active_material != None \ - or ui_props.asset_type == 'BRUSH' and utils.get_active_brush() is not None\ - or ui_props.asset_type =='SCENE' or ui_props.asset_type == 'HDR': + or ui_props.asset_type == 'BRUSH' and utils.get_active_brush() is not None \ + or ui_props.asset_type == 'SCENE' or ui_props.asset_type == 'HDR': export_data, upload_data = upload.get_upload_data(self, context, ui_props.asset_type) if upload_data: ui_props.tooltip = search.generate_tooltip(upload_data) @@ -1460,10 +1335,10 @@ class AssetBarOperator(bpy.types.Operator): ui_props.mouse_x = mx ui_props.mouse_y = my - if ui_props.dragging_rating or ui_props.rating_menu_on: - res = interact_rating(r, mx, my, event) - if res == True: - return {'RUNNING_MODAL'} + # if ui_props.dragging_rating or ui_props.rating_menu_on: + # res = interact_rating(r, mx, my, event) + # if res == True: + # return {'RUNNING_MODAL'} if ui_props.drag_init: ui_props.drag_length += 1 @@ -1552,7 +1427,7 @@ class AssetBarOperator(bpy.types.Operator): ui_props = context.scene.blenderkitUI if event.value == 'PRESS' and ui_props.active_index > -1: - #start dragging models and materials + # start dragging models and materials 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 @@ -1666,8 +1541,8 @@ class AssetBarOperator(bpy.types.Operator): if ao != None and not ao.is_library_indirect: target_object = bpy.context.active_object.name target_slot = bpy.context.active_object.active_material_index - #change snapped location for placing material downloader. - ui_props.snapped_location = bpy.context.active_object.location + # change snapped location for placing material downloader. + ui_props.snapped_location = bpy.context.active_object.location else: target_object = '' target_slot = '' @@ -1677,7 +1552,7 @@ class AssetBarOperator(bpy.types.Operator): return {'RUNNING_MODAL'} if asset_search_index > -3: - #picking of assets and using them + # picking of assets and using them if ui_props.asset_type == 'MATERIAL': if target_object != '': # position is for downloader: @@ -1712,8 +1587,8 @@ class AssetBarOperator(bpy.types.Operator): target_object=target_object) else: - bpy.ops.scene.blenderkit_download(#asset_type=ui_props.asset_type, - asset_index=asset_search_index) + bpy.ops.scene.blenderkit_download( # asset_type=ui_props.asset_type, + asset_index=asset_search_index) ui_props.dragging = False return {'RUNNING_MODAL'} @@ -1877,7 +1752,7 @@ class RunAssetBarWithContext(bpy.types.Operator): def execute(self, context): C_dict = utils.get_fake_context(context) - if C_dict.get('window'): # no 3d view, no asset bar. + if C_dict.get('window'): # no 3d view, no asset bar. bpy.ops.view3d.blenderkit_asset_bar(C_dict, 'INVOKE_REGION_WIN', keep_running=True, do_search=False) return {'FINISHED'} @@ -1928,6 +1803,7 @@ def register_ui(): wm = bpy.context.window_manager km = wm.keyconfigs.addon.keymaps['Window'] kmi = km.keymap_items.new(ratings.FastRateMenu.bl_idname, 'F', 'PRESS', ctrl=False, shift=False) + addon_keymapitems.append(kmi) kmi = km.keymap_items.new(upload.FastCategory.bl_idname, 'F', 'PRESS', ctrl=True, shift=False) addon_keymapitems.append(kmi) diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py index c4ed5e40..6d89e110 100644 --- a/blenderkit/ui_panels.py +++ b/blenderkit/ui_panels.py @@ -917,6 +917,7 @@ class VIEW3D_PT_blenderkit_import_settings(Panel): row.prop(props, 'append_method', expand=True, icon_only=False) + layout.prop(props, 'resolution') # layout.prop(props, 'unpack_files') @@ -1180,6 +1181,12 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False): # if asset_data['downloaded'] == 100: # only show for downloaded/used assets # if ui_props.asset_type in ('MODEL', 'MATERIAL'): # layout.menu(OBJECT_MT_blenderkit_resolution_menu.bl_idname) + layout.operator_context = 'INVOKE_DEFAULT' + + op = layout.operator('wm.blenderkit_menu_rating_upload', text='Rate') + op.asset_name = asset_data['name'] + op.asset_id = asset_data['id'] + op.asset_type = asset_data['assetType'] if ui_props.asset_type in ('MODEL', 'MATERIAL') and \ utils.get_param(asset_data, 'textureResolutionMax') is not None and \ @@ -1273,13 +1280,9 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False): op.state = 'deleted' if utils.profile_is_validator(): - layout.label(text='Admin rating Tools:') + layout.label(text='Admin Tools:') - op = layout.operator('wm.blenderkit_menu_rating_upload', text='Fast rate') - op.asset_id = asset_data['id'] - op.asset_type = asset_data['assetType'] - layout.operator_context = 'INVOKE_DEFAULT' op = layout.operator('object.blenderkit_print_asset_debug', text='Print asset debug') op.asset_id = asset_data['id'] @@ -1338,6 +1341,7 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu): # sr = bpy.context.scene['search results'] sr = bpy.context.scene['search results'] asset_data = sr[ui_props.active_index] + draw_asset_context_menu(self, context, asset_data, from_panel=False) |