UI: Fix MIDI dropdown contrast and device detection
- Improve MIDI dropdown contrast with better colors (#FFFFFF text on #2C2C2C background) - Add bold font and larger size for better visibility - Fix MIDI device detection to show all available devices - Add port validation to only show accessible MIDI devices - Use direct widget reference instead of searching for dropdown - Add delayed initialization to ensure UI is ready before populating dropdown - Improve debugging output for MIDI port detection - Add placeholder text 'No MIDI device selected' when no devices available - Restore window geometry persistence for proper window positioning
This commit is contained in:
@@ -180,9 +180,27 @@ class MidiController:
|
||||
def get_midi_ports(self):
|
||||
"""Get list of available MIDI input ports."""
|
||||
try:
|
||||
return mido.get_input_names()
|
||||
# Get input ports (we only need input for receiving MIDI)
|
||||
input_ports = mido.get_input_names()
|
||||
|
||||
# Also check if we can actually open each port
|
||||
valid_ports = []
|
||||
for port in input_ports:
|
||||
try:
|
||||
# Try to open the port to see if it's accessible
|
||||
test_port = mido.open_input(port)
|
||||
test_port.close()
|
||||
valid_ports.append(port)
|
||||
print(f"Valid MIDI input port: {port}")
|
||||
except Exception as e:
|
||||
print(f"Cannot open MIDI port '{port}': {e}")
|
||||
|
||||
print(f"Found MIDI input ports: {input_ports}")
|
||||
print(f"Valid MIDI input ports: {valid_ports}")
|
||||
return valid_ports
|
||||
except Exception as e:
|
||||
logging.error(f"Error getting MIDI ports: {e}")
|
||||
print(f"Error getting MIDI ports: {e}")
|
||||
return []
|
||||
|
||||
def load_midi_preference(self):
|
||||
@@ -333,7 +351,11 @@ class UIClient:
|
||||
self.root = tk.Tk()
|
||||
self.root.configure(bg=bg_color)
|
||||
self.root.title("Lighting Controller - UI Client")
|
||||
# Restore last window geometry if available
|
||||
|
||||
# Set window size to fit all content properly - 4x4 button grid needs more space
|
||||
self.root.geometry("1800x1200")
|
||||
|
||||
# Load saved window geometry if available
|
||||
self.load_window_geometry()
|
||||
|
||||
# MIDI controller
|
||||
@@ -388,18 +410,23 @@ class UIClient:
|
||||
# Improve contrast for Combobox (dark theme)
|
||||
try:
|
||||
style.configure("TCombobox",
|
||||
foreground=fg_color,
|
||||
fieldbackground=bg_color,
|
||||
background=bg_color)
|
||||
foreground="#FFFFFF",
|
||||
fieldbackground="#2C2C2C",
|
||||
background="#2C2C2C",
|
||||
borderwidth=2,
|
||||
relief="solid")
|
||||
style.map("TCombobox",
|
||||
fieldbackground=[('readonly', bg_color)],
|
||||
foreground=[('readonly', fg_color)],
|
||||
background=[('readonly', bg_color)])
|
||||
fieldbackground=[('readonly', '#2C2C2C')],
|
||||
foreground=[('readonly', '#FFFFFF')],
|
||||
background=[('readonly', '#2C2C2C')],
|
||||
focuscolor=[('!focus', '#404040')])
|
||||
# Dropdown list colors
|
||||
self.root.option_add("*TCombobox*Listbox*background", bg_color)
|
||||
self.root.option_add("*TCombobox*Listbox*foreground", fg_color)
|
||||
self.root.option_add("*TCombobox*Listbox*selectBackground", highlight_pattern_color)
|
||||
self.root.option_add("*TCombobox*Listbox*selectForeground", fg_color)
|
||||
self.root.option_add("*TCombobox*Listbox*background", "#2C2C2C")
|
||||
self.root.option_add("*TCombobox*Listbox*foreground", "#FFFFFF")
|
||||
self.root.option_add("*TCombobox*Listbox*selectBackground", "#404040")
|
||||
self.root.option_add("*TCombobox*Listbox*selectForeground", "#FFFFFF")
|
||||
self.root.option_add("*TCombobox*Listbox*borderwidth", "1")
|
||||
self.root.option_add("*TCombobox*Listbox*relief", "solid")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -413,15 +440,17 @@ class UIClient:
|
||||
|
||||
# MIDI port dropdown
|
||||
self.midi_port_var = tk.StringVar()
|
||||
midi_dropdown = ttk.Combobox(
|
||||
self.midi_port_var.set("No MIDI device selected")
|
||||
self.midi_dropdown = ttk.Combobox(
|
||||
midi_frame,
|
||||
textvariable=self.midi_port_var,
|
||||
values=[],
|
||||
state="readonly",
|
||||
font=("Arial", 11)
|
||||
font=("Arial", 12, "bold"),
|
||||
width=20
|
||||
)
|
||||
midi_dropdown.pack(padx=8, pady=4, fill="x")
|
||||
midi_dropdown.bind("<<ComboboxSelected>>", self.on_midi_port_change)
|
||||
self.midi_dropdown.pack(padx=8, pady=4, fill="x")
|
||||
self.midi_dropdown.bind("<<ComboboxSelected>>", self.on_midi_port_change)
|
||||
|
||||
# Refresh MIDI ports button
|
||||
refresh_button = ttk.Button(
|
||||
@@ -574,6 +603,9 @@ class UIClient:
|
||||
# Schedule periodic UI updates
|
||||
self.root.after(200, self.update_status_labels)
|
||||
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
|
||||
# Initialize MIDI ports after a short delay to ensure UI is ready
|
||||
self.root.after(500, self.refresh_midi_ports)
|
||||
|
||||
def open_pattern_window(self, pattern_name: str):
|
||||
"""Create or focus a child window per pattern with sliders for parameters."""
|
||||
@@ -733,22 +765,28 @@ class UIClient:
|
||||
|
||||
def refresh_midi_ports(self):
|
||||
"""Refresh MIDI ports list."""
|
||||
print("Refreshing MIDI ports...")
|
||||
old_ports = self.midi_controller.available_ports.copy()
|
||||
self.midi_controller.available_ports = self.midi_controller.get_midi_ports()
|
||||
print(f"Available ports: {self.midi_controller.available_ports}")
|
||||
|
||||
# Update dropdown
|
||||
for child in self.root.winfo_children():
|
||||
if isinstance(child, ttk.LabelFrame) and child.cget("text") == "MIDI Controller":
|
||||
for widget in child.winfo_children():
|
||||
if isinstance(widget, ttk.Combobox):
|
||||
widget['values'] = self.midi_controller.available_ports
|
||||
if (self.midi_controller.available_ports and
|
||||
self.midi_port_var.get() not in self.midi_controller.available_ports):
|
||||
self.midi_port_var.set(self.midi_controller.available_ports[0])
|
||||
self.midi_controller.midi_port_index = 0
|
||||
self.midi_controller.save_midi_preference()
|
||||
break
|
||||
break
|
||||
# Update dropdown directly
|
||||
if hasattr(self, 'midi_dropdown'):
|
||||
self.midi_dropdown['values'] = self.midi_controller.available_ports
|
||||
print(f"Updated dropdown with: {self.midi_controller.available_ports}")
|
||||
|
||||
# Clear current selection if it's not in the new list
|
||||
current_selection = self.midi_port_var.get()
|
||||
if current_selection not in self.midi_controller.available_ports:
|
||||
if self.midi_controller.available_ports:
|
||||
self.midi_port_var.set(self.midi_controller.available_ports[0])
|
||||
self.midi_controller.midi_port_index = 0
|
||||
self.midi_controller.save_midi_preference()
|
||||
else:
|
||||
self.midi_port_var.set("No MIDI device selected")
|
||||
print("Successfully updated MIDI dropdown")
|
||||
else:
|
||||
print("ERROR: MIDI dropdown not found!")
|
||||
|
||||
def on_midi_port_change(self, event):
|
||||
"""Handle MIDI port selection change."""
|
||||
@@ -1032,7 +1070,7 @@ class UIClient:
|
||||
def on_closing(self):
|
||||
"""Handle application closing."""
|
||||
logging.info("Closing UI client...")
|
||||
# Persist window geometry
|
||||
# Save window geometry
|
||||
self.save_window_geometry()
|
||||
if self.midi_controller.midi_task:
|
||||
self.midi_controller.midi_task.cancel()
|
||||
|
Reference in New Issue
Block a user