Skip to content
Snippets Groups Projects
xedit_set_meas.py 77 KiB
Newer Older
  • Learn to ignore specific revisions
  • NBurn's avatar
    NBurn committed
            temp = mid_align.copy()
            temp.rotate(rot_val)
            arc_pts.append(temp + piv)
    
    
        elif TransDat.axis_lock is not None:
            #if TransDat.axis_lock == 'X':
    
    NBurn's avatar
    NBurn committed
            #    rot_val = Euler((pi*2, 0.0, 0.0), 'XYZ')
    
            if TransDat.axis_lock == 'X':
    
    NBurn's avatar
    NBurn committed
                piv_norm = 1.0, 0.0, 0.0
    
            elif TransDat.axis_lock == 'Y':
    
    NBurn's avatar
    NBurn committed
                piv_norm = 0.0, 1.0, 0.0
    
            elif TransDat.axis_lock == 'Z':
    
    NBurn's avatar
    NBurn committed
                piv_norm = 0.0, 0.0, 1.0
            dis_p_f = (piv - fre).length
            dis_p_a = (piv - anc).length
            if dis_p_f < dis_p_a:
                ratio = 0.5
            else:  # dis_p_a < dis_p_f:
                ratio = dis_p_a / dis_p_f * 0.5
            mid_piv_free = piv.lerp(fre, ratio)
            arc_pts = [mid_piv_free]
            steps = 36
    
            ang_step = pi * 2 / steps
    
    NBurn's avatar
    NBurn committed
            mid_align = mid_piv_free - piv
            for a in range(1, steps+1):
                rot_val = Quaternion(piv_norm, ang_step * a)
                temp = mid_align.copy()
                temp.rotate(rot_val)
                arc_pts.append(temp + piv)
    
    
        TransDat.arc_pts = arc_pts
    
    NBurn's avatar
    NBurn committed
    
    
    # Takes a ref_pts (ReferencePoints class) argument and modifies its member
    # variable lp_ls (lock pt list). The lp_ls variable is assigned a modified list
    # of 3D coordinates (if an axis lock was provided), the contents of the
    # ref_pts' rp_ls var (if no axis lock was provided), or an empty list (if there
    # wasn't enough ref_pts or there was a problem creating the modified list).
    # todo : move inside ReferencePoints class ?
    def set_lock_pts(ref_pts, pt_cnt):
        if pt_cnt < 2:
    
            TransDat.lock_pts = []
        elif TransDat.axis_lock is None:
            TransDat.lock_pts = ref_pts
    
    NBurn's avatar
    NBurn committed
            if pt_cnt == 3:
                set_arc_pts(ref_pts)
        else:
    
            TransDat.lock_pts = []
    
    NBurn's avatar
    NBurn committed
            new1 = ref_pts[1].copy()
            ptls = [ref_pts[i].co3d for i in range(pt_cnt)]  # shorthand
            # finds 3D midpoint between 2 supplied coordinates
            # axis determines which coordinates are assigned midpoint values
            # if X, Anchor is [AncX, MidY, MidZ] and Free is [FreeX, MidY, MidZ]
            if pt_cnt == 2:  # translate
                new0 = ref_pts[0].copy()
                mid3d = ptls[0].lerp(ptls[1], 0.5)
    
                if TransDat.axis_lock == 'X':
    
    NBurn's avatar
    NBurn committed
                    new0.co3d = Vector([ ptls[0][0], mid3d[1], mid3d[2] ])
                    new1.co3d = Vector([ ptls[1][0], mid3d[1], mid3d[2] ])
    
                elif TransDat.axis_lock == 'Y':
    
    NBurn's avatar
    NBurn committed
                    new0.co3d = Vector([ mid3d[0], ptls[0][1], mid3d[2] ])
                    new1.co3d = Vector([ mid3d[0], ptls[1][1], mid3d[2] ])
    
                elif TransDat.axis_lock == 'Z':
    
    NBurn's avatar
    NBurn committed
                    new0.co3d = Vector([ mid3d[0], mid3d[1], ptls[0][2] ])
                    new1.co3d = Vector([ mid3d[0], mid3d[1], ptls[1][2] ])
                if not vec3s_alm_eq(new0.co3d, new1.co3d):
    
                    TransDat.lock_pts = [new0, new1]
    
    NBurn's avatar
    NBurn committed
    
            # axis determines which of the Free's coordinates are assigned
            # to Anchor and Pivot coordinates eg:
            # if X, Anchor is [FreeX, AncY, AncZ] and Pivot is [FreeX, PivY, PivZ]
            elif pt_cnt == 3:  # rotate
                new2 = ref_pts[2].copy()
                mov_co = ref_pts[0].co3d.copy()
    
                if TransDat.axis_lock == 'X':
    
    NBurn's avatar
    NBurn committed
                    new1.co3d = Vector([ mov_co[0], ptls[1][1], ptls[1][2] ])
                    new2.co3d = Vector([ mov_co[0], ptls[2][1], ptls[2][2] ])
    
                elif TransDat.axis_lock == 'Y':
    
    NBurn's avatar
    NBurn committed
                    new1.co3d = Vector([ ptls[1][0], mov_co[1], ptls[1][2] ])
                    new2.co3d = Vector([ ptls[2][0], mov_co[1], ptls[2][2] ])
    
                elif TransDat.axis_lock == 'Z':
    
    NBurn's avatar
    NBurn committed
                    new1.co3d = Vector([ ptls[1][0], ptls[1][1], mov_co[2] ])
                    new2.co3d = Vector([ ptls[2][0], ptls[2][1], mov_co[2] ])
                if not vec3s_alm_eq(new1.co3d, new2.co3d) and \
                not vec3s_alm_eq(new1.co3d, mov_co) and \
                not vec3s_alm_eq(new2.co3d, mov_co):
                    #new0 = ReferencePoint("piv", Colr.blue, mov_co)
                    new0 = ReferencePoint("fre", Colr.green, mov_co)
    
                    TransDat.lock_pts = [new0, new1, new2]
    
    NBurn's avatar
    NBurn committed
                    set_arc_pts([new0, new1, new2])
                else:
                    set_arc_pts(ref_pts)
    
    
    # Takes  new_co (Vector) and old_co (Vector) as arguments. Calculates
    # difference between the 3D locations in new_co and old_co to determine
    # the translation to apply to the selected geometry.
    def do_translation(new_co, old_co):
    
        co_chg = -(old_co - new_co)
        bpy.ops.transform.translate(value=co_chg)
    
    NBurn's avatar
    NBurn committed
    
    
    # Performs a scale transformation using the provided s_fac (scale factor)
    # argument. The scale factor is the result from dividing the user input
    # measure (new_meas_stor) by the distance between the Anchor and Free
    # (curr_meas_stor). After the scale is performed, settings are returned to
    # their "pre-scaled" state.
    # takes:  ref_pts (ReferencePoints), s_fac (float)
    def do_scale(ref_pts, s_fac):
        # back up settings before changing them
    
        piv_back = deepcopy(bpy.context.tool_settings.transform_pivot_point)
    
        curs_back = bpy.context.scene.cursor.location.copy()
    
        bpy.context.tool_settings.transform_pivot_point = 'CURSOR'
    
        bpy.context.scene.cursor.location = ref_pts[1].co3d.copy()
    
    NBurn's avatar
    NBurn committed
        ax_multip, cnstrt_bls = (), ()
    
        if   TransDat.axis_lock is None:
    
    NBurn's avatar
    NBurn committed
            ax_multip, cnstrt_bls = (s_fac, s_fac, s_fac), (True, True, True)
    
        elif TransDat.axis_lock == 'X':
    
    NBurn's avatar
    NBurn committed
            ax_multip, cnstrt_bls = (s_fac, 1, 1), (True, False, False)
    
        elif TransDat.axis_lock == 'Y':
    
    NBurn's avatar
    NBurn committed
            ax_multip, cnstrt_bls = (1, s_fac, 1), (False, True, False)
    
        elif TransDat.axis_lock == 'Z':
    
    NBurn's avatar
    NBurn committed
            ax_multip, cnstrt_bls = (1, 1, s_fac), (False, False, True)
        bpy.ops.transform.resize(value=ax_multip, constraint_axis=cnstrt_bls)
        # restore settings back to their pre "do_scale" state
    
        bpy.context.scene.cursor.location = curs_back.copy()
    
        bpy.context.tool_settings.transform_pivot_point = deepcopy(piv_back)
    
    NBurn's avatar
    NBurn committed
    
    
    # end_a, piv_pt, and end_b are Vector based 3D coordinates
    # coordinates must share a common center "pivot" point (piv_pt)
    def get_line_ang_3d(end_a, piv_pt, end_b):
        algn_a = end_a - piv_pt
        algn_b = end_b - piv_pt
        return algn_a.angle(algn_b)
    
    
    # Checks if the 3 Vector coordinate arguments (end_a, piv_pt, end_b)
    # will create an angle with a measurement matching the value in the
    # argument exp_ang (expected angle measurement).
    def ang_match3d(end_a, piv_pt, end_b, exp_ang):
        ang_meas = get_line_ang_3d(end_a, piv_pt, end_b)
        #print("end_a", end_a)  # debug
        #print("piv_pt", piv_pt)  # debug
        #print("end_b", end_b)  # debug
        #print("exp_ang ", exp_ang)  # debug
        #print("ang_meas ", ang_meas)  # debug
        return flts_alm_eq(ang_meas, exp_ang)
    
    
    # Calculates rotation around axis or face normal at Pivot's location.
    # Takes two 3D coordinate Vectors (piv_co and mov_co), rotation angle in
    # radians (ang_diff_rad), and rotation data storage object (rot_dat).
    # Aligns mov_co to world origin (0, 0, 0) and rotates aligned
    # mov_co (mov_aligned) around axis stored in rot_dat. After rotation,
    # removes world-origin alignment.
    def get_rotated_pt(piv_co, ang_diff_rad, mov_co):
        mov_aligned = mov_co - piv_co
    
        rot_val, axis_lock = [], TransDat.axis_lock
    
    NBurn's avatar
    NBurn committed
        if   axis_lock is None:  # arbitrary axis / spherical rotations
    
            #print('  RotDat.piv_norm', RotDat.piv_norm,  # debug
            #        '\n  ang_diff_rad', ang_diff_rad)  # debug
    
            rot_val = Quaternion(TransDat.piv_norm, ang_diff_rad)
    
    NBurn's avatar
    NBurn committed
        elif axis_lock == 'X':
            rot_val = Euler((ang_diff_rad, 0.0, 0.0), 'XYZ')
        elif axis_lock == 'Y':
            rot_val = Euler((0.0, ang_diff_rad, 0.0), 'XYZ')
        elif axis_lock == 'Z':
            rot_val = Euler((0.0, 0.0, ang_diff_rad), 'XYZ')
        mov_aligned.rotate(rot_val)
        return mov_aligned + piv_co
    
    
    
    # Finds out whether positive TransDat.new_ang_r or negative TransDat.new_ang_r
    
    NBurn's avatar
    NBurn committed
    # will result in the desired rotation angle.
    def find_correct_rot(ref_pts, pt_cnt):
    
        ang_diff_rad, new_ang_rad = TransDat.ang_diff_r, TransDat.new_ang_r
    
    NBurn's avatar
    NBurn committed
        piv_pt, move_pt = ref_pts[2].co3d, ref_pts[0].co3d
    
        t_co_pos = get_rotated_pt(piv_pt, ang_diff_rad, move_pt)
        t_co_neg = get_rotated_pt(piv_pt,-ang_diff_rad, move_pt)
        set_lock_pts(ref_pts, pt_cnt)
    
        lock_pts = TransDat.lock_pts
    
    NBurn's avatar
    NBurn committed
        if ang_match3d(lock_pts[1].co3d, lock_pts[2].co3d, t_co_pos, new_ang_rad):
            #print("matched t_co_pos:", t_co_pos, ang_diff_rad)
            return t_co_pos, ang_diff_rad
        else:
            #print("matched t_co_neg:", t_co_neg, -ang_diff_rad)
            return t_co_neg, -ang_diff_rad
    
    
    # Takes 2D Pivot Point (piv) for piv to temp lines, 2 possible rotation
    
    # coordinates to choose between (rot_co3d_pos, rot_co3d_neg), and a
    
    NBurn's avatar
    NBurn committed
    # 2D mouse location (mouse_co) for determining which rotation coordinate
    # is closest to the cursor.
    # Returns the rotation coordinate closest to the 2d mouse position and the
    # rotation angles used to obtain the coordinates (rot_ang_rad).
    
    # rot_co3d_pos == rotated coordinate positive,  rot_co3d_neg == rot coor Negative
    # todo : make rot_pos_co2d and rot_neg_co2d VertObj types ?
    #def choose_0_or_180(piv, rot_co3d_pos, rot_pos_ang_rad, rot_co3d_neg, r_n_ang_r, mouse_co):
    def choose_0_or_180(piv, rot_co3d_pos, rot_co3d_neg, rot_ang_rad, mouse_co):
    
    NBurn's avatar
    NBurn committed
        #global reg_rv3d
        #region, rv3d = reg_rv3d[0], reg_rv3d[1]
        region = bpy.context.region
        rv3d = bpy.context.region_data
    
        rot_pos_co2d = loc3d_to_reg2d(region, rv3d, rot_co3d_pos)
        rot_neg_co2d = loc3d_to_reg2d(region, rv3d, rot_co3d_neg)
    
    NBurn's avatar
    NBurn committed
        piv2d = loc3d_to_reg2d(region, rv3d, piv.co3d)
    
        ms_co_1_dis = (rot_pos_co2d - mouse_co).length
        ms_co_2_dis = (rot_neg_co2d - mouse_co).length
    
    NBurn's avatar
    NBurn committed
        # draw both buttons and show which is closer to mouse
        psize_small, psize_large = 8, 14
    
        if ms_co_1_dis < ms_co_2_dis:
            draw_line_2d(piv2d, rot_pos_co2d, Colr.green)
            draw_pt_2d(rot_pos_co2d, Colr.green, psize_large)
            draw_pt_2d(rot_neg_co2d, Colr.grey, psize_small)
            return rot_co3d_pos, rot_ang_rad
    
    NBurn's avatar
    NBurn committed
        elif ms_co_2_dis < ms_co_1_dis:
    
            draw_line_2d(piv2d, rot_neg_co2d, Colr.green)
            draw_pt_2d(rot_neg_co2d, Colr.green, psize_large)
            draw_pt_2d(rot_pos_co2d, Colr.grey, psize_small)
            return rot_co3d_neg, -rot_ang_rad
    
    NBurn's avatar
    NBurn committed
        else:
    
            draw_pt_2d(rot_pos_co2d, Colr.grey, psize_small)
            draw_pt_2d(rot_neg_co2d, Colr.grey, psize_small)
    
    NBurn's avatar
    NBurn committed
        return None, None
    
    
    # Reduces the provided rotation amount (new_ms_stor) to an "equivalent" value
    # less than or equal to 180 degrees. Calculates the angle offset from
    # curr_ms_stor to achieve a new_ms_stor value.
    def prep_rotation_info(curr_ms_stor, new_ms_stor):
        # workaround for negative angles and angles over 360 degrees
        if new_ms_stor < 0 or new_ms_stor > 360:
            new_ms_stor = new_ms_stor % 360
        # fix for angles over 180 degrees
        if new_ms_stor > 180:
    
            TransDat.new_ang_r = radians(180 - (new_ms_stor % 180))
    
    NBurn's avatar
    NBurn committed
        else:
    
            TransDat.new_ang_r = radians(new_ms_stor)
        #print("TransDat.new_ang_r", TransDat.new_ang_r)
        TransDat.ang_diff_r = radians(new_ms_stor - curr_ms_stor)
    
    def create_z_orient(rot_vec):
        x_dir_p = Vector(( 1.0,  0.0,  0.0))
        y_dir_p = Vector(( 0.0,  1.0,  0.0))
        z_dir_p = Vector(( 0.0,  0.0,  1.0))
        if flt_lists_alm_eq(rot_vec, (0.0, 0.0, 0.0)) or \
                flt_lists_alm_eq(rot_vec, z_dir_p):
            return Matrix((x_dir_p, y_dir_p, z_dir_p))  # 3x3 identity
        new_z = rot_vec.copy()  # rot_vec already normalized
    
    NBurn's avatar
    NBurn committed
        new_y = new_z.cross(z_dir_p)
    
        if flt_lists_alm_eq(new_y, (0.0, 0.0, 0.0)):
            new_y = y_dir_p
        new_x = new_y.cross(new_z)
        new_x.normalize()
        new_y.normalize()
        return Matrix(((new_x.x, new_y.x, new_z.x),
                       (new_x.y, new_y.y, new_z.y),
                       (new_x.z, new_y.z, new_z.z)))
    
    
    
    # Uses axis_lock or piv_norm from TransDat to obtain rotation axis.
    
    NBurn's avatar
    NBurn committed
    # Then rotates selected objects or selected vertices around the
    
    # 3D cursor using TransDat's ang_diff_r radian value.
    
    def do_rotate(pivot_co):
    
        #print("def do_rotate(self):")  # debug
    
        axis_lock = TransDat.axis_lock
    
        pivot = pivot_co.copy()
        constr_ax = False, False, False
    
        if axis_lock is None:
    
            constr_ax = False, False, True
    
            #rot_matr = Matrix.Rotation(TransDat.ang_diff_r, 4, TransDat.piv_norm)
            norml = TransDat.piv_norm
    
            o_mat = create_z_orient(norml)
    
            bpy.ops.transform.rotate(
    
                value=TransDat.ang_diff_r,
    
                orient_axis='Z',
                orient_type='LOCAL',
                #orient_type='GLOBAL',
                orient_matrix=o_mat,
                orient_matrix_type='LOCAL',
                center_override=pivot,
    
                constraint_axis=constr_ax)
    
        else:
            # back up settings before changing them
            piv_back = deepcopy(bpy.context.tool_settings.transform_pivot_point)
            bpy.context.tool_settings.transform_pivot_point = 'CURSOR'
            curs_loc_back = bpy.context.scene.cursor.location.copy()
            bpy.context.scene.cursor.location = pivot.copy()
            '''
    
            if   axis_lock == 'X':  constr_ax = True, False, False
            elif axis_lock == 'Y':  constr_ax = False, True, False
            elif axis_lock == 'Z':  constr_ax = False, False, True
    
            bpy.ops.transform.rotate(value=-TransDat.ang_diff_r, orient_axis=axis_lock,
    
                center_override=pivot.copy(), constraint_axis=constr_ax)
    
    
            # restore settings back to their pre "do_rotate" state
            bpy.context.scene.cursor.location = curs_loc_back.copy()
            bpy.context.tool_settings.transform_pivot_point = deepcopy(piv_back)
    
        editmode_refresh()
    
    
    # Uses axis_lock or piv_norm from TransDat to obtain rotation axis.
    
    # Then rotates selected objects or selected vertices around the
    
    # 3D cursor using TransDat's ang_diff_r radian value.
    
    def do_rotate_old(self):
    
    NBurn's avatar
    NBurn committed
        # back up settings before changing them
    
        piv_back = deepcopy(bpy.context.tool_settings.transform_pivot_point)
    
        curs_back = bpy.context.scene.cursor.location.copy()
    
        bpy.context.tool_settings.transform_pivot_point = 'CURSOR'
    
        bpy.context.scene.cursor.location = self.pts[2].co3d.copy()
    
        axis_lock = TransDat.axis_lock
    
    NBurn's avatar
    NBurn committed
        ops_lock = ()  # axis lock data for bpy.ops.transform
    
        if   axis_lock is None: ops_lock = TransDat.piv_norm
    
    NBurn's avatar
    NBurn committed
        elif axis_lock == 'X':  ops_lock = 1, 0, 0
        elif axis_lock == 'Y':  ops_lock = 0, 1, 0
        elif axis_lock == 'Z':  ops_lock = 0, 0, 1
    
    
        bpy.ops.transform.rotate(value=TransDat.ang_diff_r, axis=ops_lock,
    
                constraint_axis=(False, False, False))
    
        editmode_refresh()
    
    NBurn's avatar
    NBurn committed
    
        # restore settings back to their pre "do_rotate" state
    
        bpy.context.scene.cursor.location = curs_back.copy()
    
        bpy.context.tool_settings.transform_pivot_point = deepcopy(piv_back)
    
    NBurn's avatar
    NBurn committed
    
    
    # Updates lock points and changes curr_meas_stor to use measure based on
    # lock points instead of ref_pts (for axis constrained transformations).
    def updatelock_pts(self, ref_pts):
        global curr_meas_stor
        set_lock_pts(ref_pts, self.pt_cnt)
    
        if TransDat.lock_pts == []:
            if TransDat.axis_lock is not None:
                self.report({'ERROR'}, 'Axis lock \''+ TransDat.axis_lock+
    
    NBurn's avatar
    NBurn committed
                        '\' creates identical points')
    
            TransDat.lock_pts = ref_pts
            TransDat.axis_lock = None
    
    NBurn's avatar
    NBurn committed
        # update Measurement in curr_meas_stor
    
        lk_pts = TransDat.lock_pts
    
    NBurn's avatar
    NBurn committed
        if self.pt_cnt < 2:
            curr_meas_stor = 0.0
        elif self.pt_cnt == 2:
            curr_meas_stor = (lk_pts[0].co3d - lk_pts[1].co3d).length
        elif self.pt_cnt == 3:
            line_ang_r = get_line_ang_3d(lk_pts[1].co3d, lk_pts[2].co3d, lk_pts[0].co3d)
            curr_meas_stor = degrees(line_ang_r)
    
    
    # See if key was pressed that would require updating the axis lock info.
    # If one was, update the lock points to use new info.
    def axis_key_check(self, new_axis):
        if self.pt_cnt > 1:
    
            if new_axis != TransDat.axis_lock:
                TransDat.axis_lock = new_axis
    
    NBurn's avatar
    NBurn committed
                updatelock_pts(self, self.pts)
                set_meas_btn(self)
    
    
    # Adjusts settings so proc_click can run again for next possible transform
    def reset_settings(self):
        #print("reset_settings")  # debug
        global new_meas_stor
        new_meas_stor = None
        self.new_free_co = ()
        self.mouse_co = Vector((-9900, -9900))
        editmode_refresh()
        if self.pt_cnt < 2:
            self.meas_btn.is_drawn = False
            set_lock_pts(self.pts, self.pt_cnt)
        else:
            updatelock_pts(self, self.pts)
            self.meas_btn.is_drawn = True
            set_meas_btn(self)
        #self.snap_btn_act = True
        self.addon_mode = CLICK_CHECK
    
        # restore selected items (except Anchor)
        # needed so GRABONLY and SLOW3DTO2D update selection correctly
        #self.sel_backup.restore_selected()
    
        # make sure last transform didn't cause points to overlap
        if vec3s_alm_eq(self.pts[0].co3d, self.pts[1].co3d):
            self.report({'ERROR'}, 'Free and Anchor share same location.')
            # reset ref pt data
            self.pt_cnt = 0
            self.menu.change_menu(self.pt_cnt)
            init_ref_pts(self)
    
            set_transform_data_none()
    
    NBurn's avatar
    NBurn committed
            self.highlight_mouse = True
    
        #if self.pt_find_md == GRABONLY:
        #    create_snap_pt(self.left_click_co, self.sel_backup)
    
    
    # runs transformation functions depending on which options are set.
    # transform functions cannot be called directly due to use of pop-up for
    # getting user input
    def do_transform(self):
        #print("do_transform")  # debug
        global curr_meas_stor, new_meas_stor
    
        # Onto Transformations...
        if self.transf_type == MOVE:
    
            #print("  MOVE!!")  # debug
    
    NBurn's avatar
    NBurn committed
            new_coor = get_new_3d_co(self, curr_meas_stor, new_meas_stor)
            if new_coor is not None:
                do_translation(new_coor, self.pts[0].co3d)
                self.pts[0].co3d = new_coor.copy()
            reset_settings(self)
    
        elif self.transf_type == SCALE:
    
            #print("  SCALE!!")  # debug
    
    NBurn's avatar
    NBurn committed
            new_coor = get_new_3d_co(self, curr_meas_stor, new_meas_stor)
            if new_coor is not None:
                scale_factor = new_meas_stor / curr_meas_stor
                do_scale(self.pts, scale_factor)
                self.pts[0].co3d = new_coor.copy()
            reset_settings(self)
    
        elif self.transf_type == ROTATE:
    
            #print("  ROTATE!!")  # debug
    
    NBurn's avatar
    NBurn committed
            if self.new_free_co != ():
    
                do_rotate(self.pts[2].co3d)
    
    NBurn's avatar
    NBurn committed
                self.pts[0].co3d = self.new_free_co.copy()
            reset_settings(self)
    
    
    
    # Run after XEDIT_OT_meas_inp_dlg pop-up disables popup_active.
    
    NBurn's avatar
    NBurn committed
    # Checks to see if a valid number was input into the pop-up dialog and
    
    # determines what to do based on what value was supplied to the pop-up.
    
    NBurn's avatar
    NBurn committed
    def process_popup_input(self):
        global curr_meas_stor, new_meas_stor
        #print("process_popup_input")  # debug
        #print("curr_meas_stor", curr_meas_stor, " new_meas_stor", new_meas_stor)  # debug
        if new_meas_stor is not None:
            self.addon_mode = DO_TRANSFORM
            if self.transf_type == MOVE:
                do_transform(self)
            elif self.transf_type == SCALE:
                do_transform(self)
            elif self.transf_type == ROTATE:
                prep_rotation_info(curr_meas_stor, new_meas_stor)
                # if angle is flat...
                if flts_alm_eq(curr_meas_stor, 0.0) or \
                flts_alm_eq(curr_meas_stor, 180.0):
                    piv, mov = self.pts[2].co3d, self.pts[0].co3d
    
                    ang_rad = TransDat.ang_diff_r
    
    NBurn's avatar
    NBurn committed
                    if flts_alm_eq(new_meas_stor, 0.0) or \
                    flts_alm_eq(new_meas_stor, 180.0):
                        self.new_free_co = get_rotated_pt(piv, ang_rad, mov)
                        do_transform(self)
                    else:
    
                        TransDat.rot_pt_pos = get_rotated_pt(piv, ang_rad, mov)
                        TransDat.rot_pt_neg = get_rotated_pt(piv, -ang_rad, mov)
    
    NBurn's avatar
    NBurn committed
                        self.addon_mode = GET_0_OR_180
                else:  # non-flat angle
    
                    self.new_free_co, TransDat.ang_diff_r = \
    
    NBurn's avatar
    NBurn committed
                            find_correct_rot(self.pts, self.pt_cnt)
                    do_transform(self)
        else:
            reset_settings(self)
    
    
    def draw_rot_arc(colr):
        reg = bpy.context.region
        rv3d = bpy.context.region_data
    
        len_arc_pts = len(TransDat.arc_pts)
    
    NBurn's avatar
    NBurn committed
        if len_arc_pts > 1:
    
            last = loc3d_to_reg2d(reg, rv3d, TransDat.arc_pts[0])
    
    NBurn's avatar
    NBurn committed
            for p in range(1, len_arc_pts):
    
                p2d = loc3d_to_reg2d(reg, rv3d, TransDat.arc_pts[p])
    
    NBurn's avatar
    NBurn committed
                draw_line_2d(last, p2d, Colr.white)
                last = p2d
    
    
    # Called when add-on mode changes and every time point is added or removed.
    def set_help_text(self, mode):
        text = ""
        if mode == "CLICK":
            if self.pt_cnt == 0:
                text = "ESC/LMB+RMB - exits add-on, LMB - add ref point"
            elif self.pt_cnt == 1:
                text = "ESC/LMB+RMB - exits add-on, LMB - add/remove ref points, G - grab point, SHIFT+LMB enter mid point mode"
            elif self.pt_cnt == 2:
                text = "ESC/LMB+RMB - exits add-on, LMB - add/remove ref points, X/Y/Z - set axis lock, C - clear axis lock, G - grab point, SHIFT+LMB enter mid point mode, UP/DOWN - change tranform mode"
            else:  # self.pt_cnt == 3
                text = "ESC/LMB+RMB - exits add-on, LMB - remove ref points, X/Y/Z - set axis lock, C - clear axis lock, G - grab point, SHIFT+LMB enter mid point mode, UP/DOWN - change tranform mode"
        elif mode == "MULTI":
            text = "ESC/LMB+RMB - exits add-on, SHIFT+LMB exit mid point mode, LMB - add/remove point"
        elif mode == "GRAB":
            text = "ESC/LMB+RMB - exits add-on, G - cancel grab, LMB - place/swap ref points"
        elif mode == "POPUP":
            text = "ESC/LMB+RMB - exits add-on, LMB/RMB (outside pop-up) - cancel pop-up input"
    
        bpy.context.area.header_text_set(text)
    
    
    # todo : move most of below to mouse_co update in modal?
    def draw_callback_px(self, context):
        reg = bpy.context.region
        rv3d = bpy.context.region_data
        ptsz_lrg = 20
        ptsz_sml = 10
    
        add_rm_co = Vector((self.rtoolsw, 0))
        self.add_rm_btn.draw_btn(add_rm_co, self.mouse_co, self.shift_held)
    
        # allow appending None so indexing does not get messed up
        # causing potential false positive for overlap
        pts2d = [p.get_co2d() for p in self.pts]
        ms_colr = Colr.yellow
        if self.pt_cnt < 3:
            ms_colr = self.pts[self.pt_cnt].colr
    
        lk_pts2d = None  # lock points 2D
        self.meas_btn.is_drawn = False  # todo : cleaner btn activation
    
        # note, can't chain above if-elif block in with one below as
        # it breaks axis lock drawing
        if self.grab_pt is not None:  # not enabled if mod_pt active
            line_beg = pts2d[self.grab_pt]  # backup orignal co for move line
            pts2d[self.grab_pt] = None  # prevent check on grabbed pt
            closest_pt, self.overlap_idx = closest_to_point(self.mouse_co, pts2d)
            pts2d[self.grab_pt] = self.mouse_co
            ms_colr = self.pts[self.grab_pt].colr
            if not self.shift_held:
                draw_line_2d(line_beg, self.mouse_co, self.pts[self.grab_pt].colr)
                draw_pt_2d(closest_pt, Colr.white, ptsz_lrg)
    
        elif self.mod_pt is not None:
            ms_colr = self.pts[self.mod_pt].colr
            m_pts2d = [loc3d_to_reg2d(reg, rv3d, p) for p in self.multi_tmp.ls]
            closest_pt, self.overlap_idx = closest_to_point(self.mouse_co, m_pts2d)
            draw_pt_2d(pts2d[self.mod_pt], Colr.white, ptsz_lrg)
            if self.shift_held:
                draw_pt_2d(self.mouse_co, Colr.black, ptsz_lrg)
                if len(m_pts2d) > 1:
                    for mp in m_pts2d:
                        draw_pt_2d(mp, Colr.black, ptsz_lrg)
            else:
                draw_pt_2d(closest_pt, Colr.black, ptsz_lrg)
            if len(m_pts2d) > 1:
                for p in m_pts2d:
                    draw_pt_2d(p, ms_colr, ptsz_sml)
            last_mod_pt = loc3d_to_reg2d(reg, rv3d, self.multi_tmp.ls[-1])
            draw_line_2d(last_mod_pt, self.mouse_co, self.pts[self.mod_pt].colr)
    
        else:  # "Normal" mode
            closest_pt, self.overlap_idx = closest_to_point(self.mouse_co, pts2d)
            lin_p = pts2d
            if self.shift_held:
                draw_pt_2d(closest_pt, Colr.white, ptsz_lrg)
            else:
                draw_pt_2d(closest_pt, Colr.black, ptsz_lrg)
    
            if TransDat.axis_lock is not None:
                lk_pts2d = [p.get_co2d() for p in TransDat.lock_pts]
    
    NBurn's avatar
    NBurn committed
                lin_p = lk_pts2d
                # draw axis lock indicator
    
                if   TransDat.axis_lock == 'X':
    
    NBurn's avatar
    NBurn committed
                    txt_colr = Colr.red
    
                elif TransDat.axis_lock == 'Y':
    
    NBurn's avatar
    NBurn committed
                    txt_colr = Colr.green
    
                elif TransDat.axis_lock == 'Z':
    
    NBurn's avatar
    NBurn committed
                    txt_colr = Colr.blue
    
                dpi = bpy.context.preferences.system.dpi
    
    NBurn's avatar
    NBurn committed
                font_id, txt_sz = 0, 32
                x_pos, y_pos = self.rtoolsw + 80, 36
    
                blf.color(font_id, *txt_colr)
    
    NBurn's avatar
    NBurn committed
                blf.size(font_id, txt_sz, dpi)
                blf.position(font_id, x_pos, y_pos, 0)
    
                blf.draw(font_id, TransDat.axis_lock)
    
    NBurn's avatar
    NBurn committed
            if self.pt_cnt == 2:
                draw_line_2d(lin_p[0], lin_p[1], Colr.white)
                if None not in (lin_p[0], lin_p[1]):
                    btn_co = lin_p[0].lerp(lin_p[1], 0.5)
                    self.meas_btn.draw_btn(btn_co, self.mouse_co)
                    self.meas_btn.is_drawn = True
            elif self.pt_cnt == 3:
                draw_rot_arc(self.pts[2].colr)
                draw_line_2d(lin_p[0], lin_p[2], Colr.white)
                draw_line_2d(lin_p[1], lin_p[2], Colr.white)
                self.meas_btn.draw_btn(lin_p[2], self.mouse_co)
                self.meas_btn.is_drawn = True
    
        # draw reference points
        for p in range(self.pt_cnt):
            draw_pt_2d(pts2d[p], self.pts[p].colr, ptsz_sml)
    
        # draw lock points
        if lk_pts2d is not None:
    
            lp_cnt = len(TransDat.lock_pts)
    
    NBurn's avatar
    NBurn committed
            for p in range(lp_cnt):
                draw_pt_2d(lk_pts2d[p], self.pts[p].colr, ptsz_sml)
    
        if self.highlight_mouse:
            draw_pt_2d(self.mouse_co, ms_colr, ptsz_sml)
    
        # draw mode selection menu
        self.menu.draw(self.meas_btn.is_drawn)
    
    
    def exit_addon(self):
        restore_blender_settings(self.settings_backup)
    
        bpy.context.area.header_text_set(None)
    
    NBurn's avatar
    NBurn committed
        # todo : reset openGL settings?
        #bgl.glColor4f()
        #blf.size()
        #blf.position()
        #print("\n\nAdd-On Exited\n")  # debug
    
    
    
    # Checks if "use_region_overlap" is enabled and X offset is needed.
    
    NBurn's avatar
    NBurn committed
    def get_reg_overlap():
        rtoolsw = 0  # region tools (toolbar) width
        #ruiw = 0  # region ui (Number/n-panel) width
    
        system = bpy.context.preferences.system
    
    NBurn's avatar
    NBurn committed
        if system.use_region_overlap:
    
            area = bpy.context.area
            for r in area.regions:
                if r.type == 'TOOLS':
                    rtoolsw = r.width
                    #elif r.type == 'UI':
                    #    ruiw = r.width
    
    NBurn's avatar
    NBurn committed
        #return rtoolsw, ruiw
        return rtoolsw
    
    
    
    class XEDIT_OT_set_meas(bpy.types.Operator):
    
    NBurn's avatar
    NBurn committed
        bl_idname = "view3d.xedit_set_meas_op"
    
        bl_label = "Exact Edit Set Measure"
    
    NBurn's avatar
    NBurn committed
    
        # Only launch Add-On from OBJECT or EDIT modes
        @classmethod
        def poll(self, context):
            return context.mode == 'OBJECT' or context.mode == 'EDIT_MESH'
    
        def modal(self, context, event):
    
            global popup_active
    
    NBurn's avatar
    NBurn committed
            context.area.tag_redraw()
    
            if event.type in {'A', 'MIDDLEMOUSE', 'WHEELUPMOUSE',
            'WHEELDOWNMOUSE', 'NUMPAD_1', 'NUMPAD_2', 'NUMPAD_3', 'NUMPAD_4',
            'NUMPAD_6', 'NUMPAD_7', 'NUMPAD_8', 'NUMPAD_9', 'NUMPAD_0', 'TAB'}:
                return {'PASS_THROUGH'}
    
            if event.type == 'MOUSEMOVE':
                self.mouse_co = Vector((event.mouse_region_x, event.mouse_region_y))
    
            if event.type in {'LEFT_SHIFT', 'RIGHT_SHIFT'}:
                if event.value == 'PRESS':
                    self.shift_held = True
                    #print("\nShift pressed")  # debug
                elif event.value == 'RELEASE':
                    self.shift_held = False
                    #print("\nShift released")  # debug
    
            if event.type == 'RIGHTMOUSE' and event.value == 'PRESS':
                if self.lmb_held:
                    bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                    exit_addon(self)
                    return {'CANCELLED'}
                else:
                    return {'PASS_THROUGH'}
    
            if event.type == 'LEFTMOUSE' and event.value == 'PRESS':
                self.lmb_held = True
    
            elif event.type == 'UP_ARROW' and event.value == 'RELEASE':
                if self.meas_btn.is_drawn:
                    self.menu.update_active(-1)
    
            elif event.type == 'DOWN_ARROW' and event.value == 'RELEASE':
                if self.meas_btn.is_drawn:
                    self.menu.update_active( 1)
    
            elif event.type in {'RET', 'LEFTMOUSE'} and event.value == 'RELEASE':
                # prevent click/enter that launched add-on from doing anything
                if self.first_run:
                    self.first_run = False
                    return {'RUNNING_MODAL'}
                if event.type == 'LEFTMOUSE':
                    self.lmb_held = False
                #print("LeftMouse released")  # debug
                self.mouse_co = Vector((event.mouse_region_x, event.mouse_region_y))
    
                #===========================
                # Check for 0 or 180 click
                #===========================
                if self.addon_mode == GET_0_OR_180:
    
                    self.new_free_co, TransDat.ang_diff_r = choose_0_or_180(
                            self.pts[2], TransDat.rot_pt_pos, TransDat.rot_pt_neg,
                            TransDat.ang_diff_r, self.mouse_co
    
    NBurn's avatar
    NBurn committed
                    )
                    self.addon_mode = DO_TRANSFORM  # todo : find why this needed
                    do_transform(self)
    
                #===================================
                # Check for click on Measure Button
                #===================================
                elif self.meas_btn.is_drawn and self.meas_btn.ms_over:
                    #print("\nMeas Button Clicked")
                    if can_transf(self):
    
                        #global popup_active
    
    NBurn's avatar
    NBurn committed
                        self.addon_mode = WAIT_FOR_POPUP
                        popup_active = True
                        set_help_text(self, "POPUP")
                        bpy.ops.object.ms_input_dialog_op('INVOKE_DEFAULT')
    
                #===========================================
                # Check for click on "Add Selected" Button
                #===========================================
                elif self.add_rm_btn.ms_over:
                    if self.mod_pt is not None:
                        if not self.shift_held:
                            add_select_multi(self)
                        else:
                            if self.pt_cnt < 3:
                                new_select_multi(self)
                                exit_multi_mode(self)
                                self.menu.change_menu(self.pt_cnt)
                    elif self.grab_pt is not None:
                        co3d = None
                        if bpy.context.mode == "OBJECT":
                            if len(bpy.context.selected_objects) > 0:
                                if not self.shift_held:
                                    co3d = bpy.context.selected_objects[0].location
                                else:
                                    new_select_multi(self)
                                    exit_multi_mode(self)
                                    self.menu.change_menu(self.pt_cnt)
                        elif bpy.context.mode == "EDIT_MESH":
                            m_w = bpy.context.edit_object.matrix_world
                            bm = bmesh.from_edit_mesh(bpy.context.edit_object.data)
                            if len(bm.select_history) > 0:
                                if not self.shift_held:
                                    for sel in bm.select_history:
                                        if type(sel) is bmesh.types.BMVert:
    
                                            co3d = m_w @ sel.co
    
    NBurn's avatar
    NBurn committed
                                            break
                                        elif type(sel) is bmesh.types.BMEdge or \
                                                type(sel) is bmesh.types.BMFace:
                                            co3d = Vector()
                                            for v in sel.verts:
    
                                                co3d += m_w @ v.co
    
    NBurn's avatar
    NBurn committed
                                            co3d = co3d / len(sel.verts)
                                            break
                                else:
                                    new_select_multi(self)
                                    exit_multi_mode(self)
                                    self.menu.change_menu(self.pt_cnt)
    
                        if co3d is not None:
                            if not in_ref_pts(self, co3d):
                                self.pts[self.grab_pt].co3d = co3d
                            else:
                                swap_ref_pts(self, self.grab_pt, self.swap_pt)
                                self.swap_pt = None
                        self.grab_pt = None
                        updatelock_pts(self, self.pts)
                        set_meas_btn(self)
                    else:  # no grab or mod point
                        if self.shift_held:
                            if self.pt_cnt < 3:
                                new_select_multi(self)
                                if in_ref_pts(self, self.multi_tmp.get_co(), self.mod_pt):
                                    self.report({'WARNING'}, 'Points overlap.')
                                self.pts[self.mod_pt].co3d = self.multi_tmp.get_co()
                                self.menu.change_menu(self.pt_cnt)
                        else:
                            add_select(self)
                    # todo : see if this is really a good solution...
                    if self.mod_pt is None:
                        set_help_text(self, "CLICK")
                    else:
                        set_help_text(self, "MULTI")
    
                #===========================
                # Point Place or Grab Mode
                #===========================
                elif self.mod_pt is None:
                    if self.overlap_idx is None:  # no point overlap
                        if not self.shift_held:
                            if self.grab_pt is not None:
                                found_pt = find_closest_point(self.mouse_co)
                                if found_pt is not None:
                                    if not in_ref_pts(self, found_pt):
                                        self.pts[self.grab_pt].co3d = found_pt
                                self.grab_pt = None
                                if self.pt_cnt > 1:
                                    updatelock_pts(self, self.pts)
                                set_mouse_highlight(self)
                                set_meas_btn(self)
                                set_help_text(self, "CLICK")
                            elif self.pt_cnt < 3:
                                found_pt = find_closest_point(self.mouse_co)
                                if found_pt is not None:
                                    if not in_ref_pts(self, found_pt):
                                        self.pts[self.pt_cnt].co3d = found_pt
                                        self.pt_cnt += 1
                                        self.menu.change_menu(self.pt_cnt)
                                        if self.pt_cnt > 1:
                                            updatelock_pts(self, self.pts)
                                            #if self.pt_cnt
                                        set_mouse_highlight(self)
                                        set_meas_btn(self)
                                        set_help_text(self, "CLICK")
                                        ''' Begin Debug
                                        cnt = self.pt_cnt - 1
                                        pt_fnd_str = str(self.pts[cnt].co3d)
                                        pt_fnd_str = pt_fnd_str.replace("<Vector ", "Vector(")
                                        pt_fnd_str = pt_fnd_str.replace(">", ")")
                                        print("ref_pt_" + str(cnt) + ' =', pt_fnd_str)
                                        #print("ref pt added:", self.cnt, "cnt:", self.cnt+1)
                                        End Debug '''
                    else:  # overlap
                        if self.grab_pt is not None:
                            if not self.shift_held:
                                if self.grab_pt != self.overlap_idx:
                                    swap_ref_pts(self, self.grab_pt, self.overlap_idx)
                                    set_meas_btn(self)
                                self.grab_pt = None
                                if self.pt_cnt > 1:
                                    updatelock_pts(self, self.pts)
                                set_mouse_highlight(self)
                                set_meas_btn(self)
                                set_help_text(self, "CLICK")
    
                        elif not self.shift_held:
                            # overlap and shift not held == remove point
                            rem_ref_pt(self, self.overlap_idx)
                            set_meas_btn(self)
                            set_help_text(self, "CLICK")
                        else:  # shift_held
                            # enable multi point mode
                            self.mod_pt = self.overlap_idx
                            self.multi_tmp.reset(self.pts[self.mod_pt].co3d)
                            self.highlight_mouse = True
                            set_help_text(self, "MULTI")
    
                #===========================
                # Mod Ref Point Mode
                #===========================
                else:  # mod_pt exists
                    if self.overlap_idx is None:  # no point overlap
                        if not self.shift_held:
                            # attempt to add new point to multi_tmp
                            found_pt = find_closest_point(self.mouse_co)
                            if found_pt is not None:
                                self.multi_tmp.try_add(found_pt)
                                mult_co3d = self.multi_tmp.get_co()
                                if in_ref_pts(self, mult_co3d, self.mod_pt):
                                    self.report({'WARNING'}, 'Points overlap.')
                                self.pts[self.mod_pt].co3d = mult_co3d
                        else:  # shift_held, exit multi_tmp
                            exit_multi_mode(self)
                    else:  # overlap multi_tmp
                        if not self.shift_held:
                            # remove multi_tmp point
                            self.multi_tmp.rem_pt(self.overlap_idx)
                            # if all multi_tmp points removed,
                            # exit multi mode, remove edited point
                            if self.multi_tmp.co3d is None:
                                rem_ref_pt(self, self.mod_pt)
                                self.mod_pt = None
                                set_meas_btn(self)
                                set_help_text(self, "CLICK")
                            elif in_ref_pts(self, self.multi_tmp.co3d, self.mod_pt):
                                self.report({'WARNING'}, 'Points overlap.')
                                self.pts[self.mod_pt].co3d = self.multi_tmp.get_co()
                            else:
                                self.pts[self.mod_pt].co3d = self.multi_tmp.get_co()
                        else:  # shift_held
                            exit_multi_mode(self)
    
            if event.type == 'C' and event.value == 'PRESS':
                #print("Pressed C\n")  # debug
                axis_key_check(self, None)
    
            elif event.type == 'X' and event.value == 'PRESS':
                #print("Pressed X\n")  # debug
                axis_key_check(self, 'X')
    
            elif event.type == 'Y' and event.value == 'PRESS':
                #print("Pressed Y\n")  # debug
                axis_key_check(self, 'Y')
    
            elif event.type == 'Z' and event.value == 'PRESS':
                #print("Pressed Z\n")  # debug
                axis_key_check(self, 'Z')
    
                '''
    
            elif event.type == 'D' and event.value == 'RELEASE':
                # open debug console
                __import__('code').interact(local=dict(globals(), **locals()))
    
    NBurn's avatar
    NBurn committed
                '''
    
            elif event.type == 'G' and event.value == 'RELEASE':
                # if already in grab mode, cancel grab
                if self.grab_pt is not None:
                    self.grab_pt = None
                    set_mouse_highlight(self)
                    set_help_text(self, "CLICK")
                # else enable grab mode (if possible)
                elif self.mod_pt is None:
                    if self.overlap_idx is not None:
                        self.grab_pt = self.overlap_idx
                        self.highlight_mouse = False
                        set_help_text(self, "GRAB")
    
            elif event.type in {'ESC'} and event.value == 'RELEASE':
                bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                exit_addon(self)
                return {'CANCELLED'}
    
            if self.force_quit:
                bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                exit_addon(self)
                return {'FINISHED'}
    
    
            # if the addon_mode is WAIT_FOR_POPUP, wait on POPUP to disable
            # popup_active, then run process_popup_input
            # would prefer not to do pop-up check inside draw_callback, but not sure
            # how else to check for input. need higher level "input handler" class?
            if self.addon_mode == WAIT_FOR_POPUP:
                if not popup_active:
                    process_popup_input(self)
                    set_help_text(self, "CLICK")
    
            elif self.addon_mode == GET_0_OR_180:
    
                choose_0_or_180(TransDat.lock_pts[2], TransDat.rot_pt_pos,
                        TransDat.rot_pt_neg, TransDat.ang_diff_r, self.mouse_co)
    
    NBurn's avatar
    NBurn committed
            return {'RUNNING_MODAL'}
    
        def invoke(self, context, event):
            if context.area.type == 'VIEW_3D':
                args = (self, context)
    
                # Add the region OpenGL drawing callback
                # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
    
                self._handle = bpy.types.SpaceView3D.draw_handler_add(
                        draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
    
    NBurn's avatar
    NBurn committed
    
                self.settings_backup = backup_blender_settings()
                self.mouse_co = Vector((event.mouse_region_x, event.mouse_region_y))
                self.rtoolsw = get_reg_overlap()  # region tools (toolbar) width
                self.highlight_mouse = True  # draw ref point on mouse
                self.pts = []
                self.pt_cnt = 0
                self.lk_pts = []
                self.multi_tmp = TempPoint()
                self.meas_btn = ViewButton(Colr.red, Colr.white, 18, Colr.white, (0, 20))
                self.add_rm_btn = ViewButton(Colr.red, Colr.white, 18, Colr.white, (190, 36))
                self.overlap_idx = None
                self.shift_held = False
                #self.debug_flag = False
                self.mod_pt = None
                self.first_run = event.type in {'RET', 'LEFTMOUSE'} and event.value != 'RELEASE'
                self.force_quit = False
                self.grab_pt = None
                self.new_free_co = ()
                self.swap_pt = None
                self.addon_mode = CLICK_CHECK
                self.transf_type = ""  # transform type
                #self.pt_find_md = SLOW3DTO2D  # point find mode
                self.lmb_held = False
    
    
                self.menu = MenuHandler("Set Measaure", 18, Colr.yellow, \
                        Colr.white, self.rtoolsw, context.region)
    
    NBurn's avatar
    NBurn committed
                self.menu.add_menu(["Move", "Scale"])
                self.menu.add_menu(["Rotate"])
    
                context.window_manager.modal_handler_add(self)
    
                init_blender_settings()
    
                init_ref_pts(self)
                set_transform_data_none()
    
    NBurn's avatar
    NBurn committed
                editmode_refresh()
                #print("Add-on started")  # debug
                self.add_rm_btn.set_text("Add Selected")
                set_help_text(self, "CLICK")
    
                return {'RUNNING_MODAL'}
            else:
                self.report({'WARNING'}, "View3D not found, cannot run operator")
                return {'CANCELLED'}