Skip to content

Latest commit

 

History

History
73 lines (55 loc) · 9.29 KB

AGENTS.md

File metadata and controls

73 lines (55 loc) · 9.29 KB

AGENTS.md

Project Shape

BallonsTranslator is a PyQt/qtpy desktop app for comic image translation.

  • ballontranslator/launch.py: startup, dependencies, Qt setup, and headless mode.
  • ballontranslator/ui/: canvas, panels, module manager, and workers.
  • ballontranslator/modules/: registered detector/OCR/translator/inpainter implementations.
  • ballontranslator/utils/proj_imgtrans.py: project persistence and image/textblock state.
  • ballontranslator/utils/textblock.py: central TextBlock domain object.
  • ballontranslator/utils/config.py: persistent config and module settings.
  • Read Text engine before changing text layout, effects, interaction, geometry, performance, or rendering; follow its topic links.
  • Read Draw panel before changing drawing tools, canvas gestures, brush modifiers, drawing/inpaint state transitions, or drawing save/export behavior.

Use rg for repo search.

Changes and Data Safety

  • Preserve behavior unless explicitly asked to change it; prefer small, reviewable changes within the existing architecture.
  • Treat pre-existing modified, untracked, and ignored files as user-owned. Never delete, overwrite, move, clean, or restore them without explicit authorization for the exact paths, especially config, backups, credentials, projects, and models. Follow existing save/backup behavior for source images, translations, masks, and project JSON.
  • Passive config/project loading must warn about unknown, removed, renamed, malformed, or out-of-range optional data, discard only invalid portions, and continue. Never let it replace an existing file with empty/template state. Keep live runtime values and explicit write/export boundaries strict; give new saved fields defaults for older projects.
  • Use the existing module registries and stable keys; renames require compatibility aliases. Preserve lazy/eager model-loading behavior. Config UI metadata must be lazy or SafeEval-compatible and pure, without executing initialization, _setup_*, updates, flush, model loading, downloads, or network calls.
  • New dependencies require approval. Optional integrations must fail gracefully with a clear setup message.
  • Make surprising behavior opt-in or clearly discoverable through existing config/UI/module parameters. Preserve Qt localization and ensure pipeline features work or safely no-op in headless mode.
  • Keep long-running inference, IO, downloads, and model loading off the Qt main thread; trace signal and worker ordering, especially in ui/module_manager.py.

Performance and Maintainability

  • Trace production callers and data flow before changing code. Search for existing methods, helpers, and patterns; reuse or extend the owning implementation before adding another. Prefer standard-library and Qt facilities over custom equivalents.
  • Use the simplest structure that meets current requirements. Add a helper or abstraction only when it removes demonstrated duplication or establishes a meaningful responsibility boundary. Avoid pass-through wrappers, speculative extension points, generic frameworks for one concrete operation, and layers that merely forward the same data.
  • Put integration in the feature's owning module and shape APIs around production callers. Avoid test-only constructors, injection points, and shared hooks; tests can patch small instance attributes or narrower internals. Use names that make ownership clear.
  • Check call frequency across the full operation and repeated lifecycle events. Reuse available results instead of repeating lookups, conversions, copies, validation, IO, or initialization. Fix duplicate calls and signal-driven work at their owner before adding caches or parallelism; justify performance complexity with tracing or measurement.
  • Update only changed data and widgets. Keep setters and refreshers idempotent and coalesce equivalent work. Sanitize config at load/migration boundaries; reserve whole-panel rebuilds for reset/restore rather than ordinary row/card edits.
  • Use indexed lookups for repeated access and derive values on demand, avoiding per-item full scans and eagerly materialized maps. Reuse existing caches; new caches need a demonstrated cost and explicit invalidation/lifetime. Keep render-only state out of shared config.
  • Give state transitions one clear owner. Avoid redundant synchronization paths, equivalent signal emissions, and broad blockSignals() used to hide update loops.
  • Simplification must remove the obsolete path too: unused helpers, shims, hooks, duplicate state, and architecture-preserving tests. Review the complete caller chain for leftover indirection and repeated work.
  • Add useful type hints and return types to new or modified functions. Prefer domain/Qt types and precise callables; use Any only at dynamic boundaries and avoid unrelated annotation churn.

