diff options
Diffstat (limited to 'blenderkit/ui.py')
-rw-r--r-- | blenderkit/ui.py | 299 |
1 files changed, 244 insertions, 55 deletions
diff --git a/blenderkit/ui.py b/blenderkit/ui.py index 9f60d471..0dfed1d6 100644 --- a/blenderkit/ui.py +++ b/blenderkit/ui.py @@ -21,6 +21,7 @@ from blenderkit import paths, ratings, utils, search, upload, ui_bgl, download, bg_blender, colors, tasks_queue, \ ui_panels,icons + import bpy import math, random @@ -304,7 +305,6 @@ def draw_tooltip(x, y, text='', author='', img=None, gravatar=None): isizey = int(512 * scale * img.size[1] / max(img.size[0], img.size[1])) estimated_height = 2 * ttipmargin + textmargin + isizey - if estimated_height > y: scaledown = y / (estimated_height) scale *= scaledown @@ -350,7 +350,6 @@ def draw_tooltip(x, y, text='', author='', img=None, gravatar=None): bgcol) # main preview image ui_bgl.draw_image(x, y - isizey - ttipmargin, isizex, isizey, img, 1) - # text overlay background ui_bgl.draw_rect(x - ttipmargin, y - 2 * ttipmargin - isizey, @@ -436,6 +435,23 @@ def draw_tooltip(x, y, text='', author='', img=None, gravatar=None): t = time.time() +def draw_tooltip_with_author(asset_data, x,y): + # TODO move this lazy loading into a function and don't duplicate through the code + + img = get_large_thumbnail_image(asset_data) + gimg = None + atip = '' + if bpy.context.window_manager.get('bkit authors') is not None: + a = bpy.context.window_manager['bkit authors'].get(asset_data['author']['id']) + if a is not None and a != '': + if a.get('gravatarImg') is not None: + gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash']) + atip = a['tooltip'] + + # scene = bpy.context.scene + # ui_props = scene.blenderkitUI + draw_tooltip(x,y, text=asset_data['tooltip'], author=atip, img=img, + gravatar=gimg) def draw_tooltip_old(x, y, text='', author='', img=None): region = bpy.context.region @@ -678,6 +694,22 @@ def is_upload_old(asset_data): return (age.days - old.days) return 0 +def get_large_thumbnail_image(asset_data): + '''Get thumbnail image from asset data''' + scene = bpy.context.scene + ui_props = scene.blenderkitUI + iname = utils.previmg_name(ui_props.active_index, fullsize=True) + directory = paths.get_temp_dir('%s_search' % mappingdict[ui_props.asset_type]) + tpath = os.path.join(directory, asset_data['thumbnail']) + if not asset_data['thumbnail']: + tpath = paths.get_addon_thumbnail_path('thumbnail_not_available.jpg') + + if asset_data['assetType'] == 'hdr': + colorspace = 'Non-Color' + else: + colorspace = 'sRGB' + img = utils.get_hidden_image(tpath, iname, colorspace=colorspace) + return img def draw_asset_bar(self, context): s = bpy.context.scene @@ -817,63 +849,17 @@ def draw_asset_bar(self, context): # report = 'BlenderKit - No matching results found.' # ui_bgl.draw_text(report, ui_props.bar_x + ui_props.margin, # ui_props.bar_y - 25 - ui_props.margin, 15) + if ui_props.draw_tooltip: + r = search_results[ui_props.active_index] + draw_tooltip_with_author(r, ui_props.mouse_x, ui_props.mouse_y) s = bpy.context.scene props = utils.get_search_props() # if props.report != '' and props.is_searching or props.search_error: # ui_bgl.draw_text(props.report, ui_props.bar_x, # ui_props.bar_y - 15 - ui_props.margin - ui_props.bar_height, 15) - props = s.blenderkitUI - if props.draw_tooltip: - # TODO move this lazy loading into a function and don't duplicate through the code - iname = utils.previmg_name(ui_props.active_index, fullsize=True) - - directory = paths.get_temp_dir('%s_search' % mappingdict[props.asset_type]) - sr = s.get('search results') - if sr != None and -1 < ui_props.active_index < len(sr): - r = sr[ui_props.active_index] - tpath = os.path.join(directory, r['thumbnail']) - if not r['thumbnail']: - tpath = paths.get_addon_thumbnail_path('thumbnail_not_available.jpg') - - # img = bpy.data.images.get(iname) - # if img == None or img.filepath != tpath: - # # TODO replace it with a function - # if os.path.exists(tpath): - # - # if img is None: - # img = bpy.data.images.load(tpath) - # img.name = iname - # else: - # if img.filepath != tpath: - # # todo replace imgs reloads with a method that forces unpack for thumbs. - # if img.packed_file is not None: - # img.unpack(method='USE_ORIGINAL') - # img.filepath = tpath - # img.reload() - # img.name = iname - # else: - # iname = utils.previmg_name(ui_props.active_index) - # img = bpy.data.images.get(iname) - # if img: - # img.colorspace_settings.name = 'sRGB' - if r['assetType'] == 'hdr': - colorspace = 'Non-Color' - else: - colorspace = 'sRGB' - img = utils.get_hidden_image(tpath, iname, colorspace=colorspace) - gimg = None - atip = '' - if bpy.context.window_manager.get('bkit authors') is not None: - a = bpy.context.window_manager['bkit authors'].get(r['author']['id']) - if a is not None and a != '': - if a.get('gravatarImg') is not None: - gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash']) - atip = a['tooltip'] - draw_tooltip(ui_props.mouse_x, ui_props.mouse_y, text=ui_props.tooltip, author=atip, img=img, - gravatar=gimg) if ui_props.dragging and ( ui_props.draw_drag_image or ui_props.draw_snapped_bounds) and ui_props.active_index > -1: @@ -1303,9 +1289,6 @@ class AssetBarOperator(bpy.types.Operator): ui_props.mouse_x = 0 ui_props.mouse_y = self.region.height - mx = event.mouse_x - my = event.mouse_y - ui_props.draw_tooltip = True # only generate tooltip once in a while @@ -1472,6 +1455,7 @@ class AssetBarOperator(bpy.types.Operator): my = event.mouse_y - r.y if event.value == 'PRESS' and mouse_in_asset_bar(mx, my): + # bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT') bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu') return {'RUNNING_MODAL'} @@ -1803,6 +1787,205 @@ class UndoWithContext(bpy.types.Operator): return {'FINISHED'} +def draw_callback_dragging(self, context): + img = bpy.data.images.get(self.iname) + linelength = 35 + scene = bpy.context.scene + ui_props = scene.blenderkitUI + ui_bgl.draw_image(self.mouse_x + linelength, self.mouse_y - linelength - ui_props.thumb_size, + ui_props.thumb_size, ui_props.thumb_size, img, 1) + ui_bgl.draw_line2d(self.mouse_x, self.mouse_y, self.mouse_x + linelength, + self.mouse_y - linelength, 2, colors.WHITE) + + +def draw_callback_3d_dragging(self, context): + ''' Draw snapped bbox while dragging. ''' + if not utils.guard_from_crash(): + return + ui_props = context.scene.blenderkitUI + # print(ui_props.asset_type, self.has_hit, self.snapped_location) + if ui_props.asset_type == 'MODEL': + if self.has_hit: + draw_bbox(self.snapped_location, self.snapped_rotation, self.snapped_bbox_min, self.snapped_bbox_max) + + +class AssetDragOperator(bpy.types.Operator): + """Draw a line with the mouse""" + bl_idname = "view3d.asset_drag_drop" + bl_label = "BlenderKit asset drag drop" + + asset_search_index: IntProperty(name="Active Index", default=0) + + def handlers_remove(self): + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW') + + def mouse_release(self): + scene = bpy.context.scene + ui_props = scene.blenderkitUI + + if not self.has_hit: + return {'RUNNING_MODAL'} + + if ui_props.asset_type == 'MODEL': + target_object = '' + if self.object_name is not None: + target_object = self.object_name + target_slot = '' + + if ui_props.asset_type == 'MATERIAL': + # first, test if object can have material applied. + object = bpy.data.objects[self.object_name] + if object is not None and not object.is_library_indirect and object.type == 'MESH': + target_object = object.name + # create final mesh to extract correct material slot + depsgraph = bpy.context.evaluated_depsgraph_get() + object_eval = object.evaluated_get(depsgraph) + temp_mesh = object_eval.to_mesh() + target_slot = temp_mesh.polygons[self.face_index].material_index + object_eval.to_mesh_clear() + else: + self.report({'WARNING'}, "Invalid or library object as input:") + target_object = '' + target_slot = '' + + if abs(self.start_mouse_x - self.mouse_x) < 20 and abs(self.start_mouse_y - self.mouse_y)<20: + #no dragging actually this was a click. + self.snapped_location = scene.cursor.location + self.snapped_rotation = (0,0,0) + if ui_props.asset_type in ('MATERIAL',): + ao = bpy.context.active_object + 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. + self.snapped_location = bpy.context.active_object.location + else: + target_object = '' + target_slot = '' + + + # picking of assets and using them + if ui_props.asset_type == 'MATERIAL': + if target_object != '': + # position is for downloader: + loc = self.snapped_location + rotation = (0, 0, 0) + + utils.automap(target_object, target_slot=target_slot, + tex_size=self.asset_data.get('texture_size_meters', 1.0)) + bpy.ops.scene.blenderkit_download(True, + # asset_type=ui_props.asset_type, + asset_index=self.asset_search_index, + model_location=loc, + model_rotation=rotation, + target_object=target_object, + material_target_slot=target_slot) + + + elif ui_props.asset_type == 'MODEL': + + if 'particle_plants' in self.asset_data['tags']: + bpy.ops.object.blenderkit_particles_drop("INVOKE_DEFAULT", + asset_search_index=self.asset_search_index, + model_location=self.snapped_location, + model_rotation=self.snapped_rotation, + target_object=target_object) + else: + bpy.ops.scene.blenderkit_download(True, + # asset_type=ui_props.asset_type, + asset_index=self.asset_search_index, + model_location=self.snapped_location, + model_rotation=self.snapped_rotation, + target_object=target_object) + + else: + bpy.ops.scene.blenderkit_download( # asset_type=ui_props.asset_type, + asset_index=self.asset_search_index) + + def modal(self, context, event): + scene = bpy.context.scene + ui_props = scene.blenderkitUI + context.area.tag_redraw() + + # if event.type == 'MOUSEMOVE': + if not hasattr(self,'start_mouse_x'): + self.start_mouse_x = event.mouse_region_x + self.start_mouse_y = event.mouse_region_y + + self.mouse_x = event.mouse_region_x + self.mouse_y = event.mouse_region_y + + if event.type == 'LEFTMOUSE' and event.value == 'RELEASE': + self.mouse_release() + self.handlers_remove() + return {'FINISHED'} + + elif event.type in {'RIGHTMOUSE', 'ESC'}: + self.handlers_remove() + return {'CANCELLED'} + + sprops = bpy.context.scene.blenderkit_models + if event.type == 'WHEELUPMOUSE': + sprops.offset_rotation_amount += sprops.offset_rotation_step + elif event.type == 'WHEELDOWNMOUSE': + sprops.offset_rotation_amount -= sprops.offset_rotation_step + + #### TODO - this snapping code below is 3x in this file.... refactor it. + self.has_hit, self.snapped_location, self.snapped_normal, self.snapped_rotation, self.face_index, object, self.matrix = mouse_raycast( + context, event.mouse_region_x, event.mouse_region_y) + if object is not None: + self.object_name =object.name + + + + # MODELS can be dragged on scene floor + if not self.has_hit and ui_props.asset_type == 'MODEL': + self.has_hit, self.snapped_location, self.snapped_normal, self.snapped_rotation, self.face_index, object, self.matrix = floor_raycast( + context, + event.mouse_region_x, event.mouse_region_y) + if object is not None: + self.object_name = object.name + + if ui_props.asset_type == 'MODEL': + self.snapped_bbox_min = Vector(self.asset_data['bbox_min']) + self.snapped_bbox_max = Vector(self.asset_data['bbox_max']) + + return {'RUNNING_MODAL'} + + def invoke(self, context, event): + if context.area.type == 'VIEW_3D': + # the arguments we pass the the callback + args = (self, context) + # Add the region OpenGL drawing callback + # draw in view space with 'POST_VIEW' and 'PRE_VIEW' + self.iname = utils.previmg_name(self.asset_search_index) + + self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_dragging, args, 'WINDOW', 'POST_PIXEL') + self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d_dragging, args, 'WINDOW', + 'POST_VIEW') + + self.mouse_x = 0 + self.mouse_y = 0 + + self.has_hit = False + self.snapped_location = (0,0,0) + self.snapped_normal = (0,0,1) + self.snapped_rotation = (0,0,0) + self.face_index = 0 + object = None + self.matrix = None + + sr = bpy.context.scene['search results'] + self.asset_data = sr[self.asset_search_index] + + context.window_manager.modal_handler_add(self) + return {'RUNNING_MODAL'} + else: + self.report({'WARNING'}, "View3D not found, cannot run operator") + return {'CANCELLED'} + + class RunAssetBarWithContext(bpy.types.Operator): """Regenerate cobweb""" bl_idname = "object.run_assetbar_fix_context" @@ -1816,13 +1999,19 @@ 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. - bpy.ops.view3d.blenderkit_asset_bar(C_dict, 'INVOKE_REGION_WIN', keep_running=True, do_search=False) + preferences = bpy.context.preferences.addons['blenderkit'].preferences + if preferences.experimental_features: + bpy.ops.view3d.blenderkit_asset_bar_widget(C_dict, 'INVOKE_REGION_WIN', keep_running=True, do_search=False) + + else: + bpy.ops.view3d.blenderkit_asset_bar(C_dict, 'INVOKE_REGION_WIN', keep_running=True, do_search=False) return {'FINISHED'} classes = ( AssetBarOperator, # AssetBarExperiment, + AssetDragOperator, RunAssetBarWithContext, TransferBlenderkitData, UndoWithContext, |