OverviewFilesCommitsIssuesDocsReleasesPeers

hardops / operators / third_party / video_window.py

165 lines · python ref:
import bpy, webbrowser
from bpy_extras.image_utils import load_image
from ... utility import addon
from ...ui_framework.master import Master, Modal_Communications
from .video_thumbs import image_folder


def load_image_file(filename=""):
    '''Return the loaded image.'''

    directory = image_folder()
    return load_image(filename + ".png", dirname=directory)


class Video_Controller:
    def __init__(self, context):
        self.videos = []
        self.exit_modal = False

        file_link = {
            #"bbro2"      :("https://www.blenderbros.com/scifi-terminal-design-mini-course", ""),
            "bBros1"     :("https://gumroad.com/a/739308659", ""),
            "stellar1"   :("https://stellarworks.gumroad.com/l/smg45c", " "),
            "202_1"      :("https://20two.gumroad.com/l/202_SYMBOLS_VOL_001", ""),
            "carol1"     :("https://carolsung.gumroad.com/l/WRmkQ", ""),
            "kitops_3"   : ("https://www.youtube.com/watch?v=nS1TQBiRvwg", "KitOps Release Log"),
            "rach3l"     :("https://gumroad.com/a/236483699", ""),
            "roughness_maps" :("https://gumroad.com/l/mAPCZ/hardops", ""),
            "hopscut"    : ("https://hopscutter.com/", " "),
            #"ko_synth1"  : ("https://blendermarket.com/products/kit-ops-synth", " "),
            "987Log"     : ("https://masterxeon1001.com/2021/01/10/hard-ops-987-francium-release/", "987 Francium Release Log"),
            "cblr"       : ("https://gumroad.com/l/cblrtr/operative", "Cablerator"),
            "pokeball"   : ("https://www.youtube.com/watch?v=VJ64_8pEBF0&feature=emb_title", "R8CH3L"),
            "hops_one"   : ("https://youtu.be/9q54utRuka8", "HandHeld Demo"),
            "hops_two"   : ("https://gumroad.com/l/boxbot", "Rachel's Boxbot"),
            "hops_three" : ("https://gumroad.com/l/GnHrV", "BlenderBros HOPS"),
            "stellar"    : ("https://www.youtube.com/channel/UCK4RSljZQXfpwBrAUxwwxjw", " "),
            "hops_five"  : ("https://www.youtube.com/playlist?list=PLjqpj14voWsUwjkOaj6EsU9OZxs7qieR1", "Boxcutter 717.X Playlist"),
            "hops_six"   : ("https://www.youtube.com/playlist?list=PLjqpj14voWsXlLHjT8jMnn5uKLfXKFki8", "HOPS Extended Playlist"),
            "hops_seven" : ("https://www.youtube.com/playlist?list=PL0RqAjByAphEUuI2JDxIjjCQtfTRQlRh0", "H9 Content"),
            "kitops_bevel" : ("https://gumroad.com/l/kitopsbevel", "KitOps Bevel"),
            "kitops_2"   : ("https://www.youtube.com/playlist?list=PL0RqAjByAphGGBltaIL_yFbar9fR4YV0y", "KitOps 2 Playlist"),
            "HSE"        : ("https://www.youtube.com/watch?fbclid=IwAR2dhoucqRVfcUM2KVw3HlL3FEaW8ExslgVJSZR6W93pqwK0Fs2P1FYhBIA&v=w7GbBaFFgPY&feature=youtu.be", "Hard Surface Essentials"),
            "987YT"     : ("https://www.youtube.com/playlist?list=PLjqpj14voWsXjD3J-J-s6iMcE0EhmdNmk", "987 Francium Video Playlist"),
            "link_keyboard": ("https://gumroad.com/l/KeyboardRenderKit/", "Keyboard Render Kit"),
            "batch_ops"  : ("https://gumroad.com/l/batchops", " ")
        }

        for item in file_link.items():
            file_name, link, desc = item[0], item[1][0], item[1][1]
            image = load_image_file(file_name)
            if image != None:
                self.videos.append((image, link, desc))

        self.master = Master(context=context, custom_preset="Video_Page", show_fast_ui=False)


    def update(self, context, event):
        self.master.receive_event(event=event)
        self.draw_window(context, event)


    def draw_window(self, context, event):
        self.master.setup()
        prefs = addon.preference()
        window_name = "Videos"
        main_window = {}

        for image, link, desc in self.videos:
            main_window[image] = (self.video_linker, link, desc)

        self.master.receive_main(win_dict=main_window, window_name=window_name)
        self.master.finished()

    # --- Utils --- #

    def shut_down(self):
        self.master.run_fade()
        self.remove_images()


    def video_linker(self, link=""):
        self.exit_modal = True
        webbrowser.open(link)


    def remove_images(self):
        for image, link, desc in self.videos:
            try:
                bpy.data.images.remove(image)
            except:
                pass


class HOPS_OT_Videos_Window(bpy.types.Operator):

    """Link Ops"""
    bl_idname = "hops.video_window"
    bl_label = "Link Ops"
    bl_description = """Videos Window \n CTRL - Load Pizza Ops"""


    def invoke(self, context, event):

        # Go to pizza ops
        if event.ctrl:
            bpy.ops.hops.pizza_ops_window('INVOKE_DEFAULT')
            return {'FINISHED'}
        
        # Asset loaded
        self.video = Video_Controller(context)

        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}


    def modal(self, context, event):

        self.video.update(context, event)

        # Navigation
        if (event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'} and event.ctrl != True):
            if not self.video.master.is_mouse_over_ui():
                return {'PASS_THROUGH'}

        # Confirm
        if event.type == 'LEFTMOUSE':
            if not self.video.master.is_mouse_over_ui():
                self.video.shut_down()
                context.area.tag_redraw()
                return {'FINISHED'}

        # Cancel
        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            if not self.video.master.is_mouse_over_ui():
                self.video.shut_down()
                context.area.tag_redraw()
                return {'CANCELLED'}

        # Exit after load
        if self.video.exit_modal:
            self.video.shut_down()
            context.area.tag_redraw()
            return {'FINISHED'}

        direction = 1 if event.type in ['UP_ARROW', 'LEFT_ARROW'] and event.value == 'PRESS' else None
        direction = -1 if event.type in ['DOWN_ARROW', 'RIGHT_ARROW'] and event.value == 'PRESS' else direction
        self.arrows_next(direction)

        context.area.tag_redraw()
        return {'RUNNING_MODAL'}


    def arrows_next(self, direction=0):
        if not direction: return
        if self.video.master.unique_id not in Modal_Communications.coms: return

        db = Modal_Communications.coms[self.video.master.unique_id].db_ref
        window = db.windows['Video_Page']
        panel = window.panels[-1]
        widget = panel.widget

        widget.scroll_bar.bottom_offset += (panel.panel_height / len(self.video.videos)) * direction
        widget.scroll_bar.clamp_offset()