Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# AGENTS.md

Guidelines for AI agents working on the Setuav Studio repository.

## Commands

- **Development / Environment:**
- Run application: `uv run python -m setuav_studio`
- Linting: `uv run ruff check .`
- Code formatting: `uv run ruff format .`
- Type checking: `uv run pyright`

- **Test Execution Policy:**
- **During Active Iteration:** Do NOT run the full test suite (`python -m tests.suites all`) for routine edits or focused debugging. Run only specific, affected test files (e.g. `uv run pytest tests/core/test_status_bar_problems.py`).
- **Pre-Push / Pre-PR Only:** Run full verification (`uv run python -m tests.suites all` and `uv run python scripts/sdk_contract_tests.py`) as a final check before committing or pushing changes.

## Architectural Guidelines

- **Core & Plugin Decoupling:**
- Core studio engine (`src/setuav_studio/`) and plugins (`src/plugins/`) must remain decoupled.
- Domain assets and data (e.g., `src/plugins/geometry/data/airfoils`) and icons (`src/plugins/<plugin>/assets/icons/`) must reside within their respective plugin directories.

- **Style and Icon Management:**
- Use `setuav_studio.ui.style` (`icons` and `theme`) for styling and icon resolution.
- Plugin icon assets are registered dynamically via `register_plugin_icons(...)`. Do not pollute core asset manifests.

- **SDK Contracts & Thread Safety:**
- Preserve `setuav_studio_sdk` API compatibility.
- Do not invoke blocking calls (`time.sleep`, synchronous locks) on the main Qt UI event loop thread.

## Code Quality Standards

- **No Symptom Masking:**
- Do not swallow exceptions silently, remove failing tests, or return dummy fallback values. Identify and fix underlying root causes.
- **Verification:**
- Code must pass `ruff check`, `ruff format`, and `pyright` without errors or warnings.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,14 @@ fail-on = "GNU Affero General Public License v3;GNU Affero General Public Licens
[tool.ruff]
target-version = "py311"
line-length = 100
src = ["src", "tests", "packages/setuav-studio-sdk/src"]

[tool.ruff.lint]
allowed-confusables = ["α", "γ", "ρ", "×", "–", "ℹ"]
select = ["B", "C4", "C90", "E4", "E7", "E9", "F", "I", "RUF", "SIM", "UP"]

[tool.ruff.lint.isort]
known-first-party = ["setuav_studio_sdk"]
known-first-party = ["setuav_studio", "plugins", "setuav_studio_sdk"]

[tool.ruff.lint.mccabe]
max-complexity = 15
Expand Down
2 changes: 1 addition & 1 deletion scripts/package_smoke_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"setuav_studio/assets/icons/studio.svg",
"setuav_studio/assets/fonts/Inter/Inter-VariableFont_opsz,wght.ttf",
"setuav_studio/assets/fonts/Inter/OFL.txt",
"setuav_studio/data/airfoils/clarky.dat",
"plugins/geometry/data/airfoils/clarky.dat",
)


Expand Down
4 changes: 2 additions & 2 deletions src/plugins/aerodynamics/charts_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def plot_single(
series = QLineSeries()
series.setName(name)
series.setProperty("themeColorRole", color_role)
from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

pen = QPen(QColor(chart_color(color_role)), 2.5)
series.setPen(pen)
Expand Down Expand Up @@ -121,7 +121,7 @@ def plot_multi(
all_x: list[float] = []
all_y: list[float] = []

from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

for x_vals, y_vals, name, color_role in curves:
if not x_vals or not y_vals:
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/aerodynamics/controls_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
QWidget,
)

from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.theme import tokens
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.style.theme import tokens
from setuav_studio.ui.widget.button import refresh_button_role, set_button_role, set_native_button
from setuav_studio.ui.widget.spinbox import NumericSpinBox
from setuav_studio.ui.widget.table import PropertyTableMixin
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/aerodynamics/results_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
QWidget,
)

from setuav_studio.ui.icons import get_icon
from setuav_studio.ui.style.icons import get_icon
from setuav_studio.ui.widget.button import refresh_button_role, set_native_button
from setuav_studio.ui.widget.table import ContentFitTableWidget, PropertyTableMixin
from setuav_studio_sdk import StudioAPI, StudioEvents
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/electrical_propulsion/catalog_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
get_motor_database,
get_propeller_database,
)
from setuav_studio.ui.icons import get_icon
from setuav_studio.ui.style.icons import get_icon
from setuav_studio.ui.widget.button import set_button_role

