Skip to content

Commit e3c604c

Browse files
authored
Merge pull request #871 from eoyilmaz/845-qt-bpc-choice-dialog-measurement-mode
[#845] Reproduce the BPC choice dialog on Qt measurement-mode switch
2 parents d3287aa + a82500f commit e3c604c

2 files changed

Lines changed: 268 additions & 1 deletion

File tree

DisplayCAL/ui/main_window.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5574,14 +5574,19 @@ def measurement_mode_ctrl_handler(self, index: int) -> None:
55745574
Mirrors wx's ``measurement_mode_ctrl_handler``, minus the old-Argyll
55755575
"projector/adaptive mode unavailable" fallback dialogs (those only
55765576
applied to Argyll versions far older than anything this Qt port
5577-
targets).
5577+
targets). The confirm-and-toggle-BPC prompt, a separate dialog, is
5578+
reproduced via :meth:`_confirm_black_point_correction_choice`.
55785579
55795580
Args:
55805581
index (int): The newly selected combo index.
55815582
"""
55825583
if self._updating or index < 0:
55835584
return
55845585
code = self.get_measurement_mode()
5586+
cal_changed = (
5587+
code != getcfg("measurement_mode")
5588+
and getcfg("calibration.file", False) not in self.presets[1:]
5589+
)
55855590
instrument_features = self.worker.get_instrument_features()
55865591
if (
55875592
code
@@ -5601,6 +5606,61 @@ def measurement_mode_ctrl_handler(self, index: int) -> None:
56015606
setcfg("measurement_mode.highres", 1 if code and "H" in code else 0)
56025607
setcfg("measurement_mode.projector", 1 if code and "p" in code else None)
56035608
self.update_colorimeter_correction_matrix_ctrl()
5609+
if (
5610+
code
5611+
and self.get_trc()
5612+
and ("c" not in code or "p" in code)
5613+
and float(self.get_black_point_correction()) > 0
5614+
and getcfg("calibration.black_point_correction_choice.show")
5615+
and not getcfg("calibration.black_point_correction.auto")
5616+
):
5617+
self._confirm_black_point_correction_choice(code, cal_changed)
5618+
5619+
def _confirm_black_point_correction_choice(
5620+
self, code: str, cal_changed: bool
5621+
) -> None:
5622+
"""Confirm-and-toggle black-point-correction prompt on mode switch.
5623+
5624+
Qt port of the "don't ask again" ``ConfirmDialog`` in wx's
5625+
``measurement_mode_ctrl_handler``, shown when the newly selected
5626+
measurement mode implies black-point-correction should also toggle.
5627+
5628+
Args:
5629+
code: The (ColorHug-adjusted) measurement mode code from
5630+
:meth:`get_measurement_mode`.
5631+
cal_changed: Whether the mode switch itself already marked the
5632+
calibration as changed, so accepting shouldn't re-mark it.
5633+
"""
5634+
turn_on = "c" in code
5635+
box = QMessageBox(self)
5636+
box.setWindowTitle(lang.getstr("calibration.black_point_correction"))
5637+
box.setIcon(QMessageBox.Question)
5638+
box.setText(lang.getstr("calibration.black_point_correction_choice"))
5639+
ok_button = box.addButton(
5640+
lang.getstr("turn_on" if turn_on else "turn_off"), QMessageBox.AcceptRole
5641+
)
5642+
box.addButton(lang.getstr("setting.keep_current"), QMessageBox.RejectRole)
5643+
checkbox = QCheckBox(lang.getstr("dialog.do_not_show_again"))
5644+
box.setCheckBox(checkbox)
5645+
message_box.exec_box(box)
5646+
setcfg(
5647+
"calibration.black_point_correction_choice.show",
5648+
int(not checkbox.isChecked()),
5649+
)
5650+
if box.clickedButton() is not ok_button:
5651+
return
5652+
bkpt_corr = 1.0 if turn_on else 0.0
5653+
if not cal_changed and bkpt_corr != getcfg(
5654+
"calibration.black_point_correction"
5655+
):
5656+
self._mark_profile_settings_changed()
5657+
setcfg("calibration.black_point_correction", bkpt_corr)
5658+
was_updating = self._updating
5659+
self._updating = True
5660+
try:
5661+
self.update_calibration_controls()
5662+
finally:
5663+
self._updating = was_updating
56045664

56055665
def update_measurement_mode_ctrl(self) -> None:
56065666
"""Populate the measurement-mode combo for the current instrument.

tests/test_ui_main_window.py

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,195 @@ def test_measurement_mode_ctrl_rebuilds_on_instrument_change(window):
473473
assert before # sanity: there was something to compare against
474474

475475

