Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVilém Duha <vilda.novak@gmail.com>2021-01-17 15:35:23 +0300
committerVilém Duha <vilda.novak@gmail.com>2021-01-17 15:35:23 +0300
commite237c47811583d92c2ad07f00591cf4499fa0ae4 (patch)
treee644088d8bcb03cad9e8c6ad4f4579823ff2b4ca /blenderkit/asset_bar_op.py
parentebdf1861dc568a9b4b92b29a9b8f7117ad1eec05 (diff)
BlenderKit: fixing asset bar code
This is now only included under experimental features. It includes a stripped down version of bl_ui_widngets library by Jayanam. Basically the asset bar code got split and now both asset bar codes are next to each other.
Diffstat (limited to 'blenderkit/asset_bar_op.py')
-rw-r--r--blenderkit/asset_bar_op.py591
1 files changed, 591 insertions, 0 deletions
diff --git a/blenderkit/asset_bar_op.py b/blenderkit/asset_bar_op.py
new file mode 100644
index 00000000..612f5885
--- /dev/null
+++ b/blenderkit/asset_bar_op.py
@@ -0,0 +1,591 @@
+import bpy
+
+from bpy.types import Operator
+
+from blenderkit.bl_ui_widgets.bl_ui_label import *
+from blenderkit.bl_ui_widgets.bl_ui_button import *
+# from blenderkit.bl_ui_widgets.bl_ui_checkbox import *
+# from blenderkit.bl_ui_widgets.bl_ui_slider import *
+# from blenderkit.bl_ui_widgets.bl_ui_up_down import *
+from blenderkit.bl_ui_widgets.bl_ui_drag_panel import *
+from blenderkit.bl_ui_widgets.bl_ui_draw_op import *
+# from blenderkit.bl_ui_widgets.bl_ui_textbox import *
+import random
+import math
+
+import blenderkit
+from blenderkit import ui, paths, utils, search
+
+from bpy.props import (
+ IntProperty,
+ BoolProperty,
+ StringProperty
+)
+
+
+def draw_callback_tooltip(self, context):
+ if self.draw_tooltip:
+ s = bpy.context.scene
+ sr = s.get('search results')
+ r = sr[self.active_index]
+ ui.draw_tooltip_with_author(r, 0, 500)
+
+def get_area_height(self):
+ if type(self.context)!= dict:
+ self.context = self.context.copy()
+ # print(self.context)
+ if self.context.get('area') is not None:
+ return self.context['area'].height
+ # else:
+ # maxw, maxa, region = utils.get_largest_area()
+ # if maxa:
+ # self.context['area'] = maxa
+ # self.context['window'] = maxw
+ # self.context['region'] = region
+ # self.update(self.x,self.y)
+ #
+ # return self.context['area'].height
+ # print('no area found')
+ return 100
+
+BL_UI_Widget.get_area_height = get_area_height
+
+
+def asset_bar_modal(self, context, event):
+ if self._finished:
+ return {'FINISHED'}
+
+ if context.area:
+ context.area.tag_redraw()
+ else:
+ self.finish()
+ return {'FINISHED'}
+
+ if self.handle_widget_events(event):
+ return {'RUNNING_MODAL'}
+
+ if event.type in {"ESC"}:
+ self.finish()
+
+ if event.type == 'WHEELUPMOUSE':
+ self.scroll_offset -= 5
+ self.scroll_update()
+ return {'RUNNING_MODAL'}
+ elif event.type == 'WHEELDOWNMOUSE':
+ self.scroll_offset += 5
+ self.scroll_update()
+ return {'RUNNING_MODAL'}
+
+
+ return {"PASS_THROUGH"}
+
+def asset_bar_invoke(self, context, event):
+
+ if not self.on_invoke(context, event):
+ return {"CANCELLED"}
+
+ args = (self, context)
+
+ self.register_handlers(args, context)
+
+ context.window_manager.modal_handler_add(self)
+ return {"RUNNING_MODAL"}
+
+BL_UI_OT_draw_operator.modal = asset_bar_modal
+BL_UI_OT_draw_operator.invoke = asset_bar_invoke
+
+
+def set_mouse_down_right(self, mouse_down_right_func):
+ self.mouse_down_right_func = mouse_down_right_func
+
+
+def mouse_down_right(self, x, y):
+ if self.is_in_rect(x, y):
+ self.__state = 1
+ try:
+ self.mouse_down_right_func(self)
+ except Exception as e:
+ print(e)
+
+ return True
+
+ return False
+
+# def handle_event(self, event):
+# x = event.mouse_region_x
+# y = event.mouse_region_y
+#
+# if (event.type == 'LEFTMOUSE'):
+# if (event.value == 'PRESS'):
+# self._mouse_down = True
+# return self.mouse_down(x, y)
+# else:
+# self._mouse_down = False
+# self.mouse_up(x, y)
+#
+# elif (event.type == 'RIGHTMOUSE'):
+# if (event.value == 'PRESS'):
+# self._mouse_down_right = True
+# return self.mouse_down_right(x, y)
+# else:
+# self._mouse_down_right = False
+# self.mouse_up(x, y)
+#
+# elif (event.type == 'MOUSEMOVE'):
+# self.mouse_move(x, y)
+#
+# inrect = self.is_in_rect(x, y)
+#
+# # we enter the rect
+# if not self.__inrect and inrect:
+# self.__inrect = True
+# self.mouse_enter(event, x, y)
+#
+# # we are leaving the rect
+# elif self.__inrect and not inrect:
+# self.__inrect = False
+# self.mouse_exit(event, x, y)
+#
+# return False
+#
+# elif event.value == 'PRESS' and (event.ascii != '' or event.type in self.get_input_keys()):
+# return self.text_input(event)
+#
+# return False
+
+BL_UI_Button.mouse_down_right = mouse_down_right
+BL_UI_Button.set_mouse_down_right = set_mouse_down_right
+# BL_UI_Button.handle_event = handle_event
+
+
+
+
+class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
+ bl_idname = "view3d.blenderkit_asset_bar_widget"
+ bl_label = "BlenderKit asset bar refresh"
+ bl_description = "BlenderKit asset bar refresh"
+ bl_options = {'REGISTER'}
+
+ do_search: BoolProperty(name="Run Search", description='', default=True, options={'SKIP_SAVE'})
+ keep_running: BoolProperty(name="Keep Running", description='', default=True, options={'SKIP_SAVE'})
+ free_only: BoolProperty(name="Free first", description='', default=False, options={'SKIP_SAVE'})
+
+ category: StringProperty(
+ name="Category",
+ description="search only subtree of this category",
+ default="", options={'SKIP_SAVE'})
+
+ tooltip: bpy.props.StringProperty(default='runs search and displays the asset bar at the same time')
+
+ @classmethod
+ def description(cls, context, properties):
+ return properties.tooltip
+
+ def new_text(self, text, x, y, width=100, height=15, text_size=None):
+ label = BL_UI_Label(x, y, width, height)
+ label.text = text
+ if text_size is None:
+ text_size = 14
+ label.text_size = text_size
+ label.text_color = self.text_color
+ return label
+
+ def init_tooltip(self):
+ self.tooltip_widgets = []
+ tooltip_size = 500
+ total_size = tooltip_size + 2 * self.assetbar_margin
+ self.tooltip_panel = BL_UI_Drag_Panel(0, 0, total_size, total_size)
+ self.tooltip_panel.bg_color = (0.0, 0.0, 0.0, 0.5)
+ self.tooltip_panel.visible = False
+
+ tooltip_image = BL_UI_Button(self.assetbar_margin, self.assetbar_margin, 1, 1)
+ tooltip_image.text = ""
+ img_path = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
+ tooltip_image.set_image(img_path)
+ tooltip_image.set_image_size((tooltip_size, tooltip_size))
+ tooltip_image.set_image_position((0, 0))
+ self.tooltip_image = tooltip_image
+ self.tooltip_widgets.append(tooltip_image)
+
+ bottom_panel_fraction = 0.1
+ labels_start = total_size * (1 - bottom_panel_fraction) - self.margin
+
+ dark_panel = BL_UI_Widget(0, labels_start, total_size, total_size * bottom_panel_fraction)
+ dark_panel.bg_color = (0.0, 0.0, 0.0, 0.7)
+ self.tooltip_widgets.append(dark_panel)
+
+ name_label = self.new_text('', self.assetbar_margin*2, labels_start, text_size=16)
+ self.asset_name = name_label
+ self.tooltip_widgets.append(name_label)
+ offset_y = 16 + self.margin
+ label = self.new_text('Left click or drag to append/link. Right click for more options.', self.assetbar_margin*2, labels_start + offset_y,
+ text_size=14)
+ self.tooltip_widgets.append(label)
+
+
+ self.hide_tooltip()
+
+ def hide_tooltip(self):
+ self.tooltip_panel.visible = False
+ for w in self.tooltip_widgets:
+ w.visible = False
+
+ def show_tooltip(self):
+ self.tooltip_panel.visible = True
+ for w in self.tooltip_widgets:
+ w.visible = True
+
+ def update_ui_size(self, context):
+
+ if bpy.app.background or not context.area:
+ return
+
+ region = context.region
+ area = context.area
+
+ ui_props = bpy.context.scene.blenderkitUI
+ user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
+ ui_scale = bpy.context.preferences.view.ui_scale
+
+ self.margin = ui_props.bl_rna.properties['margin'].default * ui_scale
+ self.margin = 3
+ self.assetbar_margin = self.margin
+
+ self.thumb_size = user_preferences.thumb_size * ui_scale
+ self.button_size = 2 * self.margin + self.thumb_size
+
+ reg_multiplier = 1
+ if not bpy.context.preferences.system.use_region_overlap:
+ reg_multiplier = 0
+
+ for r in area.regions:
+ if r.type == 'TOOLS':
+ self.bar_x = r.width * reg_multiplier + self.margin + ui_props.bar_x_offset * ui_scale
+ elif r.type == 'UI':
+ self.bar_end = r.width * reg_multiplier + 100 * ui_scale
+
+ self.bar_width = region.width - ui_props.bar_x - ui_props.bar_end
+
+ self.wcount = math.floor(
+ (self.bar_width) / (self.button_size))
+
+ search_results = bpy.context.scene.get('search results')
+ if search_results is not None and self.wcount > 0:
+ self.hcount = min(user_preferences.max_assetbar_rows, math.ceil(len(search_results) / self.wcount))
+ else:
+ self.hcount = 1
+
+ self.bar_height = (self.button_size) * self.hcount + 2 * self.assetbar_margin
+ # self.bar_y = region.height - ui_props.bar_y_offset * ui_scale
+ self.bar_y = ui_props.bar_y_offset * ui_scale
+ if ui_props.down_up == 'UPLOAD':
+ self.reports_y = self.bar_y - 600
+ self.reports_x = self.bar_x
+ else:
+ self.reports_y = self.bar_y - self.bar_height - 100
+ self.reports_x = self.bar_x
+
+ def __init__(self):
+ super().__init__()
+
+ self.update_ui_size(bpy.context)
+
+ ui_props = bpy.context.scene.blenderkitUI
+
+ # todo move all this to update UI size
+
+ self.draw_tooltip = False
+ self.scroll_offset = 0
+
+ self.text_color = (0.9, 0.9, 0.9, 1.0)
+ button_bg_color = (0.2, 0.2, 0.2, .1)
+ button_hover_color = (0.8, 0.8, 0.8, .2)
+
+ self.init_tooltip()
+
+ self.buttons = []
+ self.asset_buttons = []
+ self.validation_icons = []
+ self.widgets_panel = []
+
+ self.panel = BL_UI_Drag_Panel(0, 0, self.bar_width, self.bar_height)
+ self.panel.bg_color = (0.0, 0.0, 0.0, 0.5)
+
+ sr = bpy.context.scene['search results']
+
+ for a in range(0, self.wcount):
+ for b in range(0, self.hcount):
+ asset_x = self.assetbar_margin + a * (self.button_size)
+ asset_y = self.assetbar_margin + b * (self.button_size)
+ new_button = BL_UI_Button(asset_x, asset_y, self.button_size, self.button_size)
+
+ asset_idx = a + b * self.wcount + self.scroll_offset
+ # asset_data = sr[asset_idx]
+ # iname = blenderkit.utils.previmg_name(asset_idx)
+ # img = bpy.data.images.get(iname)
+
+ new_button.bg_color = button_bg_color
+ new_button.hover_bg_color = button_hover_color
+ new_button.text = "" # asset_data['name']
+ # if img:
+ # new_button.set_image(img.filepath)
+
+ new_button.set_image_size((self.thumb_size, self.thumb_size))
+ new_button.set_image_position((self.margin, self.margin))
+ new_button.button_index = asset_idx
+ new_button.search_index = asset_idx
+ new_button.set_mouse_down(self.drag_drop_asset)
+ new_button.set_mouse_down_right(self.asset_menu)
+ new_button.set_mouse_enter(self.enter_button)
+ new_button.set_mouse_exit(self.exit_button)
+ new_button.text_input = self.handle_key_input
+ self.asset_buttons.append(new_button)
+ # add validation icon to button
+ icon_size = 24
+ validation_icon = BL_UI_Button(asset_x + self.button_size - icon_size - self.margin,
+ asset_y + self.button_size - icon_size - self.margin, 0, 0)
+
+ # v_icon = ui.verification_icons[asset_data.get('verificationStatus', 'validated')]
+ # if v_icon is not None:
+ # img_fp = paths.get_addon_thumbnail_path(v_icon)
+ # validation_icon.set_image(img_fp)
+ validation_icon.text = ''
+ validation_icon.set_image_size((icon_size, icon_size))
+ validation_icon.set_image_position((0, 0))
+ self.validation_icons.append(validation_icon)
+ new_button.validation_icon = validation_icon
+
+ other_button_size = 30
+
+ self.button_close = BL_UI_Button(self.bar_width - other_button_size, -0, other_button_size, 15)
+ self.button_close.bg_color = button_bg_color
+ self.button_close.hover_bg_color = button_hover_color
+ self.button_close.text = "x"
+ self.button_close.set_mouse_down(self.cancel_press)
+
+ self.widgets_panel.append(self.button_close)
+ scroll_width = 30
+ self.button_scroll_down = BL_UI_Button(-scroll_width, 0, scroll_width, self.bar_height)
+ self.button_scroll_down.bg_color = button_bg_color
+ self.button_scroll_down.hover_bg_color = button_hover_color
+ self.button_scroll_down.text = ""
+ self.button_scroll_down.set_image(paths.get_addon_thumbnail_path('arrow_left.png'))
+ self.button_scroll_down.set_image_size((scroll_width, self.button_size))
+ self.button_scroll_down.set_image_position((0, int((self.bar_height - self.button_size) / 2)))
+
+ self.button_scroll_down.set_mouse_down(self.scroll_down)
+
+ self.widgets_panel.append(self.button_scroll_down)
+
+ self.button_scroll_up = BL_UI_Button(self.bar_width, 0, scroll_width, self.bar_height)
+ self.button_scroll_up.bg_color = button_bg_color
+ self.button_scroll_up.hover_bg_color = button_hover_color
+ self.button_scroll_up.text = ""
+ self.button_scroll_up.set_image(paths.get_addon_thumbnail_path('arrow_right.png'))
+ self.button_scroll_up.set_image_size((scroll_width, self.button_size))
+ self.button_scroll_up.set_image_position((0, int((self.bar_height - self.button_size) / 2)))
+
+ self.button_scroll_up.set_mouse_down(self.scroll_up)
+
+ self.widgets_panel.append(self.button_scroll_up)
+
+ self.update_images()
+
+ def on_invoke(self, context, event):
+
+
+ if self.do_search:
+ #TODO: move the search behaviour to separate operator, since asset bar can be already woken up from a timer.
+
+ # we erase search keywords for cateogry search now, since these combinations usually return nothing now.
+ # when the db gets bigger, this can be deleted.
+ if self.category != '':
+ sprops = utils.get_search_props()
+ sprops.search_keywords = ''
+ search.search(category=self.category)
+
+ ui_props = context.scene.blenderkitUI
+ if ui_props.assetbar_on:
+ #TODO solve this otehrwise to enable more asset bars?
+
+ # we don't want to run the assetbar many times, that's why it has a switch on/off behaviour,
+ # unless being called with 'keep_running' prop.
+ if not self.keep_running:
+ # this sends message to the originally running operator, so it quits, and then it ends this one too.
+ # If it initiated a search, the search will finish in a thread. The switch off procedure is run
+ # by the 'original' operator, since if we get here, it means
+ # same operator is already running.
+ ui_props.turn_off = True
+ # if there was an error, we need to turn off these props so we can restart after 2 clicks
+ ui_props.assetbar_on = False
+
+ else:
+ pass
+ return False
+
+ ui_props.assetbar_on = True
+
+ self.active_index = -1
+
+ widgets_panel = self.widgets_panel
+ widgets_panel.extend(self.buttons)
+ widgets_panel.extend(self.asset_buttons)
+ widgets_panel.extend(self.validation_icons)
+
+ widgets = [self.panel]
+
+ widgets += widgets_panel
+ widgets.append(self.tooltip_panel)
+ widgets += self.tooltip_widgets
+
+ self.init_widgets(context, widgets)
+
+ self.panel.add_widgets(widgets_panel)
+ self.tooltip_panel.add_widgets(self.tooltip_widgets)
+
+ # Open the panel at the mouse location
+ # self.panel.set_location(bpy.context.area.width - event.mouse_x,
+ # bpy.context.area.height - event.mouse_y + 20)
+ self.panel.set_location(self.bar_x,
+ self.bar_y)
+
+ self.context = context
+ args = (self, context)
+
+ # self._handle_2d_tooltip = bpy.types.SpaceView3D.draw_handler_add(draw_callback_tooltip, args, 'WINDOW', 'POST_PIXEL')
+ return True
+
+ def on_finish(self, context):
+ # redraw all areas, since otherwise it stays to hang for some more time.
+ # bpy.types.SpaceView3D.draw_handler_remove(self._handle_2d_tooltip, 'WINDOW')
+
+ scene = bpy.context.scene
+ ui_props = scene.blenderkitUI
+ ui_props.assetbar_on = False
+
+ wm = bpy.data.window_managers[0]
+
+ for w in wm.windows:
+ for a in w.screen.areas:
+ a.tag_redraw()
+
+ self._finished = True
+
+ # handlers
+
+ def enter_button(self, widget):
+ self.show_tooltip()
+
+ if self.active_index != widget.search_index:
+ scene = bpy.context.scene
+ sr = scene['search results']
+ asset_data = sr[widget.search_index + self.scroll_offset]
+
+ self.active_index = widget.search_index
+ self.draw_tooltip = True
+ self.tooltip = asset_data['tooltip']
+ ui_props = scene.blenderkitUI
+ ui_props.active_index = widget.search_index +self.scroll_offset
+
+ img = ui.get_large_thumbnail_image(asset_data)
+ if img:
+ self.tooltip_image.set_image(img.filepath)
+ self.asset_name.text = asset_data['name']
+ self.tooltip_panel.update(widget.x_screen + widget.width, widget.y_screen + widget.height)
+ self.tooltip_panel.layout_widgets()
+
+ def exit_button(self, widget):
+ # this condition checks if there wasn't another button already entered, which can happen with small button gaps
+ if self.active_index == widget.search_index:
+ scene = bpy.context.scene
+ ui_props = scene.blenderkitUI
+ ui_props.draw_tooltip = False
+ self.draw_tooltip = False
+ self.hide_tooltip()
+
+ def drag_drop_asset(self, widget):
+ bpy.ops.view3d.asset_drag_drop('INVOKE_DEFAULT', asset_search_index=widget.search_index + self.scroll_offset)
+
+ def cancel_press(self, widget):
+ self.finish()
+
+ def asset_menu(self, widget):
+ bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
+ # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
+
+ def search_more(self):
+ sro = bpy.context.scene.get('search results orig')
+ if sro is not None and sro.get('next') is not None:
+ blenderkit.search.search(get_next=True)
+ def update_images(self):
+ sr = bpy.context.scene['search results']
+
+ for asset_button in self.asset_buttons:
+ asset_button.asset_index = asset_button.button_index + self.scroll_offset
+ if asset_button.asset_index < len(sr):
+ asset_button.visible = True
+
+ asset_data = sr[asset_button.asset_index]
+
+ iname = blenderkit.utils.previmg_name(asset_button.asset_index)
+ # show indices for debug purposes
+ # asset_button.text = str(asset_button.asset_index)
+ img = bpy.data.images.get(iname)
+ if not img:
+ img_filepath = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
+ else:
+ img_filepath = img.filepath
+ asset_button.set_image(img_filepath)
+ v_icon = ui.verification_icons[asset_data.get('verificationStatus', 'validated')]
+ if v_icon is not None:
+ img_fp = paths.get_addon_thumbnail_path(v_icon)
+ asset_button.validation_icon.set_image(img_fp)
+ asset_button.validation_icon.visible = True
+ else:
+ asset_button.validation_icon.visible = False
+ else:
+ asset_button.visible = False
+ asset_button.validation_icon.visible = False
+
+ def scroll_update(self):
+ sr = bpy.context.scene['search results']
+ self.scroll_offset = min(self.scroll_offset, len(sr) - (self.wcount * self.hcount))
+ self.scroll_offset = max(self.scroll_offset, 0)
+ self.update_images()
+ if len(sr) - self.scroll_offset < (self.wcount * self.hcount) + 10:
+ self.search_more()
+
+ def search_by_author(self, asset_index):
+ sr = bpy.context.scene['search results']
+ asset_data = sr[asset_index]
+ a = asset_data['author']['id']
+ if a is not None:
+ sprops = utils.get_search_props()
+ sprops.search_keywords = ''
+ sprops.search_verification_status = 'ALL'
+ utils.p('author:', a)
+ search.search(author_id=a)
+ return True
+
+ def handle_key_input(self, event):
+ if event.type == 'A':
+ self.search_by_author(self.active_index + self.scroll_offset)
+ return False
+
+ def scroll_up(self, widget):
+ sr = bpy.context.scene['search results']
+ self.scroll_offset += self.wcount * self.hcount
+ self.scroll_update()
+
+ def scroll_down(self, widget):
+ sr = bpy.context.scene['search results']
+ self.scroll_offset -= self.wcount * self.hcount
+ self.scroll_update()
+
+
+def register():
+ bpy.utils.register_class(BlenderKitAssetBarOperator)
+
+
+def unregister():
+ bpy.utils.unregister_class(BlenderKitAssetBarOperator)