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.
This commit is contained in:
Vilém Duha 2021-01-17 13:35:23 +01:00
parent ebdf1861dc
commit e237c47811
14 changed files with 1620 additions and 85 deletions

View File

@ -34,6 +34,7 @@ if "bpy" in locals():
# modules with _bg are used for background computations in separate blender instance and that's why they don't need reload.
append_link = reload(append_link)
asset_bar_op = reload(asset_bar_op)
asset_inspector = reload(asset_inspector)
autothumb = reload(autothumb)
bg_blender = reload(bg_blender)
@ -55,8 +56,19 @@ if "bpy" in locals():
ui_panels = reload(ui_panels)
upload = reload(upload)
utils = reload(utils)
bl_ui_label = reload(bl_ui_label)
bl_ui_button = reload(bl_ui_button)
# bl_ui_checkbox = reload(bl_ui_checkbox)
# bl_ui_slider = reload(bl_ui_slider)
# bl_ui_up_down = reload(bl_ui_up_down)
bl_ui_drag_panel = reload(bl_ui_drag_panel)
bl_ui_draw_op = reload(bl_ui_draw_op)
# bl_ui_textbox = reload(bl_ui_textbox)
else:
from blenderkit import append_link
from blenderkit import asset_bar_op
from blenderkit import asset_inspector
from blenderkit import autothumb
from blenderkit import bg_blender
@ -79,6 +91,15 @@ else:
from blenderkit import upload
from blenderkit import utils
from blenderkit.bl_ui_widgets import bl_ui_label
from blenderkit.bl_ui_widgets import bl_ui_button
# from blenderkit.bl_ui_widgets import bl_ui_checkbox
# from blenderkit.bl_ui_widgets import bl_ui_slider
# from blenderkit.bl_ui_widgets import bl_ui_up_down
from blenderkit.bl_ui_widgets import bl_ui_drag_panel
from blenderkit.bl_ui_widgets import bl_ui_draw_op
# from blenderkit.bl_ui_widgets import bl_ui_textbox
import os
import math
@ -1787,6 +1808,7 @@ def register():
overrides.register_overrides()
bkit_oauth.register()
tasks_queue.register()
asset_bar_op.register()
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
if user_preferences.use_timers:
@ -1818,6 +1840,7 @@ def unregister():
overrides.unregister_overrides()
bkit_oauth.unregister()
tasks_queue.unregister()
asset_bar_op.unregister()
del bpy.types.Scene.blenderkit_models
del bpy.types.Scene.blenderkit_scene

591
blenderkit/asset_bar_op.py Normal file
View File

@ -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)

View File

@ -0,0 +1,36 @@
bl_info = {
"name": "BL UI Widgets",
"description": "UI Widgets to draw in the 3D view",
"author": "Jayanam",
"version": (0, 6, 4, 2),
"blender": (2, 80, 0),
"location": "View3D",
"category": "Object"}
# Blender imports
import bpy
from bpy.props import *
addon_keymaps = []
def register():
bpy.utils.register_class(DP_OT_draw_operator)
kcfg = bpy.context.window_manager.keyconfigs.addon
if kcfg:
km = kcfg.keymaps.new(name='3D View', space_type='VIEW_3D')
addon_keymaps.append((km, kmi))
def unregister():
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()
bpy.utils.unregister_class(DP_OT_draw_operator)
if __name__ == "__main__":
register()

View File

