330 lines
11 KiB
Python
330 lines
11 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 random
|
|
import time
|
|
|
|
import bpy
|
|
from bpy.props import BoolProperty, IntProperty, StringProperty
|
|
|
|
from . import client_tasks, global_vars, paths, reports, tasks_queue, utils
|
|
from .bl_ui_widgets.bl_ui_button import BL_UI_Button
|
|
from .bl_ui_widgets.bl_ui_drag_panel import BL_UI_Drag_Panel
|
|
from .bl_ui_widgets.bl_ui_draw_op import BL_UI_OT_draw_operator
|
|
from .bl_ui_widgets.bl_ui_image import BL_UI_Image
|
|
from .ui_bgl import get_text_size
|
|
|
|
|
|
bk_logger = logging.getLogger(__name__)
|
|
|
|
disclaimer_counter = 0
|
|
|
|
|
|
class BlenderKitDisclaimerOperator(BL_UI_OT_draw_operator):
|
|
bl_idname = "view3d.blenderkit_disclaimer_widget"
|
|
bl_label = "BlenderKit disclaimer"
|
|
bl_description = "BlenderKit disclaimer"
|
|
bl_options = {"REGISTER"}
|
|
instances = []
|
|
|
|
message: StringProperty( # type: ignore[valid-type]
|
|
name="message",
|
|
description="message",
|
|
default="Welcome to BlenderKit!",
|
|
options={"SKIP_SAVE"},
|
|
)
|
|
|
|
url: StringProperty( # type: ignore[valid-type]
|
|
name="url",
|
|
description="ULR",
|
|
default="www.blenderkit.com",
|
|
options={"SKIP_SAVE"},
|
|
)
|
|
|
|
fadeout_time: IntProperty( # type: ignore[valid-type]
|
|
name="Fadout time",
|
|
description="after how many seconds do fadout",
|
|
default=5,
|
|
min=1,
|
|
max=50,
|
|
options={"SKIP_SAVE"},
|
|
)
|
|
tip: BoolProperty( # type: ignore[valid-type]
|
|
name="Tip",
|
|
description="Message is a tip, not from server",
|
|
default=True,
|
|
options={"SKIP_SAVE"},
|
|
)
|
|
|
|
def cancel_press(self, widget):
|
|
self.finish()
|
|
|
|
def open_link(self, widget):
|
|
if self.url == "":
|
|
return
|
|
server_url = global_vars.SERVER
|
|
if self.url[:4] != "http":
|
|
self.url = server_url + self.url
|
|
|
|
bpy.ops.wm.url_open(url=self.url)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
ui_scale = bpy.context.preferences.view.ui_scale
|
|
|
|
text_size = int(14 * ui_scale)
|
|
margin = int(10 * ui_scale)
|
|
area_margin = int(50 * ui_scale)
|
|
if self.tip:
|
|
self.bg_color = (0.05, 0.05, 0.05, 0.5)
|
|
self.hover_bg_color = (0.05, 0.05, 0.05, 1.0)
|
|
else:
|
|
self.bg_color = (0.127, 0.034, 1, 0.1)
|
|
self.hover_bg_color = (0.127, 0.034, 1, 1.0)
|
|
self.text_color = (0.9, 0.9, 0.9, 1)
|
|
|
|
bk_logger.info("%s", self.message)
|
|
|
|
pix_size = get_text_size(
|
|
font_id=1,
|
|
text=self.message,
|
|
text_size=text_size,
|
|
dpi=int(bpy.context.preferences.system.dpi / ui_scale),
|
|
)
|
|
self.height = pix_size[1] + 2 * margin
|
|
self.button_size = int(self.height)
|
|
self.width = (
|
|
pix_size[0] + 2 * margin + 2 * self.button_size
|
|
) # adding logo and cancel button to width
|
|
|
|
a = bpy.context.area
|
|
self.panel = BL_UI_Drag_Panel(
|
|
area_margin, a.height - self.height - area_margin, self.width, self.height
|
|
)
|
|
self.panel.bg_color = (0.2, 0.2, 0.2, 0.02)
|
|
|
|
self.logo = BL_UI_Image(0, 0, self.button_size, self.button_size)
|
|
|
|
self.label = BL_UI_Button(
|
|
self.button_size, 0, pix_size[0] + 2 * margin, self.height
|
|
)
|
|
self.label.text = self.message
|
|
self.label.text_size = text_size
|
|
self.label.text_color = self.text_color
|
|
|
|
self.label.bg_color = self.bg_color
|
|
self.label.hover_bg_color = self.hover_bg_color
|
|
self.label.set_mouse_down(self.open_link)
|
|
|
|
self.button_close = BL_UI_Button(
|
|
self.width - self.button_size, 0, self.button_size, self.button_size
|
|
)
|
|
self.button_close.bg_color = self.bg_color
|
|
self.button_close.hover_bg_color = self.hover_bg_color
|
|
self.button_close.text = ""
|
|
self.button_close.set_mouse_down(self.cancel_press)
|
|
|
|
def on_invoke(self, context, event):
|
|
# Add new widgets here (TODO: perhaps a better, more automated solution?)
|
|
self.context = context
|
|
self.instances.append(self)
|
|
widgets_panel = [self.label, self.button_close, self.logo]
|
|
widgets = [self.panel]
|
|
|
|
widgets += widgets_panel
|
|
|
|
# assign image to the cancel button
|
|
img_fp = paths.get_addon_thumbnail_path("vs_rejected.png")
|
|
img_size = int(self.button_size / 2)
|
|
img_pos = int(img_size / 2)
|
|
|
|
self.button_close.set_image(img_fp)
|
|
self.button_close.set_image_size((img_size, img_size))
|
|
self.button_close.set_image_position((img_pos, img_pos))
|
|
|
|
img_fp = paths.get_addon_thumbnail_path("blenderkit_logo.png")
|
|
self.logo.set_image(img_fp)
|
|
self.logo.set_image_size((img_size, img_size))
|
|
self.logo.set_image_position((img_pos, img_pos))
|
|
|
|
# self.logo.set_image_position(0,0)
|
|
self.init_widgets(context, widgets)
|
|
self.panel.add_widgets(widgets_panel)
|
|
self.start_time = time.time()
|
|
|
|
def modal(self, context, event):
|
|
if self._finished:
|
|
return {"FINISHED"}
|
|
|
|
if not context.area:
|
|
# end if area disappears
|
|
self.finish()
|
|
return {"FINISHED"} # so region.tag_redraw() is not called later
|
|
|
|
if self.handle_widget_events(event):
|
|
self.start_time = time.time()
|
|
self.reset_colours()
|
|
return {"RUNNING_MODAL"}
|
|
|
|
if event.type in {"ESC"}:
|
|
self.finish()
|
|
return {"FINISHED"}
|
|
|
|
if event.type == "TIMER":
|
|
run_time = time.time() - self.start_time
|
|
if run_time > self.fadeout_time:
|
|
self.fadeout()
|
|
|
|
return {"PASS_THROUGH"}
|
|
|
|
def reset_colours(self):
|
|
for widget in self.widgets:
|
|
widget.bg_color = self.bg_color
|
|
widget.hover_bg_color = self.hover_bg_color
|
|
if hasattr(widget, "text_color"):
|
|
widget.text_color = self.text_color
|
|
|
|
def fadeout(self):
|
|
"""Fade out widget after some time"""
|
|
m = 0.08
|
|
all_zero = True
|
|
for widget in self.widgets:
|
|
# background color
|
|
bc = widget.bg_color
|
|
widget.bg_color = (bc[0], bc[1], bc[2], max(0, bc[3] - m))
|
|
if widget.bg_color[3] > 0:
|
|
# wait for the last to fade out
|
|
all_zero = False
|
|
# text color
|
|
if hasattr(widget, "text_color"):
|
|
tc = widget.text_color
|
|
widget.text_color = (tc[0], tc[1], tc[2], max(0, tc[3] - m))
|
|
if widget.text_color[3] > 0:
|
|
# wait for the last to fade out
|
|
all_zero = False
|
|
|
|
if all_zero:
|
|
self.finish()
|
|
|
|
@classmethod
|
|
def unregister(cls):
|
|
bk_logger.debug(f"unregistering class {cls}")
|
|
instances_copy = cls.instances.copy()
|
|
for instance in instances_copy:
|
|
bk_logger.debug(f"- class instance {instance}")
|
|
try:
|
|
instance.unregister_handlers(instance.context)
|
|
except Exception as e:
|
|
bk_logger.debug(f"-- error unregister_handlers(): {e}")
|
|
try:
|
|
instance.on_finish(instance.context)
|
|
except Exception as e:
|
|
bk_logger.debug(f"-- error calling on_finish() {e}")
|
|
if bpy.context.region is not None:
|
|
bpy.context.region.tag_redraw()
|
|
|
|
cls.instances.remove(instance)
|
|
|
|
|
|
def run_disclaimer_task(message: str, url: str, tip: bool):
|
|
message = " ".join(message.split())
|
|
fake_context = utils.get_fake_context(bpy.context)
|
|
if bpy.app.version < (4, 0, 0):
|
|
bpy.ops.view3d.blenderkit_disclaimer_widget( # type: ignore[attr-defined]
|
|
fake_context,
|
|
"INVOKE_DEFAULT",
|
|
message=message,
|
|
url=url,
|
|
fadeout_time=8,
|
|
tip=tip,
|
|
)
|
|
else:
|
|
with bpy.context.temp_override(**fake_context): # type: ignore[attr-defined]
|
|
bpy.ops.view3d.blenderkit_disclaimer_widget( # type: ignore[attr-defined]
|
|
"INVOKE_DEFAULT",
|
|
message=message,
|
|
url=url,
|
|
fadeout_time=8,
|
|
tip=tip,
|
|
)
|
|
|
|
|
|
def handle_disclaimer_task(task: client_tasks.Task):
|
|
"""Handles incoming disclaimer task. If there are any results, it shows them in disclaimer popup.
|
|
If the results are empty, it shows random tip in the disclaimer popup.
|
|
"""
|
|
global disclaimer_counter
|
|
disclaimer_counter = -1
|
|
if task.status == "finished":
|
|
if task.result.get("count", 0) == 0:
|
|
return show_random_tip()
|
|
|
|
disclaimer = task.result["results"][0]
|
|
preferences = bpy.context.preferences.addons[__package__].preferences # type: ignore
|
|
if preferences.announcements_on_start is False: # type: ignore[union-attr]
|
|
bk_logger.warning(
|
|
f"Online announcements are disabled! Message hidden from GUI: {disclaimer['message']}"
|
|
)
|
|
return show_random_tip()
|
|
|
|
tasks_queue.add_task(
|
|
(run_disclaimer_task, (disclaimer["message"], disclaimer["url"], False)),
|
|
wait=0,
|
|
)
|
|
return
|
|
|
|
if task.status == "error":
|
|
bk_logger.warning(f"Could not load disclaimer: {task.message}")
|
|
return show_random_tip()
|
|
|
|
|
|
def show_random_tip():
|
|
"""Shows random tip in the disclaimer popup if tips_on_start are enabled."""
|
|
preferences = bpy.context.preferences.addons[__package__].preferences
|
|
if preferences.tips_on_start is False:
|
|
return
|
|
tip = random.choice(global_vars.TIPS)
|
|
tasks_queue.add_task((run_disclaimer_task, (tip[0], tip[1], True)), wait=0)
|
|
|
|
|
|
def register():
|
|
bpy.utils.register_class(BlenderKitDisclaimerOperator)
|
|
|
|
|
|
def unregister():
|
|
bpy.utils.unregister_class(BlenderKitDisclaimerOperator)
|
|
|
|
|
|
@bpy.app.handlers.persistent
|
|
def show_disclaimer_timer():
|
|
"""Timer responsible for showing the tip disclaimer after the startup once.
|
|
It waits for BlenderKit-Client to be online, then prompts Client to get the disclaimers and ends.
|
|
If Client does not go online in few seconds, it shows the tips instead and ends.
|
|
"""
|
|
global disclaimer_counter
|
|
if disclaimer_counter == -1:
|
|
return
|
|
|
|
if disclaimer_counter > 2:
|
|
show_random_tip()
|
|
return
|
|
|
|
disclaimer_counter = disclaimer_counter + 1
|
|
return disclaimer_counter
|