diff --git a/README.md b/README.md index 4990e89..2afd459 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,8 @@ ![](https://github.com/mostypc123/XediX/blob/main/XediX%20main%20image%20dark.png?raw=true) # XediX -XediX is a text editor using Python. It is created for programming in Python. This text editor have syntax highlighting, run codes, sqlite3 database for accounts and more. It support Python and Java. -# Run -**a pre release for a big update will be out, so this will not work after it will be pushed** - -Download it and run it or if you have python and all modules, write this to terminal(Is reqired to have opened the folder where is XediX installed): -**Windows** -```shell -python XediX.py -``` -**Linux** -```shell -python3 XediX.py -``` +XediX is a text editor for programming in Python. +To run XediX, use the xedixSetup.exe file to install it on your computer. +This is a pre release for the version 4, so this is not complete. +The docs page will update, when the full version will be released. diff --git a/XediX.py b/XediX.py deleted file mode 100644 index f91153e..0000000 --- a/XediX.py +++ /dev/null @@ -1,477 +0,0 @@ -import customtkinter as ctk -import tkinter as tk -from tkinter import ttk -from tkinter import messagebox -import webview -from tkinter import filedialog -import subprocess -from tkinter import colorchooser # import colorchooser module -from tkinter import font # import font module -from tkinter import * -import re -from tkinter.font import Font -import sqlite3 -from tkterminal import Terminal -from idlelib.percolator import Percolator -import pyperclip -from idlelib.colorizer import ColorDelegator as ic -import os -import webbrowser -from ttkthemes import ThemedTk -import pyttsx3 - -engine = pyttsx3.init() - -def speak_text(text): - engine.say(text) - engine.runAndWait() - -def ext(): - # Funkcia na spustenie Python kódu - def run_python_code(code): - try: - exec(code) - except Exception as e: - print(f"Error in running Python code: {e}") - - # Funkcia na spustenie Java kódu - def run_java_code(code): - try: - subprocess.run(['java', code], capture_output=True, text=True) - except Exception as e: - print(f"Error in running Java code: {e}") - - # Funkcia pre pridanie nového rozšírenia do databázy - def add_extension(): - name = entry_name.get() - code = text_code.get("1.0", tk.END).strip() - ext_type = var.get() - - if name and code: - conn = sqlite3.connect('extensions.db') - c = conn.cursor() - c.execute("INSERT INTO extensions (name, code, type) VALUES (?, ?, ?)", (name, code, ext_type)) - conn.commit() - conn.close() - refresh_extension_list() - entry_name.delete(0, tk.END) - text_code.delete("1.0", tk.END) - var.set("python") - - # Funkcia pre spustenie rozšírenia podľa názvu - def run_extension(): - name = listbox_extensions.get(listbox_extensions.curselection()) - conn = sqlite3.connect('extensions.db') - c = conn.cursor() - - c.execute("SELECT code, type FROM extensions WHERE name=?", (name,)) - result = c.fetchone() - - if result: - code, ext_type = result - if ext_type == 'python': - run_python_code(code) - elif ext_type == 'java': - run_java_code(code) - else: - print("Extension with this name is not existing.") - - conn.close() - - # Funkcia na získanie zoznamu existujúcich rozšírení - def refresh_extension_list(): - conn = sqlite3.connect('extensions.db') - c = conn.cursor() - - c.execute("SELECT name FROM extensions") - extensions = c.fetchall() - - listbox_extensions.delete(0, tk.END) - for extension in extensions: - listbox_extensions.insert(tk.END, extension[0]) - - conn.close() - - # Vytvorenie databázy a tabuľky, ak neexistujú - conn = sqlite3.connect('extensions.db') - c = conn.cursor() - c.execute('''CREATE TABLE IF NOT EXISTS extensions - (name TEXT, code TEXT, type TEXT)''') - conn.commit() - conn.close() - - # GUI - ext = ctk.CTk() - ext.title("XediX Extensions") - - frame_add_extension = ctk.CTkFrame(ext) - frame_add_extension.pack(padx=10, pady=10) - - label_name = ctk.CTkLabel(frame_add_extension, text="Enter the name of extension:") - label_name.grid(row=0, column=0, sticky=tk.W) - - entry_name = ctk.CTkEntry(frame_add_extension) - entry_name.grid(row=0, column=1, padx=5, pady=5) - - label_code = ctk.CTkLabel(frame_add_extension, text="Enter the code of extension:") - label_code.grid(row=1, column=0, sticky=tk.W) - - text_code = tk.Text(frame_add_extension, height=10, width=50) - text_code.grid(row=1, column=1, padx=5, pady=5) - - label_type = ctk.CTkLabel(frame_add_extension, text="Type of extension") - label_type.grid(row=2, column=0, sticky=tk.W) - - var = tk.StringVar(value="python") - radio_python = ctk.CTkRadioButton(frame_add_extension, text="Python", variable=var, value="python") - radio_python.grid(row=2, column=1, sticky=tk.W) - - radio_java = ctk.CTkRadioButton(frame_add_extension, text="Java", variable=var, value="java") - radio_java.grid(row=2, column=1, sticky=tk.E) - - button_add_extension = ctk.CTkButton(frame_add_extension, text="Add extension", command=add_extension) - button_add_extension.grid(row=3, columnspan=2, pady=10) - - frame_extension_list = ctk.CTkFrame(ext) - frame_extension_list.pack(padx=10, pady=10) - - listbox_extensions = tk.Listbox(frame_extension_list, selectmode=tk.SINGLE, width=30) - listbox_extensions.pack(side=tk.LEFT, padx=5) - - scrollbar = ctk.CTkScrollbar(frame_extension_list, command=listbox_extensions.yview) - scrollbar.pack(side=tk.RIGHT, fill=tk.Y) - - listbox_extensions.config(yscrollcommand=scrollbar.set) - - button_run_extension = ctk.CTkButton(ext, text="Run extension", command=run_extension) - button_run_extension.pack(pady=10) - - # Aktualizujte zoznam rozšírení pri spustení aplikácie - refresh_extension_list() - - ext.mainloop() - -def Cloud(): - webview.create_window('Qiwi',"https://qiwi.gg") - webview.start() - -def Marks(): - gui = tk.Tk() - - def copy_to_clipboard(text): - pyperclip.copy(text) - messagebox.showinfo("Copy to Clipboard", "Mark copied to clipboard!") - - marks = ['ß', 'æ', 'œ', 'þ', 'ð', '¿', '¡', '§', '¶', '•', '£', '€', '¥', '¢', '‰', '†', '‡', '°', '±', 'µ', - 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י', 'כ', 'ך', 'ל', 'מ', 'ם', 'נ', 'ן', 'ס', 'ע', 'פ', - 'ף', 'צ', 'ץ', 'ק', 'ר', 'ש', 'ת', 'あ', 'い', 'う', 'え', 'お', 'か', 'き', 'く', 'け', 'こ', 'さ', 'し', 'す', - 'せ', 'そ', 'た', 'ち', 'つ', 'て', 'と', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ひ', 'ふ', 'へ', 'ほ', 'ま', 'み', 'む', - 'め', 'も', 'や', 'ゆ', 'よ', 'ら', 'り', 'る', 'れ', 'ろ', 'わ', 'を', 'ん', 'ア', 'イ', 'ウ', 'エ', 'オ', 'カ', 'キ', - 'ク', 'ケ', 'コ', 'サ', 'シ', 'ス', 'セ', 'ソ', 'タ', 'チ', 'ツ', 'テ', 'ト', 'ナ', 'ニ', 'ヌ', 'ネ', 'ノ', 'ハ', 'ヒ', 'フ', - 'ヘ', 'ホ', 'マ', 'ミ', 'ム', 'メ', 'モ', 'ヤ', 'ユ', 'ヨ', 'ラ', 'リ', 'ル', 'レ', 'ロ', 'ワ', 'ヲ', 'ン', 'ا', 'ب', 'ت', - 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', - '←', '↑', '→', '↓', '😀', '😃', '😄', '😊', '😎', '🙂', '😉', '😋', '😍', '😘', '😚', '😜', '😝', '😏', '😌', '😔', '😞', '😟', '😢', '😭', - '­▓', '­░', '▒', '▓', '█', 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', - 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я', '√', '≡', '≈', '≠', '▲', '■', '□', '●', '○', '♂', '♀'] - - button_width = 2 - button_height = 1 - buttons_per_row = 45 # Number of buttons per row - - row_count = (len(marks) - 1) // buttons_per_row + 1 - column_count = buttons_per_row - - for i, x in enumerate(marks): - btn = tk.Button(gui, text=x, command=lambda t=x: copy_to_clipboard(t), width=button_width, height=button_height) - btn.grid(row=i // buttons_per_row, column=i % buttons_per_row, padx=5, pady=5) - - # Calculate window dimensions based on button size and number of buttons - window_width = button_width * buttons_per_row + 15 - window_height = button_height * row_count + 15 - - gui.geometry(f"{window_width}x{window_height}") - - gui.mainloop() -def terminal(): - terminal = Terminal(pady=5, padx=5) - terminal.shell = True - terminal.linebar = True - terminal.pack(expand=True, fill='both') - -def XediX(): - root = tk.Toplevel(roott) - rew = 0 - menu = tk.Menu(root) - text = tk.Text(root, height=20) - text.pack() - output = tk.Text(root, height=10) - output.pack() - style = ttk.Style() - style.theme_use("winnative") - style.map("TButton", background=[("pressed", "green"), ("active", "yellow")]) - style.theme_use("winnative") - entrydd = Entry(root) - command = entrydd.get() - entrydd.pack() - def run_command(): - out = subprocess.check_output(command, shell=True, text=True) - output.insert('end', out) - btn = Button(root, command=run_command, text="Run") - btn.pack() - cdg = ic() - gicdg = ic() - - def detect_gitignore(): - if "#xedix/python" in text.get(2.0): - cdg.tagdefs["KEYWORD"] = {'foreground': '#AD1035'} - cdg.tagdefs["BUILTIN"] = {'foreground': '#0000FF'} - cdg.tagdefs["STRING"] = {'foreground': '#ff9c00'} - cdg.tagdefs["COMMENT"] = {'foreground': '#7277CC', 'font': "TkFixedFont italic"} - cdg.tagdefs["ERROR"] = {"background": "red"} - cdg.tagdefs["DEFINITION"] = {'foreground':'#F0DC82'} - - Percolator(text).insertfilter(cdg) - if "#xedix/gitignore" in text.get(2.0): - gicdg.tagdefs["COMMENT"] = {'foreground': '#7277CC', 'font': "TkFixedFont italic"} - - def opensite(): - webbrowser.open("xedix.w3spaces.com", 0, False) - - def toggle_theme(): - if root['bg'] == 'black': - root.config(bg='white') - text.config(bg='white', fg='black') - else: - root.config(bg='black') - text.config(bg='black', fg='white') - output.config(bg='black', fg='white') - - def run_code(): - # Save the code to a temporary file - code = text.get("1.0", tk.END) - with open("temp.py", "w") as f: - f.write(code) - # Run the code with the chosen interpreter - try: - # Use sys.executable to get the path of the current interpreter - result = os.system("python temp.py") - except Exception as e: - output.insert(tk.END, str(e) + "\n") - else: - messagebox.showinfo("output", "The output is in the terminal") - output.insert(tk.END, result) #type: ignore - - # Check if a Tk instance already exists - if not 'root' in globals(): - global root - root = tk.Tk() - - - def save_file(): - file = filedialog.asksaveasfile(defaultextension=".py") - if file is not None: - file.write(text.get("1.0", tk.END)) - file.close() - - def open_file(): - file = filedialog.askopenfile() - if file is not None: - text.delete("1.0", tk.END) - text.insert(tk.END, file.read()) - file.close() - - def choose_color(): - color = colorchooser.askcolor() - if color is not None: # check if a color is selected - text.config(fg=color[1]) # change the text color to the selected color - - def choose_bg(): # define a function to choose background color - bg = colorchooser.askcolor() # open the color chooser dialog - if bg is not None: # check if a color is selected - text.config(bg=bg[1]) # change the text background color to the selected color - def choose_font(): # define a function to choose font - fonts = list(font.families()) # get a list of available fonts - font_menu = tk.Toplevel(root) # create a new window for font selection - font_menu.title("Vybrať font") # set the title of the window - font_var = tk.StringVar() # create a variable to store the selected font - font_var.set(fonts[0]) # set the default font to the first one in the list - font_list = tk.Listbox(font_menu, listvariable=font_var) # create a listbox to display the fonts - font_list.pack() # pack the listbox - def select_font(): # define a function to select the font from the listbox - font_name = font_var.get() # get the selected font name - text_font = font.Font(family=font_name) # create a font object with the selected name - text.config(font=text_font) # change the text font to the selected one - font_menu.destroy() # close the font selection window - select_button = tk.Button(font_menu, text="Vybrať", command=select_font) # create a button to confirm the selection - select_button.pack() # pack the button - expression = tk.StringVar() - def calculate(): - try: - result = eval(expression.get()) - expression.set(str(result)) - except Exception as e: - expression.set("Error") - - def clear(): - expression.set("") - - def append(char): - current = expression.get() - expression.set(current + char) - - def launch_calculator(): - clc = tk.Toplevel(root) - clc.title("Calculator") - - entry = tk.Entry(clc, textvariable=expression, font=("Courier", 20)) - entry.grid(row=0, column=0, columnspan=4, padx=10, pady=10) - - buttons = [ - ("7", lambda: append("7")), - ("8", lambda: append("8")), - ("9", lambda: append("9")), - ("/", lambda: append("/")), - ("4", lambda: append("4")), - ("5", lambda: append("5")), - ("6", lambda: append("6")), - ("*", lambda: append("*")), - ("1", lambda: append("1")), - ("2", lambda: append("2")), - ("3", lambda: append("3")), - ("-", lambda: append("-")), - (".", lambda: append(".")), - ("0", lambda: append("0")), - ("=", calculate), - ("+", lambda: append("+")) - ] - - row = 1 - col = 0 - for button_text, command in buttons: - button = tk.Button(clc, text=button_text, width=5, height=2, command=command) - button.grid(row=row, column=col, padx=5, pady=5) - col += 1 - if col > 3: - col = 0 - row += 1 - - clear_button = tk.Button(clc, text="C", width=5, height=2, command=clear) - clear_button.grid(row=row, column=0, padx=5, pady=5) - - clc.mainloop() - - root.config(menu=menu) - - file_menu = tk.Menu(menu) - menu.add_cascade(label="File", menu=file_menu) - file_menu.add_command(label="Open", command=open_file) - file_menu.add_command(label="Save", command=save_file) - - run_menu = tk.Menu(menu) - menu.add_cascade(label="Run", menu=run_menu) - run_menu.add_command(label="Run code", command=run_code) - run_menu.add_command(label="App Marks", command=Marks) - run_menu.add_command(label="Launch Calculator", command=launch_calculator) - run_menu.add_command(label="Terminal", command=terminal) - run_menu.add_command(label="Cloud", command=Cloud) - run_menu.add_command(label="Extensions", command=ext) - - color_menu = tk.Menu(menu) - menu.add_cascade(label="Settings", menu=color_menu) - color_menu.add_command(label="Select color of text", command=choose_color) - color_menu.add_command(label="Select collor of background", command=choose_bg) - color_menu.add_command(label='Toggle Dark/Light', command=toggle_theme) - color_menu.add_command(label="Select font", command=choose_font) - color_menu.add_command(label="Refresh SH", command=detect_gitignore) - - root.config(menu=menu) - - help_menu = tk.Menu(menu) - menu.add_cascade(label="Help", menu=help_menu) - help_menu.add_command(label="Site", command=opensite) - - menu.config(bg="black",fg="white") - - root.mainloop() -# Vytvorenie alebo pripojenie k databáze -conn = sqlite3.connect("users.db") -c = conn.cursor() - -# Vytvorenie tabuľky pre používateľov, ak neexistuje -c.execute('''CREATE TABLE IF NOT EXISTS users ( - username TEXT PRIMARY KEY, - password TEXT)''') - -def login(): - username = username_entry.get() - password = password_entry.get() - - c.execute("SELECT * FROM users WHERE username=? AND password=?", (username, password)) - user = c.fetchone() - - if user: - roott.quit() - message = f"Welcome, {username}! Login successful." - speak_text(message) # Speak the welcome message - messagebox.showinfo("Login Successful", message) - XediX() - else: - speak_text("Invalid username or password. Please try again.") - messagebox.showerror("Login Failed", "Invalid username or password.") - -def create_account(): - username = username_entry.get() - password = password_entry.get() - - if username and password: - try: - c.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username, password)) - conn.commit() - speak_text("Your account has been created successfully.") - messagebox.showinfo("Account Created", "Your account has been created successfully.") - except sqlite3.IntegrityError: - speak_text("Username already exists. Please choose a different username.") - messagebox.showerror("Account Creation Failed", "Username already exists.") - else: - speak_text("Username and password are required.") - messagebox.showerror("Account Creation Failed", "Username and password are required.") - -roott = ThemedTk(theme="arc") -roott.title("XediX") - -# Nastavenie písma -font = Font(family="Helvetica", size=12) - -# Nastavenie farieb -background_color = "#f0f0f0" -button_color = "#336699" -button_foreground_color = "white" - -# Prihlasovacie okno -login_frame = tk.Frame(roott, bg=background_color) -login_frame.pack(pady=20) - -username_label = tk.Label(login_frame, text="Username:", bg=background_color, font=font) -username_label.grid(row=0, column=0, padx=5, pady=5) -username_entry = tk.Entry(login_frame, font=font) -username_entry.grid(row=0, column=1, padx=5, pady=5) - -password_label = tk.Label(login_frame, text="Password:", bg=background_color, font=font) -password_label.grid(row=1, column=0, padx=5, pady=5) -password_entry = tk.Entry(login_frame, show="•", font=font) -password_entry.grid(row=1, column=1, padx=5, pady=5) - -login_button = tk.Button(login_frame, text="Login", command=login, bg=button_color, fg=button_foreground_color, font=font) -login_button.grid(row=2, column=0, padx=5, pady=5) - -create_account_button = tk.Button(login_frame, text="Create Account", command=create_account, bg=button_color, fg=button_foreground_color, font=font) -create_account_button.grid(row=2, column=1, padx=5, pady=5) - -medzeri = tk.Label(login_frame, text="\n ") -#medzeri var is for a test and it's won't packed at roott window - -btnc = tk.Button(login_frame, text="Continue with no account", command=XediX) -btnc.grid() -roott.mainloop() -# Zatvorenie spojenia s databázou po ukončení programu -conn.close() diff --git a/main.py b/main.py new file mode 100644 index 0000000..9a7899e --- /dev/null +++ b/main.py @@ -0,0 +1,304 @@ +import wx +import wx.stc as stc +import os +import subprocess +import time +import threading + +class TextEditor(wx.Frame): + def __init__(self, *args, **kwargs): + super(TextEditor, self).__init__(*args, **kwargs) + self.output_window = None + self.InitUI() + + def InitUI(self): + panel = wx.Panel(self) + splitter = wx.SplitterWindow(panel) + + self.sidebar = wx.Panel(splitter) + + # Add New File button + new_file_btn = wx.Button(self.sidebar, label="New File") + new_file_btn.Bind(wx.EVT_BUTTON, self.OnNewFile) + + self.file_list = wx.ListBox(self.sidebar) + self.PopulateFileList() + + self.main_panel = wx.Panel(splitter) + self.default_message = wx.StaticText(self.main_panel, label="Open a file first", style=wx.ALIGN_CENTER) + font = self.default_message.GetFont() + font.PointSize += 4 + self.default_message.SetFont(font) + + main_vbox = wx.BoxSizer(wx.VERTICAL) + main_vbox.AddStretchSpacer(1) + main_vbox.Add(self.default_message, proportion=0, flag=wx.ALIGN_CENTER) + main_vbox.AddStretchSpacer(1) + self.main_panel.SetSizer(main_vbox) + + self.notebook = wx.Notebook(splitter) + self.notebook.Hide() + + self.ApplyDarkMode() + + sidebar_vbox = wx.BoxSizer(wx.VERTICAL) + + # Add the New File button and file list to the sidebar layout + sidebar_vbox.Add(new_file_btn, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + sidebar_vbox.Add(self.file_list, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + self.sidebar.SetSizer(sidebar_vbox) + + splitter.SplitVertically(self.sidebar, self.main_panel) + splitter.SetMinimumPaneSize(150) + + self.CreateMenuBar() + vbox = wx.BoxSizer(wx.VERTICAL) + vbox.Add(splitter, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + panel.SetSizer(vbox) + + self.SetTitle("XediX") + self.SetSize((800, 600)) + self.Centre() + + self.file_list.Bind(wx.EVT_LISTBOX_DCLICK, self.OnFileOpen) + + def CreateMenuBar(self): + menubar = wx.MenuBar() + + 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') + fileMenu.AppendSeparator() + exit_item = fileMenu.Append(wx.ID_EXIT, '&Exit\tCtrl+Q', 'Exit application') + + editMenu = wx.Menu() + cut_item = editMenu.Append(wx.ID_CUT, '&Cut\tCtrl+X', 'Cut selection') + copy_item = editMenu.Append(wx.ID_COPY, '&Copy\tCtrl+C', 'Copy selection') + paste_item = editMenu.Append(wx.ID_PASTE, '&Paste\tCtrl+V', 'Paste from clipboard') + + menubar.Append(fileMenu, '&File') + menubar.Append(editMenu, '&Edit') + self.SetMenuBar(menubar) + + self.Bind(wx.EVT_MENU, self.OnSave, save_item) + self.Bind(wx.EVT_MENU, self.OnRunCode, run_item) # Bind the run code action + 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.OnPaste, paste_item) + + def ApplyDarkMode(self): + dark_bg_color = wx.Colour(30, 30, 30) + text_color = wx.Colour(255, 255, 255) + self.sidebar.SetBackgroundColour(dark_bg_color) + self.notebook.SetBackgroundColour(dark_bg_color) + self.main_panel.SetBackgroundColour(dark_bg_color) + self.default_message.SetForegroundColour(text_color) + self.file_list.SetBackgroundColour(dark_bg_color) + self.file_list.SetForegroundColour(text_color) + + def PopulateFileList(self): + current_dir = os.getcwd() + files = [f for f in os.listdir(current_dir) if os.path.isfile(os.path.join(current_dir, f))] + self.file_list.AppendItems(files) + + def OnFileOpen(self, event): + file_name = self.file_list.GetStringSelection() + if file_name: + file_path = os.path.join(os.getcwd(), file_name) + with open(file_path, 'r') as file: + content = file.read() + + if not self.notebook.IsShown(): + self.default_message.Hide() + self.main_panel.Hide() + splitter = self.main_panel.GetParent() + splitter.ReplaceWindow(self.main_panel, self.notebook) + self.notebook.Show() + + + tab = wx.Panel(self.notebook) + text_area = stc.StyledTextCtrl(tab, style=wx.TE_MULTILINE) + text_area.SetText(content) + # Set dark background and light text for the entire control + dark_bg_color = "#1E1E1E" + light_text_color = "#FFFFFF" + text_area.StyleSetBackground(stc.STC_STYLE_DEFAULT, dark_bg_color) + text_area.StyleSetForeground(stc.STC_STYLE_DEFAULT, light_text_color) + text_area.StyleClearAll() # Apply the default style to all text + + # Set up Python syntax highlighting + text_area.SetLexer(stc.STC_LEX_PYTHON) + + # Default style + text_area.StyleSetSpec(stc.STC_P_DEFAULT, f"fore:{light_text_color},italic,back:{dark_bg_color}") + + # Comments + text_area.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#68C147,italic,back:#1E1E1E") + + # Strings + text_area.StyleSetSpec(stc.STC_P_STRING, "fore:#BA9EFE,italic,back:#1E1E1E") + + # Keywords + text_area.StyleSetSpec(stc.STC_P_WORD, "fore:#569CD6,bold,back:#1E1E1E") + text_area.SetKeyWords(0, "def class return if else elif import from as not is try except finally for while in with pass lambda") + + # Functions and variables + text_area.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#7BCCE1,italic,back:#1E1E1E") + + # Operators + text_area.StyleSetSpec(stc.STC_P_OPERATOR, "fore:#D4D4D4,bold,back:#1E1E1E") + + # Numbers + text_area.StyleSetSpec(stc.STC_P_NUMBER, "fore:#FFDD54,italic,back:#1E1E1E") + + # Decorators + text_area.StyleSetSpec(stc.STC_P_DECORATOR, "fore:#C586C0,italic,back:#1E1E1E") + + # Adjust indentation guides + text_area.SetIndentationGuides(True) + text_area.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "fore:#858585,italic,back:#1E1E1E") + text_area.SetMarginType(1, stc.STC_MARGIN_NUMBER) + text_area.SetMarginWidth(1, 40) + + # Ensure code folding is enabled + text_area.SetProperty("fold", "1") + text_area.SetMarginType(2, stc.STC_MARGIN_SYMBOL) + text_area.SetMarginMask(2, stc.STC_MASK_FOLDERS) + text_area.SetMarginSensitive(2, True) + text_area.SetMarginWidth(2, 16) + + # Set fold marker colors + text_area.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "#FFFFFF", "#1E1E1E") + text_area.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "#FFFFFF", "#1E1E1E") + + + tab_sizer = wx.BoxSizer(wx.VERTICAL) + tab_sizer.Add(text_area, proportion=1, flag=wx.EXPAND) + tab.SetSizer(tab_sizer) + + self.notebook.AddPage(tab, file_name) + + def OnNewFile(self, event): + # Create an empty file name and open it + temp_file_path = os.path.join(os.getcwd(), "Untitled.py") + + # Check if notebook is hidden and show it + if not self.notebook.IsShown(): + self.default_message.Hide() + self.main_panel.Hide() + splitter = self.main_panel.GetParent() + splitter.ReplaceWindow(self.main_panel, self.notebook) + self.notebook.Show() + + # Simulate "opening" an empty file by directly calling OnFileOpen with a file name + with open(temp_file_path, 'w') as temp_file: + temp_file.write('') # Create an empty file + + # Add it to the list box so it can be selected + self.file_list.Append(temp_file_path) + self.file_list.SetStringSelection(temp_file_path) + + # Call OnFileOpen to handle everything else + self.OnFileOpen(None) + + def ApplyTextAreaDarkMode(self, text_area): + dark_bg_color = wx.Colour(30, 30, 30) + text_color = wx.Colour(255, 255, 255) + text_area.SetBackgroundColour(dark_bg_color) + text_area.SetForegroundColour(text_color) + + def OnRunCode(self, event): + current_tab = self.notebook.GetCurrentPage() + if current_tab: + text_area = current_tab.GetChildren()[0] + code = text_area.GetValue() + + # Start measuring time + start_time = time.time() + + # Execute the code using Popen + self.process = subprocess.Popen( + ['python', '-c', code], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + # Start a thread to handle output and execution time + threading.Thread(target=self.HandleExecution, args=(start_time,), daemon=True).start() + + def HandleExecution(self, start_time): + stdout, stderr = self.process.communicate() + end_time = time.time() + execution_time = end_time - start_time + + # Create output dialog if it doesn't exist + if self.output_window is None: + self.output_window = wx.Dialog(self, title="Output Window", size=(600, 400)) + output_panel = wx.Panel(self.output_window) + output_vbox = wx.BoxSizer(wx.VERTICAL) + + self.output_text = wx.TextCtrl(output_panel, style=wx.TE_MULTILINE | wx.TE_READONLY) + + output_vbox.Add(self.output_text, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + output_panel.SetSizer(output_vbox) + + # Prepare output message with execution time + output_message = f"{stdout}\nErrors:\n{stderr}\n" + output_message += f"Execution Time: {execution_time:.4f} seconds\n" + + self.output_text.SetValue(output_message) + self.output_window.ShowModal() # Show the output dialog modally + + + def OnSave(self, event): + current_tab = self.notebook.GetCurrentPage() + if current_tab: + text_area = current_tab.GetChildren()[0] # The text area is the first child of the tab + content = text_area.GetValue() + file_name = self.notebook.GetPageText(self.notebook.GetSelection()) + + if file_name == "Untitled": + # Handle saving as a new file + save_dialog = wx.FileDialog(self, "Save File", "", "", wildcard="Python files (*.py)|*.py", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) + if save_dialog.ShowModal() == wx.ID_OK: + file_name = save_dialog.GetPath() + with open(file_name, 'w') as file: + file.write(content) + self.notebook.SetPageText(self.notebook.GetSelection(), os.path.basename(file_name)) + else: + # Overwrite the opened file + with open(file_name, 'w') as file: + file.write(content) + + + def OnExit(self, event): + self.Close() + + def OnCut(self, event): + current_tab = self.notebook.GetCurrentPage() + if current_tab: + text_area = current_tab.GetChildren()[0] + text_area.Cut() + + def OnCopy(self, event): + current_tab = self.notebook.GetCurrentPage() + if current_tab: + text_area = current_tab.GetChildren()[0] + text_area.Copy() + + def OnPaste(self, event): + current_tab = self.notebook.GetCurrentPage() + if current_tab: + text_area = current_tab.GetChildren()[0] + text_area.Paste() + +def main(): + app = wx.App(False) + frame = TextEditor(None) + frame.Show() + app.MainLoop() + +if __name__ == '__main__': + main() diff --git a/screenshot1.png b/screenshot1.png deleted file mode 100644 index 1f9c9a5..0000000 Binary files a/screenshot1.png and /dev/null differ diff --git a/screenshot2.png b/screenshot2.png deleted file mode 100644 index 466f0a2..0000000 Binary files a/screenshot2.png and /dev/null differ diff --git a/setup/xedixSetup.exe b/setup/xedixSetup.exe new file mode 100644 index 0000000..d3f5a12 --- /dev/null +++ b/setup/xedixSetup.exe @@ -0,0 +1 @@ +