@ -0,0 +1,192 @@
from . bl_ui_widget import *
import blf
import bpy
class BL_UI_Button(BL_UI_Widget):
def __init__(self, x, y, width, height):
super().__init__(x, y, width, height)
self._text_color = (1.0, 1.0, 1.0, 1.0)
self._hover_bg_color = (0.5, 0.5, 0.5, 1.0)
self._select_bg_color = (0.7, 0.7, 0.7, 1.0)
self._text = "Button"
self._text_size = 16
self._textpos = (x, y)
self.__state = 0
self.__image = None
self.__image_size = (24, 24)
self.__image_position = (4, 2)
@property
def text_color(self):
return self._text_color
@text_color.setter
def text_color(self, value):
self._text_color = value
@property
def text(self):
return self._text
@text.setter
def text(self, value):
self._text = value
@property
def text_size(self):
return self._text_size
@text_size.setter
def text_size(self, value):
self._text_size = value
@property
def hover_bg_color(self):
return self._hover_bg_color
@hover_bg_color.setter
def hover_bg_color(self, value):
self._hover_bg_color = value
@property
def select_bg_color(self):
return self._select_bg_color
@select_bg_color.setter
def select_bg_color(self, value):
self._select_bg_color = value
def set_image_size(self, imgage_size):
self.__image_size = imgage_size
def set_image_position(self, image_position):
self.__image_position = image_position
def set_image(self, rel_filepath):
try:
self.__image = bpy.data.images.load(rel_filepath, check_existing=True)
self.__image.gl_load()
except:
pass
def update(self, x, y):
super().update(x, y)
self._textpos = [x, y]
def draw(self):
if not self.visible:
return
area_height = self.get_area_height()
self.shader.bind()
self.set_colors()
bgl.glEnable(bgl.GL_BLEND)
self.batch_panel.draw(self.shader)
self.draw_image()
bgl.glDisable(bgl.GL_BLEND)
# Draw text
self.draw_text(area_height)
def set_colors(self):
color = self._bg_color
text_color = self._text_color
# pressed
if self.__state == 1:
color = self._select_bg_color
# hover
elif self.__state == 2:
color = self._hover_bg_color
self.shader.uniform_float("color", color)
def draw_text(self, area_height):
blf.size(0, self._text_size, 72)
size = blf.dimensions(0, self._text)
textpos_y = area_height - self._textpos[1] - (self.height + size[1]) / 2.0
blf.position(0, self._textpos[0] + (self.width - size[0]) / 2.0, textpos_y + 1, 0)
r, g, b, a = self._text_color
blf.color(0, r, g, b, a)
blf.draw(0, self._text)
def draw_image(self):
if self.__image is not None:
try:
y_screen_flip = self.get_area_height() - self.y_screen
off_x, off_y = self.__image_position
sx, sy = self.__image_size
# bottom left, top left, top right, bottom right
vertices = (
(self.x_screen + off_x, y_screen_flip - off_y),
(self.x_screen + off_x, y_screen_flip - sy - off_y),
(self.x_screen + off_x + sx, y_screen_flip - sy - off_y),
(self.x_screen + off_x + sx, y_screen_flip - off_y))
self.shader_img = gpu.shader.from_builtin('2D_IMAGE')
self.batch_img = batch_for_shader(self.shader_img, 'TRI_FAN',
{ "pos" : vertices,
"texCoord": ((0, 1), (0, 0), (1, 0), (1, 1))
},)
# send image to gpu if it isn't there already
if self.__image.gl_load():
raise Exception()
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.__image.bindcode)
self.shader_img.bind()
self.shader_img.uniform_int("image", 0)
self.batch_img.draw(self.shader_img)
return True
except:
pass
return False
def set_mouse_down(self, mouse_down_func):
self.mouse_down_func = mouse_down_func
def mouse_down(self, x, y):
if self.is_in_rect(x,y):
self.__state = 1
try:
self.mouse_down_func(self)
except Exception as e:
print(e)
return True
return False
def mouse_move(self, x, y):
if self.is_in_rect(x,y):
if(self.__state != 1):
# hover state
self.__state = 2
else:
self.__state = 0
def mouse_up(self, x, y):
if self.is_in_rect(x,y):
self.__state = 2
else:
self.__state = 0

View File

@ -0,0 +1,58 @@
from . bl_ui_widget import *
class BL_UI_Drag_Panel(BL_UI_Widget):
def __init__(self, x, y, width, height):
super().__init__(x,y, width, height)
self.drag_offset_x = 0
self.drag_offset_y = 0
self.is_drag = False
self.widgets = []
def set_location(self, x, y):
super().set_location(x,y)
self.layout_widgets()
def add_widget(self, widget):
self.widgets.append(widget)
def add_widgets(self, widgets):
self.widgets = widgets
self.layout_widgets()
def layout_widgets(self):
for widget in self.widgets:
widget.update(self.x_screen + widget.x, self.y_screen + widget.y)
def update(self, x, y):
super().update(x - self.drag_offset_x, y + self.drag_offset_y)
def child_widget_focused(self, x, y):
for widget in self.widgets:
if widget.is_in_rect(x, y):
return True
return False
def mouse_down(self, x, y):
if self.child_widget_focused(x, y):
return False
if self.is_in_rect(x,y):
height = self.get_area_height()
self.is_drag = True
self.drag_offset_x = x - self.x_screen
self.drag_offset_y = y - (height - self.y_screen)
return True
return False
def mouse_move(self, x, y):
if self.is_drag:
height = self.get_area_height()
self.update(x, height - y)
self.layout_widgets()
def mouse_up(self, x, y):
self.is_drag = False
self.drag_offset_x = 0
self.drag_offset_y = 0

