Beispiel #1
0
    def NewFile(self):
        """
        Prompts the user for a type of file to create, and a location & name for the new file. Then creates that
        file, and loads the respective editor
        """
        # Only allow this is there is an active project
        if not Settings.getInstance().user_project_name:
            self.ShowNoActiveProjectPrompt()
        else:
            new_file_prompt = NewFileMenu("Content/Icons/Engine_Logo.png",
                                          "Choose a File Type")

            # Did the user successfully choose something?
            if new_file_prompt.exec():

                selected_type = new_file_prompt.GetSelection()
                prompt = FileSystemPrompt(self.main_window)
                result = prompt.SaveFile(
                    Settings.getInstance().supported_content_types['Data'],
                    Settings.getInstance().GetProjectContentDirectory(),
                    "Save File As")

                # Did the user choose a place and a name for the new file?
                if result:
                    with open(result, 'w') as new_file:
                        pass
                        Logger.getInstance().Log(f"File created - {result}", 2)

                    # Create the editor, then export to initially populate the new file
                    self.OpenEditor(result, selected_type)
                    self.active_editor.Export()
                else:
                    Logger.getInstance().Log(
                        "File information was not provided - Cancelling 'New File' action",
                        3)
Beispiel #2
0
    def OpenEditor(self, target_file_path, editor_type, import_file=False):
        """ Creates an editor tab based on the provided file information """
        if not Settings.getInstance().editor_data["EditorSettings"][
                "max_tabs"] <= self.e_ui.main_tab_editor.count():
            editor_classes = {
                FileType.Scene_Dialogue: EditorDialogue,
                FileType.Scene_Point_And_Click: EditorPointAndClick,
                FileType.Project_Settings: EditorProjectSettings
            }

            # Let's check if we already have an editor open for this file
            result = self.CheckIfFileOpen(target_file_path)
            if result:
                #@TODO: Should there be a reimport if the user tries to open an opened file? Or maybe a refesh button?
                Logger.getInstance().Log(
                    "An editor for the selected file is already open - Switching to the open editor ",
                    3)
                self.e_ui.main_tab_editor.setCurrentWidget(result)
            else:
                # Initialize the Editor
                self.active_editor = editor_classes[editor_type](
                    target_file_path)

                # Allow the caller to load the provided file instead of just marking it as the export target
                if import_file:
                    self.active_editor.Import()

                self.e_ui.AddTab(self.active_editor.GetUI(),
                                 os.path.basename(target_file_path),
                                 self.e_ui.main_tab_editor)
        else:
            QtWidgets.QMessageBox.about(
                self.e_ui.central_widget, "Tab Limit Reached!",
                "You have reached the maximum number of open tabs. Please close "
                "a tab before attempting to open another")
Beispiel #3
0
    def Import(self):
        super().Import()
        Logger.getInstance().Log(
            f"Importing Dialogue data for: {self.file_path}")

        file_data = Reader.ReadAll(self.file_path)

        # Skip importing if the file has no data to load
        if file_data:
            db_manager = DBManager()
            converted_data = db_manager.ConvertDialogueFileToEditorFormat(
                file_data["dialogue"])

            # The main branch is treated specially since we don't need to create it
            for branch_name, branch_data in converted_data.items():
                if not branch_name == "Main":
                    self.editor_ui.branches.CreateBranch(
                        branch_name, branch_data["description"])

                for action in branch_data["entries"]:
                    self.editor_ui.dialogue_sequence.AddEntry(
                        action, None, True)

            # Select the main branch by default
            self.editor_ui.branches.ChangeBranch(0)
Beispiel #4
0
    def MoveEntryDown(self):
        """ If an entry is selected, move it down one row """
        if self.dialogue_table.rowCount():
            selection = self.GetSelectedRow()

            # Only allow moving down if we're not already at the bottom of the sequence
            if selection + 1 >= self.dialogue_table.rowCount():
                Logger.getInstance().Log(
                    "Can't move entry down as we're at the bottom of the sequence",
                    3)
            else:
                # 'cellWidget' returns a pointer which becomes invalid once we override it's row. Given this, instead
                # of gently moving the row, we recreate it by transferring it's data to a newly created entry
                taken_entry = self.dialogue_table.cellWidget(selection, 0)

                # Delete the origin row
                self.dialogue_table.removeRow(selection)

                # Add a new entry two rows above the initial row
                new_row_num = selection + 1
                new_entry = self.AddEntry(taken_entry.action_data, new_row_num)

                # Transfer the data from the original entry to the new one, before refreshing the details
                new_entry.action_data = taken_entry.action_data
                self.ed_core.UpdateActiveEntry()
Beispiel #5
0
    def CreateFile(self, path: str, file_type) -> str:
        """
        Create a file of the given file type, initially assigning it a temp name. Returns whether the action was
        successful
        """
        file_name_exists = True

        # Keep trying to create the file using a simple iterator. At some point, don't allow creating if the user has
        # somehow created enough files to max this...I really hope they don't
        for num in range(0, 100):
            full_file_path = path + f"/New_{file_type}_{num}.yaml"
            if not os.path.exists(full_file_path):

                # Doesn't exist. Create it!
                Writer.WriteFile(
                    "", full_file_path,
                    Settings.getInstance().GetMetadataString(
                        FileType[file_type]))
                return full_file_path

        # Somehow the user has all versions of the default name covered...Inform the user
        Logger.getInstance().Log(
            "Unable to create file as all default name iterations are taken",
            4)
        return None
Beispiel #6
0
    def GetAllDialogueData(self) -> dict:
        """ Collects all dialogue data in this file, including all branches, and returns them as a dict """
        data_to_export = {}
        branch_count = self.editor_ui.branches.branches_list.count()
        for index in range(0, branch_count):
            # Get the actual branch entry widget instead of the containing item widget
            branch = self.editor_ui.branches.branches_list.itemWidget(
                self.editor_ui.branches.branches_list.item(index))

            # Before we save, let's be double sure the current information in the details panel is cached properly
            self.editor_ui.details.UpdateCache()

            # If a branch is currently active, then it's likely to of not updated it's cached branch data (Only
            # happens when the active branch is switched). To account for this, make sure the active branch is checked
            # differently by scanning the current dialogue entries
            if branch is self.editor_ui.branches.active_branch:
                Logger.getInstance().Log("Scanning dialogue entries...")
                self.UpdateBranchData(branch)

            branch_name, branch_description = branch.Get()
            branch_data = branch.GetData()
            new_entry = {
                #"name": branch_name,
                "description": branch_description,
                "entries": branch_data
            }

            data_to_export[branch_name] = new_entry

        return data_to_export
Beispiel #7
0
    def SaveAs(self):
        """ Prompts the user for a new location and file name to save the active editor's data """
        # Only allow this is there is an active project
        if not Settings.getInstance().user_project_name:
            self.ShowNoActiveProjectPrompt()
        else:
            # The user is not allowed to rename the project settings file due to the number of dependencies on it
            if self.active_editor.file_type is FileType.Project_Settings:
                Logger.getInstance().Log(
                    "Project Settings can not be renamed or saved to a new location",
                    3)
            else:
                prompt = FileSystemPrompt(self.main_window)
                new_file_path = prompt.SaveFile(
                    Settings.getInstance().supported_content_types['Data'],
                    self.active_editor.GetFilePath(),
                    "Choose a Location to Save the File", True)

                if not new_file_path:
                    Logger.getInstance().Log(
                        "File path was not provided - Cancelling 'SaveAs' action",
                        3)
                else:
                    can_save = self.ValidateNewFileLocation(new_file_path)
                    if can_save:
                        self.active_editor.file_path = new_file_path
                        self.e_ui.main_tab_editor.setTabText(
                            self.e_ui.main_tab_editor.currentIndex(),
                            self.active_editor.GetFileName())
                        self.active_editor.Export()
Beispiel #8
0
 def DeleteFile(self, path):
     """ Delete the provided file. Editor will remain open if the user wishes to resave """
     try:
         os.remove(path)
         Logger.getInstance().Log(f"Successfully deleted file '{path}'", 2)
     except Exception as exc:
         Logger.getInstance().Log(
             f"Failed to delete file '{path}' - Please review the exception to understand more",
             4)
Beispiel #9
0
    def RemoveEditorTab(self, index):
        """ Remove the tab for the given index (Value is automatically provided by the tab system as an arg) """
        #@TODO: Review if a memory leak is created here due to not going down the editor reference tree and deleting things
        Logger.getInstance().Log("Closing editor...")

        editor_widget = self.main_tab_editor.widget(index)
        del editor_widget
        self.main_tab_editor.removeTab(index)

        Logger.getInstance().Log("Editor closed")
Beispiel #10
0
    def __init__(self, file_path):
        super().__init__(file_path)

        self.file_type = FileType.Scene_Dialogue

        self.editor_ui = EditorDialogueUI(self)
        self.editor_ui.branches.CreateBranch(
            "Main",
            "This is the default, main branch\nConsider this the root of your dialogue tree"
        )
        Logger.getInstance().Log("Editor initialized")
    def __init__(self, file_path):
        super().__init__(file_path)

        self.file_type = FileType.Project_Settings

        # Read this data in first as the U.I will need it to initialize properly
        self.project_settings = Reader.ReadAll(self.file_path)
        self.project_settings_schema = Reader.ReadAll(
            Settings.getInstance().ConvertPartialToAbsolutePath(
                "Config/ProjectSettingsSchema.yaml"))

        self.editor_ui = EditorProjectSettingsUI(self)
        Logger.getInstance().Log("Editor initialized")
Beispiel #12
0
 def DeleteFolder(self, path):
     """ Delete the provided folder recursively. Editors will remain open if the user wishes to resave """
     print("Deleting folder")
     try:
         print(path)
         shutil.rmtree(path)
         Logger.getInstance().Log(
             f"Successfully deleted folder '{path}' and all of it's contents",
             2)
     except Exception as exc:
         Logger.getInstance().Log(
             f"Failed to delete folder '{path}' - Please review the exception to understand more",
             4)
         print(exc)
Beispiel #13
0
    def OpenProject(self):
        """ Prompts the user for a project directory, then loads that file in the respective editor """
        Logger.getInstance().Log("Requesting path to project root...")
        prompt = FileSystemPrompt(self.main_window)
        existing_project_dir = prompt.GetDirectory(
            self.GetLastSearchPath(), "Choose a Project Directory", False)
        self.UpdateSearchHistory(existing_project_dir)

        if not existing_project_dir:
            Logger.getInstance().Log(
                "Project directory was not provided - Cancelling 'Open Project' action",
                3)
        else:
            # Does the directory already have a project in it (Denoted by the admin folder's existence)
            if os.path.exists(existing_project_dir + "/" +
                              Settings.getInstance().project_file):
                Logger.getInstance().Log(
                    "Valid project selected - Setting as Active Project...")

                # Since we aren't asking for the project name, let's infer it from the path
                project_name = os.path.basename(existing_project_dir)
                self.SetActiveProject(project_name, existing_project_dir)
            else:
                Logger.getInstance().Log(
                    "An invalid Heartbeat project was selected - Cancelling 'Open Project' action",
                    4)
                QtWidgets.QMessageBox.about(
                    self.e_ui.central_widget, "Not a Valid Project Directory!",
                    "The chosen directory is not a valid Heartbeat project.\n"
                    "Please either choose a different project, or create a new project."
                )
Beispiel #14
0
    def GetFile(self,
                starting_dir,
                type_filter,
                prompt_title="Choose a File",
                project_only=True) -> str:
        """ Opens up a prompt for choosing an existing file. If nothing is selected, return an empty string"""
        Logger.getInstance().Log("Requesting file path...")

        file_path = self.getOpenFileName(self.parent(), prompt_title,
                                         starting_dir, type_filter)

        # Did the user choose a value?
        if file_path[0]:
            selected_dir = file_path[0]

            if project_only:
                if Settings.getInstance().user_project_dir in selected_dir:
                    Logger.getInstance().Log("Valid file chosen")
                    return selected_dir
                else:
                    self.ShowPathOutsideProjectMessage()
                    return ""
            else:
                Logger.getInstance().Log("Valid file chosen")
                return selected_dir
        else:
            Logger.getInstance().Log("File name and path not provided", 3)
            return ""
    def __init__(self, file_path):
        super().__init__(file_path)

        self.file_type = FileType.Scene_Point_And_Click

        # Since the Point & Click editor doesn't make use of all actions, but only those that can be rendered
        # (interactables, sprites, text, etc), we need to compile a custom action_data dict with only the options
        # we'll allow
        possible_actions = {
            "Renderables":
            ["Create Sprite", "Create Text", "Create Background"],
        }
        self.action_data = self.BuildActionDataDict(possible_actions)

        # Initialize the editor U.I
        self.editor_ui = EditorPointAndClickUI(self)
        Logger.getInstance().Log("Editor initialized")
Beispiel #16
0
 def Clean(self):
     """ Cleans the active project's build folder """
     # Only allow this is there is an active project
     if not Settings.getInstance().user_project_name:
         self.ShowNoActiveProjectPrompt()
     else:
         HBBuilder.Clean(Logger.getInstance(),
                         Settings.getInstance().user_project_dir)
Beispiel #17
0
    def CreateFolder(self, path: str) -> bool:
        """ Create a directory, initially assigning it a temp name. Returns whether the action was successful """
        folder_name_exists = True

        # Keep trying to create the folder using a simple iterator. At some point, don't allow creating if the user has
        # somehow created enough folders to max this...I really hope they don't
        for num in range(0, 100):
            full_folder_path = path + f"/New_Folder_{num}"
            if not os.path.exists(full_folder_path):
                # Doesn't exist. Create it!
                os.mkdir(full_folder_path)
                return full_folder_path

        # Somehow the user has all versions of the default name covered...Inform the user
        Logger.getInstance().Log(
            "Unable to create folder as all default name iterations are taken",
            4)
        return None
Beispiel #18
0
 def Build(self):
     """ Launches the HBBuilder in order to generate an executable from the active project """
     # Only allow this is there is an active project
     if not Settings.getInstance().user_project_name:
         self.ShowNoActiveProjectPrompt()
     else:
         HBBuilder.Build(Logger.getInstance(),
                         Settings.getInstance().engine_root,
                         Settings.getInstance().user_project_dir,
                         Settings.getInstance().user_project_name)
Beispiel #19
0
    def setupUi(self, MainWindow):
        # Configure the Window
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1024, 720)
        MainWindow.setWindowIcon(
            QtGui.QIcon(Settings.getInstance().ConvertPartialToAbsolutePath(
                "Content/Icons/Engine_Logo.png")))

        # Build the core window widget object
        self.central_widget = QtWidgets.QWidget(MainWindow)
        MainWindow.setCentralWidget(self.central_widget)

        # Build the core window layout object
        self.central_grid_layout = QtWidgets.QGridLayout(self.central_widget)
        self.central_grid_layout.setContentsMargins(0, 0, 0, 0)
        self.central_grid_layout.setSpacing(0)

        # Initialize the Menu Bar
        self.CreateMenuBar(MainWindow)

        # Allow the user to resize each row
        self.main_resize_container = QtWidgets.QSplitter(self.central_widget)
        self.main_resize_container.setOrientation(Qt.Vertical)

        # ****** Add everything to the interface ******
        self.central_grid_layout.addWidget(self.main_resize_container, 0, 0)
        self.CreateGettingStartedDisplay()
        self.CreateBottomTabContainer()
        self.AddTab(Logger.getInstance().GetUI(), "Logger",
                    self.bottom_tab_editor)

        # Adjust the main editor container so it takes up as much space as possible
        self.main_resize_container.setStretchFactor(0, 10)

        # Hook up buttons
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        # Update the text of all U.I elements using a translation function. That way, we centralize text updates
        # through a common point where localization can take place
        self.retranslateUi(MainWindow)

        Logger.getInstance().Log("Initialized Editor Interface")
Beispiel #20
0
    def SaveFile(self,
                 type_filter,
                 starting_dir,
                 prompt_title="Save File",
                 project_only=True) -> str:
        """
        Prompts the user with a filedialog which has them specify a file to create or write to. If nothing
        is selected, return an empty string
        """

        file_path = self.getSaveFileName(self.parent(), prompt_title,
                                         starting_dir, type_filter)

        # Did the user choose a value?
        if file_path[0]:
            selected_dir = file_path[0]

            if project_only:
                if Settings.getInstance().user_project_dir in selected_dir:
                    Logger.getInstance().Log("Valid file chosen")
                    return selected_dir
                else:
                    self.ShowPathOutsideProjectMessage()
                    return ""
            else:
                Logger.getInstance().Log("Valid file chosen")
                return selected_dir
        else:
            Logger.getInstance().Log("File name and path not provided", 3)
            return ""
Beispiel #21
0
    def Play(self, parent, project_path, engine_parent_root):
        Logger.getInstance().Log("Launching engine...")
        try:
            # Launch the engine, and wait until it shuts down before continuing
            result = subprocess.Popen(
                [
                    f"venv/Scripts/python",
                    "HBEngine/hb_engine.py",
                    "-p",
                     project_path
                ],
                stdout=True,
                stderr=True
            )
            Logger.getInstance().Log("Engine Launched - Editor temporarily unavailable")
            result.wait()

            Logger.getInstance().Log("Engine closed - Editor functionality resumed")

        except Exception as exc:
            QMessageBox.about(
                parent,
                "Unable to Launch Engine",
                "The HBEngine could not be launched.\n\n"
                "Please make sure the engine is available alongside the editor, or that you're\n"
                "PYTHONPATH is configured correctly to include the engine."
            )
            print(exc)
    def Export(self):
        super().Export()
        Logger.getInstance().Log(f"Exporting Project Settings")

        # Just in case the user has made any changes to the settings, save them
        self.editor_ui.UpdateProjectSettingsData()

        # Write the data out
        Logger.getInstance().Log("Writing data to file...")
        try:
            Writer.WriteFile(
                self.project_settings, self.file_path,
                f"# Type: {FileType.Project_Settings.name}\n" +
                f"# {Settings.getInstance().editor_data['EditorSettings']['version_string']}"
            )
            Logger.getInstance().Log("File Exported!", 2)
        except:
            Logger.getInstance().Log("Failed to Export!", 4)
Beispiel #23
0
 def ReadFromTemp(self, temp_file: str, key: str) -> str:
     """ Read from the provided temp file using the provided key, returning the results if found """
     if not os.path.exists(temp_file):
         Logger.getInstance().Log(
             f"The temp file '{temp_file}' was not found")
         return ""
     try:
         req_data = Reader.ReadAll(temp_file)[key]
         return req_data
     except Exception as exc:
         Logger.getInstance().Log(f"Failed to read '{temp_file}'")
         Logger.getInstance().Log(str(exc), 4)
         return ""
