commit 25

This commit is contained in:
2025-07-30 01:15:53 +02:00
parent 9314548928
commit 98b16e664b
2 changed files with 99 additions and 53 deletions

View File

@@ -238,13 +238,15 @@ class CustomFileDialog(tk.Toplevel):
('selected', "black" if not self.is_dark else "white")])
style.configure("TButton.Borderless.Round", anchor="w")
style.configure("Vertical.TScrollbar", width=10) # Make scrollbar narrower
def create_widgets(self):
# Main container
main_frame = ttk.Frame(self, style='Accent.TFrame')
main_frame.pack(fill="both", expand=True)
main_frame.grid_rowconfigure(2, weight=1)
main_frame.grid_columnconfigure(1, weight=1)
main_frame.grid_columnconfigure(0, weight=0) # Sidebar column
main_frame.grid_columnconfigure(1, weight=1) # Content column
# Top bar for navigation and path
top_bar = ttk.Frame(
@@ -309,12 +311,38 @@ class CustomFileDialog(tk.Toplevel):
sidebar_frame = ttk.Frame(
main_frame, style="Sidebar.TFrame", padding=(0, 0, 0, 15))
sidebar_frame.grid(row=2, column=0, sticky="nsw")
sidebar_frame.grid_rowconfigure(0, weight=1)
sidebar_frame.grid_rowconfigure(0, weight=1) # Allow canvas to expand
sidebar_frame.grid_columnconfigure(0, weight=1)
# Create a canvas for the scrollable sidebar content
sidebar_canvas = tk.Canvas(sidebar_frame, highlightthickness=0, bg=self.sidebar_color)
sidebar_canvas.grid(row=0, column=0, sticky="nsew")
sidebar_scrollbar = ttk.Scrollbar(sidebar_frame, orient="vertical", command=sidebar_canvas.yview, style="Vertical.TScrollbar")
sidebar_scrollbar.grid(row=0, column=1, sticky="ns")
sidebar_canvas.configure(yscrollcommand=sidebar_scrollbar.set)
sidebar_canvas.bind('<Configure>', lambda e: sidebar_canvas.configure(scrollregion = sidebar_canvas.bbox("all")))
# Create a frame inside the canvas to hold all sidebar content
self.sidebar_inner_frame = ttk.Frame(sidebar_canvas, style="Sidebar.TFrame")
sidebar_canvas.create_window((0, 0), window=self.sidebar_inner_frame, anchor="nw")
# Bind mouse wheel to the inner frame
def _on_sidebar_mouse_wheel(event):
sidebar_canvas.yview_scroll(-1*(event.delta//120), "units")
self.sidebar_inner_frame.bind("<MouseWheel>", _on_sidebar_mouse_wheel)
self.sidebar_inner_frame.bind("<Button-4>", lambda e: _on_sidebar_mouse_wheel(e)) # For Linux
self.sidebar_inner_frame.bind("<Button-5>", lambda e: _on_sidebar_mouse_wheel(e)) # For Linux
# Propagate mouse wheel events from children to the inner frame
for child in self.sidebar_inner_frame.winfo_children():
child.bind("<MouseWheel>", _on_sidebar_mouse_wheel)
child.bind("<Button-4>", lambda e: _on_sidebar_mouse_wheel(e))
child.bind("<Button-5>", lambda e: _on_sidebar_mouse_wheel(e))
sidebar_buttons_frame = ttk.Frame(
sidebar_frame, style="Sidebar.TFrame", padding=(0, 15, 0, 0))
sidebar_buttons_frame.grid(
row=0, column=0, sticky="nsew")
self.sidebar_inner_frame, style="Sidebar.TFrame", padding=(0, 15, 0, 0))
sidebar_buttons_frame.pack(fill="x", expand=False)
sidebar_buttons_config = [
{'name': 'Computer',
'icon': self.icons['computer_small'], 'path': '/'},
@@ -334,26 +362,29 @@ class CustomFileDialog(tk.Toplevel):
compound="left", command=lambda p=config['path']: self.navigate_to(p), style="Dark.TButton.Borderless")
btn.pack(fill="x", pady=1)
ttk.Separator(sidebar_buttons_frame, orient='horizontal').pack(
ttk.Separator(self.sidebar_inner_frame, orient='horizontal').pack(
fill='x', pady=10, padx=20)
# Mounted devices
mounted_devices_frame = ttk.Frame(
sidebar_frame, style="Sidebar.TFrame")
mounted_devices_frame.grid(row=1, column=0, sticky="ew", padx=10)
self.sidebar_inner_frame, style="Sidebar.TFrame")
mounted_devices_frame.pack(fill="x", expand=False, padx=10)
ttk.Label(mounted_devices_frame, text="Geräte:", background=self.sidebar_color,
foreground=self.color_foreground).pack(fill="x", padx=10, pady=(5, 0))
for device_name, mount_point in self._get_mounted_devices():
btn = ttk.Button(mounted_devices_frame, text=f" {device_name}", image=self.icons['computer_small'],
for device_name, mount_point, removable in self._get_mounted_devices():
icon = self.icons['usb_small'] if removable else self.icons['device_small']
btn = ttk.Button(mounted_devices_frame, text=f" {device_name}", image=icon,
compound="left", command=lambda p=mount_point: self.navigate_to(p), style="Dark.TButton.Borderless")
btn.pack(fill="x", pady=1)
ttk.Separator(sidebar_buttons_frame, orient='horizontal').pack(
# New separator before storage_frame
ttk.Separator(self.sidebar_inner_frame, orient='horizontal').pack(
fill='x', pady=10, padx=20)
storage_frame = ttk.Frame(sidebar_frame, style="Sidebar.TFrame")
storage_frame.grid(row=2, column=0, sticky="ew", padx=10)
storage_frame = ttk.Frame(self.sidebar_inner_frame, style="Sidebar.TFrame")
storage_frame.pack(fill="x", expand=False, padx=10)
self.storage_label = ttk.Label(
storage_frame, text="Freier Speicher:", background=self.freespace_background)
self.storage_label.pack(fill="x", padx=10)
@@ -415,16 +446,7 @@ class CustomFileDialog(tk.Toplevel):
self.resize_job = self.after(200, self.populate_files)
self.last_width = new_width
def _unbind_mouse_wheel_events(self):
# Unbind all mouse wheel events from the root window
self.unbind_all("<MouseWheel>")
self.unbind_all("<Button-4>")
self.unbind_all("<Button-5>")
def populate_files(self):
# Unbind previous global mouse wheel events
self._unbind_mouse_wheel_events()
for widget in self.file_list_frame.winfo_children():
widget.destroy()
self.path_entry.delete(0, tk.END)
@@ -467,12 +489,12 @@ class CustomFileDialog(tk.Toplevel):
scrollregion=canvas.bbox("all")))
def _on_mouse_wheel(event):
delta = -1 if event.num == 4 else 1
delta = -1*(event.delta//120) # Normalize delta for cross-platform consistency
canvas.yview_scroll(delta, "units")
canvas.bind_all("<MouseWheel>", _on_mouse_wheel)
canvas.bind_all("<Button-4>", _on_mouse_wheel)
canvas.bind_all("<Button-5>", _on_mouse_wheel)
container_frame.bind("<MouseWheel>", _on_mouse_wheel)
container_frame.bind("<Button-4>", lambda e: _on_mouse_wheel(e)) # For Linux
container_frame.bind("<Button-5>", lambda e: _on_mouse_wheel(e)) # For Linux
items, error, warning = self._get_sorted_items()
if warning:
@@ -742,42 +764,66 @@ class CustomFileDialog(tk.Toplevel):
def _get_mounted_devices(self):
devices = []
root_disk_name = None
try:
# Use lsblk to get information about block devices
# -o NAME,MOUNTPOINT,FSTYPE,SIZE,RO,RM,TYPE,LABEL,UUID
# -J for JSON output
result = subprocess.run(['lsblk', '-J', '-o', 'NAME,MOUNTPOINT,FSTYPE,SIZE,RO,RM,TYPE,LABEL'],
result = subprocess.run(['lsblk', '-J', '-o', 'NAME,MOUNTPOINT,FSTYPE,SIZE,RO,RM,TYPE,LABEL,PKNAME'],
capture_output=True, text=True, check=True)
data = json.loads(result.stdout)
# First pass: Find the root disk name
for block_device in data.get('blockdevices', []):
# Consider only devices with a mountpoint and not of type 'loop' or 'rom'
if block_device.get('mountpoint') and block_device.get('type') not in ['loop', 'rom']:
name = block_device.get('name')
mountpoint = block_device.get('mountpoint')
label = block_device.get('label')
size = block_device.get('size')
display_name = label if label else name
if size:
display_name += f" ({size})"
devices.append((display_name, mountpoint))
# Recursively check partitions if any
if 'children' in block_device:
for child_device in block_device['children']:
if child_device.get('mountpoint') and child_device.get('type') not in ['loop', 'rom']:
name = child_device.get('name')
mountpoint = child_device.get('mountpoint')
label = child_device.get('label')
size = child_device.get('size')
if child_device.get('mountpoint') == '/':
root_disk_name = block_device.get('name')
break
if root_disk_name:
break
display_name = label if label else name
if size:
display_name += f" ({size})"
# Second pass: Collect devices based on new criteria
for block_device in data.get('blockdevices', []):
# Process main device if it has a mountpoint
if block_device.get('mountpoint') and \
block_device.get('type') not in ['loop', 'rom'] and \
block_device.get('mountpoint') != '/': # Exclude root mountpoint itself
# Exclude non-removable partitions of the root disk
if block_device.get('name').startswith(root_disk_name) and not block_device.get('rm', False):
pass # Skip this device
else:
name = block_device.get('name')
mountpoint = block_device.get('mountpoint')
label = block_device.get('label')
size = block_device.get('size')
removable = block_device.get('rm', False)
display_name = label if label else name
if size:
display_name += f" ({size})"
devices.append((display_name, mountpoint, removable))
# Process children (partitions)
if 'children' in block_device:
for child_device in block_device['children']:
if child_device.get('mountpoint') and \
child_device.get('type') not in ['loop', 'rom'] and \
child_device.get('mountpoint') != '/': # Exclude root mountpoint itself
# Exclude non-removable partitions of the root disk
if block_device.get('name') == root_disk_name and not child_device.get('rm', False):
pass # Skip this partition
else:
name = child_device.get('name')
mountpoint = child_device.get('mountpoint')
label = child_device.get('label')
size = child_device.get('size')
removable = child_device.get('rm', False)
display_name = label if label else name
if size:
display_name += f" ({size})"
devices.append((display_name, mountpoint, removable))
devices.append((display_name, mountpoint))
except Exception as e:
print(f"Error getting mounted devices: {e}")
return devices