|
1 | 1 | """Triggers tab: image / window / pixel / file event watchers.""" |
2 | | -from typing import Optional |
| 2 | +from typing import Any, Dict, Iterable, List, Optional, Sequence |
3 | 3 |
|
4 | 4 | from PySide6.QtCore import QTimer |
5 | 5 | from PySide6.QtWidgets import ( |
@@ -29,6 +29,24 @@ def _t(key: str) -> str: |
29 | 29 | ) |
30 | 30 |
|
31 | 31 |
|
| 32 | +#: Which composite trigger each "combine" button builds. |
| 33 | +COMPOSITE_BY_MODE: Dict[str, type] = { |
| 34 | + "all": AllOfTrigger, "any": AnyOfTrigger, "sequence": SequenceTrigger, |
| 35 | +} |
| 36 | + |
| 37 | + |
| 38 | +def children_to_combine(ids: Sequence[str], |
| 39 | + triggers: Iterable[Any]) -> List[Any]: |
| 40 | + """The triggers named by ``ids``, or ``[]`` when fewer than two resolve. |
| 41 | +
|
| 42 | + Ids that no longer name a trigger are dropped: the table can outlive a |
| 43 | + removal, and combining one trigger with nothing is not a composite. |
| 44 | + """ |
| 45 | + by_id = {trigger.trigger_id: trigger for trigger in triggers} |
| 46 | + children = [by_id[tid] for tid in ids if tid in by_id] |
| 47 | + return children if len(children) >= 2 else [] |
| 48 | + |
| 49 | + |
32 | 50 | class TriggersTab(TranslatableMixin, QWidget): |
33 | 51 | """Build triggers, run the engine, inspect the table.""" |
34 | 52 |
|
@@ -256,27 +274,28 @@ def _on_remove(self) -> None: |
256 | 274 | default_trigger_engine.remove(tid) |
257 | 275 | self._refresh() |
258 | 276 |
|
259 | | - def _on_combine(self, mode: str) -> None: |
| 277 | + def _selected_ids(self) -> List[str]: |
| 278 | + """Trigger ids of the selected rows, in row order, without duplicates.""" |
260 | 279 | rows = sorted({idx.row() for idx in self._table.selectedIndexes()}) |
261 | | - ids = [self._table.item(row, 0).text() for row in rows |
262 | | - if self._table.item(row, 0) is not None] |
| 280 | + return [self._table.item(row, 0).text() for row in rows |
| 281 | + if self._table.item(row, 0) is not None] |
| 282 | + |
| 283 | + def _on_combine(self, mode: str) -> None: |
| 284 | + ids = self._selected_ids() |
263 | 285 | if len(ids) < 2: |
264 | 286 | QMessageBox.warning(self, "Error", _t("tr_combine_need_two")) |
265 | 287 | return |
266 | 288 | script = self._script_input.text().strip() |
267 | 289 | if not script: |
268 | 290 | QMessageBox.warning(self, "Error", "Script path is required") |
269 | 291 | return |
270 | | - by_id = {t.trigger_id: t |
271 | | - for t in default_trigger_engine.list_triggers()} |
272 | | - children = [by_id[tid] for tid in ids if tid in by_id] |
273 | | - if len(children) < 2: |
| 292 | + children = children_to_combine( |
| 293 | + ids, default_trigger_engine.list_triggers()) |
| 294 | + if not children: |
274 | 295 | return |
275 | 296 | for tid in ids: |
276 | 297 | default_trigger_engine.remove(tid) |
277 | | - composite_cls = {"all": AllOfTrigger, "any": AnyOfTrigger, |
278 | | - "sequence": SequenceTrigger}[mode] |
279 | | - default_trigger_engine.add(composite_cls( |
| 298 | + default_trigger_engine.add(COMPOSITE_BY_MODE[mode]( |
280 | 299 | trigger_id="", script_path=script, |
281 | 300 | repeat=self._repeat_check.isChecked(), children=children, |
282 | 301 | )) |
|
0 commit comments