_INVALID_MODEL_INDEX = QModelIndex()
Expand Down
8 changes: 4 additions & 4 deletions src/plugins/electrical_propulsion/charts_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def plot_data(
series_thrust = QLineSeries()
series_thrust.setName("Thrust (N)")
series_thrust.setProperty("themeColorRole", "blue")
from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

series_thrust.setPen(QPen(QColor(chart_color("blue")), 2.5))

Expand Down Expand Up @@ -149,7 +149,7 @@ def plot_data(
series_current = QLineSeries()
series_current.setName("Current (A)")
series_current.setProperty("themeColorRole", "red")
from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

series_current.setPen(QPen(QColor(chart_color("red")), 2.5))

Expand Down Expand Up @@ -237,7 +237,7 @@ def plot_data(
series_eta_tot = QLineSeries()
series_eta_tot.setName("Total η")
series_eta_tot.setProperty("themeColorRole", "green")
from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

series_eta_tot.setPen(QPen(QColor(chart_color("green")), 2.5))

Expand Down Expand Up @@ -321,7 +321,7 @@ def plot_data(
series_pl = QLineSeries()
series_pl.setName("g/W")
series_pl.setProperty("themeColorRole", "orange")
from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

series_pl.setPen(QPen(QColor(chart_color("orange")), 2.5))

Expand Down
4 changes: 2 additions & 2 deletions src/plugins/electrical_propulsion/controls_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from pythrust.propulsion.models.motor import MotorSpec
from pythrust.propulsion.models.propeller import PropellerSpec

from setuav_studio.ui.icons import get_icon, set_label_icon
from setuav_studio.ui.style.icons import get_icon, set_label_icon
from setuav_studio.ui.widget.button import refresh_button_role, set_button_role, set_native_button
from setuav_studio.ui.widget.table import PropertyTableMixin
from setuav_studio_sdk import StudioAPI, StudioEvents
Expand Down Expand Up @@ -283,7 +283,7 @@ def _create_alert_box(self) -> None:
self._content_layout.addWidget(self.alert_box)

def show_alert(self, severity: str, title: str, message: str) -> None:
from setuav_studio.ui.theme import status_color
from setuav_studio.ui.style.theme import status_color

self._alert_severity = severity
if severity in ("warning", "danger", "error"):
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/electrical_propulsion/editors/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
QWidget,
)

from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.widget.table import PropertyTableMixin
from setuav_studio_sdk import StudioAPI

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/electrical_propulsion/editors/battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
QWidget,
)

from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.widget.table import PropertyTableMixin
from setuav_studio_sdk import StudioAPI

Expand Down
6 changes: 3 additions & 3 deletions src/plugins/electrical_propulsion/results_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
QWidget,
)

from setuav_studio.ui.icons import get_icon
from setuav_studio.ui.theme import tokens
from setuav_studio.ui.style.icons import get_icon
from setuav_studio.ui.style.theme import tokens
from setuav_studio.ui.widget.button import refresh_button_role, set_native_button
from setuav_studio.ui.widget.table import ContentFitTableWidget, PropertyTableMixin
from setuav_studio_sdk import StudioAPI, StudioEvents
Expand Down Expand Up @@ -298,7 +298,7 @@ def _detail_values(row: dict[str, Any], is_best: bool, is_overcurrent: bool) ->

@staticmethod
def _detail_colors() -> tuple[QColor, QColor, QColor]:
from setuav_studio.ui.theme import is_light_theme
from setuav_studio.ui.style.theme import is_light_theme

if is_light_theme():
return QColor("#cf222e"), QColor("#0e8a5b"), QColor("#1a7f37")
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/flight_performance/charts_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def _add_line_series(
axis_x: QValueAxis,
axis_y: QValueAxis,
) -> QLineSeries:
from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

series = QLineSeries()
series.setName(label)
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/flight_performance/controls_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from plugins.electrical_propulsion.database import get_propeller_database
from plugins.electrical_propulsion.engine.solver import PropulsionSolverEngine
from plugins.weight_balance.engine.solver import WeightBalanceSolver
from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.widget.button import refresh_button_role, set_button_role
from setuav_studio.ui.widget.table import PropertyTableMixin
from setuav_studio_sdk import StudioAPI, StudioEvents
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/flight_performance/results_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
QWidget,
)

from setuav_studio.ui.icons import get_icon
from setuav_studio.ui.theme import status_color, tokens
from setuav_studio.ui.style.icons import get_icon
from setuav_studio.ui.style.theme import status_color, tokens
from setuav_studio.ui.widget.button import set_native_button
from setuav_studio.ui.widget.table import ContentFitTableWidget, PropertyTableMixin
from setuav_studio_sdk import StudioAPI, StudioEvents
Expand Down
34 changes: 34 additions & 0 deletions src/plugins/geometry/assets/icons/manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[icons]
# Geometry Creation toolbar
geometry_add_fuselage = "geometry-add-fuselage.png"
geometry_add_lifting_surface = "geometry-add-lifting-surface.png"
geometry_add_control_surface = "geometry-add-control-surface.png"

# Transform & Envelope
transform = "transform.svg"
coordinate_system = "transform.svg"
envelope = "envelope.svg"
physical_envelope = "envelope.svg"

# View menu 3D panel
viewer_3d = "view-isometric.png"

