fix(gui): keep cover candidate controls below images
This commit is contained in:
+118
-35
@@ -30,6 +30,58 @@ class _CoverThumbnailLabel(QLabel):
|
|||||||
super().mouseDoubleClickEvent(event)
|
super().mouseDoubleClickEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
class _CoverCandidateCard(QWidget):
|
||||||
|
EXTRA_WIDTH = 16
|
||||||
|
|
||||||
|
def __init__(self, thumbnail, radio, meta, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.thumbnail = thumbnail
|
||||||
|
self.radio = radio
|
||||||
|
self.meta = meta
|
||||||
|
self.card_layout = QVBoxLayout(self)
|
||||||
|
self.card_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.card_layout.setSpacing(6)
|
||||||
|
self.card_layout.addWidget(self.thumbnail)
|
||||||
|
self.card_layout.addWidget(self.radio)
|
||||||
|
self.card_layout.addWidget(self.meta)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _widget_height(widget, width):
|
||||||
|
height = widget.heightForWidth(width) if widget.hasHeightForWidth() else -1
|
||||||
|
if height < 0:
|
||||||
|
height = widget.sizeHint().height()
|
||||||
|
return max(height, widget.minimumHeight(), widget.minimumSizeHint().height())
|
||||||
|
|
||||||
|
def set_thumbnail_size(self, size):
|
||||||
|
size = max(1, int(size))
|
||||||
|
self.setFixedWidth(size + self.EXTRA_WIDTH)
|
||||||
|
self.thumbnail.setFixedSize(size, size)
|
||||||
|
self.sync_geometry()
|
||||||
|
|
||||||
|
def sync_geometry(self):
|
||||||
|
margins = self.card_layout.contentsMargins()
|
||||||
|
content_width = max(1, self.width() - margins.left() - margins.right())
|
||||||
|
widget_heights = [
|
||||||
|
self.thumbnail.height(),
|
||||||
|
self._widget_height(self.radio, content_width),
|
||||||
|
self._widget_height(self.meta, content_width),
|
||||||
|
]
|
||||||
|
required_height = (
|
||||||
|
margins.top()
|
||||||
|
+ margins.bottom()
|
||||||
|
+ sum(widget_heights)
|
||||||
|
+ max(0, len(widget_heights) - 1) * max(0, self.card_layout.spacing())
|
||||||
|
)
|
||||||
|
self.card_layout.invalidate()
|
||||||
|
self.setFixedHeight(required_height)
|
||||||
|
self.card_layout.activate()
|
||||||
|
self.updateGeometry()
|
||||||
|
return required_height
|
||||||
|
|
||||||
|
def control_height(self):
|
||||||
|
return max(0, self.height() - self.thumbnail.height())
|
||||||
|
|
||||||
|
|
||||||
class OriginalImageDialog(QDialog):
|
class OriginalImageDialog(QDialog):
|
||||||
def __init__(self, image_path, parent=None):
|
def __init__(self, image_path, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@@ -190,7 +242,7 @@ class _SegmentedProgressBar(QProgressBar):
|
|||||||
class CoverGalleryDialog(QDialog):
|
class CoverGalleryDialog(QDialog):
|
||||||
THUMBNAIL_SIZE = 180
|
THUMBNAIL_SIZE = 180
|
||||||
MAX_THUMBNAIL_SIZE = 360
|
MAX_THUMBNAIL_SIZE = 360
|
||||||
CANDIDATE_TEXT_HEIGHT = 72
|
CANDIDATE_CONTROL_FALLBACK_HEIGHT = 72
|
||||||
OLD_THUMBNAIL_SIZE = 300
|
OLD_THUMBNAIL_SIZE = 300
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -320,7 +372,11 @@ class CoverGalleryDialog(QDialog):
|
|||||||
self.candidate_layout.setSpacing(12)
|
self.candidate_layout.setSpacing(12)
|
||||||
if self.candidates:
|
if self.candidates:
|
||||||
for index, candidate_path in enumerate(self.candidates):
|
for index, candidate_path in enumerate(self.candidates):
|
||||||
self.candidate_layout.addWidget(self._candidate_item(candidate_path, index))
|
self.candidate_layout.addWidget(
|
||||||
|
self._candidate_item(candidate_path, index),
|
||||||
|
0,
|
||||||
|
Qt.AlignTop,
|
||||||
|
)
|
||||||
self.candidate_layout.addStretch(1)
|
self.candidate_layout.addStretch(1)
|
||||||
else:
|
else:
|
||||||
empty_label = QLabel("暂无生成封面图片")
|
empty_label = QLabel("暂无生成封面图片")
|
||||||
@@ -334,17 +390,12 @@ class CoverGalleryDialog(QDialog):
|
|||||||
return panel
|
return panel
|
||||||
|
|
||||||
def _candidate_item(self, candidate_path, index):
|
def _candidate_item(self, candidate_path, index):
|
||||||
item = QWidget()
|
|
||||||
item.setFixedWidth(self.candidate_thumbnail_size + 16)
|
|
||||||
layout = QVBoxLayout(item)
|
|
||||||
layout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
thumbnail = _CoverThumbnailLabel(candidate_path, self.open_original_image)
|
thumbnail = _CoverThumbnailLabel(candidate_path, self.open_original_image)
|
||||||
thumbnail.setObjectName("coverCandidateThumbnail")
|
thumbnail.setObjectName("coverCandidateThumbnail")
|
||||||
thumbnail.setAlignment(Qt.AlignCenter)
|
thumbnail.setAlignment(Qt.AlignCenter)
|
||||||
image = _load_image(candidate_path)
|
image = _load_image(candidate_path)
|
||||||
self.candidate_images[candidate_path] = image
|
self.candidate_images[candidate_path] = image
|
||||||
self.candidate_thumbnails[candidate_path] = thumbnail
|
self.candidate_thumbnails[candidate_path] = thumbnail
|
||||||
self.candidate_items[candidate_path] = item
|
|
||||||
if image.isNull():
|
if image.isNull():
|
||||||
thumbnail.setText("图片读取失败")
|
thumbnail.setText("图片读取失败")
|
||||||
else:
|
else:
|
||||||
@@ -358,8 +409,7 @@ class CoverGalleryDialog(QDialog):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
thumbnail.setFixedSize(self.candidate_thumbnail_size, self.candidate_thumbnail_size)
|
radio = QRadioButton(_candidate_label(candidate_path, self.current_path, index))
|
||||||
radio = QRadioButton(_candidate_label(candidate_path, self.current_path))
|
|
||||||
radio.setObjectName(f"coverCandidateRadio{index}")
|
radio.setObjectName(f"coverCandidateRadio{index}")
|
||||||
radio.setFocusPolicy(Qt.ClickFocus)
|
radio.setFocusPolicy(Qt.ClickFocus)
|
||||||
radio.toggled.connect(
|
radio.toggled.connect(
|
||||||
@@ -370,10 +420,16 @@ class CoverGalleryDialog(QDialog):
|
|||||||
meta = QLabel(_candidate_meta(candidate_path, self.current_path))
|
meta = QLabel(_candidate_meta(candidate_path, self.current_path))
|
||||||
meta.setWordWrap(True)
|
meta.setWordWrap(True)
|
||||||
meta.setObjectName("coverCandidateMetaLabel")
|
meta.setObjectName("coverCandidateMetaLabel")
|
||||||
layout.addWidget(thumbnail)
|
basename = os.path.basename(str(candidate_path or ""))
|
||||||
layout.addWidget(radio)
|
file_tooltip = f"完整文件名:{basename}"
|
||||||
layout.addWidget(meta)
|
radio.setToolTip(file_tooltip)
|
||||||
layout.addStretch(1)
|
meta.setToolTip(file_tooltip)
|
||||||
|
thumbnail.setToolTip(f"双击查看原图\n{file_tooltip}")
|
||||||
|
item = _CoverCandidateCard(thumbnail, radio, meta)
|
||||||
|
item.setObjectName("coverCandidateCard")
|
||||||
|
item.setToolTip(file_tooltip)
|
||||||
|
item.set_thumbnail_size(self.candidate_thumbnail_size)
|
||||||
|
self.candidate_items[candidate_path] = item
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def _sync_candidate_content_size(self):
|
def _sync_candidate_content_size(self):
|
||||||
@@ -381,27 +437,40 @@ class CoverGalleryDialog(QDialog):
|
|||||||
content = getattr(self, "candidate_content", None)
|
content = getattr(self, "candidate_content", None)
|
||||||
if layout is None or content is None:
|
if layout is None or content is None:
|
||||||
return
|
return
|
||||||
|
candidate_items = [
|
||||||
|
self.candidate_items[candidate_path]
|
||||||
|
for candidate_path in self.candidates
|
||||||
|
if candidate_path in self.candidate_items
|
||||||
|
]
|
||||||
|
for item in candidate_items:
|
||||||
|
if isinstance(item, _CoverCandidateCard):
|
||||||
|
item.sync_geometry()
|
||||||
|
layout.invalidate()
|
||||||
layout.activate()
|
layout.activate()
|
||||||
margins = layout.contentsMargins()
|
margins = layout.contentsMargins()
|
||||||
spacing = max(0, layout.spacing())
|
spacing = max(0, layout.spacing())
|
||||||
hint = layout.sizeHint()
|
hint = layout.sizeHint()
|
||||||
if self.candidates:
|
if candidate_items:
|
||||||
candidate_count = len(self.candidates)
|
|
||||||
min_width = (
|
min_width = (
|
||||||
margins.left()
|
margins.left()
|
||||||
+ margins.right()
|
+ margins.right()
|
||||||
+ candidate_count * (self.candidate_thumbnail_size + 16)
|
+ sum(item.width() for item in candidate_items)
|
||||||
+ max(0, candidate_count - 1) * spacing
|
+ max(0, len(candidate_items) - 1) * spacing
|
||||||
|
)
|
||||||
|
min_height = (
|
||||||
|
margins.top()
|
||||||
|
+ margins.bottom()
|
||||||
|
+ max(item.height() for item in candidate_items)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
min_width = margins.left() + margins.right() + 320
|
min_width = margins.left() + margins.right() + 320
|
||||||
min_height = max(
|
min_height = max(self.THUMBNAIL_SIZE, hint.height())
|
||||||
self.candidate_thumbnail_size,
|
size = QSize(max(min_width, hint.width()), max(1, min_height))
|
||||||
hint.height(),
|
|
||||||
)
|
|
||||||
size = QSize(max(min_width, hint.width()), min_height)
|
|
||||||
content.setMinimumSize(size)
|
content.setMinimumSize(size)
|
||||||
content.resize(size)
|
content.resize(size)
|
||||||
|
layout.invalidate()
|
||||||
|
layout.setGeometry(content.rect())
|
||||||
|
layout.activate()
|
||||||
content.updateGeometry()
|
content.updateGeometry()
|
||||||
scroll = getattr(self, "candidate_scroll", None)
|
scroll = getattr(self, "candidate_scroll", None)
|
||||||
if scroll is not None:
|
if scroll is not None:
|
||||||
@@ -425,30 +494,38 @@ class CoverGalleryDialog(QDialog):
|
|||||||
width_budget = (
|
width_budget = (
|
||||||
viewport_width
|
viewport_width
|
||||||
- max(0, visible_count - 1) * spacing
|
- max(0, visible_count - 1) * spacing
|
||||||
- visible_count * 16
|
- visible_count * _CoverCandidateCard.EXTRA_WIDTH
|
||||||
) // visible_count
|
) // visible_count
|
||||||
height_budget = viewport_height - self.CANDIDATE_TEXT_HEIGHT
|
control_heights = [
|
||||||
|
item.control_height()
|
||||||
|
for item in self.candidate_items.values()
|
||||||
|
if isinstance(item, _CoverCandidateCard)
|
||||||
|
]
|
||||||
|
control_height = max(
|
||||||
|
control_heights,
|
||||||
|
default=self.CANDIDATE_CONTROL_FALLBACK_HEIGHT,
|
||||||
|
)
|
||||||
|
height_budget = viewport_height - control_height
|
||||||
target = min(width_budget, height_budget, self.MAX_THUMBNAIL_SIZE)
|
target = min(width_budget, height_budget, self.MAX_THUMBNAIL_SIZE)
|
||||||
return max(self.THUMBNAIL_SIZE, int(target))
|
return max(self.THUMBNAIL_SIZE, int(target))
|
||||||
|
|
||||||
def _update_candidate_thumbnail_layout(self):
|
def _update_candidate_thumbnail_layout(self, force=False):
|
||||||
if not self.candidates:
|
if not self.candidates:
|
||||||
self._sync_candidate_content_size()
|
self._sync_candidate_content_size()
|
||||||
return
|
return
|
||||||
target_size = self._candidate_thumbnail_target_size()
|
target_size = self._candidate_thumbnail_target_size()
|
||||||
if target_size == self.candidate_thumbnail_size:
|
size_changed = target_size != self.candidate_thumbnail_size
|
||||||
self._sync_candidate_content_size()
|
|
||||||
return
|
|
||||||
self.candidate_thumbnail_size = target_size
|
self.candidate_thumbnail_size = target_size
|
||||||
for candidate_path in self.candidates:
|
for candidate_path in self.candidates:
|
||||||
item = self.candidate_items.get(candidate_path)
|
item = self.candidate_items.get(candidate_path)
|
||||||
thumbnail = self.candidate_thumbnails.get(candidate_path)
|
thumbnail = self.candidate_thumbnails.get(candidate_path)
|
||||||
image = self.candidate_images.get(candidate_path)
|
image = self.candidate_images.get(candidate_path)
|
||||||
if item is not None:
|
if isinstance(item, _CoverCandidateCard):
|
||||||
item.setFixedWidth(target_size + 16)
|
item.set_thumbnail_size(target_size)
|
||||||
if thumbnail is None:
|
if thumbnail is None:
|
||||||
continue
|
continue
|
||||||
thumbnail.setFixedSize(target_size, target_size)
|
if not size_changed and not force:
|
||||||
|
continue
|
||||||
thumbnail.clear()
|
thumbnail.clear()
|
||||||
if image is None or image.isNull():
|
if image is None or image.isNull():
|
||||||
thumbnail.setText("图片读取失败")
|
thumbnail.setText("图片读取失败")
|
||||||
@@ -743,7 +820,11 @@ class CoverGalleryDialog(QDialog):
|
|||||||
self.button_group.setExclusive(True)
|
self.button_group.setExclusive(True)
|
||||||
if self.candidates:
|
if self.candidates:
|
||||||
for index, candidate_path in enumerate(self.candidates):
|
for index, candidate_path in enumerate(self.candidates):
|
||||||
self.candidate_layout.addWidget(self._candidate_item(candidate_path, index))
|
self.candidate_layout.addWidget(
|
||||||
|
self._candidate_item(candidate_path, index),
|
||||||
|
0,
|
||||||
|
Qt.AlignTop,
|
||||||
|
)
|
||||||
self.candidate_layout.addStretch(1)
|
self.candidate_layout.addStretch(1)
|
||||||
else:
|
else:
|
||||||
empty_label = QLabel("暂无生成封面图片")
|
empty_label = QLabel("暂无生成封面图片")
|
||||||
@@ -751,7 +832,9 @@ class CoverGalleryDialog(QDialog):
|
|||||||
empty_label.setMinimumSize(320, self.THUMBNAIL_SIZE)
|
empty_label.setMinimumSize(320, self.THUMBNAIL_SIZE)
|
||||||
empty_label.setAlignment(Qt.AlignCenter)
|
empty_label.setAlignment(Qt.AlignCenter)
|
||||||
self.candidate_layout.addWidget(empty_label)
|
self.candidate_layout.addWidget(empty_label)
|
||||||
self._sync_candidate_content_size()
|
self._candidate_resize_timer.stop()
|
||||||
|
self._update_candidate_thumbnail_layout(force=True)
|
||||||
|
self.candidate_scroll.horizontalScrollBar().setValue(0)
|
||||||
self._candidate_resize_timer.start()
|
self._candidate_resize_timer.start()
|
||||||
self._install_navigation_event_filters()
|
self._install_navigation_event_filters()
|
||||||
|
|
||||||
@@ -805,8 +888,8 @@ def _set_image_label(label, image_path, size, empty_text):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _candidate_label(candidate_path, current_path):
|
def _candidate_label(candidate_path, current_path, index):
|
||||||
return "当前生效" if _same_file(candidate_path, current_path) else os.path.basename(candidate_path)
|
return "当前生效" if _same_file(candidate_path, current_path) else f"候选 {int(index) + 1}"
|
||||||
|
|
||||||
|
|
||||||
def _candidate_meta(candidate_path, current_path):
|
def _candidate_meta(candidate_path, current_path):
|
||||||
|
|||||||
+8
-2
@@ -3,7 +3,7 @@ id: T-629
|
|||||||
title: ②封面画廊切换记录后候选勾选区自适应布局修复
|
title: ②封面画廊切换记录后候选勾选区自适应布局修复
|
||||||
phase: 7
|
phase: 7
|
||||||
deps: [T-626]
|
deps: [T-626]
|
||||||
status: TODO
|
status: DONE
|
||||||
created: 2026-07-14
|
created: 2026-07-14
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -88,4 +88,10 @@ created: 2026-07-14
|
|||||||
|
|
||||||
## 执行记录
|
## 执行记录
|
||||||
|
|
||||||
- 待实现。
|
- 2026-07-14:完成 T-629。
|
||||||
|
- 复现确认:从单候选切换到 6 张候选时,旧实现把候选内容高度暂时设为图片高度 `360px`,但完整卡片实际需要 `402px`,导致勾选框被压到图片内部;延迟 resize timer 执行后才可能恢复。
|
||||||
|
- `app/gui/tabs/generate.py`:新增内部候选卡片组件,统一按图片、勾选框、说明文字、margin 和 spacing 的实际尺寸计算固定卡片高度;内容容器按所有卡片真实宽高同步尺寸,候选卡片顶部对齐。
|
||||||
|
- 任务切换和候选重建后立即按新候选数量及当前 viewport 强制重算图片与完整卡片尺寸,不再依赖约 `60ms` timer 才获得正确布局;切换记录时同时重置横向滚动位置,窗口连续 resize 仍保留合并重绘。
|
||||||
|
- 非当前候选的可见名称改为「候选 N」,完整文件名保留在中文 tooltip,避免长文件名干扰尺寸;损坏图片继续使用固定图片区和「图片读取失败」占位。
|
||||||
|
- `tests/test_gui.py`:新增真实 `↓` 键切换回归测试,覆盖单候选到多候选、长文件名、损坏图片、切换同步阶段、Qt 事件处理后、横向滚动复位和往返切换;逐卡断言图片、勾选框、说明文字及横向卡片几何不重叠。
|
||||||
|
- 当前工作区运行 `tests.test_gui` 时,仅有任务开始前已存在的默认封面提示词 `papa1.txt` 改名造成的 2 项旧断言失败;未回退用户改动。在只包含 T-629 三个文件的隔离 worktree 中验证通过:`py -3.10 -m unittest tests.test_gui`(182 项)、`py -3.10 -m unittest discover -s tests`(462 项)、`python -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`git diff --check`。
|
||||||
|
|||||||
@@ -181,6 +181,38 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
self.assertTrue(image.save(path))
|
self.assertTrue(image.save(path))
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
def assert_cover_candidate_cards_do_not_overlap(self, dialog, check_horizontal=True):
|
||||||
|
previous_right = None
|
||||||
|
maximum_card_height = 0
|
||||||
|
for candidate_path in dialog.candidates:
|
||||||
|
card = dialog.candidate_items[candidate_path]
|
||||||
|
layout = card.layout()
|
||||||
|
thumbnail = layout.itemAt(0).widget()
|
||||||
|
radio = layout.itemAt(1).widget()
|
||||||
|
meta = layout.itemAt(2).widget()
|
||||||
|
spacing = max(0, layout.spacing())
|
||||||
|
|
||||||
|
self.assertGreaterEqual(
|
||||||
|
radio.geometry().top(),
|
||||||
|
thumbnail.geometry().bottom() + 1 + spacing,
|
||||||
|
)
|
||||||
|
self.assertGreaterEqual(
|
||||||
|
meta.geometry().top(),
|
||||||
|
radio.geometry().bottom() + 1 + spacing,
|
||||||
|
)
|
||||||
|
self.assertGreaterEqual(card.minimumHeight(), layout.sizeHint().height())
|
||||||
|
self.assertGreaterEqual(card.height(), meta.geometry().bottom() + 1)
|
||||||
|
if check_horizontal and previous_right is not None:
|
||||||
|
self.assertGreaterEqual(
|
||||||
|
card.geometry().left(),
|
||||||
|
previous_right + 1 + dialog.candidate_layout.spacing(),
|
||||||
|
)
|
||||||
|
previous_right = card.geometry().right()
|
||||||
|
maximum_card_height = max(maximum_card_height, card.height())
|
||||||
|
|
||||||
|
self.assertGreaterEqual(dialog.candidate_content.minimumHeight(), maximum_card_height)
|
||||||
|
self.assertGreaterEqual(dialog.candidate_content.height(), maximum_card_height)
|
||||||
|
|
||||||
def _cover_gallery_task(self, temp_dir, generate_cover=True):
|
def _cover_gallery_task(self, temp_dir, generate_cover=True):
|
||||||
cfg = self.make_config(temp_dir)
|
cfg = self.make_config(temp_dir)
|
||||||
cfg.setdefault("ai", {})["generate_cover"] = bool(generate_cover)
|
cfg.setdefault("ai", {})["generate_cover"] = bool(generate_cover)
|
||||||
@@ -4205,6 +4237,77 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
|
|
||||||
self.assert_removed(temp_dir)
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
def test_cover_gallery_arrow_switch_syncs_full_candidate_card_geometry(self):
|
||||||
|
with self.make_temp_dir() as temp_dir:
|
||||||
|
cfg, account, tasks, canonicals, archives = self._cover_gallery_task_set(
|
||||||
|
temp_dir,
|
||||||
|
count=2,
|
||||||
|
)
|
||||||
|
os.remove(archives[0])
|
||||||
|
second_prefix = os.path.splitext(canonicals[1])[0]
|
||||||
|
long_candidate = self.write_test_image(
|
||||||
|
f"{second_prefix}_20260709101100_候选图片文件名很长用于验证自适应布局.jpg"
|
||||||
|
)
|
||||||
|
self.write_test_image(f"{second_prefix}_20260709101200.jpg")
|
||||||
|
broken_candidate = f"{second_prefix}_20260709101300.jpg"
|
||||||
|
with open(broken_candidate, "wb") as file_handle:
|
||||||
|
file_handle.write(b"not-an-image")
|
||||||
|
|
||||||
|
dialog = CoverGalleryDialog(
|
||||||
|
tasks[0],
|
||||||
|
cfg["image_dir"],
|
||||||
|
cfg["db_path"],
|
||||||
|
account=account,
|
||||||
|
visible_tasks=tasks,
|
||||||
|
task_index=0,
|
||||||
|
account_by_alias={"alias-a": account},
|
||||||
|
)
|
||||||
|
self.addCleanup(dialog.close)
|
||||||
|
dialog.resize(1100, 700)
|
||||||
|
dialog.show()
|
||||||
|
QApplication.processEvents()
|
||||||
|
dialog._candidate_resize_timer.stop()
|
||||||
|
dialog._update_candidate_thumbnail_layout()
|
||||||
|
initial_thumbnail_size = dialog.candidate_thumbnail_size
|
||||||
|
dialog.next_button.setFocus()
|
||||||
|
down_event = QKeyEvent(QKeyEvent.KeyPress, gui.Qt.Key_Down, gui.Qt.NoModifier)
|
||||||
|
|
||||||
|
QApplication.sendEvent(dialog.next_button, down_event)
|
||||||
|
|
||||||
|
self.assertTrue(down_event.isAccepted())
|
||||||
|
self.assertEqual(tasks[1].id, dialog.task.id)
|
||||||
|
self.assertGreaterEqual(len(dialog.candidates), 5)
|
||||||
|
self.assertLess(dialog.candidate_thumbnail_size, initial_thumbnail_size)
|
||||||
|
self.assertEqual(0, dialog.candidate_scroll.horizontalScrollBar().value())
|
||||||
|
self.assert_cover_candidate_cards_do_not_overlap(dialog, check_horizontal=False)
|
||||||
|
self.assertEqual("图片读取失败", dialog.candidate_thumbnails[broken_candidate].text())
|
||||||
|
self.assertNotEqual(
|
||||||
|
os.path.basename(long_candidate),
|
||||||
|
dialog.candidate_buttons[long_candidate].text(),
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
os.path.basename(long_candidate),
|
||||||
|
dialog.candidate_buttons[long_candidate].toolTip(),
|
||||||
|
)
|
||||||
|
|
||||||
|
QApplication.processEvents()
|
||||||
|
dialog._candidate_resize_timer.stop()
|
||||||
|
dialog._update_candidate_thumbnail_layout()
|
||||||
|
QApplication.processEvents()
|
||||||
|
self.assert_cover_candidate_cards_do_not_overlap(dialog)
|
||||||
|
|
||||||
|
horizontal_bar = dialog.candidate_scroll.horizontalScrollBar()
|
||||||
|
self.assertGreater(horizontal_bar.maximum(), 0)
|
||||||
|
horizontal_bar.setValue(horizontal_bar.maximum())
|
||||||
|
self.assertGreater(horizontal_bar.value(), 0)
|
||||||
|
self.assertTrue(dialog.switch_task(-1))
|
||||||
|
self.assertEqual(0, horizontal_bar.value())
|
||||||
|
self.assert_cover_candidate_cards_do_not_overlap(dialog, check_horizontal=False)
|
||||||
|
QApplication.processEvents()
|
||||||
|
self.assert_cover_candidate_cards_do_not_overlap(dialog)
|
||||||
|
|
||||||
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
def test_cover_gallery_save_switches_current_cover(self):
|
def test_cover_gallery_save_switches_current_cover(self):
|
||||||
with self.make_temp_dir() as temp_dir:
|
with self.make_temp_dir() as temp_dir:
|
||||||
cfg = self.make_config(temp_dir)
|
cfg = self.make_config(temp_dir)
|
||||||
|
|||||||
Reference in New Issue
Block a user