Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter as tk
- from tkinter import ttk, filedialog, messagebox, colorchooser
- from PIL import Image, ImageTk
- import os
- import sys
- import datetime
- import json
- import shutil
- import random
- import string
- import threading
- import subprocess
- # Tente importar pygame para sons, mas garanta que o programa funcione sem ele.
- try:
- import pygame
- pygame.mixer.init()
- sound_enabled = True
- except ImportError:
- print("Módulo 'pygame' não encontrado. Sons do sistema serão desabilitados.")
- sound_enabled = False
- except Exception as e:
- print(f"Erro ao inicializar pygame mixer: {e}. Sons do sistema desabilitados.")
- sound_enabled = False
- # Tente importar webview para o navegador
- try:
- import webview
- webview_enabled = True
- except ImportError:
- print("Módulo 'pywebview' não encontrado. Navegador será desabilitado.")
- webview_enabled = False
- # --- Constantes e Estilos ---
- class NovaColors:
- BLUE_LUNA_PRIMARY = "#4076BC"
- BLUE_LUNA_ACCENT = "#285493"
- BLUE_LUNA_HIGHLIGHT = "#73A8E0"
- GREEN_START_BUTTON = "#368832"
- GRAY_TASKBAR = "#C0C0C0"
- GRAY_TRANSPARENT = "#B0B0B0"
- WHITE_TEXT = "#FFFFFF"
- DARK_TEXT = "#000000"
- RED_CLOSE = "#D82D2D"
- GREEN_MAXIMIZE = "#5CB85C"
- YELLOW_MINIMIZE = "#F0AD4E"
- LIGHT_GRAY_BG = "#F0F0F0"
- BLUE_BUTTON = "#0056B3"
- DESKTOP_BG = "#0080FF" # Cor padrão azul do Windows XP
- ONLINE_COLOR = "#00C000"
- OFFLINE_COLOR = "#C00000"
- # --- Classes de Janelas Padrão ---
- class DraggableToplevel(tk.Toplevel):
- def __init__(self, master, nova_os_instance, title="Nova Janela", default_geometry="500x400", bg_color="#FFFFFF"):
- super().__init__(master, bg=bg_color, relief="raised", bd=2)
- self.nova_os = nova_os_instance
- self.title(title)
- self.geometry(default_geometry)
- self.overrideredirect(True)
- self.x = 0
- self.y = 0
- self.start_x = 0
- self.start_y = 0
- self.last_geometry = default_geometry
- self.title_bar = tk.Frame(self, relief="raised", bd=0)
- self.title_bar.pack(side="top", fill="x")
- self._create_gradient_title_bar(self.title_bar)
- self.title_label = tk.Label(self.title_bar, text=title, fg="white", bg=NovaColors.BLUE_LUNA_ACCENT, font=("Segoe UI", 10, "bold"))
- self.title_label.place(relx=0.5, rely=0.5, anchor="center")
- controls_frame = tk.Frame(self.title_bar, bg=NovaColors.BLUE_LUNA_ACCENT)
- controls_frame.place(relx=1.0, rely=0.5, anchor="e")
- self.minimize_button = tk.Button(controls_frame, text="—", bg=NovaColors.YELLOW_MINIMIZE, fg=NovaColors.DARK_TEXT, relief="flat", command=self.minimize, font=("Segoe UI", 10), width=3)
- self.minimize_button.pack(side="right", padx=(0, 2))
- self.maximize_button = tk.Button(controls_frame, text="▢", bg=NovaColors.GREEN_MAXIMIZE, fg=NovaColors.WHITE_TEXT, relief="flat", command=self.maximize, font=("Segoe UI", 10), width=3)
- self.maximize_button.pack(side="right", padx=(0, 2))
- self.close_button = tk.Button(controls_frame, text="✕", bg=NovaColors.RED_CLOSE, fg=NovaColors.WHITE_TEXT, relief="flat", command=self._on_closing, font=("Segoe UI", 10), width=3)
- self.close_button.pack(side="right", padx=(0, 2))
- self.content_frame = tk.Frame(self, bg=self['bg'])
- self.content_frame.pack(fill="both", expand=True)
- self.title_bar.bind("<Button-1>", self.start_move)
- self.title_bar.bind("<B1-Motion>", self.do_move)
- self.resizable_frame = tk.Frame(self, cursor="sizing", width=10, height=10, bg="#FFFFFF")
- self.resizable_frame.pack(side="bottom", fill="x")
- self.resizable_frame.bind("<Button-1>", self.start_resize)
- self.resizable_frame.bind("<B1-Motion>", self.do_resize)
- self.bind("<Button-1>", self.on_click_focus)
- def _create_gradient_title_bar(self, parent_frame):
- canvas = tk.Canvas(parent_frame, height=25, bd=0, highlightthickness=0)
- canvas.pack(fill="both", expand=True)
- def draw_gradient(event):
- width = event.width
- height = event.height
- canvas.delete("all")
- r1, g1, b1 = self.hex_to_rgb(NovaColors.BLUE_LUNA_HIGHLIGHT)
- r2, g2, b2 = self.hex_to_rgb(NovaColors.BLUE_LUNA_ACCENT)
- for i in range(height):
- r = r1 + int((r2 - r1) * i / height)
- g = g1 + int((g2 - g1) * i / height)
- b = b1 + int((b2 - b1) * i / height)
- color = f'#{r:02x}{g:02x}{b:02x}'
- canvas.create_line(0, i, width, i, fill=color)
- canvas.bind("<Configure>", draw_gradient)
- def hex_to_rgb(self, hex_color):
- hex_color = hex_color.lstrip('#')
- return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
- def _on_closing(self):
- key_to_close = self.nova_os.window_instances_to_keys.get(self)
- self.nova_os._close_window(key_to_close)
- def on_click_focus(self, event=None):
- self.lift()
- if self.nova_os.window_instances_to_keys.get(self) != "sidebar":
- try:
- self.grab_set()
- except tk.TclError:
- pass
- def start_move(self, event):
- self.x = event.x
- self.y = event.y
- def do_move(self, event):
- deltax = event.x - self.x
- deltay = event.y - self.y
- new_x = self.winfo_x() + deltax
- new_y = self.winfo_y() + deltay
- self.geometry(f"+{new_x}+{new_y}")
- def start_resize(self, event):
- self.start_x = event.x_root
- self.start_y = event.y_root
- self.start_width = self.winfo_width()
- self.start_height = self.winfo_height()
- def do_resize(self, event):
- deltax = event.x_root - self.start_x
- deltay = event.y_root - self.start_y
- new_width = self.start_width + deltax
- new_height = self.start_height + deltay
- self.geometry(f"{new_width}x{new_height}")
- def minimize(self):
- self.withdraw()
- self.nova_os._on_minimize(self)
- def maximize(self):
- current_state = self.state()
- if current_state == 'normal' or self.last_geometry is None:
- self.last_geometry = self.geometry()
- self.geometry(f"{self.nova_os.root.winfo_width()}x{self.nova_os.root.winfo_height() - self.nova_os.taskbar_frame.winfo_height()}+0+0")
- else:
- self.geometry(self.last_geometry)
- self.last_geometry = None
- def set_title(self, new_title):
- self.title(new_title)
- self.title_label.config(text=new_title)
- def destroy(self):
- try:
- self.grab_release()
- except tk.TclError:
- pass
- super().destroy()
- # --- Classes de Aplicativos ---
- class PromptWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Nova Prompt", default_geometry="700x500", bg_color="#000000")
- self.current_dir = self.nova_os.saves_folder
- self.output_text = tk.Text(self.content_frame, bg="#000000", fg="#00FF00", insertbackground="#00FF00", font=("Consolas", 10), relief="flat")
- self.output_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
- self.output_text.bind("<Key>", self._on_key_press)
- self.input_frame = tk.Frame(self.content_frame, bg="#000000")
- self.input_frame.pack(fill=tk.X)
- self.prompt_label = tk.Label(self.input_frame, text=self._get_prompt_text(), bg="#000000", fg="#00FF00", font=("Consolas", 10))
- self.prompt_label.pack(side=tk.LEFT, padx=5)
- self.input_entry = tk.Entry(self.input_frame, bg="#000000", fg="#00FF00", insertbackground="#00FF00", font=("Consolas", 10), relief="flat")
- self.input_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
- self.input_entry.bind("<Return>", self.execute_command)
- self.input_entry.focus_set()
- self.print_output("Bem-vindo ao Nova Prompt (Build Vista). Digite 'help' para comandos.")
- def _get_prompt_text(self):
- dir_name = os.path.basename(self.current_dir)
- return f"C:\\NovaOS\\{dir_name}>"
- def _on_key_press(self, event):
- if self.output_text.cget('state') == 'disabled':
- return "break"
- def print_output(self, text):
- self.output_text.config(state="normal")
- self.output_text.insert(tk.END, text + "\n")
- self.output_text.see(tk.END)
- self.output_text.config(state="disabled")
- def execute_command(self, event=None):
- command = self.input_entry.get().strip()
- self.print_output(self._get_prompt_text() + command)
- self.input_entry.delete(0, tk.END)
- self.nova_os._play_sound("command")
- if not command:
- return
- if command == "help":
- self.print_output("""
- Comandos disponíveis:
- ls - Lista arquivos e diretórios
- cd <dir> - Muda de diretório
- mkdir <dir> - Cria um novo diretório
- rmdir <dir> - Remove um diretório vazio
- touch <file> - Cria/atualiza um arquivo
- rm <file> - Remove um arquivo
- color #RRGGBB - Altera a cor da barra de tarefas
- clear - Limpa a tela
- exit - Fecha o prompt
- """)
- elif command == "clear":
- self.output_text.config(state="normal")
- self.output_text.delete(1.0, tk.END)
- self.output_text.config(state="disabled")
- elif command == "ls":
- try:
- items = os.listdir(self.current_dir)
- for item in items:
- path = os.path.join(self.current_dir, item)
- if os.path.isdir(path):
- self.print_output(f"<DIR> {item}")
- else:
- self.print_output(f" {item}")
- except Exception as e:
- self.print_output(f"Erro: {e}")
- elif command.startswith("cd "):
- target_dir = command[3:].strip()
- if target_dir == "..":
- new_dir = os.path.dirname(self.current_dir)
- else:
- new_dir = os.path.join(self.current_dir, target_dir)
- if os.path.isdir(new_dir):
- self.current_dir = new_dir
- self.prompt_label.config(text=self._get_prompt_text())
- else:
- self.print_output(f"Diretório '{target_dir}' não encontrado.")
- elif command.startswith("mkdir "):
- dir_name = command[6:].strip()
- path = os.path.join(self.current_dir, dir_name)
- try:
- os.makedirs(path)
- self.print_output(f"Diretório '{dir_name}' criado.")
- except Exception as e:
- self.print_output(f"Erro: {e}")
- elif command.startswith("rmdir "):
- dir_name = command[6:].strip()
- path = os.path.join(self.current_dir, dir_name)
- try:
- os.rmdir(path)
- self.print_output(f"Diretório '{dir_name}' removido.")
- except OSError as e:
- self.print_output(f"Erro ao remover: {e}. O diretório deve estar vazio.")
- except Exception as e:
- self.print_output(f"Erro: {e}")
- elif command.startswith("touch "):
- file_name = command[6:].strip()
- path = os.path.join(self.current_dir, file_name)
- try:
- with open(path, 'a'):
- os.utime(path, None)
- self.print_output(f"Arquivo '{file_name}' criado/atualizado.")
- except Exception as e:
- self.print_output(f"Erro: {e}")
- elif command.startswith("rm "):
- file_name = command[3:].strip()
- path = os.path.join(self.current_dir, file_name)
- try:
- os.remove(path)
- self.print_output(f"Arquivo '{file_name}' removido.")
- except FileNotFoundError:
- self.print_output(f"Arquivo '{file_name}' não encontrado.")
- except Exception as e:
- self.print_output(f"Erro: {e}")
- elif command.startswith("color "):
- color_code = command[6:].strip()
- if color_code.startswith("#") and len(color_code) == 7:
- self.nova_os._set_taskbar_color(color_code)
- self.print_output(f"Cor da barra de tarefas alterada para {color_code}.")
- else:
- self.print_output("Formato de cor inválido. Use #RRGGBB.")
- elif command == "exit":
- self._on_closing()
- else:
- self.print_output(f"Comando não reconhecido: '{command}'")
- class GameWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Jogo Simples", default_geometry="500x400", bg_color="#333333")
- tk.Label(self.content_frame, text="Seu jogo virá aqui!", font=("Segoe UI", 16), fg="white", bg="#333333").pack(pady=50)
- class FileManagerWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Gerenciador de Arquivos", default_geometry="800x600")
- self.current_dir = self.nova_os.saves_folder
- self.path_label = tk.Label(self.content_frame, text=f"Caminho: {self.current_dir}", font=("Segoe UI", 10), anchor="w")
- self.path_label.pack(fill="x", padx=10, pady=5)
- self.listbox = tk.Listbox(self.content_frame)
- self.listbox.pack(fill="both", expand=True, padx=10, pady=5)
- self.listbox.bind("<Double-Button-1>", self.open_item)
- self.update_list()
- def update_list(self):
- self.listbox.delete(0, tk.END)
- if self.current_dir != self.nova_os.saves_folder:
- self.listbox.insert(tk.END, "..")
- try:
- for item in os.listdir(self.current_dir):
- self.listbox.insert(tk.END, item)
- except Exception as e:
- self.nova_os._show_notification("Erro", f"Não foi possível ler o diretório: {e}", 3000)
- def open_item(self, event=None):
- selected_index = self.listbox.curselection()
- if not selected_index:
- return
- selected_item = self.listbox.get(selected_index[0])
- if selected_item == "..":
- self.current_dir = os.path.dirname(self.current_dir)
- self.path_label.config(text=f"Caminho: {self.current_dir}")
- self.update_list()
- return
- item_path = os.path.join(self.current_dir, selected_item)
- if os.path.isdir(item_path):
- self.current_dir = item_path
- self.path_label.config(text=f"Caminho: {self.current_dir}")
- self.update_list()
- else:
- try:
- os.startfile(item_path)
- except AttributeError:
- subprocess.Popen(['xdg-open', item_path])
- except Exception as e:
- self.nova_os._show_notification("Erro", f"Não foi possível abrir o arquivo: {e}", 3000)
- class BrowserWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Navegador Web", default_geometry="800x600")
- if not webview_enabled:
- tk.Label(self.content_frame, text="Navegador não disponível. Instale a biblioteca pywebview.", font=("Segoe UI", 12)).pack(pady=50)
- return
- # Interface do navegador
- url_frame = tk.Frame(self.content_frame)
- url_frame.pack(fill=tk.X, padx=5, pady=5)
- self.url_entry = tk.Entry(url_frame, font=("Segoe UI", 10))
- self.url_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
- self.url_entry.insert(0, "https://www.google.com")
- self.url_entry.bind("<Return>", self.navigate)
- go_button = tk.Button(url_frame, text="Go", command=self.navigate)
- go_button.pack(side=tk.LEFT, padx=5)
- # Usar uma thread para o webview não bloquear o Tkinter
- self.webview_thread = threading.Thread(target=self.start_webview)
- self.webview_thread.daemon = True # Garante que a thread feche com a aplicação
- self.webview_thread.start()
- def start_webview(self):
- self.browser_window = webview.create_window('Navegador Web', 'https://www.google.com')
- webview.start()
- def navigate(self, event=None):
- url = self.url_entry.get()
- if not url.startswith(("http://", "https://")):
- url = "https://" + url
- try:
- # O webview só pode ser acessado de dentro de sua própria thread.
- # O ideal seria usar uma API ou um mecanismo de comunicação entre threads,
- # mas para este caso, uma nova janela é a solução mais simples.
- # O design a seguir reabre o navegador com a nova URL, o que não é ideal
- # mas demonstra a funcionalidade.
- webview.destroy_window(self.browser_window)
- self.webview_thread = threading.Thread(target=self.start_webview_with_url, args=(url,))
- self.webview_thread.daemon = True
- self.webview_thread.start()
- except Exception as e:
- self.nova_os._show_notification("Erro no Navegador", f"Não foi possível carregar a URL: {e}", 5000)
- def start_webview_with_url(self, url):
- self.browser_window = webview.create_window('Navegador Web', url)
- webview.start()
- def _on_closing(self):
- super()._on_closing()
- # Tenta fechar a janela do webview de forma segura
- try:
- webview.destroy_window(self.browser_window)
- except Exception:
- pass
- class MailClientWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Cliente de E-mail (Decorativo)", default_geometry="800x600")
- tk.Label(self.content_frame, text="Envie e receba e-mails! (Este é um aplicativo decorativo)", font=("Segoe UI", 16)).pack(pady=50)
- class DecorativeAppWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance, app_name):
- super().__init__(master, nova_os_instance, title=f"{app_name} (Decorativo)", default_geometry="700x500")
- tk.Label(self.content_frame, text=f"Bem-vindo ao {app_name}!", font=("Segoe UI", 20, "bold")).pack(pady=100)
- tk.Label(self.content_frame, text="(Este é um aplicativo decorativo)", font=("Segoe UI", 12)).pack()
- class CalculatorWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Calculadora", default_geometry="300x400", bg_color="#E0E0E0")
- self.expression = ""
- display_frame = tk.Frame(self.content_frame, bg=self['bg'])
- display_frame.pack(fill=tk.X, padx=10, pady=10)
- self.display_label = tk.Label(display_frame, text="0", font=("Segoe UI", 24), anchor="e", bg="#FFFFFF", padx=5)
- self.display_label.pack(fill=tk.X)
- buttons_frame = tk.Frame(self.content_frame, bg=self['bg'])
- buttons_frame.pack(pady=5, padx=10)
- buttons = [
- '7', '8', '9', '/',
- '4', '5', '6', '*',
- '1', '2', '3', '-',
- 'C', '0', '=', '+'
- ]
- row, col = 0, 0
- for button_text in buttons:
- button = tk.Button(buttons_frame, text=button_text, font=("Segoe UI", 16), width=5, height=2,
- command=lambda text=button_text: self.on_button_click(text))
- button.grid(row=row, column=col, padx=5, pady=5)
- col += 1
- if col > 3:
- col = 0
- row += 1
- def on_button_click(self, text):
- if text == 'C':
- self.expression = ""
- elif text == '=':
- try:
- result = str(eval(self.expression))
- self.expression = result
- except:
- self.expression = "Erro"
- else:
- self.expression += text
- self.display_label.config(text=self.expression if self.expression else "0")
- class NotepadWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Bloco de Notas", default_geometry="600x500")
- menu_bar = tk.Menu(self)
- self.config(menu=menu_bar)
- file_menu = tk.Menu(menu_bar, tearoff=0)
- menu_bar.add_cascade(label="Arquivo", menu=file_menu)
- file_menu.add_command(label="Novo", command=self.new_file)
- file_menu.add_command(label="Abrir...", command=self.open_file)
- file_menu.add_command(label="Salvar", command=self.save_file)
- file_menu.add_separator()
- file_menu.add_command(label="Sair", command=self._on_closing)
- self.text_area = tk.Text(self.content_frame, wrap="word", font=("Segoe UI", 10), bg="white", fg="black")
- self.text_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
- self.text_area.insert(tk.END, "Comece a digitar aqui...")
- self.file_path = None
- def new_file(self):
- self.text_area.delete(1.0, tk.END)
- self.file_path = None
- self.set_title("Bloco de Notas")
- def open_file(self):
- file_path = filedialog.askopenfilename(defaultextension=".txt", filetypes=[("Arquivos de Texto", "*.txt"), ("Todos os Arquivos", "*.*")])
- if file_path:
- with open(file_path, "r") as file:
- self.text_area.delete(1.0, tk.END)
- self.text_area.insert(tk.END, file.read())
- self.file_path = file_path
- self.set_title(f"Bloco de Notas - {os.path.basename(file_path)}")
- def save_file(self):
- if self.file_path:
- with open(self.file_path, "w") as file:
- file.write(self.text_area.get(1.0, tk.END))
- else:
- self.save_as_file()
- def save_as_file(self):
- file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Arquivos de Texto", "*.txt"), ("Todos os Arquivos", "*.*")])
- if file_path:
- with open(file_path, "w") as file:
- file.write(self.text_area.get(1.0, tk.END))
- self.file_path = file_path
- self.set_title(f"Bloco de Notas - {os.path.basename(file_path)}")
- class ControlPanelWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Painel de Controle", default_geometry="600x450")
- control_frame = tk.Frame(self.content_frame, bg=self.cget('bg'))
- control_frame.pack(pady=10)
- tk.Label(control_frame, text="Configurações do Sistema", font=("Segoe UI", 14, "bold"), bg=self.cget('bg')).pack(pady=10)
- tk.Button(control_frame, text="Mudar Papel de Parede", command=self.nova_os._choose_wallpaper,
- font=("Segoe UI", 10), bg=NovaColors.BLUE_BUTTON, fg=NovaColors.WHITE_TEXT).pack(pady=5, fill=tk.X, padx=20)
- tk.Button(control_frame, text="Remover Papel de Parede", command=lambda: self.nova_os._set_wallpaper(""),
- font=("Segoe UI", 10), bg=NovaColors.BLUE_BUTTON, fg=NovaColors.WHITE_TEXT).pack(pady=5, fill=tk.X, padx=20)
- tk.Button(control_frame, text="Mudar Cor da Barra de Tarefas", command=self._choose_taskbar_color,
- font=("Segoe UI", 10), bg=NovaColors.BLUE_BUTTON, fg=NovaColors.WHITE_TEXT).pack(pady=5, fill=tk.X, padx=20)
- self.sound_var = tk.BooleanVar(value=self.nova_os.settings["system_sounds_enabled"])
- sound_check = tk.Checkbutton(control_frame, text="Habilitar Sons do Sistema", variable=self.sound_var,
- command=self._toggle_system_sounds, font=("Segoe UI", 10), bg=self.cget('bg'), fg=NovaColors.DARK_TEXT, selectcolor="lightgray")
- sound_check.pack(pady=5, fill=tk.X, padx=20)
- tk.Button(control_frame, text="Simular Download", command=self.nova_os._simulate_download,
- font=("Segoe UI", 10), bg=NovaColors.BLUE_BUTTON, fg=NovaColors.WHITE_TEXT).pack(pady=10, fill=tk.X, padx=20)
- tk.Button(control_frame, text="Abrir Barra Lateral", command=self.nova_os.open_app_sidebar,
- font=("Segoe UI", 10), bg=NovaColors.BLUE_BUTTON, fg=NovaColors.WHITE_TEXT).pack(pady=10, fill=tk.X, padx=20)
- def _choose_taskbar_color(self):
- color_code = colorchooser.askcolor(title="Escolha a Cor da Barra de Tarefas")[1]
- if color_code:
- self.nova_os._set_taskbar_color(color_code)
- def _toggle_system_sounds(self):
- self.nova_os.settings["system_sounds_enabled"] = self.sound_var.get()
- self.nova_os._save_os_settings()
- if self.sound_var.get():
- self.nova_os._show_notification("Sons", "Sons do sistema ativados.", 2000)
- else:
- self.nova_os._show_notification("Sons", "Sons do sistema desativados.", 2000)
- class Sidebar(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Nova OS Sidebar", default_geometry="200x600", bg_color=NovaColors.GRAY_TRANSPARENT)
- self.geometry(f"+{self.master.winfo_width() - 200}+0")
- self.overrideredirect(True)
- self.wm_attributes('-topmost', True)
- self.attributes('-alpha', 0.8)
- try:
- self.grab_release()
- except tk.TclError:
- pass
- tk.Label(self.content_frame, text="GADGETS", font=("Segoe UI", 12, "bold"), fg="white", bg=NovaColors.GRAY_TRANSPARENT).pack(pady=10)
- self.clock_label = tk.Label(self.content_frame, text="", font=("Segoe UI", 24), fg="white", bg=NovaColors.GRAY_TRANSPARENT)
- self.clock_label.pack(pady=5)
- self.date_label = tk.Label(self.content_frame, text="", font=("Segoe UI", 14), fg="white", bg=NovaColors.GRAY_TRANSPARENT)
- self.date_label.pack(pady=5)
- self.update_widgets()
- tk.Button(self.content_frame, text="Fechar Sidebar", command=self._on_closing,
- bg=NovaColors.RED_CLOSE, fg=NovaColors.WHITE_TEXT).pack(pady=10)
- def update_widgets(self):
- now = datetime.datetime.now()
- self.clock_label.config(text=now.strftime("%H:%M"))
- self.date_label.config(text=now.strftime("%d/%m/%Y"))
- self.after(1000, self.update_widgets)
- class TaskManagerWindow(DraggableToplevel):
- def __init__(self, master, nova_os_instance):
- super().__init__(master, nova_os_instance, title="Gerenciador de Tarefas", default_geometry="500x400")
- self.nova_os = nova_os_instance
- tk.Label(self.content_frame, text="Aplicativos Abertos:", font=("Segoe UI", 12, "bold")).pack(pady=10)
- self.app_list_frame = tk.Frame(self.content_frame)
- self.app_list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
- self.update_task_list()
- tk.Button(self.content_frame, text="Atualizar Lista", command=self.update_task_list).pack(pady=5)
- tk.Button(self.content_frame, text="Finalizar Tarefa Selecionada", command=self.kill_selected_task).pack(pady=5)
- def update_task_list(self):
- for widget in self.app_list_frame.winfo_children():
- widget.destroy()
- self.current_app_buttons = {}
- for key, instance in self.nova_os.open_windows.items():
- if instance and instance.winfo_exists() and key not in ["start_menu", "sidebar", "task_manager"]:
- app_frame = tk.Frame(self.app_list_frame)
- app_frame.pack(fill=tk.X, pady=2)
- app_name = instance.title().replace(" - Nova OS", "")
- app_label = tk.Label(app_frame, text=app_name, anchor="w", font=("Segoe UI", 10))
- app_label.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
- kill_button = tk.Button(app_frame, text="Finalizar", command=lambda k=key: self.nova_os._close_window(k))
- kill_button.pack(side=tk.RIGHT, padx=5)
- def kill_selected_task(self):
- # Esta função é mais complexa, mas a ideia é fechar o app selecionado na lista
- pass
- # --- Classe do Sistema Principal ---
- class FluxOS:
- def __init__(self, root):
- self.root = root
- self.root.title("FLUX OS - Gupy")
- self.root.geometry("1024x768")
- self.root.state('zoomed')
- # Variáveis de sistema
- self.os_folder = os.path.dirname(os.path.abspath(__file__))
- self.saves_folder = os.path.join(self.os_folder, "Saves")
- if not os.path.exists(self.saves_folder):
- os.makedirs(self.saves_folder)
- self.settings_file = os.path.join(self.saves_folder, "os_settings.json")
- self.settings = self._load_os_settings()
- self.is_online = True
- self.open_windows = {}
- self.window_instances_to_keys = {}
- self.taskbar_buttons = {}
- # Siga a ordem: tela de login -> desktop
- self.show_login_screen()
- def _load_os_settings(self):
- default_settings = {
- "wallpaper": "",
- "taskbar_color": NovaColors.GRAY_TASKBAR,
- "system_sounds_enabled": sound_enabled
- }
- if os.path.exists(self.settings_file):
- with open(self.settings_file, "r") as f:
- settings = json.load(f)
- return {**default_settings, **settings}
- return default_settings
- def _save_os_settings(self):
- with open(self.settings_file, "w") as f:
- json.dump(self.settings, f, indent=4)
- def _create_desktop(self):
- self.desktop_frame = tk.Frame(self.root, bg=NovaColors.DESKTOP_BG)
- self.desktop_frame.pack(fill="both", expand=True)
- self._set_wallpaper(self.settings["wallpaper"])
- self.root.bind("<Button-3>", self._show_desktop_context_menu)
- # Botões na área de trabalho
- app_icons_frame = tk.Frame(self.desktop_frame, bg=NovaColors.DESKTOP_BG)
- app_icons_frame.pack(side="top", anchor="nw", padx=10, pady=10)
- self._create_desktop_icon(app_icons_frame, "Nova Prompt", self.open_app_prompt)
- self._create_desktop_icon(app_icons_frame, "Ger. de Arquivos", self.open_app_file_manager)
- self._create_desktop_icon(app_icons_frame, "Calculadora", self.open_app_calculator)
- self._create_desktop_icon(app_icons_frame, "Navegador", self.open_app_browser)
- self._create_desktop_icon(app_icons_frame, "Painel de Controle", self.open_app_control_panel)
- self._create_desktop_icon(app_icons_frame, "Bloco de Notas", self.open_app_notepad)
- self._create_taskbar()
- def _create_desktop_icon(self, parent, text, command):
- icon_frame = tk.Frame(parent, bg=parent['bg'])
- icon_frame.pack(side="left", padx=10)
- icon_button = tk.Button(icon_frame, text=text, command=command,
- font=("Segoe UI", 10), bg=NovaColors.DESKTOP_BG, fg="white", bd=0, relief="flat", padx=5)
- icon_button.pack()
- def _create_taskbar(self):
- self.taskbar_frame = tk.Frame(self.root, bg=self.settings["taskbar_color"], height=40, relief="raised", bd=2)
- self.taskbar_frame.pack(side="bottom", fill="x")
- self.start_button = tk.Button(self.taskbar_frame, text="Iniciar", bg=NovaColors.GREEN_START_BUTTON, fg="white", font=("Segoe UI", 10, "bold"), command=self.show_start_menu)
- self.start_button.pack(side="left", padx=5, pady=2)
- self.taskbar_apps_frame = tk.Frame(self.taskbar_frame, bg=self.settings["taskbar_color"])
- self.taskbar_apps_frame.pack(side="left", padx=10, fill="x", expand=True)
- self.taskbar_right_frame = tk.Frame(self.taskbar_frame, bg=self.settings["taskbar_color"])
- self.taskbar_right_frame.pack(side="right", padx=5)
- # Indicador de conexão de rede
- self.network_indicator = tk.Label(self.taskbar_right_frame, text="●", font=("Arial", 16),
- fg=NovaColors.ONLINE_COLOR, bg=self.settings["taskbar_color"], cursor="hand2")
- self.network_indicator.pack(side="right", padx=5)
- self.network_indicator.bind("<Button-1>", self.toggle_online_status)
- self.clock_label = tk.Label(self.taskbar_right_frame, text="", bg=self.settings["taskbar_color"], fg="white", font=("Segoe UI", 10))
- self.clock_label.pack(side="right")
- self.update_clock()
- def _set_taskbar_color(self, color_code):
- self.taskbar_frame.configure(bg=color_code)
- self.taskbar_right_frame.configure(bg=color_code)
- self.clock_label.configure(bg=color_code)
- self.network_indicator.configure(bg=color_code)
- for widget in self.taskbar_apps_frame.winfo_children():
- widget.configure(bg=color_code)
- self.settings["taskbar_color"] = color_code
- self._save_os_settings()
- def _set_wallpaper(self, image_path):
- if image_path and os.path.exists(image_path):
- try:
- original_image = Image.open(image_path)
- resized_image = original_image.resize((self.root.winfo_width(), self.root.winfo_height()), Image.LANCZOS)
- self.wallpaper_image = ImageTk.PhotoImage(resized_image)
- if not hasattr(self, 'wallpaper_label'):
- self.wallpaper_label = tk.Label(self.desktop_frame, image=self.wallpaper_image)
- self.wallpaper_label.place(x=0, y=0, relwidth=1, relheight=1)
- self.wallpaper_label.lower()
- else:
- self.wallpaper_label.configure(image=self.wallpaper_image)
- self.settings["wallpaper"] = image_path
- self._save_os_settings()
- except Exception as e:
- self._show_notification("Erro", f"Não foi possível carregar o papel de parede: {e}", 3000)
- else:
- if hasattr(self, 'wallpaper_label'):
- self.wallpaper_label.destroy()
- self.wallpaper_label = None
- self.desktop_frame.configure(bg=NovaColors.DESKTOP_BG)
- self.settings["wallpaper"] = ""
- self._save_os_settings()
- def _choose_wallpaper(self):
- file_path = filedialog.askopenfilename(filetypes=[("Arquivos de Imagem", "*.png;*.jpg;*.jpeg;*.gif;*.bmp")])
- if file_path:
- self._set_wallpaper(file_path)
- def _show_desktop_context_menu(self, event):
- menu = tk.Menu(self.root, tearoff=0)
- menu.add_command(label="Mudar Papel de Parede", command=self._choose_wallpaper)
- menu.add_command(label="Painel de Controle", command=self.open_app_control_panel)
- menu.add_command(label="Fechar Sistema", command=self.root.destroy)
- try:
- menu.tk_popup(event.x_root, event.y_root)
- finally:
- menu.grab_release()
- def show_start_menu(self):
- # A janela do menu iniciar
- if "start_menu" in self.open_windows and self.open_windows["start_menu"].winfo_exists():
- self.open_windows["start_menu"].destroy()
- return
- start_menu = tk.Toplevel(self.root, bg=NovaColors.GRAY_TRANSPARENT, relief="raised", bd=2)
- start_menu.overrideredirect(True)
- start_menu.wm_attributes('-topmost', True, '-alpha', 0.9)
- start_menu.geometry("200x400")
- taskbar_height = self.taskbar_frame.winfo_height()
- menu_x = 0
- menu_y = self.root.winfo_height() - taskbar_height - 400
- start_menu.geometry(f"+{menu_x}+{menu_y}")
- self.open_windows["start_menu"] = start_menu
- # Crie os botões do menu iniciar
- apps_frame = tk.Frame(start_menu, bg=NovaColors.GRAY_TRANSPARENT)
- apps_frame.pack(fill="both", expand=True, padx=5, pady=5)
- tk.Button(apps_frame, text="Nova Prompt", command=lambda: self.open_app_prompt(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Gerenciador de Arquivos", command=lambda: self.open_app_file_manager(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Calculadora", command=lambda: self.open_app_calculator(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Navegador Web", command=lambda: self.open_app_browser(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Bloco de Notas", command=lambda: self.open_app_notepad(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Painel de Controle", command=lambda: self.open_app_control_panel(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Gerenciador de Tarefas", command=lambda: self.open_app_task_manager(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="E-mail", command=lambda: self.open_app_mail_client(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Jogo Simples", command=lambda: self.open_app_game(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Barra Lateral", command=lambda: self.open_app_sidebar(start_menu), anchor="w").pack(fill="x", pady=2)
- tk.Button(apps_frame, text="Sair do Sistema", command=self.root.destroy, anchor="w").pack(fill="x", pady=2)
- def update_clock(self):
- now = datetime.datetime.now()
- self.clock_label.config(text=now.strftime("%H:%M:%S"))
- self.root.after(1000, self.update_clock)
- def _play_sound(self, sound_name):
- if sound_enabled and self.settings["system_sounds_enabled"]:
- try:
- pygame.mixer.Sound(f"sounds/{sound_name}.wav").play()
- except Exception as e:
- print(f"Erro ao tocar som '{sound_name}': {e}")
- def _show_notification(self, title, message, duration_ms):
- # Aqui você pode implementar um sistema de notificação visual
- print(f"[{title}] {message}")
- def _simulate_download(self):
- self._show_notification("Download", "Iniciando download simulado...", 2000)
- def toggle_online_status(self, event=None):
- self.is_online = not self.is_online
- if self.is_online:
- self.network_indicator.config(fg=NovaColors.ONLINE_COLOR)
- self._show_notification("Conexão", "Você está online.", 2000)
- else:
- self.network_indicator.config(fg=NovaColors.OFFLINE_COLOR)
- self._show_notification("Conexão", "Você está offline.", 2000)
- def _add_taskbar_button(self, key, title, window_instance):
- button = tk.Button(self.taskbar_apps_frame, text=title, font=("Segoe UI", 10), command=lambda: self._toggle_window(key), relief="raised")
- button.pack(side="left", padx=2, pady=2)
- self.taskbar_buttons[key] = button
- def _remove_taskbar_button(self, key):
- if key in self.taskbar_buttons:
- self.taskbar_buttons[key].destroy()
- del self.taskbar_buttons[key]
- def _toggle_window(self, key):
- window = self.open_windows.get(key)
- if window and window.winfo_exists():
- if window.state() == 'normal':
- window.withdraw()
- self.taskbar_buttons[key].config(relief="raised")
- else:
- window.deiconify()
- window.lift()
- window.focus_force()
- self.taskbar_buttons[key].config(relief="sunken")
- def _close_window(self, key):
- if key in self.open_windows and self.open_windows[key].winfo_exists():
- self.open_windows[key].destroy()
- if key in self.open_windows:
- del self.open_windows[key]
- self._remove_taskbar_button(key)
- def open_app(self, key, title, AppClass, master=None):
- if key not in self.open_windows or not self.open_windows[key].winfo_exists():
- if master:
- master.destroy() # Fecha o menu iniciar se o app for aberto de lá
- app_instance = AppClass(self.root, self)
- self.open_windows[key] = app_instance
- self.window_instances_to_keys[app_instance] = key
- if key not in ["start_menu"]:
- self._add_taskbar_button(key, title, app_instance)
- return app_instance
- else:
- self.open_windows[key].deiconify()
- self.open_windows[key].lift()
- self.taskbar_buttons[key].config(relief="sunken")
- def open_app_prompt(self, master=None):
- self.open_app("prompt", "Nova Prompt", PromptWindow, master)
- def open_app_file_manager(self, master=None):
- self.open_app("file_manager", "Ger. de Arquivos", FileManagerWindow, master)
- def open_app_calculator(self, master=None):
- self.open_app("calculator", "Calculadora", CalculatorWindow, master)
- def open_app_notepad(self, master=None):
- self.open_app("notepad", "Bloco de Notas", NotepadWindow, master)
- def open_app_browser(self, master=None):
- self.open_app("browser", "Navegador Web", BrowserWindow, master)
- def open_app_control_panel(self, master=None):
- self.open_app("control_panel", "Painel de Controle", ControlPanelWindow, master)
- def open_app_task_manager(self, master=None):
- self.open_app("task_manager", "Gerenciador de Tarefas", TaskManagerWindow, master)
- def open_app_game(self, master=None):
- self.open_app("game", "Jogo Simples", GameWindow, master)
- def open_app_sidebar(self, master=None):
- # A sidebar não tem um botão na barra de tarefas para evitar duplicação
- self.open_app("sidebar", "Barra Lateral", Sidebar, master)
- def open_app_mail_client(self, master=None):
- self.open_app("mail_client", "E-mail", MailClientWindow, master)
- # --- Módulo de Login ---
- def show_login_screen(self):
- self.login_window = tk.Toplevel(self.root)
- self.login_window.title("Login Flux OS")
- self.login_window.geometry("400x200")
- self.login_window.overrideredirect(True)
- self.login_window.grab_set()
- self.login_window.update_idletasks()
- width = self.login_window.winfo_width()
- height = self.login_window.winfo_height()
- x = (self.login_window.winfo_screenwidth() // 2) - (width // 2)
- y = (self.login_window.winfo_screenheight() // 2) - (height // 2)
- self.login_window.geometry(f'+{x}+{y}')
- self.password_file = os.path.join(self.saves_folder, "password.txt")
- login_frame = tk.Frame(self.login_window, padx=20, pady=20)
- login_frame.pack()
- tk.Label(login_frame, text="Digite a senha:", font=("Segoe UI", 12)).pack(pady=5)
- self.password_entry = tk.Entry(login_frame, show="*", font=("Segoe UI", 12))
- self.password_entry.pack(pady=5)
- self.password_entry.bind("<Return>", self.check_password)
- tk.Button(login_frame, text="Entrar", command=self.check_password, font=("Segoe UI", 12)).pack(pady=10)
- if not os.path.exists(self.password_file):
- tk.Label(login_frame, text="Crie uma nova senha. Deixe em branco para sem senha.", font=("Segoe UI", 8)).pack(pady=5)
- def check_password(self, event=None):
- password = self.password_entry.get()
- if not os.path.exists(self.password_file):
- if password:
- with open(self.password_file, "w") as f:
- f.write(password)
- self.login_window.destroy()
- self._create_desktop()
- else:
- with open(self.password_file, "r") as f:
- stored_password = f.read().strip()
- if password == stored_password:
- self.login_window.destroy()
- self._create_desktop()
- else:
- messagebox.showerror("Erro de Login", "Senha incorreta.")
- # --- Início do Programa ---
- if __name__ == "__main__":
- root = tk.Tk()
- root.withdraw() # Esconde a janela principal até o login
- app = FluxOS(root)
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment