399 lines
13 KiB
Python
399 lines
13 KiB
Python
# ##### BEGIN GPL LICENSE BLOCK #####
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
import logging
|
|
import time
|
|
|
|
import bpy
|
|
from bpy.props import StringProperty
|
|
from bpy.types import Gizmo, GizmoGroup, Operator
|
|
from mathutils import Matrix
|
|
|
|
from . import (
|
|
client_lib,
|
|
datas,
|
|
global_vars,
|
|
icons,
|
|
ratings_utils,
|
|
search,
|
|
ui,
|
|
ui_panels,
|
|
utils,
|
|
)
|
|
|
|
|
|
bk_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_assets_for_rating():
|
|
"""Get assets from scene that could/should be rated by the user. TODO: this is only a draft"""
|
|
assets = []
|
|
for ob in bpy.context.scene.objects:
|
|
if should_be_rated(ob):
|
|
assets.append(ob)
|
|
for m in bpy.data.materials:
|
|
if m.get("asset_data"):
|
|
assets.append(m)
|
|
for b in bpy.data.brushes:
|
|
if b.get("asset_data"):
|
|
assets.append(b)
|
|
return assets
|
|
|
|
|
|
asset_types = (
|
|
("MODEL", "Model", "set of objects"),
|
|
("PRINTABLE", "Printable", "3D printable model"),
|
|
("SCENE", "Scene", "scene"),
|
|
("HDR", "HDR", "hdr"),
|
|
("MATERIAL", "Material", "any .blend Material"),
|
|
("TEXTURE", "Texture", "a texture, or texture set"),
|
|
("BRUSH", "Brush", "brush, can be any type of blender brush"),
|
|
("ADDON", "Addon", "addnon"),
|
|
)
|
|
|
|
|
|
def draw_ratings_menu(self, context, layout):
|
|
pcoll = icons.icon_collections["main"]
|
|
|
|
if not utils.user_logged_in():
|
|
user_preferences = bpy.context.preferences.addons[__package__].preferences
|
|
if user_preferences.login_attempt:
|
|
ui_panels.draw_login_progress(layout)
|
|
else:
|
|
layout.operator_context = "EXEC_DEFAULT"
|
|
layout.operator(
|
|
"wm.blenderkit_login",
|
|
text="Login to Rate and Comment assets",
|
|
icon="URL",
|
|
).signup = False
|
|
return
|
|
|
|
col = layout.column()
|
|
# layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0)
|
|
row = col.row()
|
|
|
|
if self.asset_data.get("canDownload") is not True:
|
|
row.label(text="Asset in Full Plan. Subscribe to rate it.", icon="SOLO_ON")
|
|
return
|
|
|
|
profile_name = ""
|
|
profile = global_vars.BKIT_PROFILE
|
|
if profile and len(profile.firstName) > 0:
|
|
profile_name = " " + profile.firstName
|
|
|
|
row.label(text="Rate Quality:", icon="SOLO_ON")
|
|
# row = col.row()
|
|
# row.label(text='Please help the community by rating quality:')
|
|
|
|
row = col.row()
|
|
row.prop(self, "rating_quality_ui", expand=True, icon_only=True, emboss=False)
|
|
if self.rating_quality > 0:
|
|
row.label(text=f" Thanks{profile_name}!", icon="FUND")
|
|
|
|
col.separator()
|
|
col.separator()
|
|
|
|
row = col.row()
|
|
row.label(text="Rate Complexity:", icon_value=pcoll["dumbbell"].icon_id)
|
|
row = col.row()
|
|
row.label(text=f"How many hours did this {self.asset_type} save you?")
|
|
|
|
if utils.profile_is_validator():
|
|
row = col.row()
|
|
row.prop(self, "rating_work_hours")
|
|
|
|
row = col.row()
|
|
|
|
row.prop(self, "rating_work_hours_ui", expand=True, icon_only=False, emboss=True)
|
|
if self.rating_work_hours > 100:
|
|
utils.label_multiline(
|
|
col,
|
|
text=f"\nThat's huge! please be sure to give such rating only to godly {self.asset_type}s.\n",
|
|
width=300,
|
|
)
|
|
elif float(self.rating_work_hours) > 18:
|
|
col.separator()
|
|
utils.label_multiline(
|
|
col,
|
|
text=f"\nThat's a lot! please be sure to give such rating only to amazing {self.asset_type}s.\n",
|
|
width=300,
|
|
)
|
|
|
|
if self.rating_work_hours > 0:
|
|
row = col.row()
|
|
row.label(text=f"Thanks{profile_name}, you are amazing!", icon="FUND")
|
|
|
|
|
|
class FastRateMenu(Operator, ratings_utils.RatingProperties):
|
|
"""Rating of the assets, also directly from the asset bar - without need to download assets"""
|
|
|
|
bl_idname = "wm.blenderkit_menu_rating_upload"
|
|
bl_label = "Ratings"
|
|
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
def draw(self, context):
|
|
# when rating gets recieved while the window is already open, we need to prefill.
|
|
self.prefill_ratings()
|
|
|
|
layout = self.layout
|
|
layout.label(text=f"Rating of the {self.asset_type}: {self.asset_data['name']}")
|
|
draw_ratings_menu(self, context, layout)
|
|
layout.template_icon(icon_value=self.img.preview.icon_id, scale=12)
|
|
|
|
def execute(self, context):
|
|
ui_props = bpy.context.window_manager.blenderkitUI
|
|
# get asset id
|
|
if ui_props.active_index > -1:
|
|
sr = search.get_search_results()
|
|
self.asset_data = dict(sr[ui_props.active_index])
|
|
self.asset_id = self.asset_data["id"]
|
|
self.asset_type = self.asset_data["assetType"]
|
|
else:
|
|
if bpy.context.view_layer.objects.active is not None:
|
|
ob = utils.get_active_model()
|
|
ad = ob.get("asset_data")
|
|
if ad:
|
|
self.asset_data = ad
|
|
self.asset_id = self.asset_data["id"]
|
|
self.asset_type = self.asset_data["assetType"]
|
|
self.asset = ob
|
|
if self.asset_id == "":
|
|
return {"CANCELLED"}
|
|
|
|
wm = context.window_manager
|
|
|
|
self.img = ui.get_large_thumbnail_image(self.asset_data)
|
|
utils.img_to_preview(self.img, copy_original=True)
|
|
|
|
ratings_utils.ensure_rating(self.asset_id)
|
|
self.prefill_ratings()
|
|
|
|
# Update last popup activity time to prevent shortcut interference
|
|
from . import ui_panels
|
|
|
|
ui_panels.last_time_dropdown_active = time.time()
|
|
|
|
if self.asset_type in ("model", "scene"):
|
|
# spawn a wider one for validators for the enum buttons
|
|
return wm.invoke_popup(self, width=400)
|
|
else:
|
|
return wm.invoke_popup(self, width=250)
|
|
|
|
|
|
class SetBookmark(bpy.types.Operator):
|
|
"""Add or remove bookmarking of the asset.\nShortcut: hover over asset in the asset bar and press 'B'."""
|
|
|
|
bl_idname = "wm.blenderkit_bookmark_asset"
|
|
bl_label = "BlenderKit bookmark assets"
|
|
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
|
|
|
|
asset_id: StringProperty( # type: ignore[valid-type]
|
|
name="Asset Base Id",
|
|
description="Unique id of the asset (hidden)",
|
|
default="",
|
|
options={"SKIP_SAVE"},
|
|
)
|
|
|
|
# bookmark: bpy.props.BoolProperty(
|
|
# name="bookmark",
|
|
# description="Pass current state of bookmark, gets inverted",
|
|
# default=True)
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
def execute(self, context):
|
|
rating = ratings_utils.get_rating_local(self.asset_id)
|
|
if rating is None:
|
|
rating = datas.AssetRating()
|
|
if rating.bookmarks == 1:
|
|
bookmark_value = 0
|
|
else:
|
|
bookmark_value = 1
|
|
ratings_utils.store_rating_local(
|
|
self.asset_id, rating_type="bookmarks", value=bookmark_value
|
|
)
|
|
client_lib.send_rating(self.asset_id, "bookmarks", str(bookmark_value))
|
|
return {"FINISHED"}
|
|
|
|
|
|
## NOT USED ANYMORE
|
|
# def rating_menu_draw(self, context):
|
|
# layout = self.layout
|
|
|
|
# ui_props = context.window_manager.blenderkitUI
|
|
# sr = search.get_search_results()
|
|
|
|
# asset_search_index = ui_props.active_index
|
|
# if asset_search_index > -1:
|
|
# asset_data = dict(sr["results"][asset_search_index])
|
|
|
|
# col = layout.column()
|
|
# layout.label(text="Admin rating Tools:")
|
|
# col.operator_context = "INVOKE_DEFAULT"
|
|
|
|
# op = col.operator("wm.blenderkit_menu_rating_upload", text="Add Rating")
|
|
# op.asset_id = asset_data["id"]
|
|
# op.asset_name = asset_data["name"]
|
|
# op.asset_type = asset_data["assetType"]
|
|
|
|
|
|
# Coordinates (each one is a triangle).
|
|
custom_shape_verts = (
|
|
(0.1896940916776657, 0.2608509361743927, 0.0),
|
|
(0.2438376545906067, 0.09421423077583313, 0.0),
|
|
(0.2979812026023865, 0.2608509361743927, 0.0),
|
|
(0.1896940916776657, 0.2608509361743927, 0.0),
|
|
(0.052547797560691833, 0.2484826147556305, 0.0),
|
|
(0.15623150765895844, 0.1578637957572937, 0.0),
|
|
(0.15623150765895844, 0.1578637957572937, 0.0),
|
|
(0.12561391294002533, 0.023607879877090454, 0.0),
|
|
(0.2438376545906067, 0.09421423077583313, 0.0),
|
|
(0.2438376545906067, 0.09421423077583313, 0.0),
|
|
(0.36206138134002686, 0.023607879877090454, 0.0),
|
|
(0.33144378662109375, 0.1578637957572937, 0.0),
|
|
(0.33144378662109375, 0.1578637957572937, 0.0),
|
|
(0.4351276159286499, 0.2484826147556305, 0.0),
|
|
(0.2979812026023865, 0.2608509361743927, 0.0),
|
|
(0.2979812026023865, 0.2608509361743927, 0.0),
|
|
(0.2438376396894455, 0.3874630033969879, 0.0),
|
|
(0.1896940916776657, 0.2608509361743927, 0.0),
|
|
(0.1896940916776657, 0.2608509361743927, 0.0),
|
|
(0.15623150765895844, 0.1578637957572937, 0.0),
|
|
(0.2438376545906067, 0.09421423077583313, 0.0),
|
|
(0.2438376545906067, 0.09421423077583313, 0.0),
|
|
(0.33144378662109375, 0.1578637957572937, 0.0),
|
|
(0.2979812026023865, 0.2608509361743927, 0.0),
|
|
)
|
|
|
|
|
|
class RatingStarWidget(Gizmo):
|
|
bl_idname = "VIEW3D_GT_custom_shape_widget"
|
|
__slots__ = (
|
|
"custom_shape",
|
|
"init_mouse_y",
|
|
"init_value",
|
|
)
|
|
|
|
def _update_draw_matrix(self):
|
|
R = bpy.context.region_data.view_rotation.to_matrix().to_4x4()
|
|
loc, _, scale = self.matrix_basis.decompose()
|
|
self.matrix_basis = Matrix.Translation(loc) @ R @ Matrix.Diagonal(scale.to_4d())
|
|
|
|
def draw(self, context):
|
|
self._update_draw_matrix()
|
|
self.draw_custom_shape(self.custom_shape)
|
|
|
|
def draw_select(self, context, select_id):
|
|
self._update_draw_matrix()
|
|
self.draw_custom_shape(self.custom_shape, select_id=select_id)
|
|
|
|
def setup(self):
|
|
if not hasattr(self, "custom_shape"):
|
|
self.custom_shape = self.new_custom_shape("TRIS", custom_shape_verts)
|
|
|
|
def invoke(self, context, event):
|
|
return {"RUNNING_MODAL"}
|
|
|
|
def exit(self, context, cancel):
|
|
pass
|
|
|
|
def modal(self, context, event, tweak):
|
|
return {"FINISHED"}
|
|
|
|
|
|
def should_be_rated(ob) -> bool:
|
|
ad = ob.get("asset_data")
|
|
if ad is None:
|
|
return False
|
|
rating = ratings_utils.get_rating_local(ad["id"])
|
|
if rating is None:
|
|
# is None would work too, but would show rating option and then hide it when the assets are already rated
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
class RatingStarWidgetGroup(GizmoGroup):
|
|
bl_idname = "OBJECT_GGT_light_test"
|
|
bl_label = "Test Light Widget"
|
|
bl_space_type = "VIEW_3D"
|
|
bl_region_type = "WINDOW"
|
|
bl_options = {"3D", "PERSISTENT"}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
if not utils.profile_is_validator():
|
|
return False
|
|
if bpy.context.view_layer.objects.active is not None:
|
|
ob = utils.get_active_model()
|
|
return should_be_rated(ob)
|
|
return False
|
|
|
|
def setup(self, context):
|
|
ob = utils.get_active_model()
|
|
gz = self.gizmos.new(RatingStarWidget.bl_idname)
|
|
props = gz.target_set_operator("wm.blenderkit_menu_rating_upload")
|
|
props.asset_id = ob["asset_data"]["assetBaseId"]
|
|
gz.color = 0.5, 0.5, 0.0
|
|
gz.alpha = 0.5
|
|
|
|
gz.color_highlight = 1.0, 1.0, 1.0
|
|
gz.alpha_highlight = 0.5
|
|
|
|
gz.scale_basis = 1
|
|
gz.use_draw_modal = True
|
|
|
|
self.energy_gizmo = gz
|
|
|
|
def refresh(self, context):
|
|
ob = utils.get_active_model()
|
|
gz = self.energy_gizmo
|
|
|
|
R = bpy.context.region_data.view_rotation.to_matrix().to_4x4()
|
|
|
|
loc, _, _ = ob.matrix_world.decompose()
|
|
_, _, scale = gz.matrix_basis.decompose()
|
|
|
|
gz.matrix_basis = Matrix.Translation(loc) @ R @ Matrix.Diagonal(scale.to_4d())
|
|
|
|
|
|
classes = (
|
|
FastRateMenu,
|
|
SetBookmark,
|
|
RatingStarWidget,
|
|
RatingStarWidgetGroup,
|
|
ratings_utils.RatingProperties,
|
|
# ratings_utils.RatingPropsCollection,
|
|
)
|
|
|
|
|
|
def register_ratings():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
def unregister_ratings():
|
|
for cls in classes:
|
|
bpy.utils.unregister_class(cls)
|