ScanSlicer/scanslicer/controller_params.py
dan 426a18f342 chore: prune boilerplate and refresh stale docs
- Remove 257 redundant per-definition comment stubs across the package
- Drop dead nonlocal declarations in autoslicer_detection.py
- Document the swapped flag and swap_left_right in architecture docs
- Remove unsupported 'legacy override' claims from autotune/runtime docs
2026-09-11 23:07:30 +02:00

215 lines
7.7 KiB
Python

from PySide6.QtWidgets import QComboBox, QInputDialog, QMessageBox, QSlider
class ScanSlicerParamsMixin:
def set_autotune_profile(self, profile_name):
normalized = self.autoslicer.normalize_autotune_profile(profile_name)
self.autotune_profile = normalized
dropdown = getattr(self, "autotune_profile_dropdown", None)
if dropdown is not None and dropdown.currentText() != normalized:
dropdown.blockSignals(True)
dropdown.setCurrentText(normalized)
dropdown.blockSignals(False)
def set_show_advanced_parameters(self, checked):
self.show_advanced_params = bool(checked)
self.update_parameter_visibility()
def sync_param_controls_from_model(self):
self.updating_param_controls = True
for name, p in self.params.items():
control = self.param_controls[name]
if isinstance(control, QSlider):
control.setValue(p.get())
elif isinstance(control, QComboBox):
idx = control.findData(p.get())
if idx >= 0:
control.setCurrentIndex(idx)
self.updating_param_controls = False
self.update_parameter_visibility()
def update_parameter_visibility(self):
pipeline = self.params.detect_pipeline.get()
method = self.params.bw_method.get()
morph_op = self.params.morph_op.get()
show_advanced = bool(getattr(self, "show_advanced_params", False))
advanced_params = set(getattr(self, "ADVANCED_PARAMS", set()))
visibility = {
"bw_method": pipeline == 0,
"bw_thresh": pipeline == 0 and method == 0,
"bw_gauss": pipeline == 0 and method == 1,
"bw_adaptive_c": pipeline == 0 and method == 1,
"canny_low": pipeline == 1,
"canny_high": pipeline == 1,
"dilate_kernel": morph_op != 0,
}
for param_name, block in self.param_blocks.items():
if block is None:
continue
is_visible = visibility.get(param_name, True)
if param_name in advanced_params and not show_advanced:
is_visible = False
block.setVisible(is_visible)
def load_default_parameters(self):
mode = self.params.load_defaults()
self.sync_param_controls_from_model()
self.set_preset_dropdown_custom()
if mode == "saved":
self.update_statusbar("Loaded saved defaults.")
else:
self.update_statusbar("Loaded factory defaults (no saved defaults found).")
def save_default_parameters(self):
try:
path = self.params.save_user_defaults()
except OSError as exc:
QMessageBox.critical(self, "Save defaults failed", str(exc))
self.update_statusbar("Failed to save defaults.")
return
self.update_statusbar("Saved defaults to " + path)
def autotune_parameters(self):
if self.processing_busy:
return
if not self.autoslicer.image_loaded():
QMessageBox.warning(self, "No image loaded", "Load an image first")
return
self._start_autotune_worker()
def clear_autotune_history(self):
if self.processing_busy:
return
entry_count = len(self.autoslicer.feedback_entries)
prompt = (
"Clear auto-tune feedback history?\n\n"
"This removes learned examples from previous saves and resets auto-tune learning."
)
if entry_count > 0:
prompt += f"\n\nSaved examples: {entry_count}"
choice = QMessageBox.question(
self,
"Clear auto-tune history",
prompt,
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
if choice != QMessageBox.Yes:
return
try:
result = self.autoslicer.clear_feedback_entries()
except OSError as exc:
QMessageBox.critical(self, "Clear history failed", str(exc))
self.update_statusbar("Failed to clear auto-tune history.")
return
self.append_status_log(
"Auto-tune feedback cleared: "
+ f"entries={result['cleared_count']}, path={result['path']}, removed_file={result['removed_file']}"
)
self.update_statusbar("Auto-tune history cleared.")
def set_preset_dropdown_custom(self):
if self.preset_dropdown.currentText() == "Custom":
return
self.preset_dropdown.blockSignals(True)
self.preset_dropdown.setCurrentText("Custom")
self.preset_dropdown.blockSignals(False)
def refresh_preset_dropdown(self, selected_name=None):
if selected_name is None:
selected_name = self.preset_dropdown.currentText()
self.preset_dropdown.blockSignals(True)
self.preset_dropdown.clear()
self.preset_dropdown.addItem("Custom")
self.preset_dropdown.addItems(self.params.preset_names())
if selected_name and self.preset_dropdown.findText(selected_name) >= 0:
self.preset_dropdown.setCurrentText(selected_name)
else:
self.preset_dropdown.setCurrentText("Custom")
self.preset_dropdown.blockSignals(False)
def save_current_as_preset(self):
if self.processing_busy:
return
suggested_name = self.preset_dropdown.currentText()
if suggested_name == "Custom":
suggested_name = "My Preset"
preset_name, ok = QInputDialog.getText(
self,
"Save Preset",
"Preset name:",
text=suggested_name,
)
if not ok:
return
preset_name = preset_name.strip()
if len(preset_name) == 0:
QMessageBox.warning(self, "Invalid preset name", "Preset name cannot be empty.")
return
try:
saved_name = self.params.save_named_preset(preset_name)
except ValueError as exc:
QMessageBox.warning(self, "Invalid preset name", str(exc))
return
except OSError as exc:
QMessageBox.critical(self, "Save preset failed", str(exc))
return
self.refresh_preset_dropdown(selected_name=saved_name)
self.update_statusbar("Saved preset: " + saved_name)
def delete_current_preset(self):
if self.processing_busy:
return
preset_name = self.preset_dropdown.currentText().strip()
if len(preset_name) == 0 or preset_name == "Custom":
QMessageBox.warning(self, "No preset selected", "Select a user preset to delete.")
return
choice = QMessageBox.question(
self,
"Delete Preset",
f"Delete preset '{preset_name}'?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
if choice != QMessageBox.Yes:
return
try:
deleted_name = self.params.delete_named_preset(preset_name)
except ValueError as exc:
QMessageBox.warning(self, "Delete preset failed", str(exc))
return
except OSError as exc:
QMessageBox.critical(self, "Delete preset failed", str(exc))
return
self.refresh_preset_dropdown(selected_name="Custom")
self.update_statusbar("Deleted preset: " + deleted_name)
def apply_parameter_preset(self, preset_name):
if preset_name == "Custom":
return
if not self.params.apply_preset(preset_name):
return
self.sync_param_controls_from_model()
self.preset_dropdown.blockSignals(True)
self.preset_dropdown.setCurrentText(preset_name)
self.preset_dropdown.blockSignals(False)
self.update_statusbar("Applied preset: " + preset_name)