Skip to content

Commit d26107a

Browse files
authored
Add files via upload
1 parent 9b9bd5a commit d26107a

6 files changed

Lines changed: 421 additions & 0 deletions

File tree

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# PythonOS
2+
3+
PythonOS è un mini-sistema operativo sviluppato in Python con interfaccia grafica Tkinter.
4+
5+
## Caratteristiche
6+
7+
- Interfaccia desktop stile mini-OS con barre e icone
8+
- Finestre interne trascinabili per app multiple
9+
- Terminale integrato
10+
- Editor di appunti
11+
- File manager
12+
- Impostazioni di sistema e lockscreen
13+
14+
## Requisiti
15+
16+
- Python 3.8+
17+
- tkinter (incluso con la maggior parte delle distribuzioni Python)
18+
19+
## Installazione
20+
21+
1. Crea un ambiente virtuale:
22+
23+
```bash
24+
python -m venv venv
25+
```
26+
27+
2. Attiva l'ambiente:
28+
29+
- Windows:
30+
```powershell
31+
.\venv\Scripts\Activate.ps1
32+
```
33+
34+
3. Installa le dipendenze:
35+
36+
```bash
37+
pip install -r requirements.txt
38+
```
39+
40+
## Esecuzione
41+
42+
```bash
43+
python main.py
44+
```
45+
46+
## Struttura del progetto
47+
48+
- `main.py` - punto di ingresso dell'applicazione
49+
- `pythonos/gui.py` - logica dell'interfaccia grafica
50+
- `pythonos/os.py` - stato e comandi del mini-OS
51+
52+
## Note
53+
54+
Questo progetto è pensato come base per un mini-sistema operativo in Python e può essere esteso con nuove applicazioni e funzionalità.

main.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from pyos_gaps.decorators import verify_pyos_dir
2+
import os
3+
4+
os.path.abspath(os.path.dirname(__file__))
5+
6+
verify_pyos_dir()
7+
8+
from pythonos.gui import PythonOSApp
9+
10+
def main():
11+
app = PythonOSApp()
12+
app.run()
13+
14+
if __name__ == "__main__":
15+
main()

pythonos/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""PythonOS: mini-sistema operativo in Python."""
2+
3+
from .gui import PythonOSApp
4+
5+
__all__ = ["PythonOSApp"]

pythonos/gui.py

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
import tkinter as tk
2+
from tkinter import messagebox, scrolledtext
3+
from datetime import datetime
4+
from .os import OSState
5+
6+
7+
class AppWindow:
8+
def __init__(self, parent, title, width=520, height=340, x=40, y=40):
9+
self.parent = parent
10+
self.frame = tk.Frame(parent, bg="#3b3d59", bd=2, relief="raised")
11+
self.frame.place(x=x, y=y, width=width, height=height)
12+
13+
self.title_bar = tk.Frame(self.frame, bg="#44475a", height=32)
14+
self.title_bar.pack(fill="x")
15+
16+
self.title_label = tk.Label(self.title_bar, text=title, fg="#f8f8f2", bg="#44475a", font=("Segoe UI", 10, "bold"))
17+
self.title_label.pack(side="left", padx=8)
18+
19+
self.close_btn = tk.Button(self.title_bar, text="✕", bg="#ff5555", fg="#f8f8f2", bd=0, width=3, command=self.close)
20+
self.close_btn.pack(side="right", padx=4, pady=2)
21+
22+
self.content = tk.Frame(self.frame, bg="#282a36")
23+
self.content.pack(expand=True, fill="both")
24+
25+
self._drag_data = {"x": 0, "y": 0}
26+
self.title_bar.bind("<ButtonPress-1>", self._start_drag)
27+
self.title_bar.bind("<ButtonRelease-1>", self._stop_drag)
28+
self.title_bar.bind("<B1-Motion>", self._do_drag)
29+
30+
def _start_drag(self, event):
31+
self._drag_data["x"] = event.x
32+
self._drag_data["y"] = event.y
33+
34+
def _stop_drag(self, event):
35+
self._drag_data["x"] = 0
36+
self._drag_data["y"] = 0
37+
38+
def _do_drag(self, event):
39+
dx = event.x - self._drag_data["x"]
40+
dy = event.y - self._drag_data["y"]
41+
x = self.frame.winfo_x() + dx
42+
y = self.frame.winfo_y() + dy
43+
self.frame.place(x=x, y=y)
44+
45+
def close(self):
46+
self.frame.destroy()
47+
48+
49+
class PythonOSApp:
50+
def __init__(self):
51+
self.root = tk.Tk()
52+
self.root.title("PythonOS")
53+
self.root.geometry("1000x650")
54+
self.root.configure(bg="#1f1f2e")
55+
self.root.minsize(900, 600)
56+
57+
self.state = OSState()
58+
self.windows = []
59+
self.start_menu = None
60+
self.lock_screen = None
61+
62+
self._build_ui()
63+
self._show_welcome()
64+
self._show_lock_screen()
65+
self._update_clock()
66+
67+
def _build_ui(self):
68+
self.top_bar = tk.Frame(self.root, bg="#1f1f2e", height=36)
69+
self.top_bar.pack(side="top", fill="x")
70+
71+
self.start_btn = tk.Button(self.top_bar, text="Start", command=self._toggle_start_menu, bg="#6272a4", fg="#f8f8f2", bd=0, padx=12, pady=4)
72+
self.start_btn.pack(side="left", padx=8, pady=4)
73+
74+
self.status_label = tk.Label(self.top_bar, text="Pronto", bg="#1f1f2e", fg="#f8f8f2", font=("Segoe UI", 9))
75+
self.status_label.pack(side="left", padx=12)
76+
77+
self.clock_label = tk.Label(self.top_bar, text="00:00", bg="#1f1f2e", fg="#f8f8f2", font=("Segoe UI", 9, "bold"))
78+
self.clock_label.pack(side="right", padx=12)
79+
80+
self.sidebar = tk.Frame(self.root, bg="#2b2b44", width=180)
81+
self.sidebar.pack(side="left", fill="y")
82+
83+
self.desktop = tk.Frame(self.root, bg="#282a36")
84+
self.desktop.pack(side="right", expand=True, fill="both")
85+
86+
title = tk.Label(self.sidebar, text="PythonOS", fg="#f8f8f2", bg="#2b2b44", font=("Segoe UI", 18, "bold"))
87+
title.pack(pady=20)
88+
89+
self._add_sidebar_button("Terminale", self.open_terminal)
90+
self._add_sidebar_button("Appunti", self.open_notes)
91+
self._add_sidebar_button("File Manager", self.open_file_manager)
92+
self._add_sidebar_button("Impostazioni", self.open_settings)
93+
self._add_sidebar_button("Blocca schermo", self._show_lock_screen)
94+
95+
self.status_bar = tk.Label(self.root, text="PythonOS mini-OS pronto", bg="#1f1f2e", fg="#f8f8f2", anchor="w")
96+
self.status_bar.pack(side="bottom", fill="x")
97+
98+
def _add_sidebar_button(self, text, command):
99+
btn = tk.Button(self.sidebar, text=text, command=command, bg="#6272a4", fg="#f8f8f2", relief="flat")
100+
btn.pack(fill="x", padx=20, pady=8)
101+
102+
def _show_welcome(self):
103+
for widget in self.desktop.winfo_children():
104+
widget.destroy()
105+
106+
wallpaper = tk.Label(self.desktop, bg="#282a36")
107+
wallpaper.pack(expand=True, fill="both")
108+
109+
self._create_desktop_icon(wallpaper, "Terminale", self.open_terminal, 60, 80)
110+
self._create_desktop_icon(wallpaper, "Appunti", self.open_notes, 160, 80)
111+
self._create_desktop_icon(wallpaper, "File Manager", self.open_file_manager, 260, 80)
112+
self._create_desktop_icon(wallpaper, "Impostazioni", self.open_settings, 360, 80)
113+
114+
welcome = tk.Label(wallpaper, text=f"Benvenuto, {self.state.user_name}", fg="#f8f8f2", bg="#282a36", font=("Segoe UI", 24, "bold"))
115+
welcome.place(x=60, y=20)
116+
117+
subtitle = tk.Label(wallpaper, text="Sistema operativo PythonOS - Apri un'app dal desktop o dalla barra laterale.", fg="#f8f8f2", bg="#282a36", font=("Segoe UI", 11))
118+
subtitle.place(x=60, y=60)
119+
120+
def _create_desktop_icon(self, parent, text, command, x, y):
121+
icon = tk.Button(parent, text=text, command=command, bg="#44475a", fg="#f8f8f2", bd=0, width=12, height=3)
122+
icon.place(x=x, y=y)
123+
124+
def _toggle_start_menu(self):
125+
if self.start_menu and self.start_menu.winfo_exists():
126+
self.start_menu.destroy()
127+
self.start_menu = None
128+
return
129+
130+
self.start_menu = tk.Frame(self.root, bg="#3b3d59", bd=2, relief="raised")
131+
self.start_menu.place(x=10, y=42, width=200, height=220)
132+
133+
apps = [
134+
("Terminale", self.open_terminal),
135+
("Appunti", self.open_notes),
136+
("File Manager", self.open_file_manager),
137+
("Impostazioni", self.open_settings),
138+
("Blocca", self._show_lock_screen),
139+
]
140+
for idx, (name, action) in enumerate(apps):
141+
btn = tk.Button(self.start_menu, text=name, command=lambda action=action: [action(), self._toggle_start_menu()], bg="#6272a4", fg="#f8f8f2", relief="flat")
142+
btn.pack(fill="x", padx=10, pady=5)
143+
144+
def _show_lock_screen(self):
145+
if self.lock_screen and self.lock_screen.winfo_exists():
146+
return
147+
148+
self.lock_screen = tk.Frame(self.root, bg="#0f101a")
149+
self.lock_screen.place(relx=0, rely=0, relwidth=1, relheight=1)
150+
151+
label = tk.Label(self.lock_screen, text="Sistema Bloccato", fg="#f8f8f2", bg="#0f101a", font=("Segoe UI", 28, "bold"))
152+
label.pack(pady=80)
153+
154+
pin_label = tk.Label(self.lock_screen, text="Inserisci PIN per sbloccare", fg="#f8f8f2", bg="#0f101a", font=("Segoe UI", 12))
155+
pin_label.pack(pady=10)
156+
157+
self.pin_entry = tk.Entry(self.lock_screen, show="*", width=16, justify="center", font=("Segoe UI", 12))
158+
self.pin_entry.pack(pady=10)
159+
self.pin_entry.focus_set()
160+
161+
unlock_btn = tk.Button(self.lock_screen, text="Sblocca", command=self._unlock_screen, bg="#50fa7b", fg="#282a36", relief="flat", padx=12, pady=6)
162+
unlock_btn.pack(pady=10)
163+
164+
self.lock_status = tk.Label(self.lock_screen, text="", fg="#ff5555", bg="#0f101a", font=("Segoe UI", 10))
165+
self.lock_status.pack(pady=4)
166+
167+
self.root.bind("<Return>", self._unlock_screen_event)
168+
169+
def _unlock_screen_event(self, event):
170+
if self.lock_screen and self.lock_screen.winfo_exists():
171+
self._unlock_screen()
172+
173+
def _unlock_screen(self):
174+
if self.pin_entry.get() == self.state.lock_code:
175+
self.lock_screen.destroy()
176+
self.lock_screen = None
177+
self.status_bar.config(text="Schermo sbloccato")
178+
else:
179+
self.lock_status.config(text="PIN errato. Riprova.")
180+
self.pin_entry.delete(0, "end")
181+
182+
def open_terminal(self):
183+
self.status_bar.config(text="Terminale aperto")
184+
self._open_terminal_window()
185+
186+
def open_notes(self):
187+
self.status_bar.config(text="Appunti aperti")
188+
self._open_notes_window()
189+
190+
def open_file_manager(self):
191+
self.status_bar.config(text="File Manager aperto")
192+
self._open_file_manager_window()
193+
194+
def open_settings(self):
195+
self.status_bar.config(text="Impostazioni aperte")
196+
self._open_settings_window()
197+
198+
def open_about(self):
199+
messagebox.showinfo(
200+
"Informazioni su PythonOS",
201+
"PythonOS è un mini-sistema operativo costruito con Python e Tkinter.\n"
202+
"Versione: 1.0.0 Beta 1",
203+
)
204+
205+
def _open_terminal_window(self):
206+
window = AppWindow(self.desktop, "Terminale", width=520, height=320, x=120, y=120)
207+
console = scrolledtext.ScrolledText(window.content, bg="#1e1f2b", fg="#f8f8f2", insertbackground="#f8f8f2")
208+
console.pack(expand=True, fill="both", padx=10, pady=10)
209+
console.insert("end", "PythonOS Terminale\n> digita 'help' e premi Invio\n")
210+
console.bind("<Return>", lambda event: self._handle_terminal_command(console))
211+
self.windows.append(window)
212+
213+
def _handle_terminal_command(self, console):
214+
text = console.get("1.0", "end-1c").strip().splitlines()[-1]
215+
command = text.replace("> ", "").strip()
216+
response = self.state.run_command(command)
217+
console.insert("end", f"\n{response}\n> ")
218+
console.see("end")
219+
return "break"
220+
221+
def _open_notes_window(self):
222+
window = AppWindow(self.desktop, "Appunti", width=520, height=320, x=140, y=130)
223+
text_area = scrolledtext.ScrolledText(window.content, bg="#1f1f2b", fg="#f8f8f2")
224+
text_area.pack(expand=True, fill="both", padx=10, pady=10)
225+
text_area.insert("1.0", self.state.notes)
226+
227+
def save_notes():
228+
self.state.notes = text_area.get("1.0", "end-1c")
229+
self.status_bar.config(text="Appunti salvati")
230+
231+
save_btn = tk.Button(window.content, text="Salva", command=save_notes, bg="#50fa7b", fg="#282a36", relief="flat")
232+
save_btn.pack(pady=8)
233+
self.windows.append(window)
234+
235+
def _open_file_manager_window(self):
236+
window = AppWindow(self.desktop, "File Manager", width=520, height=320, x=160, y=140)
237+
files_text = tk.Text(window.content, bg="#1e1f2b", fg="#f8f8f2")
238+
files_text.pack(expand=True, fill="both", padx=10, pady=10)
239+
files_text.insert("1.0", "\n".join(self.state.get_file_listing()))
240+
files_text.config(state="disabled")
241+
self.windows.append(window)
242+
243+
def _open_settings_window(self):
244+
window = AppWindow(self.desktop, "Impostazioni", width=520, height=340, x=180, y=160)
245+
246+
theme_label = tk.Label(window.content, text="Tema:", fg="#f8f8f2", bg="#282a36", font=("Segoe UI", 10, "bold"))
247+
theme_label.pack(anchor="w", padx=12, pady=(12, 4))
248+
249+
theme_frame = tk.Frame(window.content, bg="#282a36")
250+
theme_frame.pack(anchor="w", padx=12)
251+
light_btn = tk.Button(theme_frame, text="Chiaro", command=lambda: self._set_theme("light"), bg="#50fa7b", fg="#282a36", relief="flat")
252+
dark_btn = tk.Button(theme_frame, text="Scuro", command=lambda: self._set_theme("dark"), bg="#6272a4", fg="#f8f8f2", relief="flat")
253+
light_btn.pack(side="left", padx=4)
254+
dark_btn.pack(side="left", padx=4)
255+
256+
username_label = tk.Label(window.content, text="Nome utente:", fg="#f8f8f2", bg="#282a36", font=("Segoe UI", 10, "bold"))
257+
username_label.pack(anchor="w", padx=12, pady=(12, 4))
258+
username_entry = tk.Entry(window.content, bg="#1e1f2b", fg="#f8f8f2", insertbackground="#f8f8f2")
259+
username_entry.insert(0, self.state.user_name)
260+
username_entry.pack(fill="x", padx=12)
261+
262+
lock_label = tk.Label(window.content, text="PIN blocco schermo:", fg="#f8f8f2", bg="#282a36", font=("Segoe UI", 10, "bold"))
263+
lock_label.pack(anchor="w", padx=12, pady=(12, 4))
264+
lock_entry = tk.Entry(window.content, bg="#1e1f2b", fg="#f8f8f2", insertbackground="#f8f8f2")
265+
lock_entry.insert(0, self.state.lock_code)
266+
lock_entry.pack(fill="x", padx=12)
267+
268+
269+
def save_settings():
270+
self.state.user_name = username_entry.get().strip() or self.state.user_name
271+
self.state.lock_code = lock_entry.get().strip() or self.state.lock_code
272+
self.status_bar.config(text="Impostazioni salvate")
273+
self._show_welcome()
274+
275+
info_label = tk.Button(window.content, text="Informazioni sistema", command=self.open_about, bg="#6272a4", fg="#f8f8f2", relief="flat")
276+
info_label.pack(pady=12)
277+
278+
save_btn = tk.Button(window.content, text="Salva impostazioni", command=save_settings, bg="#50fa7b", fg="#282a36", relief="flat")
279+
save_btn.pack(pady=12)
280+
281+
self.windows.append(window)
282+
283+
def _set_theme(self, theme_name):
284+
self.state.theme = theme_name
285+
if theme_name == "light":
286+
self.desktop.configure(bg="#dcdde1")
287+
self.status_bar.config(bg="#f0f0f0", fg="#1f1f2e")
288+
self.top_bar.config(bg="#f0f0f0")
289+
self.status_label.config(bg="#f0f0f0", fg="#1f1f2e")
290+
self.clock_label.config(bg="#f0f0f0", fg="#1f1f2e")
291+
else:
292+
self.desktop.configure(bg="#282a36")
293+
self.status_bar.config(bg="#1f1f2e", fg="#f8f8f2")
294+
self.top_bar.config(bg="#1f1f2e")
295+
self.status_label.config(bg="#1f1f2e", fg="#f8f8f2")
296+
self.clock_label.config(bg="#1f1f2e", fg="#f8f8f2")
297+
self.status_bar.config(text=f"Tema impostato su {theme_name}")
298+
299+
def _update_clock(self):
300+
self.clock_label.config(text=datetime.now().strftime("%H:%M"))
301+
self.root.after(1000, self._update_clock)
302+
303+
def run(self):
304+
self.root.mainloop()

0 commit comments

Comments
 (0)