UI Styling

  • Lightweight settings/tools should reuse a frameless Qt.Dialog, transparent outer widget, rounded theme-token QFrame, and scoped stylesheet. Keep native dialogs for platform workflows; confirmations, progress, and costly-to-dismiss flows must not close on outside clicks.
  • Keep selectors and lists in the application font; use a dedicated preview for content fonts. Match widget structure before adjusting alignment, such as bare checkboxes plus ParamNameLabel.
  • Scope config styles by object/section names, never broad widget selectors. Use resources/themes.json and resources/stylesheet.css tokens, except established accents such as rgb(30, 147, 229). Custom config rows needing a painted background require an object name and WA_StyledBackground.
  • Scope ordinary checkbox indicators without affecting icon-based controls. QListWidget indicators are item-view subcontrols; style their selected, hover, and disabled states separately and check readability in both themes.
  • Render manually painted SVG pixmaps through ui/icon_rendering.py.
  • Never change style machinery inside Polish, StyleChange, or Paint: no setStyle, setStyleSheet, explicit polish/unpolish, ensurePolished, or delegate replacement. Re-entering native style code can crash Qt. Prefer scoped subcontrols, construction-time setup, or idempotent setup in safe show/input events.

Qt Event Filters

  • Reuse OutsideClickFramelessMixin from ui/framelesswindow.py before the Qt base for lightweight centered, draggable windows with Escape/outside-click dismissal, title_bar, and close_button. Keep hide() for cached panels; override _dismiss_transient_window() with reject() for staged dialogs and _preserve_on_outside_click() for owned popups/dialogs.
  • Application event filters are global hooks: install only while active where possible, and remove on hide, collapse, close, or destruction.
  • Check relevance before event details. Global filters first check visibility, receiver, and widget/event types; local filters first guard the watched object. Only then access event.type(), global positions, or widget-specific methods.
  • Outside-click handling should use widget-target mouse presses and explicit popup/dialog whitelists, not broad geometry or QWindow interpretation.

Qt Signals and QObject Lifetimes

  • Never connect child/transient signals to lambdas, nested functions, or partials capturing parents or other QObjects. Bindings can retain callbacks and invalid wrappers after native deletion. Prefer bound QObject slots, action data/properties read through sender(), or typed row signals.
  • Pure-Python or fixed-lifetime callbacks without a demonstrated lifetime problem need no blanket rewrite.
  • close()/hide() do not delete objects. For one-shot modal dialogs, read state after exec_() and call deleteLater() in finally; preserve intentionally cached panels.

Comments and Documentation

  • Comment non-obvious intent, invariants, compatibility, and ordering/failure constraints, especially around Qt, model loading, persistence, and IO. Explain subtle preserved behavior during refactors; omit boilerplate and narration. Include a standard Python >>> doctest example for core classes and complex functions.
  • Keep maintainer guides focused on ownership, stable contracts, failure modes, extension points, and verification. Update only missing or changed guidance; a bug fix alone does not justify an addition. Keep implementation details in code/tests and investigation history in PRs. Revise existing explanations, document each fact once, and check the whole document for redundancy.

Verification

  • Test observable behavior and failure modes through real construction paths, not obsolete APIs, incidental widget hierarchy, object names, sizes, margins, spacing, or stretch factors.
  • Run targeted import checks and relevant tests for Python changes. UI-heavy changes require python -m py_compile on touched files, git diff --check, and an offscreen Qt smoke check when practical. Use a themed-app pass for styling and state any unverified UI/threading behavior.
  • Risky global-filter changes need a regression proving irrelevant receivers/non-mouse events are ignored before event.type() is requested.
  • QObject lifecycle fixes need deferred-delete processing and assertions for behavior plus wrapper/registry release. Run both PyQt5 and PyQt6 when binding behavior matters.
  • Completion requires existing workflows and older projects to work, new behavior to be configurable or discoverable, and verification results or limitations to be stated.