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:
parent
ebdf1861dc
commit
e237c47811
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
299
blenderkit/ui.py
299
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,
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue