diff --git a/src/main.py b/src/main.py index 2f075dd..f74d5ee 100644 --- a/src/main.py +++ b/src/main.py @@ -15,6 +15,7 @@ import extension_mainclass import requirements import git_integration +import settings class TextEditor(wx.Frame): def __init__(self, *args, **kwargs): @@ -92,6 +93,7 @@ def InitUI(self): self.file_list = wx.ListBox(self.sidebar) self.PopulateFileList() + self.file_list.Bind(wx.EVT_RIGHT_DOWN, self.OnFileListRightClick) self.matching_brackets = { '(': ')', @@ -171,6 +173,7 @@ def CreateMenuBar(self): fileMenu = wx.Menu() save_item = fileMenu.Append(wx.ID_SAVE, '&Save\tCtrl+S', 'Save the file') run_item = fileMenu.Append(wx.ID_ANY, '&Run Code\tCtrl+R', 'Run the code') + folder_item = fileMenu.Append(wx.ID_ANY, '&Open Folder\tCtrl+Shift+O', 'Open Folder') fileMenu.AppendSeparator() pylint_item = fileMenu.Append(wx.ID_ANY, '&Run pylint\tCtrl+P', 'Run pylint on code') exit_item = fileMenu.Append(wx.ID_EXIT, '&Exit\tCtrl+Q', 'Exit application') @@ -195,9 +198,6 @@ def CreateMenuBar(self): req_item = deployment_submenu.Append(wx.ID_ANY, 'Generate requirements.txt') toolsMenu.AppendSubMenu(deployment_submenu, 'Deployment Tools') - # Create the Customize menu item - customize_item = toolsMenu.Append(wx.ID_ANY, '&Customize\tCtrl+Shift+C', 'Customize the UI') - # Create the Git submenu git_submenu = wx.Menu() # This is a Menu, not a MenuItem commit_item = git_submenu.Append(wx.ID_ANY, 'Git Commit', 'Commit the code') # Append to the git submenu @@ -210,10 +210,14 @@ def CreateMenuBar(self): about_item = helpMenu.Append(wx.ID_ABOUT, '&About', 'About') docs_item = helpMenu.Append(wx.ID_ANY, "&Docs", "Open Documentation") + configMenu = wx.Menu() + customize_item = configMenu.Append(wx.ID_ANY, '&Customize manually\tCtrl+Shift+C', 'Customize the UI') + settings_item = configMenu.Append(wx.ID_ANY, '&Settings', 'Open Settings') menubar.Append(fileMenu, '&File') menubar.Append(editMenu, '&Edit') menubar.Append(toolsMenu,'&Tools') + menubar.Append(configMenu, '&Config') menubar.Append(helpMenu, '&Help') # minsize self.SetMenuBar(menubar) @@ -229,6 +233,8 @@ def CreateMenuBar(self): self.Bind(wx.EVT_MENU, self.OnExit, exit_item) self.Bind(wx.EVT_MENU, self.OnCut, cut_item) self.Bind(wx.EVT_MENU, self.OnCopy, copy_item) + self.Bind(wx.EVT_MENU, self.OnOpenFolder, folder_item) + self.Bind(wx.EVT_MENU, self.OnConfig, settings_item) self.Bind(wx.EVT_MENU, self.OnPaste, paste_item) self.Bind(wx.EVT_MENU, self.OnRunPylint, pylint_item) self.Bind(wx.EVT_MENU, self.OnFindReplace, find_replace_item) @@ -261,6 +267,35 @@ def Homepage(self, event): webbrowser.open("https://xedix.w3spaces.com") self.SetStatusText(" Webpage opened", 2) + def OnConfig(self, event): + settings.main() + + def OnOpenFolder(self, event): + # Create and show the directory dialog + dlg = wx.DirDialog(self, "Choose a directory:", + style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST) + + if dlg.ShowModal() == wx.ID_OK: + # Get the selected path + path = dlg.GetPath() + + # Change directory using os.system + os.system(f'cd "{path}"') + + # Also change the Python script's working directory + os.chdir(path) + + # Show confirmation message + self.SetStatusText(f" Changed directory to: {path}") + + # Clear the current file list + self.file_list.Clear() + + # Populate the file list with files from the new directory + self.PopulateFileList() + + dlg.Destroy() + def RequirementsGeneration(self, event): current_tab = self.notebook.GetCurrentPage() if current_tab: @@ -272,6 +307,91 @@ def RequirementsGeneration(self, event): else: self.SetStatusText("Error saving requirements") + # Add these methods to the TextEditor class + + def OnFileListRightClick(self, event): + """Handle right-click events on file list items.""" + # Get the item that was clicked + index = self.file_list.HitTest(event.GetPosition()) + if index != wx.NOT_FOUND: + self.file_list.SetSelection(index) + + # Create and show the context menu + menu = wx.Menu() + rename_item = menu.Append(wx.ID_ANY, "Rename") + delete_item = menu.Append(wx.ID_ANY, "Delete") + + # Bind menu events + self.Bind(wx.EVT_MENU, self.OnRenameFile, rename_item) + self.Bind(wx.EVT_MENU, self.OnDeleteFile, delete_item) + + # Show the popup menu + self.PopupMenu(menu) + menu.Destroy() + + def OnRenameFile(self, event): + """Handle file rename operation.""" + selected_index = self.file_list.GetSelection() + if selected_index != wx.NOT_FOUND: + old_name = self.file_list.GetString(selected_index) + + # Show dialog to get new name + dialog = wx.TextEntryDialog(self, "Enter new filename:", "Rename File", old_name) + if dialog.ShowModal() == wx.ID_OK: + new_name = dialog.GetValue() + + try: + # Rename the file + os.rename(old_name, new_name) + + # Update the file list + self.file_list.SetString(selected_index, new_name) + + # Update the notebook tab if the file is open + for i in range(self.notebook.GetPageCount()): + if self.notebook.GetPageText(i) == old_name: + self.notebook.SetPageText(i, new_name) + + self.SetStatusText(f" Renamed {old_name} to {new_name}") + except OSError as e: + wx.MessageBox(f"Error renaming file: {str(e)}", "Error", + wx.OK | wx.ICON_ERROR) + + dialog.Destroy() + + def OnDeleteFile(self, event): + """Handle file delete operation.""" + selected_index = self.file_list.GetSelection() + if selected_index != wx.NOT_FOUND: + filename = self.file_list.GetString(selected_index) + + # Show confirmation dialog + dialog = wx.MessageDialog(self, + f"Are you sure you want to delete '{filename}'?", + "Confirm Delete", + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + + if dialog.ShowModal() == wx.ID_YES: + try: + # Close the file if it's open in the editor + for i in range(self.notebook.GetPageCount()): + if self.notebook.GetPageText(i) == filename: + self.notebook.DeletePage(i) + break + + # Delete the file + os.remove(filename) + + # Remove from file list + self.file_list.Delete(selected_index) + + self.SetStatusText(f" Deleted {filename}") + except OSError as e: + wx.MessageBox(f"Error deleting file: {str(e)}", "Error", + wx.OK | wx.ICON_ERROR) + + dialog.Destroy() + def OnJumpToLine(self, event): current_tab = self.notebook.GetCurrentPage() if current_tab: @@ -462,50 +582,6 @@ def PopulateFileList(self): ## add padding between 2 child items list # self.file_list.SetWindowStyleFlag(wx.NO_BORDER) - - - - def OnChar(self, event): - self.SetStatusText(" Character pressed",2) - self.SetStatusText(" Showing recomendations") - current_tab = self.notebook.GetCurrentPage() - if current_tab: - text_area = current_tab.GetChildren()[0] - key_code = event.GetKeyCode() - - # Auto-close brackets - if chr(key_code) in self.matching_brackets: - pos = text_area.GetCurrentPos() - text_area.InsertText(pos, self.matching_brackets[chr(key_code)]) - text_area.SetCurrentPos(pos) - text_area.SetSelection(pos, pos) - - key_code = event.GetKeyCode() - if chr(key_code).isalpha() or key_code == ord('.'): - pos = text_area.GetCurrentPos() - word_start_pos = text_area.WordStartPosition(pos, True) - length = pos - word_start_pos - - # Show autocomplete after 3 characters or when a dot is typed - if length >= 0 or key_code == ord('.'): - # List of completions - completions_list = [ - "abs", "all", "any", "bin", "bool", "bytearray", "bytes", "chr", "classmethod", - "compile", "complex", "delattr", "dict", "dir", "divmod", "enumerate", "eval", - "exec", "filter", "float", "format", "frozenset", "getattr", "globals", - "hasattr", "hash", "help", "hex", "id", "input", "int", "isinstance", "issubclass", - "iter", "len", "list", "locals", "map", "max", "memoryview", "min", "next", - "object", "oct", "open", "ord", "pow", "print", "property", "range", "repr", - "reversed", "round", "set", "setattr", "slice", "sorted", "staticmethod", "str", - "sum", "super", "tuple", "type", "vars", "zip", "__name__" - ] - - # Convert the list of completions into a space-separated string - completions = " ".join(completions_list) - - text_area.AutoCompShow(0, completions) # Show the autocomplete list - - event.Skip() # Continue processing other key events def OnFileOpen(self, event): file_name = self.file_list.GetStringSelection() @@ -919,6 +995,50 @@ def OnSave(self, event): with open(file_name, 'w') as file: file.write(content) + def OnChar(self, event): + self.SetStatusText(" Character pressed",2) + self.SetStatusText(" Showing recomendations") + current_tab = self.notebook.GetCurrentPage() + if current_tab: + text_area = current_tab.GetChildren()[0] + key_code = event.GetKeyCode() + + # Auto-close brackets + if chr(key_code) in self.matching_brackets: + pos = text_area.GetCurrentPos() + text_area.InsertText(pos, self.matching_brackets[chr(key_code)]) + text_area.SetCurrentPos(pos) + text_area.SetSelection(pos, pos) + + key_code = event.GetKeyCode() + if chr(key_code).isalpha() or key_code == ord('.'): + pos = text_area.GetCurrentPos() + word_start_pos = text_area.WordStartPosition(pos, True) + length = pos - word_start_pos + + # Show autocomplete after 3 characters or when a dot is typed + if length >= 0 or key_code == ord('.'): + # List of completions + completions_list = [ + "abs", "all", "any", "bin", "bool", "bytearray", "bytes", "chr", "classmethod", + "compile", "complex", "delattr", "dict", "dir", "divmod", "enumerate", "eval", + "exec", "filter", "float", "format", "frozenset", "getattr", "globals", + "hasattr", "hash", "help", "hex", "id", "input", "int", "isinstance", "issubclass", + "iter", "len", "list", "locals", "map", "max", "memoryview", "min", "next", + "object", "oct", "open", "ord", "pow", "print", "property", "range", "repr", + "reversed", "round", "set", "setattr", "slice", "sorted", "staticmethod", "str", + "sum", "super", "tuple", "type", "vars", "zip", "__name__" + ] + + # Convert the list of completions into a space-separated string + completions = " ".join(completions_list) + + text_area.AutoCompShow(0, completions) # Show the autocomplete list + self.OnSave(wx.EVT_CHAR) + self.SetStatusText(" Autosaved", 2) + + event.Skip() # Continue processing other key events + def OnExit(self, event): self.SetStatusText(" Exiting XediX...") time.sleep(1) @@ -944,7 +1064,6 @@ def OnPaste(self, event): extension_mainclass.main() - def main(): app = wx.App(False) frame = TextEditor(None) diff --git a/src/settings.py b/src/settings.py new file mode 100644 index 0000000..5a96e9c --- /dev/null +++ b/src/settings.py @@ -0,0 +1,94 @@ +import wx + +class SettingsApp(wx.Frame): + def __init__(self, *args, **kw): + super(SettingsApp, self).__init__(*args, **kw) + + self.initUI() + + def initUI(self): + panel = wx.Panel(self) + + vbox = wx.BoxSizer(wx.VERTICAL) + + # Theme setting + hbox1 = wx.BoxSizer(wx.HORIZONTAL) + st1 = wx.StaticText(panel, label='Theme Value:') + hbox1.Add(st1, flag=wx.RIGHT, border=8) + self.theme_text = wx.TextCtrl(panel) + hbox1.Add(self.theme_text, proportion=1) + vbox.Add(hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10) + + # Header Active setting + hbox2 = wx.BoxSizer(wx.HORIZONTAL) + st2 = wx.StaticText(panel, label='Header Active Color:') + hbox2.Add(st2, flag=wx.RIGHT, border=8) + self.header_active_text = wx.TextCtrl(panel) + hbox2.Add(self.header_active_text, proportion=1) + vbox.Add(hbox2, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10) + + # Header Inactive setting + hbox3 = wx.BoxSizer(wx.HORIZONTAL) + st3 = wx.StaticText(panel, label='Header Inactive Color:') + hbox3.Add(st3, flag=wx.RIGHT, border=8) + self.header_inactive_text = wx.TextCtrl(panel) + hbox3.Add(self.header_inactive_text, proportion=1) + vbox.Add(hbox3, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10) + + # Save button + hbox4 = wx.BoxSizer(wx.HORIZONTAL) + btn_save = wx.Button(panel, label='Save', size=(70, 30)) + hbox4.Add(btn_save) + vbox.Add(hbox4, flag=wx.ALIGN_RIGHT|wx.RIGHT|wx.BOTTOM, border=10) + + panel.SetSizer(vbox) + + # Load initial values + self.load_settings() + + # Bind the save button to the save function + btn_save.Bind(wx.EVT_BUTTON, self.on_save) + + self.SetSize((400, 250)) + self.SetTitle('Settings App') + self.Centre() + + def load_settings(self): + try: + with open('theme.xcfg', 'r') as file: + theme_value = file.read().strip() + self.theme_text.SetValue(theme_value) + except FileNotFoundError: + self.theme_text.SetValue('') + + try: + with open('xedix.xcfg', 'r') as file: + lines = file.readlines() + for line in lines: + if line.startswith('headerActive:'): + self.header_active_text.SetValue(line.split(':')[1].strip()) + elif line.startswith('headerInactive:'): + self.header_inactive_text.SetValue(line.split(':')[1].strip()) + except FileNotFoundError: + self.header_active_text.SetValue('') + self.header_inactive_text.SetValue('') + + def on_save(self, event): + theme_value = self.theme_text.GetValue().strip() + header_active_color = self.header_active_text.GetValue().strip() + header_inactive_color = self.header_inactive_text.GetValue().strip() + + with open('theme.xcfg', 'w') as file: + file.write(theme_value) + + with open('xedix.xcfg', 'w') as file: + file.write(f'headerActive:{header_active_color};\n') + file.write(f'headerInactive:{header_inactive_color};\n') + + wx.MessageBox('Settings saved successfully', 'Info', wx.OK | wx.ICON_INFORMATION) + +def main(): + app = wx.App() + frame = SettingsApp(None) + frame.Show() + app.MainLoop()