Skip to content

Commit 840eaa9

Browse files
committed
make auto default to support qupath
1 parent 4955f7e commit 840eaa9

File tree

2 files changed

+79
-16
lines changed

2 files changed

+79
-16
lines changed

gui/PyNutilGUI.py

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
QRadioButton,
2020
QButtonGroup,
2121
QGroupBox,
22+
QSizePolicy,
2223
)
2324
from PyQt6.QtGui import QAction, QIcon
2425

@@ -67,7 +68,7 @@ def __init__(self):
6768
self.arguments = {
6869
"reference_atlas": None,
6970
"registration_json": None,
70-
"object_colour": None,
71+
"object_colour": "auto",
7172
"segmentation_dir": None,
7273
"image_dir": None,
7374
"output_dir": None,
@@ -93,8 +94,9 @@ def initUI(self):
9394
# Create left panel
9495
left_layout = QVBoxLayout()
9596
left_widget = QWidget()
96-
left_widget.setMinimumWidth(350)
9797
left_widget.setLayout(left_layout)
98+
# Prefer flexible sizing over large fixed minimums to avoid overlapping on small windows
99+
left_widget.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
98100

99101
# Create menu bar
100102
menubar = QMenuBar(self)
@@ -205,9 +207,15 @@ def initUI(self):
205207
parent=self,
206208
)
207209
)
210+
# Allow manual entry (e.g. "auto", "0", "1", or "[r,g,b]")
211+
self.colour_dropdown.setEditable(True)
208212
populate_dropdown(
209213
self.colour_dropdown, self.recent_files.get("object_colour", [])
210214
)
215+
# Add an explicit "auto" option at the top (populate clears, so insert after)
216+
self.colour_dropdown.insertItem(0, "auto", userData="auto")
217+
# Default to auto
218+
self.colour_dropdown.setCurrentIndex(0)
211219
self.colour_dropdown.currentIndexChanged.connect(self.set_colour)
212220
left_layout.addLayout(color_layout)
213221

@@ -288,8 +296,10 @@ def initUI(self):
288296
# Output text browser
289297
self.output_box = QTextBrowser()
290298
self.output_box.setOpenExternalLinks(True)
291-
self.output_box.setMinimumWidth(600)
292-
self.output_box.setMinimumHeight(400)
299+
# Allow the output box to shrink reasonably on small windows
300+
self.output_box.setMinimumWidth(300)
301+
self.output_box.setMinimumHeight(300)
302+
self.output_box.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
293303
right_layout.addWidget(self.output_box)
294304

295305
# Add panels to main layout
@@ -299,7 +309,8 @@ def initUI(self):
299309
central_widget.setLayout(main_layout)
300310
self.setCentralWidget(central_widget)
301311

302-
self.setMinimumSize(1000, 600)
312+
# Reduce strict minimum size to allow resizing on Windows without overlap
313+
self.setMinimumSize(800, 500)
303314

304315
# Initialize log storage variables
305316
self.log_collection = ""
@@ -392,12 +403,44 @@ def set_custom_region_file(self, index):
392403

393404
def set_colour(self, index):
394405
if index >= 0:
395-
value = self.colour_dropdown.itemData(index) or self.colour_dropdown.currentText()
396-
if value:
397-
try:
398-
self.arguments["object_colour"] = [int(x.strip()) for x in value.strip("[]").split(",")]
399-
except Exception:
400-
self.arguments["object_colour"] = [0, 0, 0]
406+
raw = self.colour_dropdown.itemData(index)
407+
if raw is None:
408+
raw = self.colour_dropdown.currentText()
409+
value = raw
410+
if value is None:
411+
return
412+
# Accept explicit 'auto'
413+
if isinstance(value, str) and value.strip().lower() == "auto":
414+
self.arguments["object_colour"] = "auto"
415+
return
416+
# If it's a stored string representation like '[r, g, b]'
417+
if isinstance(value, str):
418+
s = value.strip()
419+
# single integer like '0' or '1'
420+
if s.isdigit():
421+
try:
422+
self.arguments["object_colour"] = [int(s)]
423+
return
424+
except Exception:
425+
pass
426+
# comma separated numbers (either 'r,g,b' or 'r, g, b')
427+
if ("," in s) or (s.startswith("[") and s.endswith("]")):
428+
try:
429+
nums = [int(x.strip()) for x in s.strip("[]").split(",") if x.strip()]
430+
self.arguments["object_colour"] = nums
431+
return
432+
except Exception:
433+
pass
434+
# If it's already a list/iterable
435+
try:
436+
# convert to list of ints
437+
lst = list(value)
438+
lst = [int(x) for x in lst]
439+
self.arguments["object_colour"] = lst
440+
return
441+
except Exception:
442+
# fallback
443+
self.arguments["object_colour"] = "auto"
401444

402445
def choose_colour(self):
403446
color = QColorDialog.getColor()
@@ -407,7 +450,15 @@ def choose_colour(self):
407450
rgb_str = str(rgb_list)
408451
self.update_recent("object_colour", rgb_str)
409452
populate_dropdown(self.colour_dropdown, self.recent_files.get("object_colour", []))
410-
self.colour_dropdown.setCurrentIndex(1)
453+
# re-insert auto at position 0 after populate
454+
try:
455+
self.colour_dropdown.insertItem(0, "auto", userData="auto")
456+
except Exception:
457+
pass
458+
# set to the newly added colour (search for its text)
459+
idx = self.colour_dropdown.findText(rgb_str)
460+
if idx >= 0:
461+
self.colour_dropdown.setCurrentIndex(idx)
411462

412463
def start_analysis(self):
413464
# Clear logs
@@ -537,12 +588,22 @@ def load_settings_from_file(self):
537588
populate_dropdown(self.registration_json_dropdown, self.recent_files["registration_json"])
538589
self.registration_json_dropdown.setCurrentIndex(0)
539590

540-
if settings.get("colour"):
591+
if settings.get("colour") is not None:
541592
self.arguments["object_colour"] = settings["colour"]
542593
rgb_str = str(settings["colour"])
543594
self.update_recent("object_colour", rgb_str)
544595
populate_dropdown(self.colour_dropdown, self.recent_files.get("object_colour", []))
545-
self.colour_dropdown.setCurrentIndex(1)
596+
try:
597+
# ensure auto option present
598+
self.colour_dropdown.insertItem(0, "auto", userData="auto")
599+
except Exception:
600+
pass
601+
# Try to select the loaded colour, otherwise leave as auto
602+
idx = self.colour_dropdown.findText(rgb_str)
603+
if idx >= 0:
604+
self.colour_dropdown.setCurrentIndex(idx)
605+
else:
606+
self.colour_dropdown.setCurrentIndex(0)
546607

547608
if settings.get("custom_region"):
548609
self.arguments["custom_region_path"] = settings["custom_region"]

gui/validation.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,13 @@ def validate_analysis_inputs(
4444
missing.append("Specify only one of Segmentation Folder or Image Folder (not both)")
4545

4646
colour = arguments.get("object_colour")
47+
# Treat 'auto' as not specifying an explicit colour
48+
explicit_colour = bool(colour) and not (isinstance(colour, str) and colour.strip().lower() == "auto")
4749
# If using cellpose, object colour must not be set
48-
if arguments.get("cellpose") and colour:
50+
if arguments.get("cellpose") and explicit_colour:
4951
missing.append("Cellpose and Object Color cannot both be selected")
5052
elif not arguments.get("cellpose"):
51-
if not colour:
53+
if not explicit_colour:
5254
missing.append("Object Color")
5355

5456
if not arguments.get("output_dir"):

0 commit comments

Comments
 (0)