Beispiel #1
0
class Launcher():
    ''' Displays a login window and option to allow users to create an account. '''
    def __init__(self, width, height, path):
        self.width, self.height = width, height

        os_user = windll.user32
        self.x_off, self.y_off = os_user.GetSystemMetrics(0), os_user.GetSystemMetrics(1)

        self.root = tkinter.Tk()
        self.root.withdraw()
        self.root.resizable(False, False)
        self.window = FloatingWindow(self.root)
        self.window.geometry("{}x{}+{}+{}".format(self.width, self.height, int((self.x_off - self.width) / 2), int((self.y_off - self.height) / 2)))
        self.window.overrideredirect(True)

        self.exit_button_size = (30, 30)
        self.sign_in_button_size = (10, 1)
        self.create_account_button_size = (15, 1)
        self.exit_button_padding = 10
        self.exit_button_pressed_padding = 0
        self.entry_size = 25
        self.entry_label_padding = 30

        self.header_label_x, self.header_label_y = self.width / 2, 115
        self.entry_label_x, self.entry_label_y = self.width / 2 - 175, self.height / 2
        self.entry_x, self.entry_y = self.width / 2 - 60, self.height / 2 + 5
        self.login_header_x, self.login_header_y = self.width / 2, 125
        self.sign_in_button_x, self.sign_in_button_y = self.width / 2 + 169, self.height / 2 + 65
        self.error_label_x, self.error_label_y = self.width / 2, self.height / 2 + 100
        self.signup_label_x, self.signup_label_y = self.width - 150, self.height - 8
        self.create_account_button_x, self.create_account_button_y = self.width - 5, self.height - 5

        self.bg_colour = '#171717'
        self.highlight_bg_colour = '#2b2b2b'
        self.highlight_fg_colour = '#7612db'
        self.hover_bg_colour = '#3b3b3b'
        self.text_colour = '#ffffff'
        self.error_colour = '#ffffff'

        self.header_font = ('Montserrat ExtraLight', '35')
        self.entry_label_font = ('Montserrat Light', '16')
        self.entry_font = ('Montserrat Light', '10')
        self.sign_in_button_font = ('Montserrat Medium', '10')
        self.error_label_font = ('Montserrat Medium', '10')
        self.signup_label_font = ('Montserrat Light', '12')

        self.parent_dir = os.path.abspath(os.path.join(path, os.pardir))
        self.db_manager = DatabaseManager(r'{}/data/EngineData.db'.format(self.parent_dir))
        self._launcher_closed = False
        self.error_text = None
        self.account_created_text = None
        self.new_sign_in_button_canvas = None
        self.path = path

        self.construct_launcher()
        self.root.mainloop()

    def launcher_closed(self):
        return self._launcher_closed

    def destruct_launcher(self):
        self.root.destroy()

    def close_window(self, event):
        self.destruct_launcher()
        self.db_manager.close_database()
        self._launcher_closed = True
    
    def construct_launcher(self):
        self.entered_username = tkinter.StringVar()
        self.entered_password = tkinter.StringVar()

        self.canvas = tkinter.Canvas(self.window, width = self.width, height = self.height, bd=0, highlightthickness=0)
        self.canvas.pack()
        self.button_canvas = tkinter.Canvas(self.canvas, width = self.exit_button_size[0], height = self.exit_button_size[1], bd=0, highlightthickness=0)
        self.button_canvas.place(x = self.width, y = 0, anchor = 'ne')

        bg_img = Image.open(r'{}/images/LAUNCHER_BG.png'.format(self.parent_dir))
        bg_top_corner_img = Image.open(r'{}/images/LAUNCHER_BG_TOPCORNER.png'.format(self.parent_dir))
        bg_top_corner_hover_img = Image.open(r'{}/images/LAUNCHER_BG_TOPCORNER_HOVER.png'.format(self.parent_dir))
        launcher_exit_img = Image.open(r'{}/images/EXIT.png'.format(self.parent_dir))
        self.bg_img = ImageTk.PhotoImage(bg_img)
        self.bg_top_corner_img = ImageTk.PhotoImage(bg_top_corner_img)
        self.bg_top_corner_hover_img = ImageTk.PhotoImage(bg_top_corner_hover_img)
        self.launcher_exit_img = ImageTk.PhotoImage(launcher_exit_img)
        self.username_entry = tkinter.Entry(self.window, textvariable = self.entered_username, width = self.entry_size, font = self.entry_font, bg = self.bg_colour, fg = self.text_colour, highlightcolor = self.highlight_fg_colour, bd = 0, highlightthickness = '1', highlightbackground = self.highlight_bg_colour)
        self.password_entry = tkinter.Entry(self.window, textvariable = self.entered_password, width = self.entry_size, font = self.entry_font, bg = self.bg_colour, fg = self.text_colour, highlightcolor = self.highlight_fg_colour, bd = 0, highlightthickness = '1', highlightbackground = self.highlight_bg_colour, show="●")
        self.sign_in_button = tkinter.Button(self.window, text = 'SIGN IN', width = self.sign_in_button_size[0], height = self.sign_in_button_size[1], font = self.sign_in_button_font, bg = self.bg_colour, fg = self.text_colour, activeforeground = self.highlight_fg_colour, bd = 0, activebackground = self.highlight_bg_colour, command = lambda: self.sign_in(self.entered_username.get(), self.entered_password.get()))
        self.create_account_button = tkinter.Button(self.window, text = 'CREATE ACCOUNT', width = self.create_account_button_size[0], height = self.create_account_button_size[1], font = self.sign_in_button_font, bg = self.bg_colour, fg = self.text_colour, activeforeground = self.highlight_fg_colour, bd = 0, activebackground = self.highlight_bg_colour, command = lambda: self.change_gui_to_create_account())

        self.canvas.create_image(self.width, 0, image = self.bg_img, anchor = 'ne')
        self.header = self.canvas.create_text(self.header_label_x, self.header_label_y, anchor = 'n', text = 'SIGN IN', font=self.header_font, fill = self.text_colour)
        self.canvas.create_text(self.entry_label_x, self.entry_label_y, anchor = 'nw', text = 'Username', font=self.entry_label_font, fill = self.text_colour)
        self.canvas.create_text(self.entry_label_x, self.entry_label_y + self.entry_label_padding, anchor = 'nw', text = 'Password', font=self.entry_label_font, fill = self.text_colour)
        self.create_account_text = self.canvas.create_text(self.signup_label_x, self.signup_label_y, anchor = 'se', text = 'Or create an account now.', font=self.signup_label_font, fill = self.text_colour)
        self.button_canvas.create_image(0, 0, anchor = 'nw', image = self.bg_top_corner_img)
        self.button_canvas.create_image(0, 0, anchor = 'nw', image = self.bg_top_corner_hover_img, tags = 'hover')
        self.button_canvas.create_image(0, 0, anchor = 'nw', image = self.launcher_exit_img, tags = 'exit_button')
        self.button_canvas.itemconfig('hover', state = 'hidden')
        self.canvas.create_window(self.entry_x, self.entry_y, anchor = 'nw', window = self.username_entry)
        self.canvas.create_window(self.entry_x, self.entry_y + self.entry_label_padding, anchor = 'nw', window = self.password_entry)
        self.sign_in_button_canvas = self.canvas.create_window(self.sign_in_button_x, self.sign_in_button_y, anchor = 'ne', window = self.sign_in_button)
        self.create_account_canvas = self.canvas.create_window(self.create_account_button_x, self.create_account_button_y, anchor = 'se', window = self.create_account_button)

        self.button_canvas.bind("<ButtonRelease-1>", self.close_window)
        self.button_canvas.bind("<Button-1>", self.pressed_exit_button)
        self.button_canvas.bind('<Enter>', self.hover_enter_exit_button)
        self.button_canvas.bind('<Leave>', self.hover_leave_exit_button)

        self.window.bind('<Return>', lambda event: self.check_sign_in_focus(self.window.focus_get()))

        self.window.bind('<Down>', self.initial_username_focus)
        self.window.bind('<Right>', self.initial_username_focus)
        self.window.bind('<Up>', self.initial_create_account_focus)
        self.window.bind('<Left>', self.initial_create_account_focus)

        self.username_entry.bind('<Down>', lambda event: self.password_entry.focus())
        self.password_entry.bind('<Down>', lambda event: self.sign_in_button.focus())
        self.sign_in_button.bind('<Down>', lambda event: self.create_account_button.focus())
        self.create_account_button.bind('<Down>', lambda event: self.username_entry.focus())
        self.create_account_button.bind('<Up>', lambda event: self.sign_in_button.focus())
        self.sign_in_button.bind('<Up>', lambda event: self.password_entry.focus())
        self.password_entry.bind('<Up>', lambda event: self.username_entry.focus())
        self.username_entry.bind('<Up>', lambda event: self.create_account_button.focus())


        self.username_entry.bind('<Right>', lambda event: self.password_entry.focus())
        self.password_entry.bind('<Right>', lambda event: self.sign_in_button.focus())
        self.sign_in_button.bind('<Right>', lambda event: self.create_account_button.focus())
        self.create_account_button.bind('<Right>', lambda event: self.username_entry.focus())
        self.create_account_button.bind('<Left>', lambda event: self.sign_in_button.focus())
        self.sign_in_button.bind('<Left>', lambda event: self.password_entry.focus())
        self.password_entry.bind('<Left>', lambda event: self.username_entry.focus())
        self.username_entry.bind('<Left>', lambda event: self.create_account_button.focus())

    def initial_username_focus(self, event):
        if self.window.focus_get() == None:
            self.username_entry.focus()
            self.window.bind('<Down>', lambda event: None)
            self.window.bind('<Right>', lambda event: None)

    def initial_create_account_focus(self, event):
        if self.window.focus_get() == None:
            self.create_account_button.focus()
            self.window.bind('<Up>', lambda event: None)
            self.window.bind('<Left>', lambda event: None)

    def check_sign_in_focus(self, focus):
        if focus == self.create_account_button:
            self.change_gui_to_create_account()
        else:
            self.sign_in(self.entered_username.get(), self.entered_password.get())

    def check_create_account_focus(self, focus):
        if focus == self.new_sign_in_button:
            self.change_gui_to_sign_in()
        else:
            self.create_account(self.entered_username.get(), self.entered_password.get())

    def pressed_exit_button(self, event):
        self.button_canvas.move('exit_button', self.exit_button_pressed_padding, self.exit_button_pressed_padding)

    def hover_enter_exit_button(self, event):
        self.button_canvas.itemconfig('hover', state = 'normal')

    def hover_leave_exit_button(self, event):
        self.button_canvas.itemconfig('hover', state = 'hidden')

    def reset_gui_to_sign_in(self):
        # Resets the gui to the original sign in screen, used when pressing escape or backspace on create account to go backwards
        self.window.bind('<Return>', lambda event: self.check_sign_in_focus(self.window.focus_get()))

        self.sign_in_button.bind('<Down>', lambda event: self.create_account_button.focus())
        self.create_account_button.bind('<Down>', lambda event: self.username_entry.focus())
        self.create_account_button.bind('<Up>', lambda event: self.sign_in_button.focus())
        self.username_entry.bind('<Up>', lambda event: self.create_account_button.focus())
        self.sign_in_button.bind('<Right>', lambda event: self.create_account_button.focus())
        self.create_account_button.bind('<Right>', lambda event: self.username_entry.focus())
        self.create_account_button.bind('<Left>', lambda event: self.sign_in_button.focus())
        self.username_entry.bind('<Left>', lambda event: self.create_account_button.focus())

        self.canvas.itemconfig(self.header, text = 'SIGN IN', font = self.header_font)
        self.canvas.itemconfig(self.account_created_text, state = 'hidden')
        self.sign_in_button.config(text = 'SIGN IN', width = self.sign_in_button_size[0], height = self.sign_in_button_size[1], command = lambda: self.sign_in(self.entered_username.get(), self.entered_password.get()))
        self.canvas.itemconfig(self.create_account_canvas, state = 'normal')
        self.canvas.itemconfig(self.create_account_text, state = 'normal')
        if self.new_sign_in_button_canvas != None:
            self.canvas.itemconfig(self.new_sign_in_button_canvas, state = 'hidden')


    def change_gui_to_create_account(self):
        # Changes the gui to create an account screen
        self.window.bind('<Escape>', lambda event: self.reset_gui_to_sign_in())
        self.window.bind('<BackSpace>', lambda event: self.reset_gui_to_sign_in())

        self.window.bind('<Return>', lambda event: self.create_account(self.entered_username.get(), self.entered_password.get()))

        self.sign_in_button.bind('<Down>', lambda event: self.username_entry.focus())
        self.sign_in_button.bind('<Right>', lambda event: self.username_entry.focus())
        self.username_entry.bind('<Up>', lambda event: self.sign_in_button.focus())
        self.username_entry.bind('<Left>', lambda event: self.sign_in_button.focus())

        self.canvas.itemconfig(self.header, text = 'CREATE ACCOUNT', font = self.header_font)
        self.canvas.itemconfig(self.create_account_canvas, state = 'hidden')
        self.canvas.itemconfig(self.create_account_text, state = 'hidden')
        self.sign_in_button.config(text = 'CREATE ACCOUNT', width = self.create_account_button_size[0], height = self.create_account_button_size[1], command = lambda: self.create_account(self.entered_username.get(), self.entered_password.get()))
        if self.error_text != None:
            self.canvas.delete(self.error_text)

    def change_gui_to_sign_in(self):
        # Changes the gui to sign in after creating an account
        self.window.bind('<Return>', lambda event: self.check_sign_in_focus(self.window.focus_get()))

        self.sign_in_button.bind('<Down>', lambda event: self.username_entry.focus())
        self.sign_in_button.bind('<Right>', lambda event: self.username_entry.focus())
        self.username_entry.bind('<Up>', lambda event: self.sign_in_button.focus())
        self.username_entry.bind('<Left>', lambda event: self.sign_in_button.focus())

        self.canvas.itemconfig(self.header, text = 'SIGN IN', font = self.header_font)
        self.canvas.itemconfig(self.account_created_text, state = 'hidden')
        self.canvas.itemconfig(self.new_sign_in_button_canvas, state = 'hidden')
        self.sign_in_button.config(text = 'SIGN IN', width = self.sign_in_button_size[0], height = self.sign_in_button_size[1], command = lambda: self.sign_in(self.entered_username.get(), self.entered_password.get()))

    def update_create_account_gui(self):
        if self.account_created_text == None:
            self.account_created_text = self.canvas.create_text(self.signup_label_x + 45, self.signup_label_y, anchor = 'se', text = 'Account sucessfully created. Sign in now.', font=self.signup_label_font, fill = self.text_colour)
            self.new_sign_in_button = tkinter.Button(self.window, text = 'SIGN IN', width = self.sign_in_button_size[0], height = self.sign_in_button_size[1], font = self.sign_in_button_font, bg = self.bg_colour, fg = self.text_colour, activeforeground = self.highlight_fg_colour, bd = 0, activebackground = self.highlight_bg_colour, command = lambda: self.change_gui_to_sign_in())
            self.new_sign_in_button_canvas = self.canvas.create_window(self.create_account_button_x, self.create_account_button_y, anchor = 'se', window = self.new_sign_in_button)

            self.window.bind('<Return>', lambda event: self.check_create_account_focus(self.window.focus_get()))

            self.sign_in_button.bind('<Down>', lambda event: self.new_sign_in_button.focus())
            self.new_sign_in_button.bind('<Down>', lambda event: self.username_entry.focus())
            self.sign_in_button.bind('<Right>', lambda event: self.new_sign_in_button.focus())
            self.new_sign_in_button.bind('<Right>', lambda event: self.username_entry.focus())

            self.username_entry.bind('<Up>', lambda event: self.new_sign_in_button.focus())
            self.new_sign_in_button.bind('<Up>', lambda event: self.sign_in_button.focus())
            self.username_entry.bind('<Left>', lambda event: self.new_sign_in_button.focus())
            self.new_sign_in_button.bind('<Left>', lambda event: self.sign_in_button.focus())

    def create_account(self, entered_username, entered_password):
        self.db_manager.add_user(entered_username, entered_password, datetime.datetime.now())
        self.update_create_account_gui()

    def sign_in(self, entered_username, entered_password):
        exists = self.db_manager.check_user_existance(entered_username, entered_password)
        if not exists:
            if self.error_text == None:
                self.error_text = self.canvas.create_text(self.error_label_x, self.error_label_y, anchor = 'n', text = 'Incorrect Username or Password', font=self.error_label_font, fill = self.error_colour)
        else:
            self.username = entered_username
            self.destruct_launcher()

    def get_username(self):
        return self.username