# 3D viewport display modes, camera presets, and overlays
view_colored = "view-colored.svg"
view_monochrome = "view-monochrome.svg"
view_palette = "view-palette.svg"
palette = "view-palette.svg"
view_solid = "view-solid.png"
view_wireframe = "view-wireframe.png"
view_transparent = "view-transparent.png"
view_grid = "view-grid.svg"
view_isometric = "view-isometric.svg"
view_perspective = "view-perspective.svg"
camera_perspective = "view-perspective.svg"
camera_iso = "view-isometric.png"
camera_top = "view-top.png"
camera_bottom = "view-bottom.png"
camera_front = "view-front.png"
camera_side = "view-side.png"
view_fit = "view-fit.png"
screenshot = "screenshot.svg"
6 changes: 3 additions & 3 deletions src/plugins/geometry/editors/airfoil_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
QWidget,
)

from setuav_studio.ui.theme import tokens
from setuav_studio.ui.style.theme import tokens
from setuav_studio.ui.widget.button import set_button_role, set_native_button

from ..engine.airfoil import (
Expand Down Expand Up @@ -68,7 +68,7 @@ def set_airfoil(self, name: str, points: tuple[tuple[float, float], ...]) -> Non
self.update()

def paintEvent(self, _event: Any) -> None:
from setuav_studio.ui.theme import is_light_theme, tokens
from setuav_studio.ui.style.theme import is_light_theme, tokens

tok = tokens()
is_light = is_light_theme()
Expand Down Expand Up @@ -130,7 +130,7 @@ def paintEvent(self, _event: Any) -> None:
path.closeSubpath()

# Fill & Stroke Airfoil
from setuav_studio.ui.theme import chart_color
from setuav_studio.ui.style.theme import chart_color

series_color = QColor(chart_color("blue"))
fill_color = QColor(series_color)
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/geometry/editors/control_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
QWidget,
)

from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.widget.table import PropertyTableMixin
from setuav_studio_sdk import StudioAPI

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/geometry/editors/fuselage.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
QWidget,
)

from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.widget.button import set_native_button
from setuav_studio.ui.widget.spinbox import (
NoWheelComboBox,
Expand Down
14 changes: 7 additions & 7 deletions src/plugins/geometry/editors/fuselage_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
QWidget,
)

from setuav_studio.ui.theme import accent_color, tokens
from setuav_studio.ui.style.theme import accent_color, tokens

from ..engine.fuselage_geometry import compute_section_metrics, sample_profile

Expand Down Expand Up @@ -432,7 +432,7 @@ def paintEvent(self, _event: Any) -> None:
height = self.height()

# Canvas background
from setuav_studio.ui.theme import is_light_theme, tokens
from setuav_studio.ui.style.theme import is_light_theme, tokens

tok = tokens()
is_light = is_light_theme()
Expand Down Expand Up @@ -534,7 +534,7 @@ def _draw_active_profile(self, painter: QPainter, world_to_screen: Any) -> None:
self._draw_polygon_handles(painter, world_to_screen)

def _draw_polygon_handles(self, painter: QPainter, to_screen: Any) -> None:
from setuav_studio.ui.theme import tokens
from setuav_studio.ui.style.theme import tokens

tok = tokens()
text_color = QColor(tok["text"])
Expand Down Expand Up @@ -620,7 +620,7 @@ def _draw_grid(
ox: float,
oy: float,
) -> None:
from setuav_studio.ui.theme import is_light_theme, tokens
from setuav_studio.ui.style.theme import is_light_theme, tokens

tok = tokens()
is_light = is_light_theme()
Expand Down Expand Up @@ -667,7 +667,7 @@ def _draw_axes(
ox: float,
oy: float,
) -> None:
from setuav_studio.ui.theme import is_light_theme, tokens
from setuav_studio.ui.style.theme import is_light_theme, tokens

tok = tokens()
is_light = is_light_theme()
Expand Down Expand Up @@ -702,7 +702,7 @@ def _draw_dimension_lines(
w_mm = max_y - min_y
h_mm = max_z - min_z

from setuav_studio.ui.theme import tokens
from setuav_studio.ui.style.theme import tokens

dim_pen = QPen(QColor(tokens()["text_dim"]), 1.0, Qt.PenStyle.SolidLine)
painter.setPen(dim_pen)
Expand Down Expand Up @@ -735,7 +735,7 @@ def _draw_dimension_lines(
)

def _draw_hud(self, painter: QPainter, width: int, _height: int) -> None:
from setuav_studio.ui.theme import chart_color, tokens
from setuav_studio.ui.style.theme import chart_color, tokens

tok = tokens()
painter.setPen(QColor(tok["text"]))
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/geometry/editors/fuselage_section_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
QWidget,
)

from setuav_studio.ui.icons import get_icon
from setuav_studio.ui.style.icons import get_icon
from setuav_studio.ui.widget.button import set_button_role, set_native_button
from setuav_studio.ui.widget.spinbox import (
NoWheelComboBox,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/geometry/editors/lifting_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
QWidget,
)

from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.widget.button import set_native_button
from setuav_studio.ui.widget.spinbox import (
NoWheelComboBox,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/geometry/editors/structural_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
QWidget,
)

from setuav_studio.ui.icons import set_label_icon
from setuav_studio.ui.style.icons import set_label_icon
from setuav_studio.ui.widget.table import PropertyTableMixin
from setuav_studio_sdk import StudioAPI

Expand Down
Loading
Loading