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):
|
def get_midi_ports(self):
|
||||||
"""Get list of available MIDI input ports."""
|
"""Get list of available MIDI input ports."""
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
logging.error(f"Error getting MIDI ports: {e}")
|
logging.error(f"Error getting MIDI ports: {e}")
|
||||||
|
print(f"Error getting MIDI ports: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def load_midi_preference(self):
|
def load_midi_preference(self):
|
||||||
@@ -333,7 +351,11 @@ class UIClient:
|
|||||||
self.root = tk.Tk()
|
self.root = tk.Tk()
|
||||||
self.root.configure(bg=bg_color)
|
self.root.configure(bg=bg_color)
|
||||||
self.root.title("Lighting Controller - UI Client")
|
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()
|
self.load_window_geometry()
|
||||||
|
|
||||||
# MIDI controller
|
# MIDI controller
|
||||||
@@ -388,18 +410,23 @@ class UIClient:
|
|||||||
# Improve contrast for Combobox (dark theme)
|
# Improve contrast for Combobox (dark theme)
|
||||||
try:
|
try:
|
||||||
style.configure("TCombobox",
|
style.configure("TCombobox",
|
||||||
foreground=fg_color,
|
foreground="#FFFFFF",
|
||||||
fieldbackground=bg_color,
|
fieldbackground="#2C2C2C",
|
||||||
background=bg_color)
|
background="#2C2C2C",
|
||||||
|
borderwidth=2,
|
||||||
|
relief="solid")
|
||||||
style.map("TCombobox",
|
style.map("TCombobox",
|
||||||
fieldbackground=[('readonly', bg_color)],
|
fieldbackground=[('readonly', '#2C2C2C')],
|
||||||
foreground=[('readonly', fg_color)],
|
foreground=[('readonly', '#FFFFFF')],
|
||||||
background=[('readonly', bg_color)])
|
background=[('readonly', '#2C2C2C')],
|
||||||
|
focuscolor=[('!focus', '#404040')])
|
||||||
# Dropdown list colors
|
# Dropdown list colors
|
||||||
self.root.option_add("*TCombobox*Listbox*background", bg_color)
|
self.root.option_add("*TCombobox*Listbox*background", "#2C2C2C")
|
||||||
self.root.option_add("*TCombobox*Listbox*foreground", fg_color)
|
self.root.option_add("*TCombobox*Listbox*foreground", "#FFFFFF")
|
||||||
self.root.option_add("*TCombobox*Listbox*selectBackground", highlight_pattern_color)
|
self.root.option_add("*TCombobox*Listbox*selectBackground", "#404040")
|
||||||
self.root.option_add("*TCombobox*Listbox*selectForeground", fg_color)
|
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:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -413,15 +440,17 @@ class UIClient:
|
|||||||
|
|
||||||
# MIDI port dropdown
|
# MIDI port dropdown
|
||||||
self.midi_port_var = tk.StringVar()
|
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,
|
midi_frame,
|
||||||
textvariable=self.midi_port_var,
|
textvariable=self.midi_port_var,
|
||||||
values=[],
|
values=[],
|
||||||
state="readonly",
|
state="readonly",
|
||||||
font=("Arial", 11)
|
font=("Arial", 12, "bold"),
|
||||||
|
width=20
|
||||||
)
|
)
|
||||||
midi_dropdown.pack(padx=8, pady=4, fill="x")
|
self.midi_dropdown.pack(padx=8, pady=4, fill="x")
|
||||||
midi_dropdown.bind("<<ComboboxSelected>>", self.on_midi_port_change)
|
self.midi_dropdown.bind("<<ComboboxSelected>>", self.on_midi_port_change)
|
||||||
|
|
||||||
# Refresh MIDI ports button
|
# Refresh MIDI ports button
|
||||||
refresh_button = ttk.Button(
|
refresh_button = ttk.Button(
|
||||||
@@ -575,6 +604,9 @@ class UIClient:
|
|||||||
self.root.after(200, self.update_status_labels)
|
self.root.after(200, self.update_status_labels)
|
||||||
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
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):
|
def open_pattern_window(self, pattern_name: str):
|
||||||
"""Create or focus a child window per pattern with sliders for parameters."""
|
"""Create or focus a child window per pattern with sliders for parameters."""
|
||||||
if pattern_name in self.pattern_windows:
|
if pattern_name in self.pattern_windows:
|
||||||
@@ -733,22 +765,28 @@ class UIClient:
|
|||||||
|
|
||||||
def refresh_midi_ports(self):
|
def refresh_midi_ports(self):
|
||||||
"""Refresh MIDI ports list."""
|
"""Refresh MIDI ports list."""
|
||||||
|
print("Refreshing MIDI ports...")
|
||||||
old_ports = self.midi_controller.available_ports.copy()
|
old_ports = self.midi_controller.available_ports.copy()
|
||||||
self.midi_controller.available_ports = self.midi_controller.get_midi_ports()
|
self.midi_controller.available_ports = self.midi_controller.get_midi_ports()
|
||||||
|
print(f"Available ports: {self.midi_controller.available_ports}")
|
||||||
|
|
||||||
# Update dropdown
|
# Update dropdown directly
|
||||||
for child in self.root.winfo_children():
|
if hasattr(self, 'midi_dropdown'):
|
||||||
if isinstance(child, ttk.LabelFrame) and child.cget("text") == "MIDI Controller":
|
self.midi_dropdown['values'] = self.midi_controller.available_ports
|
||||||
for widget in child.winfo_children():
|
print(f"Updated dropdown with: {self.midi_controller.available_ports}")
|
||||||
if isinstance(widget, ttk.Combobox):
|
|
||||||
widget['values'] = self.midi_controller.available_ports
|
# Clear current selection if it's not in the new list
|
||||||
if (self.midi_controller.available_ports and
|
current_selection = self.midi_port_var.get()
|
||||||
self.midi_port_var.get() not in self.midi_controller.available_ports):
|
if current_selection not in self.midi_controller.available_ports:
|
||||||
self.midi_port_var.set(self.midi_controller.available_ports[0])
|
if self.midi_controller.available_ports:
|
||||||
self.midi_controller.midi_port_index = 0
|
self.midi_port_var.set(self.midi_controller.available_ports[0])
|
||||||
self.midi_controller.save_midi_preference()
|
self.midi_controller.midi_port_index = 0
|
||||||
break
|
self.midi_controller.save_midi_preference()
|
||||||
break
|
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):
|
def on_midi_port_change(self, event):
|
||||||
"""Handle MIDI port selection change."""
|
"""Handle MIDI port selection change."""
|
||||||
@@ -1032,7 +1070,7 @@ class UIClient:
|
|||||||
def on_closing(self):
|
def on_closing(self):
|
||||||
"""Handle application closing."""
|
"""Handle application closing."""
|
||||||
logging.info("Closing UI client...")
|
logging.info("Closing UI client...")
|
||||||
# Persist window geometry
|
# Save window geometry
|
||||||
self.save_window_geometry()
|
self.save_window_geometry()
|
||||||
if self.midi_controller.midi_task:
|
if self.midi_controller.midi_task:
|
||||||
self.midi_controller.midi_task.cancel()
|
self.midi_controller.midi_task.cancel()
|
||||||
|
Reference in New Issue
Block a user