Beispiel #2
0
class EngineClient():
    ''' Updates and controls the Engine and GUI Objects to display the running engine. '''
    def __init__(self, width, height, login_sys, path):

        self.line_colour = (255, 255, 255)
        self.point_colour = (255, 255, 255)
        self.bg_colour = (35, 35, 35)
        self.fps_colour = (255, 255, 255)
        self.relative_line_colour = (118, 18, 219)

        self.displacement_arrows = 0
        
        self.fps_array, self.time_array = [], []
        self.fps_array_max_length = 500
        self.fps_graph_interval = 500
        self.start_time = time.time()

        # Initialising all variables used with chosen point and chosen rotation anchor to None
        self.chosen_point, self.chosen_rotation_anchor, self.input_boxes, self.responsive_text = None, None, None, None
        self.clickable_radius = 5 # The radius at which a point can be clicked beyond its shown radius
        self.translating, self.translating_x, self.translating_y = False, False, False
        self.use_custom_rotation_anchor, self.running = False, True

        self.login_sys = login_sys        
        path = os.getcwd()
        self.parent_dir = os.path.join(path, os.pardir)
        Path(r'{}/data'.format(self.parent_dir)).mkdir(parents=True, exist_ok=True)
        Path(r'{}/data/EngineData.db'.format(self.parent_dir)).touch(exist_ok=True)
        self.db_manager = DatabaseManager(r'{}/data/EngineData.db'.format(self.parent_dir))


        # lighting_factor: Controls the contrast of colour in objects, higher means more contrast
        self.display_surfaces, self.display_lines, self.display_points, \
        self.debug_mode, self.display_hud, self.display_logo, \
        self.rotation_factor, self.scaling_factor, self.translation_factor, \
        self.movement_factor, self.max_frame_rate, self.max_render_distance, \
        self.min_render_distance, self.lighting_factor , self.point_radius = self.db_manager.load_user_settings(self)

        self.camera = Camera(self)
        self.gui = GUI(self, self.db_manager, width, height, path)
        self.engine = Engine3D('orthographic', self.gui.viewer_centre)

        pygame.init()
        self.viewer = pygame.display.set_mode((self.gui.viewer_width, self.gui.viewer_height))
        self.clock = pygame.time.Clock()
        self.font = pygame.font.Font(r'{}/fonts/Montserrat-SemiBold.ttf'.format(self.parent_dir), 16)
        pygame.key.set_repeat(1, self.movement_factor)
        self.logo = pygame.image.load(r'{}/images/FL3D_small.png'.format(self.parent_dir))
        self.logo_size = (197, 70)

    def reset_rotation_anchor(self):
        self.rotation_anchor = self.engine.entities_centre()

    def reset_fps_graph(self):
        self.fps_array, self.time_array = [], []

    def save_world(self):
        self.db_manager.save_objects(self.engine.objects)

    def remove_world(self):
        self.db_manager.remove_save()

    def debug_display(self, object_3d):
        pygame.draw.circle(self.viewer, (255, 0, 0), (int(object_3d.points.access_index(0, 0)), int(object_3d.points.access_index(0, 1))), self.point_radius, 0)
        pygame.draw.circle(self.viewer, (0, 255, 0), (int(object_3d.find_centre()[0]), int(object_3d.find_centre()[1])), self.point_radius, 0)
        pygame.draw.circle(self.viewer, (0, 0, 255), (int(self.rotation_anchor[0]), int(self.rotation_anchor[1])), self.point_radius, 0)
    
    def close_window(self):
        self.gui.destruct_gui()
        self.running_fps = False
        self.running = False
        self.db_manager.update_login_time(self.login_sys.username, datetime.datetime.now())
        self.db_manager.save_user_settings(self)
        self.db_manager.close_database()
        pygame.quit()

    def minimise_window(self):
        self.gui.window.update_idletasks()
        self.gui.window.overrideredirect(False)
        self.gui.window.state('iconic')
        self.gui.maximise_window = True

    def maximise_window(self, event):
        self.gui.window.update_idletasks()
        self.gui.window.overrideredirect(True)
        if self.gui.maximise_window:
            self.gui.set_appwindow()
            self.gui.maximise_window = False

    def run(self):
        fps_animation = self.gui.animate_fps_graph()
        while self.running:
            pygame.mouse.set_cursor(*pygame.cursors.broken_x) # Ran every update to make sure that cursor stays on pygame cursor when in engine

            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key in self.camera.controls: 
                        self.camera.controls[event.key](self, self.engine)
                        self.gui.update_object_details()
                if event.type == pygame.MOUSEBUTTONDOWN:
                    self.check_translation_lines(pygame.mouse.get_pos())
                    self.translating = True
                elif event.type == pygame.MOUSEBUTTONUP:
                    self.translating_x, self.translating_y = False, False
                    self.translating = False
                elif event.type == pygame.MOUSEMOTION:
                    self.check_translation(pygame.mouse.get_pos())
                    self.check_rotation_anchor(pygame.mouse.get_pos())
                if self.input_boxes != None:
                    for input_box in self.input_boxes.access_input_boxes():
                        input_box.handle_event(event, self.movement_factor)

            if not self.use_custom_rotation_anchor:
                self.rotation_anchor = self.engine.entities_centre(self.engine.objects)

            self.render_objects()
            self.gui.update_world_objects()
            pygame.display.flip()
            self.clock.tick(self.max_frame_rate)
            self.engine.update_operating_status(False)
            if self.running:
                self.gui.root.update()

    def check_translation_lines(self, mouse_position):
        for rendered_point in self.engine.rendered_points:
            if self.check_object_radius(rendered_point[0], mouse_position):
                self.chosen_rotation_anchor, self.responsive_text = None, None
                self.engine.clear_translation_lines()
                translation_lines = GUILines(rendered_point[1], self.gui.translation_line_length)
                self.engine.set_translation_lines(translation_lines)
                if rendered_point == self.chosen_point:
                    self.engine.clear_translation_lines()
                    self.chosen_point, self.input_boxes = None, None
                else:
                    self.chosen_point = rendered_point
                    self.input_boxes = CoordinateInput(*rendered_point[1][:3], rendered_point, self.engine, self.viewer)
                break

        if self.check_point_radius(self.rotation_anchor, mouse_position):
            self.chosen_point, self.input_boxes = None, None
            if self.rotation_anchor == self.chosen_rotation_anchor:
                self.engine.clear_translation_lines()
                self.chosen_rotation_anchor, self.responsive_text = None, None
            else:
                self.chosen_rotation_anchor = self.rotation_anchor
                self.engine.clear_translation_lines()
                translation_lines = GUILines(self.rotation_anchor[:3], self.gui.translation_line_length)
                self.engine.set_translation_lines(translation_lines)
                self.responsive_text = ResponsiveText(*self.rotation_anchor[:2], 'Rotation Anchor')

    def check_point_radius(self, point, mouse_position):
        click_in_radius = False
        for x_position in range(mouse_position[0] - self.clickable_radius, mouse_position[0] + self.clickable_radius):
            for y_position in range(mouse_position[1] - self.clickable_radius, mouse_position[1] + self.clickable_radius):
                if int(point[0]) == x_position and int(point[1]) == y_position:
                    click_in_radius = True
        return click_in_radius

    def check_object_radius(self, pygame_object, mouse_position):
        click_in_radius = False
        for x_position in range(mouse_position[0] - self.clickable_radius, mouse_position[0] + self.clickable_radius):
            for y_position in range(mouse_position[1] - self.clickable_radius, mouse_position[1] + self.clickable_radius):
                if pygame_object.collidepoint((x_position, y_position)):
                    click_in_radius = True
        return click_in_radius
    
    def check_translation(self, mouse_position):
        if len(self.engine.rendered_translation_lines) > 0 and self.translating and self.chosen_point != None:
            if self.check_object_radius(self.engine.rendered_translation_lines[0], mouse_position) and self.translating_x == False and self.translating_y == False:
                self.translating_x = True
                self.translating_y = False
            if self.check_object_radius(self.engine.rendered_translation_lines[1], mouse_position) and self.translating_y == False and self.translating_x == False:
                self.translating_y = True
                self.translating_x = False

            if self.translating_x:
                current_row = self.chosen_point[2].points.access_row(self.chosen_point[3])
                new_row = mouse_position[0] - self.gui.translation_line_length / 2, current_row[1], current_row[2], current_row[3]
                self.chosen_point[2].points.set_row(self.chosen_point[3], new_row)
                self.chosen_point[2].project(self.engine.projection_type, self.engine.projection_anchor)
                translation_lines = GUILines(self.chosen_point[2].projected.access_row(self.chosen_point[3]), self.gui.translation_line_length)
                self.engine.set_translation_lines(translation_lines)

            if self.translating_y:
                current_row = self.chosen_point[2].points.access_row(self.chosen_point[3])
                new_row = current_row[0], mouse_position[1] - self.gui.translation_line_length / 2, current_row[2], current_row[3]
                self.chosen_point[2].points.set_row(self.chosen_point[3], new_row)
                self.chosen_point[2].project(self.engine.projection_type, self.engine.projection_anchor)
                translation_lines = GUILines(self.chosen_point[2].projected.access_row(self.chosen_point[3]), self.gui.translation_line_length)
                self.engine.set_translation_lines(translation_lines)

            self.input_boxes = CoordinateInput(*self.chosen_point[2].projected.access_row(self.chosen_point[3])[:3], self.chosen_point, self.engine, self.viewer)

    def check_rotation_anchor(self, mouse_position):
        if len(self.engine.rendered_translation_lines) > 0 and self.translating and self.chosen_point == None:
            if self.check_object_radius(self.engine.rendered_translation_lines[0], mouse_position) and self.translating_x == False and self.translating_y == False:
                self.translating_x = True
                self.translating_y = False
                self.use_custom_rotation_anchor = True
            if self.check_object_radius(self.engine.rendered_translation_lines[1], mouse_position) and self.translating_y == False and self.translating_x == False:
                self.translating_y = True
                self.translating_x = False
                self.use_custom_rotation_anchor = True

            if self.translating_x:
                current_row = self.rotation_anchor
                # New row z rotation has to still use centre of objects z position since only x and y can be specified by the translation lines
                new_row = mouse_position[0] - self.gui.translation_line_length / 2, current_row[1], self.engine.entities_centre(self.engine.objects)[2], 0
                self.rotation_anchor = new_row
                translation_lines = GUILines(self.rotation_anchor, self.gui.translation_line_length)
                self.engine.set_translation_lines(translation_lines)

            if self.translating_y:
                current_row = self.rotation_anchor
                new_row = current_row[0], mouse_position[1] - self.gui.translation_line_length / 2, self.engine.entities_centre(self.engine.objects)[2], 0
                self.rotation_anchor = new_row
                translation_lines = GUILines(self.rotation_anchor, self.gui.translation_line_length)
                self.engine.set_translation_lines(translation_lines)

            self.responsive_text = ResponsiveText(*self.rotation_anchor[:2], 'Rotation Anchor')

    def text_boxes_accepting_input(self):
        accepting_input = False
        if self.input_boxes != None:
            if self.input_boxes.accepting_input():
                accepting_input = True
        return accepting_input
    
    def render_objects(self):
        self.viewer.fill(self.bg_colour)
        self.engine.clear_rendered_points()
        if self.display_surfaces:
            for surface in self.engine.get_surfaces(self):
                colour, surface = surface[0], surface[1:]
                pygame.draw.polygon(self.viewer, colour, data_handling.convert_to_int_2d_array(surface))

        for object_3d in self.engine.objects.values():
            if object_3d.is_visible(self.gui.viewer_width, self.gui.viewer_height):
                if self.display_lines:
                    for point_1, point_2 in object_3d.lines:
                        pygame.draw.aaline(self.viewer, self.line_colour, object_3d.projected.access_row(point_1)[:2], object_3d.projected.access_row(point_2)[:2])

                if self.display_points:
                    for i, point in enumerate(object_3d.projected):
                        rendered_point = pygame.draw.circle(self.viewer, self.point_colour, (int(point[0]), int(point[1])), self.point_radius, 0)
                        self.engine.rendered_points.append([rendered_point, point, object_3d, i])
            else:
                self.render_relative_lines(object_3d)

            if self.debug_mode:
                self.debug_display(object_3d)

        if self.display_hud:
            fps = self.font.render('FPS: '+ str(int(self.clock.get_fps())), True, self.fps_colour)
            self.viewer.blit(fps, (10, 10))
            view = self.font.render('ORTHOGRAPHIC VIEW', True, self.fps_colour)
            self.viewer.blit(view, (self.gui.viewer_width - 200, 10))

        if self.display_logo:
            self.viewer.blit(self.logo, (self.gui.viewer_width - self.logo_size[0], self.gui.viewer_height - self.logo_size[1]))

        if self.engine.get_translation_lines() != None and not self.engine.performing_operations() and self.engine.acceptable_operation_period():
            if self.engine.get_translation_lines().is_visible(self.gui.viewer_width, self.gui.viewer_height):
                self.update_translation_system()
                self.render_translation_lines()
                self.render_input_boxes_and_text()

    def update_translation_system(self):
        if self.chosen_point != None:
            self.chosen_point[2].points.set_row(self.chosen_point[3], self.chosen_point[2].points.access_row(self.chosen_point[3]))
            self.chosen_point[2].project(self.engine.projection_type, self.engine.projection_anchor)
            translation_lines = GUILines(self.chosen_point[2].projected.access_row(self.chosen_point[3]), self.gui.translation_line_length)
            self.engine.set_translation_lines(translation_lines)
            self.input_boxes.reposition_boxes(*self.chosen_point[2].projected.access_row(self.chosen_point[3])[:2])

    def render_translation_lines(self):
        translation_lines = self.engine.get_translation_lines()
        x_line = pygame.draw.line(self.viewer, self.gui.translation_lines_colour_x, data_handling.convert_to_int_array(translation_lines.projected.access_row(0)[:2]), data_handling.convert_to_int_array(translation_lines.projected.access_row(1)[:2]), self.gui.translation_line_width)
        y_line = pygame.draw.line(self.viewer, self.gui.translation_lines_colour_y, data_handling.convert_to_int_array(translation_lines.projected.access_row(0)[:2]), data_handling.convert_to_int_array(translation_lines.projected.access_row(2)[:2]), self.gui.translation_line_width)
        rendered_point = pygame.draw.circle(self.viewer, self.point_colour, data_handling.convert_to_int_array(translation_lines.projected.access_row(0)[:2]), self.point_radius, 0)
        self.engine.rendered_translation_lines = [x_line, y_line]

    def render_input_boxes_and_text(self):
        if self.input_boxes != None:
            for input_box in self.input_boxes.access_input_boxes():
                input_box.resize()
                input_box.draw(self.viewer)
                
        if self.responsive_text != None:
            self.responsive_text.draw(self.viewer)

    def render_relative_lines(self, object_3d):
       for direction in object_3d.viewer_relativity(self.gui.viewer_width, self.gui.viewer_height):
            if direction == 'W':
                pygame.draw.line(self.viewer, self.relative_line_colour, (0,0), (0,self.gui.viewer_height), 5)
            if direction == 'E':
                pygame.draw.line(self.viewer, self.relative_line_colour, (self.gui.viewer_width,0), (self.gui.viewer_width,self.gui.viewer_height), 5)
            if direction == 'N':
                pygame.draw.line(self.viewer, self.relative_line_colour, (0,0), (self.gui.viewer_width,0), 5)
            if direction == 'S':
                pygame.draw.line(self.viewer, self.relative_line_colour, (0,self.gui.viewer_height), (self.gui.viewer_width,self.gui.viewer_height), 5)