View File

@ -0,0 +1,83 @@
import bpy
from bpy.types import Operator
class BL_UI_OT_draw_operator(Operator):
bl_idname = "object.bl_ui_ot_draw_operator"
bl_label = "bl ui widgets operator"
bl_description = "Operator for bl ui widgets"
bl_options = {'REGISTER'}
def __init__(self):
self.draw_handle = None
self.draw_event = None
self._finished = False
self.widgets = []
def init_widgets(self, context, widgets):
self.widgets = widgets
for widget in self.widgets:
widget.init(context)
def on_invoke(self, context, event):
pass
def on_finish(self, context):
self._finished = True
def invoke(self, context, event):
self.on_invoke(context, event)
args = (self, context)
self.register_handlers(args, context)
context.window_manager.modal_handler_add(self)
return {"RUNNING_MODAL"}
def register_handlers(self, args, context):
self.draw_handle = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_px, args, "WINDOW", "POST_PIXEL")
self.draw_event = context.window_manager.event_timer_add(0.1, window=context.window)
def unregister_handlers(self, context):
context.window_manager.event_timer_remove(self.draw_event)
bpy.types.SpaceView3D.draw_handler_remove(self.draw_handle, "WINDOW")
self.draw_handle = None
self.draw_event = None
def handle_widget_events(self, event):
result = False
for widget in self.widgets:
if widget.handle_event(event):
result = True
return result
def modal(self, context, event):
if self._finished:
return {'FINISHED'}
if context.area:
context.area.tag_redraw()
if self.handle_widget_events(event):
return {'RUNNING_MODAL'}
if event.type in {"ESC"}:
self.finish()
return {"PASS_THROUGH"}
def finish(self):
self.unregister_handlers(bpy.context)
self.on_finish(bpy.context)
# Draw handler to paint onto the screen
def draw_callback_px(self, op, context):
for widget in self.widgets:
widget.draw()

View File

@ -0,0 +1,57 @@
from . bl_ui_widget import *
import blf
class BL_UI_Label(BL_UI_Widget):
def __init__(self, x, y, width, height):
super().__init__(x, y, width, height)
self._text_color = (1.0, 1.0, 1.0, 1.0)
self._text = "Label"
self._text_size = 16
@property
def text_color(self):
return self._text_color
@text_color.setter
def text_color(self, value):
self._text_color = value
@property
def text(self):
return self._text
@text.setter
def text(self, value):
self._text = value
@property
def text_size(self):
return self._text_size
@text_size.setter
def text_size(self, value):
self._text_size = value
def is_in_rect(self, x, y):
return False
def draw(self):
if not self.visible:
return
area_height = self.get_area_height()
blf.size(0, self._text_size, 72)
size = blf.dimensions(0, self._text)
textpos_y = area_height - self.y_screen - self.height
blf.position(0, self.x_screen, textpos_y, 0)
r, g, b, a = self._text_color
blf.color(0, r, g, b, a)
blf.draw(0, self._text)

View File