476+
# --- measurement_mode_ctrl_handler's BPC choice dialog (issue #845) ---------
477+
478+
479+
def _prime_bpc_choice_conditions(window, monkeypatch, code):
480+
"""Stub the guards in ``measurement_mode_ctrl_handler`` so its BPC-choice
481+
dialog condition is met regardless of the stub worker's actual
482+
instrument/measurement-mode state."""
483+
setcfg("calibration.black_point_correction_choice.show", 1)
484+
setcfg("calibration.black_point_correction.auto", 0)
485+
monkeypatch.setattr(window, "get_measurement_mode", lambda: code)
486+
monkeypatch.setattr(window, "get_trc", lambda: "2.4")
487+
monkeypatch.setattr(window, "get_black_point_correction", lambda: "1.0")
488+
489+
490+
def test_measurement_mode_ctrl_handler_shows_bpc_choice_dialog_when_applicable(
491+
window, monkeypatch
492+
):
493+
# "l" has neither "c" nor "p", satisfying the guard's turn-off case
494+
# (``"c" not in code``).
495+
_prime_bpc_choice_conditions(window, monkeypatch, "l")
496+
calls = []
497+
monkeypatch.setattr(
498+
window,
499+
"_confirm_black_point_correction_choice",
500+
lambda code, cal_changed: calls.append((code, cal_changed)),
501+
)
502+
503+
window.measurement_mode_ctrl_handler(0)
504+
505+
assert calls and calls[0][0] == "l"
506+
507+
508+
def test_measurement_mode_ctrl_handler_skips_dialog_when_choice_hidden(
509+
window, monkeypatch
510+
):
511+
_prime_bpc_choice_conditions(window, monkeypatch, "l")
512+
setcfg("calibration.black_point_correction_choice.show", 0)
513+
calls = []
514+
monkeypatch.setattr(
515+
window,
516+
"_confirm_black_point_correction_choice",
517+
lambda *a, **k: calls.append(True),
518+
)
519+
520+
window.measurement_mode_ctrl_handler(0)
521+
522+
assert calls == []
523+
524+
525+
def test_measurement_mode_ctrl_handler_skips_dialog_when_bpc_auto(
526+
window, monkeypatch
527+
):
528+
_prime_bpc_choice_conditions(window, monkeypatch, "c")
529+
setcfg("calibration.black_point_correction.auto", 1)
530+
calls = []
531+
monkeypatch.setattr(
532+
window,
533+
"_confirm_black_point_correction_choice",
534+
lambda *a, **k: calls.append(True),
535+
)
536+
537+
window.measurement_mode_ctrl_handler(0)
538+
539+
assert calls == []
540+
541+
542+
def test_measurement_mode_ctrl_handler_skips_dialog_when_bpc_zero(
543+
window, monkeypatch
544+
):
545+
_prime_bpc_choice_conditions(window, monkeypatch, "c")
546+
monkeypatch.setattr(window, "get_black_point_correction", lambda: "0.0")
547+
calls = []
548+
monkeypatch.setattr(
549+
window,
550+
"_confirm_black_point_correction_choice",
551+
lambda *a, **k: calls.append(True),
552+
)
553+
554+
window.measurement_mode_ctrl_handler(0)
555+
556+
assert calls == []
557+
558+
559+
def test_confirm_bpc_choice_turn_on_accept_persists_bpc(window, monkeypatch):
560+
setcfg("calibration.black_point_correction", 0.0)
561+
monkeypatch.setattr(mw, "QMessageBox", _FakeBpcChoiceMessageBox)
562+
_FakeBpcChoiceMessageBox.clicked_role = "accept"
563+
_FakeBpcChoiceMessageBox.check_clicked = False
564+
updated = []
565+
monkeypatch.setattr(
566+
window, "update_calibration_controls", lambda: updated.append(True)
567+
)
568+
569+
window._confirm_black_point_correction_choice("c", cal_changed=True)
570+
571+
assert getcfg("calibration.black_point_correction") == 1.0
572+
assert updated == [True]
573+
574+
575+
def test_confirm_bpc_choice_turn_off_accept_persists_bpc(window, monkeypatch):
576+
setcfg("calibration.black_point_correction", 1.0)
577+
monkeypatch.setattr(mw, "QMessageBox", _FakeBpcChoiceMessageBox)
578+
_FakeBpcChoiceMessageBox.clicked_role = "accept"
579+
_FakeBpcChoiceMessageBox.check_clicked = False
580+
monkeypatch.setattr(window, "update_calibration_controls", lambda: None)
581+
582+
window._confirm_black_point_correction_choice("l", cal_changed=True)
583+
584+
assert getcfg("calibration.black_point_correction") == 0.0
585+
586+
587+
def test_confirm_bpc_choice_keep_current_leaves_bpc_unchanged(window, monkeypatch):
588+
setcfg("calibration.black_point_correction", 0.5)
589+
monkeypatch.setattr(mw, "QMessageBox", _FakeBpcChoiceMessageBox)
590+
_FakeBpcChoiceMessageBox.clicked_role = "reject"
591+
_FakeBpcChoiceMessageBox.check_clicked = False
592+
updated = []
593+
monkeypatch.setattr(
594+
window, "update_calibration_controls", lambda: updated.append(True)
595+
)
596+
597+
window._confirm_black_point_correction_choice("c", cal_changed=True)
598+
599+
assert getcfg("calibration.black_point_correction") == 0.5
600+
assert updated == []
601+
602+
603+
def test_confirm_bpc_choice_checkbox_persists_regardless_of_button(
604+
window, monkeypatch
605+
):
606+
setcfg("calibration.black_point_correction_choice.show", 1)
607+
monkeypatch.setattr(mw, "QMessageBox", _FakeBpcChoiceMessageBox)
608+
_FakeBpcChoiceMessageBox.clicked_role = "reject"
609+
_FakeBpcChoiceMessageBox.check_clicked = True
610+
monkeypatch.setattr(window, "update_calibration_controls", lambda: None)
611+
612+
window._confirm_black_point_correction_choice("c", cal_changed=True)
613+
614+
assert getcfg("calibration.black_point_correction_choice.show") == 0
615+
616+
617+
def test_confirm_bpc_choice_unchecked_keeps_showing_next_time(window, monkeypatch):
618+
setcfg("calibration.black_point_correction_choice.show", 1)
619+
monkeypatch.setattr(mw, "QMessageBox", _FakeBpcChoiceMessageBox)
620+
_FakeBpcChoiceMessageBox.clicked_role = "accept"
621+
_FakeBpcChoiceMessageBox.check_clicked = False
622+
monkeypatch.setattr(window, "update_calibration_controls", lambda: None)
623+
624+
window._confirm_black_point_correction_choice("c", cal_changed=True)
625+
626+
assert getcfg("calibration.black_point_correction_choice.show") == 1
627+
628+
629+
def test_confirm_bpc_choice_marks_settings_changed_when_cal_unchanged(
630+
window, monkeypatch
631+
):
632+
setcfg("calibration.black_point_correction", 0.0)
633+
monkeypatch.setattr(mw, "QMessageBox", _FakeBpcChoiceMessageBox)
634+
_FakeBpcChoiceMessageBox.clicked_role = "accept"
635+
_FakeBpcChoiceMessageBox.check_clicked = False
636+
monkeypatch.setattr(window, "update_calibration_controls", lambda: None)
637+
marked = []
638+
monkeypatch.setattr(
639+
window, "_mark_profile_settings_changed", lambda: marked.append(True)
640+
)
641+
642+
window._confirm_black_point_correction_choice("c", cal_changed=False)
643+
644+
assert marked == [True]
645+
646+
647+
def test_confirm_bpc_choice_skips_mark_when_cal_already_changed(
648+
window, monkeypatch
649+
):
650+
setcfg("calibration.black_point_correction", 0.0)
651+
monkeypatch.setattr(mw, "QMessageBox", _FakeBpcChoiceMessageBox)
652+
_FakeBpcChoiceMessageBox.clicked_role = "accept"
653+
_FakeBpcChoiceMessageBox.check_clicked = False
654+
monkeypatch.setattr(window, "update_calibration_controls", lambda: None)
655+
marked = []
656+
monkeypatch.setattr(
657+
window, "_mark_profile_settings_changed", lambda: marked.append(True)
658+
)
659+
660+
window._confirm_black_point_correction_choice("c", cal_changed=True)
661+
662+
assert marked == []
663+
664+
476665
def test_colorimeter_correction_matrix_ctrl_hidden_when_ccxx_unsupported(window):
477666
# The stub worker's default argyll_version ([0, 0, 0]) can't use CCXX.
478667
assert window.colorimeter_correction_matrix_ctrl.isVisibleTo(window) is False
@@ -2565,6 +2754,24 @@ def clickedButton(self):
25652754
return self._buttons[role]
25662755

25672756

2757+
class _FakeBpcChoiceMessageBox(_FakeTwoButtonMessageBox):
2758+
"""Extends :class:`_FakeTwoButtonMessageBox` with the "don't ask again"
2759+
checkbox :meth:`MainWindow._confirm_black_point_correction_choice` adds
2760+
via ``setCheckBox`` -- the real ``QCheckBox`` instance production code
2761+
creates is stored as-is, so tests can flip it via ``check_clicked`` to
2762+
simulate the user ticking it before the (mocked) modal closes."""
2763+
2764+
check_clicked = False # set per-test
2765+
2766+
def setCheckBox(self, checkbox):
2767+
self._checkbox = checkbox
2768+
2769+
def exec_(self):
2770+
if self.check_clicked:
2771+
self._checkbox.setChecked(True)
2772+
return None
2773+
2774+
25682775
def test_profile_btn_handler_stashes_apply_calibration_and_begins(
25692776
window, monkeypatch
25702777
):

0 commit comments

Comments
 (0)