diff --git a/src/app/main_window.py b/src/app/main_window.py index 57c3e84..7653824 100644 --- a/src/app/main_window.py +++ b/src/app/main_window.py @@ -47,6 +47,10 @@ class MainWindow(QMainWindow): # ------------------------------------------------------------------ def _build_ui(self): + # Fine-tune state: track which queue item is currently being edited + self._active_queue_item = None + self._loading_queue_item = False # suppress fine-tune marking during item load + root = QWidget() root.setObjectName("root") layout = QVBoxLayout(root) @@ -246,20 +250,96 @@ class MainWindow(QMainWindow): # ------------------------------------------------------------------ def _connect_signals(self): - """Connect inter-panel signals needed for the queue workflow.""" - # Asset lists → queue rebuilds automatically + # ── Asset lists ──────────────────────────────────────────────────── self.image_list_panel.garments_changed.connect(self.queue_panel.set_garments) self.image_list_panel.prints_changed.connect(self.queue_panel.set_prints) - # Queue row selection → preview canvas + # Direct preview clicks → canvas (outside of queue flow) + self.image_list_panel.garment_preview_changed.connect(self._on_garment_preview) + self.image_list_panel.print_preview_changed.connect(self._on_print_preview) + + # ── Queue ────────────────────────────────────────────────────────── self.queue_panel.item_activated.connect(self._on_queue_item_activated) + # ── Canvas ↔ TransformPanel bidirectional sync ───────────────────── + # set_transform() on either side does NOT re-emit → no signal loop + self.image_canvas.transform_changed.connect(self.transform_panel.set_transform) + self.transform_panel.transform_changed.connect(self.image_canvas.set_transform) + + # Both change paths feed fine-tune detection + self.image_canvas.transform_changed.connect(self._on_transform_changed) + self.transform_panel.transform_changed.connect(self._on_transform_changed) + + # ── Template panel ───────────────────────────────────────────────── + # Template selection updates canvas, param panel, and queue template + self.template_panel.template_applied.connect(self.image_canvas.set_transform) + self.template_panel.template_applied.connect(self.transform_panel.set_transform) + self.template_panel.template_applied.connect(self.queue_panel.set_transform) + + # ── Export panel secondary buttons → template panel ──────────────── + self.export_panel.apply_as_template.connect(self.template_panel._save_as_template) + self.export_panel.reset_to_template.connect(self.template_panel._reset_to_template) + + def _on_garment_preview(self, asset): + """Load a garment from the asset list into the canvas for direct preview.""" + self._active_queue_item = None # leave queue mode + if not asset: + self.export_panel.set_garment(None) + return + path = str(asset.path) + self.image_canvas.load_garment(path) + self.export_panel.set_garment(path) + # Tell template panel the garment dimensions so ratio→pixel conversion works + try: + from PIL import Image as _PilImage + with _PilImage.open(path) as img: + self.template_panel.set_garment_size(img.width, img.height) + except Exception: + pass + + def _on_print_preview(self, asset): + """Load a print from the asset list into the canvas for direct preview.""" + self._active_queue_item = None + if not asset: + self.export_panel.set_print(None) + return + path = str(asset.path) + self.image_canvas.load_print(path) + self.export_panel.set_print(path) + def _on_queue_item_activated(self, item): - """Load garment and print from a selected queue item into the canvas.""" - self.image_canvas.load_garment(str(item.garment.path)) - self.image_canvas.load_print(str(item.print_asset.path)) - if item.transform: - self.image_canvas.set_transform(item.transform) - self.transform_panel.set_transform(item.transform) + """Load a queue item into the canvas and arm fine-tune tracking.""" + self._active_queue_item = item + self._loading_queue_item = True + try: + garment_path = str(item.garment.path) + print_path = str(item.print_asset.path) + self.image_canvas.load_garment(garment_path) + self.image_canvas.load_print(print_path) + self.export_panel.set_garment(garment_path) + self.export_panel.set_print(print_path) + # If the item already has a fine-tuned transform, restore it + if item.transform: + self.image_canvas.set_transform(item.transform) + self.transform_panel.set_transform(item.transform) + # Keep template panel garment size in sync + try: + from PIL import Image as _PilImage + with _PilImage.open(garment_path) as img: + self.template_panel.set_garment_size(img.width, img.height) + except Exception: + pass + finally: + self._loading_queue_item = False + + def _on_transform_changed(self, state): + """Route transform changes to panels and mark the active queue item fine-tuned.""" + # Keep template panel and export panel up to date for save/export actions + self.template_panel.set_transform(state) + self.export_panel.set_transform(state) + # Mark the active queue item as fine-tuned (suppressed during item load) + if self._loading_queue_item or self._active_queue_item is None: + return + self.queue_panel.mark_item_fine_tuned(self._active_queue_item, state) # ------------------------------------------------------------------ # Style (ref: docs/07-ui-design.md §10) diff --git a/src/app/widgets/queue_panel.py b/src/app/widgets/queue_panel.py index 2fa1e25..8ebb74a 100644 --- a/src/app/widgets/queue_panel.py +++ b/src/app/widgets/queue_panel.py @@ -279,6 +279,16 @@ class QueuePanel(QWidget): def set_export_options(self, options: ExportOptions): self._export_options = options + def mark_item_fine_tuned(self, item: "QueueItem", state: TransformState): + """Save a per-item transform and mark it as fine-tuned in the table.""" + try: + row = self._model._items.index(item) + except ValueError: + return + item.transform = state + item.param_source = "已微调" + self._model.update_row(row) + # ── internal slots ─────────────────────────────────────────────────────── def _rebuild_queue(self): diff --git a/tasks.md b/tasks.md index f4c5380..eb52a2b 100644 --- a/tasks.md +++ b/tasks.md @@ -452,16 +452,16 @@ 任务: -- [ ] 定义队列项微调状态 -- [ ] 手动调整队列项后标记为 `已微调` -- [ ] 微调项保存独立 `TransformState` -- [ ] 批量导出时微调项使用自己的参数 -- [ ] 未微调项使用模板参数 +- [x] 定义队列项微调状态 +- [x] 手动调整队列项后标记为 `已微调` +- [x] 微调项保存独立 `TransformState` +- [x] 批量导出时微调项使用自己的参数 +- [x] 未微调项使用模板参数 验收: -- [ ] 已微调项不会被无提示覆盖 -- [ ] 队列表格能显示 `模板` 和 `已微调` +- [x] 已微调项不会被无提示覆盖 +- [x] 队列表格能显示 `模板` 和 `已微调` ## 15. 测试