@ -0,0 +1,189 @@
import gpu
import bgl
from gpu_extras.batch import batch_for_shader
class BL_UI_Widget:
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.x_screen = x
self.y_screen = y
self.width = width
self.height = height
self._bg_color = (0.8, 0.8, 0.8, 1.0)
self._tag = None
self.context = None
self.__inrect = False
self._mouse_down = False
self._mouse_down_right = False
self._is_visible = True
def set_location(self, x, y):
self.x = x
self.y = y
self.x_screen = x
self.y_screen = y
self.update(x,y)
@property
def bg_color(self):
return self._bg_color
@bg_color.setter
def bg_color(self, value):
self._bg_color = value
@property
def visible(self):
return self._is_visible
@visible.setter
def visible(self, value):
self._is_visible = value
@property
def tag(self):
return self._tag
@tag.setter
def tag(self, value):
self._tag = value
def draw(self):
if not self.visible:
return
self.shader.bind()
self.shader.uniform_float("color", self._bg_color)
bgl.glEnable(bgl.GL_BLEND)
self.batch_panel.draw(self.shader)
bgl.glDisable(bgl.GL_BLEND)
def init(self, context):
self.context = context
self.update(self.x, self.y)
def update(self, x, y):
area_height = self.get_area_height()
self.x_screen = x
self.y_screen = y
indices = ((0, 1, 2), (0, 2, 3))
y_screen_flip = area_height - self.y_screen
# bottom left, top left, top right, bottom right
vertices = (
(self.x_screen, y_screen_flip),
(self.x_screen, y_screen_flip - self.height),
(self.x_screen + self.width, y_screen_flip - self.height),
(self.x_screen + self.width, y_screen_flip))
self.shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
self.batch_panel = batch_for_shader(self.shader, 'TRIS', {"pos" : vertices}, indices=indices)
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
def get_input_keys(self) :
return []
def get_area_height(self):
return self.context.area.height
def is_in_rect(self, x, y):
area_height = self.get_area_height()
widget_y = area_height - self.y_screen
if (
(self.x_screen <= x <= (self.x_screen + self.width)) and
(widget_y >= y >= (widget_y - self.height))
):
return True
return False
def text_input(self, event):
return False
def mouse_down(self, x, y):
return self.is_in_rect(x,y)
def mouse_down_right(self, x, y):
return self.is_in_rect(x,y)
def mouse_up(self, x, y):
pass
def set_mouse_enter(self, mouse_enter_func):
self.mouse_enter_func = mouse_enter_func
def call_mouse_enter(self):
try:
if self.mouse_enter_func:
self.mouse_enter_func(self)
except:
pass
def mouse_enter(self, event, x, y):
self.call_mouse_enter()
def set_mouse_exit(self, mouse_exit_func):
self.mouse_exit_func = mouse_exit_func
def call_mouse_exit(self):
try:
if self.mouse_exit_func:
self.mouse_exit_func(self)
except:
pass
def mouse_exit(self, event, x, y):
self.call_mouse_exit()
def mouse_move(self, x, y):
pass

View File

@ -18,6 +18,8 @@
# this module defines color palette for BlenderKit UI
WHITE = (1, 1, 1, .9)
TEXT = (.9, .9, .9, .6)
GREEN = (.9, 1, .9, .6)
RED = (1, .5, .5, .8)

View File

@ -27,6 +27,7 @@ icon_collections = {}
icons_read = {
'fp.png': 'free',
'flp.png': 'full',
'test.jpg': 'test',
}
@ -44,6 +45,11 @@ def register_icons():
for ir in icons_read.keys():
pcoll.load(icons_read[ir], os.path.join(icons_dir, ir), 'IMAGE')
# iprev = pcoll.new(icons_read[ir])
# img = bpy.data.images.load(os.path.join(icons_dir, ir))
# iprev.image_size = (img.size[0], img.size[1])
# iprev.image_pixels_float = img.pixels[:]
icon_collections["main"] = pcoll

View File

@ -16,8 +16,6 @@
#
# ##### END GPL LICENSE BLOCK #####
from blenderkit import paths, utils, categories, ui, colors, bkit_oauth, version_checker, tasks_queue, rerequests, \
resolutions
@ -51,6 +49,7 @@ import json
import math
import logging
bk_logger = logging.getLogger('blenderkit')
search_start_time = 0
@ -320,6 +319,7 @@ def timer_update():
global first_time
preferences = bpy.context.preferences.addons['blenderkit'].preferences
if first_time and not bpy.app.background: # first time
first_time = False
if preferences.show_on_start:
# TODO here it should check if there are some results, and only open assetbar if this is the case, not search.
@ -437,11 +437,14 @@ def load_previews():
if not r['thumbnail_small']:
tpath = paths.get_addon_thumbnail_path('thumbnail_not_available.jpg')
if not os.path.exists(tpath):
continue
iname = utils.previmg_name(i)
# if os.path.exists(tpath): # sometimes we are unlucky...
img = bpy.data.images.get(iname)
if img is None and os.path.exists(tpath):
if img is None:
img = bpy.data.images.load(tpath)
img.name = iname
elif img.filepath != tpath:
@ -897,7 +900,7 @@ class Searcher(threading.Thread):
# result ordering: _score - relevance, score - BlenderKit score
order = []
if params['free_first']:
order = ['-is_free',]
order = ['-is_free', ]
if query.get('query') is None and query.get('category_subtree') == None:
# assumes no keywords and no category, thus an empty search that is triggered on start.
# orders by last core file upload

View File

@ -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,

View File

@ -17,7 +17,7 @@
# ##### END GPL LICENSE BLOCK #####
from blenderkit import paths, ratings, utils, download, categories, icons, search, resolutions
from blenderkit import paths, ratings, utils, download, categories, icons, search, resolutions, ui
from bpy.types import (
Panel
@ -313,11 +313,19 @@ def draw_assetbar_show_hide(layout, props):
else:
icon = 'HIDE_ON'
ttip = 'Click to Show Asset Bar'
op = layout.operator('view3d.blenderkit_asset_bar', text='', icon=icon)
op.keep_running = False
op.do_search = False
op.tooltip = ttip
preferences = bpy.context.preferences.addons['blenderkit'].preferences
if preferences.experimental_features:
op = layout.operator('view3d.blenderkit_asset_bar_widget', text = '', icon = icon)
op.keep_running = False
op.do_search = False
op.tooltip = ttip
else:
op = layout.operator('view3d.blenderkit_asset_bar', text='', icon=icon)
op.keep_running = False
op.do_search = False
op.tooltip = ttip
def draw_panel_model_search(self, context):
@ -403,7 +411,7 @@ class VIEW3D_PT_blenderkit_model_properties(Panel):
draw_panel_model_rating(self, context)
layout.label(text='Asset tools:')
draw_asset_context_menu(self, context, ad, from_panel=True)
draw_asset_context_menu(self.layout, context, ad, from_panel=True)
# if 'rig' in ad['tags']:
# # layout.label(text = 'can make proxy')
# layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy')
@ -447,7 +455,7 @@ class NODE_PT_blenderkit_material_properties(Panel):
draw_panel_material_ratings(self, context)
layout.label(text='Asset tools:')
draw_asset_context_menu(self, context, ad, from_panel=True)
draw_asset_context_menu(self.layout, context, ad, from_panel=True)
# if 'rig' in ad['tags']:
# # layout.label(text = 'can make proxy')
# layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy')
@ -934,7 +942,6 @@ class VIEW3D_PT_blenderkit_unified(Panel):
user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
wm = bpy.context.window_manager
layout = self.layout
# layout.prop_tabs_enum(ui_props, "asset_type", icon_only = True)
row = layout.row()
@ -1122,8 +1129,7 @@ class BlenderKitWelcomeOperator(bpy.types.Operator):
return wm.invoke_props_dialog(self)
def draw_asset_context_menu(self, context, asset_data, from_panel=False):
layout = self.layout
def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
ui_props = context.scene.blenderkitUI
author_id = str(asset_data['author'].get('id'))
@ -1269,7 +1275,7 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False):
op.asset_id = asset_data['id']
op.state = 'rejected'
if author_id == str(profile['user']['id']):
if author_id == str(profile['user']['id']) or utils.profile_is_validator():
layout.label(text='Management tools:')
row = layout.row()
@ -1277,6 +1283,7 @@ def draw_asset_context_menu(self, context, asset_data, from_panel=False):
op = layout.operator('wm.blenderkit_fast_metadata', text='Fast Edit Metadata')
op.asset_id = asset_data['id']
if author_id == str(profile['user']['id']):
row = layout.row()
row.operator_context = 'INVOKE_DEFAULT'
op = row.operator('object.blenderkit_change_status', text='Delete')
@ -1342,12 +1349,101 @@ class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu):
def draw(self, context):
ui_props = context.scene.blenderkitUI
# sr = bpy.context.scene['search results']
sr = bpy.context.scene['search results']
asset_data = sr[ui_props.active_index]
draw_asset_context_menu(self.layout, context, asset_data, from_panel=False)
draw_asset_context_menu(self, context, asset_data, from_panel=False)
# ui_props = context.scene.blenderkitUI
#
# sr = bpy.context.scene['search results']
# asset_data = sr[ui_props.active_index]
# layout = self.layout
# row = layout.row()
# split = row.split(factor=0.2)
# col = split.column()
# op = col.operator('view3d.asset_drag_drop')
# op.asset_search_index=ui_props.active_index
#
# draw_asset_context_menu(col, context, asset_data, from_panel=False)
# split = split.split(factor=0.3)
# col1 = split.column()
# box = col1.box()
# utils.label_multiline(box, asset_data['tooltip'])
# col2 = split.column()
#
# pcoll = icons.icon_collections["main"]
# my_icon = pcoll['test']
# row = col2.row()
# row.scale_y = 4
# row.template_icon(icon_value=my_icon.icon_id, scale=2.0)
# # col2.template_icon(icon_value=self.img.preview.icon_id, scale=10.0)
# box2 = col2.box()
#
# box2.label(text='and heere goes the rating')
# box2.label(text='************')
# box2.label(text='dadydadadada')
class AssetPopupCard(bpy.types.Operator):
"""Generate Cycles thumbnail for model assets"""
bl_idname = "wm.blenderkit_asset_popup"
bl_label = "BlenderKit asset popup"
# bl_options = {'REGISTER', 'INTERNAL'}
bl_options = {'REGISTER',}
@classmethod
def poll(cls, context):
return True
def draw(self, context):
ui_props = context.scene.blenderkitUI
sr = bpy.context.scene['search results']
asset_data = sr[ui_props.active_index]
layout = self.layout
row = layout.row()
split = row.split(factor=0.2)
col = split.column()
op = col.operator('view3d.asset_drag_drop')
op.asset_search_index = ui_props.active_index
draw_asset_context_menu(col, context, asset_data, from_panel=False)
split = split.split(factor=0.5)
col1 = split.column()
box = col1.box()
utils.label_multiline(box,asset_data['tooltip'], width = 300)
col2 = split.column()
pcoll = icons.icon_collections["main"]
my_icon = pcoll['test']
col2.template_icon(icon_value=my_icon.icon_id, scale=20.0)
# col2.template_icon(icon_value=self.img.preview.icon_id, scale=10.0)
box2 = col2.box()
# draw_ratings(box2, context, asset_data)
box2.label(text = 'Ratings')
# print(tp, dir(tp))
# if not hasattr(self, 'first_draw'):# try to redraw because of template preview which needs update
# for region in context.area.regions:
# region.tag_redraw()
# self.first_draw = True
def execute(self, context):
print('execute')
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
ui_props = context.scene.blenderkitUI
ui_props.draw_tooltip = False
sr = bpy.context.scene['search results']
asset_data = sr[ui_props.active_index]
self.img = ui.get_large_thumbnail_image(asset_data)
# self.tex = utils.get_hidden_texture(self.img)
# self.tex.update_tag()
bl_label = asset_data['name']
return wm.invoke_props_dialog(self, width = 700)
class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu):
bl_label = "BlenderKit login/signup:"
@ -1435,8 +1531,8 @@ class UrlPopupDialog(bpy.types.Operator):
class LoginPopupDialog(bpy.types.Operator):
"""Generate Cycles thumbnail for model assets"""
bl_idname = "wm.blenderkit_url_dialog"
"""Popup a dialog which enables the user to log in after being logged out automatically."""
bl_idname = "wm.blenderkit_login_dialog"
bl_label = "BlenderKit login"
bl_options = {'REGISTER', 'INTERNAL'}
@ -1502,10 +1598,15 @@ def draw_panel_categories(self, context):
row = row.split(factor=.8, align=True)
# row = split.split()
ctext = '%s (%i)' % (c['name'], c['assetCount'])
op = row.operator('view3d.blenderkit_asset_bar', text=ctext)
op.do_search = True
op.keep_running = True
op.category = c['slug']
preferences = bpy.context.preferences.addons['blenderkit'].preferences
if preferences.experimental_features:
op = row.operator('view3d.blenderkit_asset_bar_widget', text=ctext)
else:
op = row.operator('view3d.blenderkit_asset_bar', text=ctext)
op.do_search = True
op.keep_running = True
op.category = c['slug']
# TODO enable subcategories, now not working due to some bug on server probably
if len(c['children']) > 0 and c['assetCount'] > 15:
# row = row.split()
@ -1602,6 +1703,7 @@ classes = (
# OBJECT_MT_blenderkit_resolution_menu,
OBJECT_MT_blenderkit_asset_menu,
OBJECT_MT_blenderkit_login_menu,
AssetPopupCard,
UrlPopupDialog,
BlenderKitWelcomeOperator,
)

View File

@ -39,6 +39,10 @@ NORMAL_PRIORITY_CLASS = 0x00000020
REALTIME_PRIORITY_CLASS = 0x00000100
def experimental_enabled():
preferences = bpy.context.preferences.addons['blenderkit'].preferences
return preferences.experimental_features
def get_process_flags():
flags = BELOW_NORMAL_PRIORITY_CLASS
if sys.platform != 'win32': # TODO test this on windows
@ -299,14 +303,14 @@ def uploadable_asset_poll():
return ui_props.hdr_upload_image is not None
return True
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)
def get_hidden_texture(img, force_reload=False):
# i = get_hidden_image(tpath, bdata_name, force_reload=force_reload)
# bdata_name = f".{bdata_name}"
t = bpy.data.textures.get(img.name)
if t is None:
t = bpy.data.textures.new('.test', 'IMAGE')
if t.image != i:
t.image = i
t = bpy.data.textures.new(img.name, 'IMAGE')
if t.image != img:
t.image = img
return t