Beispiel #24
0
    def GetDirectory(self,
                     starting_dir,
                     prompt_title="Choose a Directory",
                     project_only=True) -> str:
        """ Opens up a prompt for choosing an existing directory. If nothing is selected, return an empty string"""
        Logger.getInstance().Log("Requesting directory path...")

        dir_path = self.getExistingDirectory(self.parent(), prompt_title,
                                             starting_dir)

        if dir_path:
            if project_only:
                if Settings.getInstance().user_project_dir in dir_path:
                    Logger.getInstance().Log("Valid directory chosen")
                    return dir_path
                else:
                    self.ShowPathOutsideProjectMessage()
                    return ""
            else:
                Logger.getInstance().Log("Valid directory chosen")
                return dir_path
        else:
            Logger.getInstance().Log("No directory chosen", 3)
            return ""
Beispiel #25
0
 def WriteToTemp(self, temp_file: str, data: dict) -> bool:
     """ Write to the provided temp file, creating it if it doesn't already exist """
     if not os.path.exists(temp_file):
         try:
             if not os.path.exists(Settings.editor_temp_root):
                 os.mkdir(Settings.editor_temp_root)
             with open(temp_file, "w"):
                 pass
         except Exception as exc:
             Logger.getInstance().Log(f"Unable to create '{temp_file}'", 4)
             Logger.getInstance().Log(str(exc), 4)
             return False
     temp_data = Reader.ReadAll(temp_file)
     if not temp_data:
         temp_data = {}
     try:
         for key, val in data.items():
             temp_data[key] = val
     except Exception as exc:
         Logger.getInstance().Log(f"Failed to update '{temp_file}'", 4)
         Logger.getInstance().Log(str(exc), 4)
         return False
     Writer.WriteFile(temp_data, temp_file)
     return True
Beispiel #26
0
    def Export(self):
        super().Export()
        Logger.getInstance().Log(
            f"Exporting Dialogue data for: {self.file_path}")
        data_to_export = self.GetAllDialogueData()
        db_manager = DBManager()
        data_to_export = {
            "type":
            FileType.Scene_Dialogue.name,
            "dialogue":
            db_manager.ConvertDialogueFileToEngineFormat(data_to_export)
        }

        # Write the data out
        Logger.getInstance().Log("Writing data to file...")
        try:
            Writer.WriteFile(
                data_to_export, self.file_path,
                f"# Type: {FileType.Scene_Dialogue.name}\n" +
                f"# {Settings.getInstance().editor_data['EditorSettings']['version_string']}"
            )
            Logger.getInstance().Log("File Exported!", 2)
        except:
            Logger.getInstance().Log("Failed to Export!", 4)
Beispiel #27
0
    def OpenFile(self, target_file_path=None):
        """ Prompt the user to choose a file, then load the respective editor using the data found """
        # Only allow this is there is an active project
        if not Settings.getInstance().user_project_name:
            self.ShowNoActiveProjectPrompt()
        else:
            existing_file = None

            # Validate whether the selected file is capable of being opened
            if ".yaml" not in target_file_path:
                Logger.getInstance().Log(
                    "File type does not have any interact functionality", 3)
                return
            """
            # *** Re-enable this code when the supported file types all have open functionality ***
            split_path = target_file_path.split(".")
            if len(split_path) > 1:
                extension = split_path[-1]
                is_supported = False
                for type_string in self.Settings.getInstance().supported_content_types.values():
                    if f".{extension}" in type_string:
                        is_supported = True
                        break

            if not is_supported:
                Logger.getInstance().Log("File type does not have any interact functionality", 3)
                pass
            """

            # Is the user opening a file through the main "File->Open" mechanism?
            if not target_file_path:
                prompt = FileSystemPrompt(self.main_window)
                existing_file = prompt.GetFile(
                    Settings.getInstance().GetProjectContentDirectory(),
                    Settings.getInstance().supported_content_types['Data'],
                    "Choose a File to Open")
            # Most likely the outliner requested a file be opened. Use the provided path
            else:
                existing_file = target_file_path

            # Does the file actually exist?
            if not existing_file:
                Logger.getInstance().Log(
                    "File path was not provided - Cancelling 'Open File' action",
                    3)
            else:
                # Read the first line to determine the type of file
                with open(existing_file) as f:

                    # Check the metadata at the top of the file to see which file type this is
                    line = f.readline()
                    search = re.search("# Type: (.*)", line)

                    # Was the expected metadata found?
                    if search:
                        file_type = FileType[search.group(1)]
                        self.OpenEditor(existing_file, file_type, True)
                    else:
                        Logger.getInstance().Log(
                            "An invalid file was selected - Cancelling 'Open File' action",
                            4)
                        QtWidgets.QMessageBox.about(
                            self.e_ui.central_widget, "Not a Valid File!",
                            "The chosen file was not created by the HBEditor.\n"
                            "Please either choose a different file, or create a new one.\n\n"
                            "If you authored this file by hand, please add the correct metadata to the top of the file"
                        )
