| 62 | |
| 63 | |
| 64 | class PreferencesDialog(QDialog): |
| 65 | def __init__(self, parent=None): |
| 66 | super().__init__(parent, Qt.Window) |
| 67 | self.setWindowTitle("Preferences") |
| 68 | self.setMinimumWidth(520) |
| 69 | |
| 70 | self._widgets: dict[tuple[str, str], object] = {} |
| 71 | |
| 72 | outer = QVBoxLayout(self) |
| 73 | outer.addWidget(QLabel( |
| 74 | "<small><i>Changes take effect immediately after clicking OK.</i></small>" |
| 75 | )) |
| 76 | |
| 77 | # ── two-column body ─────────────────────────────────────────────────── |
| 78 | cols = QHBoxLayout() |
| 79 | cols.setSpacing(12) |
| 80 | left = QVBoxLayout() |
| 81 | right = QVBoxLayout() |
| 82 | cols.addLayout(left) |
| 83 | cols.addLayout(right) |
| 84 | outer.addLayout(cols) |
| 85 | |
| 86 | # ── widget factories ───────────────────────────────────────────────── |
| 87 | |
| 88 | def cbtn(c: QColor) -> _ColorButton: |
| 89 | return _ColorButton(c) |
| 90 | |
| 91 | def fspin(val, lo=0.1, hi=10.0, step=0.1, dec=1) -> QDoubleSpinBox: |
| 92 | sb = QDoubleSpinBox() |
| 93 | sb.setRange(lo, hi) |
| 94 | sb.setSingleStep(step) |
| 95 | sb.setDecimals(dec) |
| 96 | sb.setValue(val) |
| 97 | sb.setFixedWidth(_SPIN_W) |
| 98 | return sb |
| 99 | |
| 100 | def ispin(val, lo=1, hi=500) -> QSpinBox: |
| 101 | sb = QSpinBox() |
| 102 | sb.setRange(lo, hi) |
| 103 | sb.setValue(val) |
| 104 | sb.setFixedWidth(_SPIN_W) |
| 105 | return sb |
| 106 | |
| 107 | def combo(current: str) -> QComboBox: |
| 108 | cb = QComboBox() |
| 109 | cb.setEditable(True) |
| 110 | cb.addItems(_FONT_FAMILIES) |
| 111 | idx = cb.findText(current) |
| 112 | if idx >= 0: |
| 113 | cb.setCurrentIndex(idx) |
| 114 | else: |
| 115 | cb.setCurrentText(current) |
| 116 | cb.setFixedWidth(_COMBO_W) |
| 117 | return cb |
| 118 | |
| 119 | def check(checked: bool) -> QCheckBox: |
| 120 | cb = QCheckBox() |
| 121 | cb.setChecked(checked) |