OverviewFilesCommitsIssuesDocsReleasesPeers

hardops / operators / misc / logo_transform.py

337 lines · python ref:
import bpy, math
from enum import Enum
from ... utility import addon
from ... utility.base_modal_controls import Base_Modal_Controls
from ... ui_framework.master import Master
from ... utils.toggle_view3d_panels import collapse_3D_view_panels
from ... utility import method_handler
from ... arcade.engine.drawing import draw_2D_geo, draw_2D_lines
from ...utility.screen import dpi_factor


class Edit_Mode(Enum):

    Move = 1
    Scale = 2
    Color = 3
    Alpha = 4


class HOPS_OT_AdjustLogo(bpy.types.Operator):
    bl_idname = "hops.adjust_logo"
    bl_label = "Adjust Hardops Logo"
    bl_options = {"REGISTER", "UNDO", "BLOCKING"}
    bl_description = """Adjust Logo"""

    def invoke(self, context, event):

        # Setup
        addon.preference().color.Hops_display_logo = True
        self.edit_mode = Edit_Mode.Move
        self.screen_width = context.area.width
        self.screen_height = context.area.height
        self.alpha = addon.preference().color.Hops_logo_color[3]
        self.color_dot_radius = 20 * dpi_factor()

        # Base Systems
        self.master = Master(context=context)
        self.master.only_use_fast_ui = True
        self.base_controls = Base_Modal_Controls(context, event)
        self.original_tool_shelf, self.original_n_panel = collapse_3D_view_panels()
        self.draw_handle = bpy.types.SpaceView3D.draw_handler_add(self.safe_draw_shader, (context,), 'WINDOW', 'POST_PIXEL')

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

    def modal(self, context, event):

        # Base Systems
        self.master.receive_event(event=event)
        self.base_controls.update(context, event)

        if self.base_controls.pass_through:
            return {'PASS_THROUGH'}

        if self.base_controls.cancel:
            self.remove_shader()
            collapse_3D_view_panels(self.original_tool_shelf, self.original_n_panel)
            self.master.run_fade()
            return {'CANCELLED'}

        if self.base_controls.confirm:
            self.remove_shader()
            collapse_3D_view_panels(self.original_tool_shelf, self.original_n_panel)
            self.master.run_fade()
            return {'FINISHED'}

        elif event.type == 'G':
            self.edit_mode = Edit_Mode.Move

        elif event.type == 'S':
            self.edit_mode = Edit_Mode.Scale

        elif event.type == 'C':
            self.edit_mode = Edit_Mode.Color

        elif event.type == 'A':
            self.edit_mode = Edit_Mode.Alpha

        elif event.type == 'W':
            addon.preference().color.Hops_logo_color[0] = 1
            addon.preference().color.Hops_logo_color[1] = 1
            addon.preference().color.Hops_logo_color[2] = 1

        elif event.type == 'X' and event.value == "PRESS":
            addon.preference().color.Hops_display_logo = not addon.preference().color.Hops_display_logo
        
        elif event.type == 'MOUSEMOVE':
            if self.edit_mode == Edit_Mode.Move:
                addon.preference().color.Hops_logo_x_position = event.mouse_x - self.screen_width
                addon.preference().color.Hops_logo_y_position = event.mouse_y - self.screen_height

            elif self.edit_mode == Edit_Mode.Scale:
                addon.preference().color.Hops_logo_size += (event.mouse_x - event.mouse_prev_x) * .25
                if addon.preference().color.Hops_logo_size < 1:
                    addon.preference().color.Hops_logo_size = 1

            elif self.edit_mode == Edit_Mode.Color:
                '''
                Ranges
                    RED   : 0 = screen_height * .25   <-||->   1 = screen_height * .75
                    GREEN : 0 = screen_width  * .75   <-||->   1 = screen_width  * .25
                    BLUE  : 0 = screen_width  * .25   <-||->   1 = screen_width  * .75
                '''
                # Clamp -> max(min(my_value, max_value), min_value)

                red = max(min(event.mouse_y, self.screen_height * .75), self.screen_height * .25)
                red /= self.screen_height * .5
                red -= .5

                green = max(min(self.screen_width - event.mouse_x, self.screen_width * .75), self.screen_width * .25)
                green /= self.screen_width * .5
                green -= .5

                blue = max(min(event.mouse_x, self.screen_width * .75), self.screen_width * .25)
                blue /= self.screen_width * .5
                blue -= .5

                addon.preference().color.Hops_logo_color = (red, green, blue, self.alpha)
                self.check_mouse_over_dot(event)

            elif self.edit_mode == Edit_Mode.Alpha:
                self.alpha += (event.mouse_x - event.mouse_prev_x) * .015625
                self.alpha = max(min(self.alpha, 1), .0625)
                addon.preference().color.Hops_logo_color[3] = self.alpha

        elif event.type == 'WHEELDOWNMOUSE':
            addon.preference().color.Hops_logo_size -= 1

        elif event.type == 'WHEELUPMOUSE':
            addon.preference().color.Hops_logo_size += 1

        self.draw_master(context=context)
        context.area.tag_redraw()
        return {"RUNNING_MODAL"}


    def draw_master(self, context):

        # Start
        self.master.setup()
        if self.master.should_build_fast_ui():

            # Main
            win_list = []
            win_list.append(self.edit_mode.name)
            if self.edit_mode == Edit_Mode.Move:
                win_list.append(f'X: {addon.preference().color.Hops_logo_x_position:.1f}')
                win_list.append(f'Y: {addon.preference().color.Hops_logo_y_position:.1f}')
            elif self.edit_mode == Edit_Mode.Scale:
                win_list.append(f'Scale: {addon.preference().color.Hops_logo_size:.1f}')
            elif self.edit_mode == Edit_Mode.Color:
                r = f'{addon.preference().color.Hops_logo_color[0]:.2f}'
                g = f'{addon.preference().color.Hops_logo_color[1]:.2f}'
                b = f'{addon.preference().color.Hops_logo_color[2]:.2f}'
                win_list.append(f'Color: {r}  {g}  {b}')
            elif self.edit_mode == Edit_Mode.Alpha:
                win_list.append(f'Alpha: {self.alpha:.3f}')

            # Help
            help_items = {"GLOBAL" : [], "STANDARD" : []}

            help_items["GLOBAL"] = [
                ("M", "Toggle mods list"),
                ("H", "Toggle help"),
                ("~", "Toggle UI Display Type"),
                ("O", "Toggle viewport rendering")]

            help_items["STANDARD"] = [
                ("G",      "Edit Location"),
                ("S",      "Edit Scale"),
                ("C",      "Edit Color"),
                ("A",      "Edit Alpha"),
                ("W",      "Set White"),
                ("B",      "Set Black"),
                ("X",      "Toggle On / Off"),
                ("Scroll", "Adjust Scale")]

            self.master.receive_fast_ui(win_list=win_list, help_list=help_items, image="logo_gray")
        self.master.finished()


    def check_mouse_over_dot(self, event):
        '''Assign a direct color to the logo if mouse over a dot.'''

        mouse_pos = (event.mouse_region_x, event.mouse_region_y)

        red_loc = (self.screen_width * .5, self.screen_height * .75)
        green_loc = (self.screen_width * .25, self.screen_height * .25)
        blue_loc = (self.screen_width * .75, self.screen_height * .25)

        # Check Red
        if mouse_pos[0] <= red_loc[0] + self.color_dot_radius:
            if mouse_pos[0] >= red_loc[0] - self.color_dot_radius:
                if mouse_pos[1] <= red_loc[1] + self.color_dot_radius:
                    if mouse_pos[1] >= red_loc[1] - self.color_dot_radius:
                        addon.preference().color.Hops_logo_color[0] = 1
                        addon.preference().color.Hops_logo_color[1] = 0
                        addon.preference().color.Hops_logo_color[2] = 0
                        return

        # Check Green
        if mouse_pos[0] <= green_loc[0] + self.color_dot_radius:
            if mouse_pos[0] >= green_loc[0] - self.color_dot_radius:
                if mouse_pos[1] <= green_loc[1]:
                    if mouse_pos[1] >= green_loc[1] - self.color_dot_radius * 2:
                        addon.preference().color.Hops_logo_color[0] = 0
                        addon.preference().color.Hops_logo_color[1] = 1
                        addon.preference().color.Hops_logo_color[2] = 0
                        return

        # Check Blue
        if mouse_pos[0] <= blue_loc[0] + self.color_dot_radius:
            if mouse_pos[0] >= blue_loc[0] - self.color_dot_radius:
                if mouse_pos[1] <= blue_loc[1]:
                    if mouse_pos[1] >= blue_loc[1] - self.color_dot_radius * 2:
                        addon.preference().color.Hops_logo_color[0] = 0
                        addon.preference().color.Hops_logo_color[1] = 0
                        addon.preference().color.Hops_logo_color[2] = 1
                        return
    ####################################################
    #   SHADERS
    ####################################################

    def safe_draw_shader(self, context):
        method_handler(self.draw_shader,
            arguments = (context,),
            identifier = 'Logo Adjust',
            exit_method = self.remove_shader)


    def remove_shader(self):
        '''Remove shader handle.'''

        if self.draw_handle:
            self.draw_handle = bpy.types.SpaceView3D.draw_handler_remove(self.draw_handle, "WINDOW")


    def draw_shader(self, context):
        '''Draw shader handle.'''

        if self.edit_mode == Edit_Mode.Color:
            segments = 20
            self.draw_red_circle(segments, self.screen_width, self.screen_height)
            self.draw_green_circle(segments, self.screen_width, self.screen_height)
            self.draw_blue_circle(segments, self.screen_width, self.screen_height)


    def draw_red_circle(self, segments=3, screen_width=0, screen_height=0):
        '''Draw the red circle : Top'''

        vertices = []
        for i in range(segments):
            index = i + 1
            angle = i * 3.14159 * 2 / segments
            x = math.cos(angle) * self.color_dot_radius
            y = math.sin(angle) * self.color_dot_radius

            x += screen_width * .5
            y += screen_height * .75

            vertices.append((x, y))

        first_vert = vertices[0]
        vertices.append(first_vert)

        # Polygon
        indices = []
        for i in range(len(vertices)):
            if i == len(vertices) - 2:
                break
            indices.append((0, i, i+1))

        # Draw
        draw_2D_geo(vertices, indices, color=(1,0,0,.75))
        draw_2D_lines(vertices, width=3, color=(1,0,0,1))


    def draw_green_circle(self, segments=3, screen_width=0, screen_height=0):
        '''Draw the green circle : Left'''
        
        vertices = []
        for i in range(segments):
            index = i + 1
            angle = i * 3.14159 * 2 / segments
            x = math.cos(angle) * self.color_dot_radius
            y = math.sin(angle) * self.color_dot_radius

            x += screen_width * .25
            y += screen_height * .25
            y -= self.color_dot_radius

            vertices.append((x, y))

        first_vert = vertices[0]
        vertices.append(first_vert)

        # Polygon
        indices = []
        for i in range(len(vertices)):
            if i == len(vertices) - 2:
                break
            indices.append((0, i, i+1))

        # Draw
        draw_2D_geo(vertices, indices, color=(0,1,0,.75))
        draw_2D_lines(vertices, width=3, color=(0,1,0,1))


    def draw_blue_circle(self, segments=3, screen_width=0, screen_height=0):
        '''Draw the blue circle : Right'''
        
        vertices = []
        for i in range(segments):
            index = i + 1
            angle = i * 3.14159 * 2 / segments
            x = math.cos(angle) * self.color_dot_radius
            y = math.sin(angle) * self.color_dot_radius

            x += screen_width * .75
            y += screen_height * .25
            y -= self.color_dot_radius

            vertices.append((x, y))

        first_vert = vertices[0]
        vertices.append(first_vert)

        # Polygon
        indices = []
        for i in range(len(vertices)):
            if i == len(vertices) - 2:
                break
            indices.append((0, i, i+1))

        # Draw
        draw_2D_geo(vertices, indices, color=(0,0,1,.75))
        draw_2D_lines(vertices, width=3, color=(0,0,1,1))