Beispiel #28
0
    def __init__(self, file_path):
        self.file_path = file_path
        self.file_type = None
        self.editor_ui = None

        Logger.getInstance().Log("Initializing Editor...")
Beispiel #29
0
    def NewProject(self):
        """
        Prompts the user for a directory to create a new project, and for a project name. Then creates the
        chosen project
        """
        Logger.getInstance().Log(
            "Requesting directory for the new project...'")
        prompt = FileSystemPrompt(self.main_window)
        new_project_dir = prompt.GetDirectory(
            self.GetLastSearchPath(), "Choose a Directory to Create a Project",
            False)
        self.UpdateSearchHistory(new_project_dir)

        if not new_project_dir:
            Logger.getInstance().Log(
                "Project directory was not provided - Cancelling 'New Project' action",
                3)
        else:
            # [0] = user_input: str, [1] = value_provided: bool
            Logger.getInstance().Log(
                "Requesting a name for the new project...'")
            user_project_name = QtWidgets.QInputDialog.getText(
                self.e_ui.central_widget, "New Project",
                "Please Enter a Project Name:")[0]

            if not user_project_name:
                Logger.getInstance().Log(
                    "Project name was not provided - Cancelling 'New Project' action",
                    3)
            else:
                # Check if the project folder exists. If so, inform the user that this is already a project dir
                if os.path.exists(new_project_dir + "/" + user_project_name):
                    Logger.getInstance().Log(
                        "Chosen project directory already exists - Cancelling 'New Project' action",
                        4)
                    QtWidgets.QMessageBox.about(
                        self.e_ui.central_widget, "Project Already Exists!",
                        "The chosen directory already contains a project of the chosen name.\n"
                        "Please either delete this project, or choose another directory"
                    )

                # Everything is good to go. Create a new project!
                else:
                    Logger.getInstance().Log(
                        "Valid project destination chosen! Creating project folder structure..."
                    )

                    # Create the project directory
                    project_path = new_project_dir + "/" + user_project_name
                    os.mkdir(project_path)

                    # Create the pre-requisite project folders
                    for main_dir in Settings.getInstance(
                    ).project_folder_structure:
                        main_dir_path = project_path + "/" + main_dir
                        os.mkdir(main_dir_path)

                    # Create the project file
                    project_file = project_path + "/" + Settings.getInstance(
                    ).project_file
                    with open(project_file, "w"):
                        pass

                    # Clone project default files
                    for key, rel_path in Settings.getInstance(
                    ).project_default_files.items():
                        shutil.copy(
                            Settings.getInstance().engine_root + "/" +
                            rel_path, project_path + "/" + rel_path)

                    Logger.getInstance().Log(
                        f"Project Created at: {project_path}", 2)

                    # Set this as the active project
                    self.SetActiveProject(user_project_name, project_path)