98ff57ed08
Fixes Module 1 UI: - wizard_cruiser/sailing/planing: perfiles sin^n calibrados por Cm, V-bottom con ángulo de astilla, corrección zona sobre chine planeador - viewer_3d: buffer hull pendiente para eliminar race condition 500ms - viewer_lines: reescritura completa — waterlines visibles, control points interactivos (drag DelftShip-style), señal offsets_edited - main_window: conecta offsets_edited → slot _on_offsets_edited_from_viewer que propaga cambios a todos los visores, editor, 3D y barra hidrostática Módulo 2 — motor HydrostaticCurves (Task 13): - integrator.py: integrate() (Simpson+trapz), waterplane_strips(), section_areas() - upright.py: UprightHydrostatics (19 campos), compute_upright() single-pass - curves_of_form.py: HydrostaticCurves.compute(), at_draft(), to_csv_lines(), to_dict() - tests/test_module2_hydrostatics.py: 83 tests — Wigley V&V, monotonicidad, CSV export, IACS Rec.34 §4.3–4.5; todos los 224 tests pasan Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
90 lines
2.0 KiB
Python
90 lines
2.0 KiB
Python
"""
|
|
Gestión de configuración de usuario con QSettings.
|
|
|
|
Persiste preferencias: idioma, tema, unidades, archivos recientes, etc.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from PySide6.QtCore import QSettings
|
|
|
|
APP_NAME = "ARShipDesign"
|
|
ORG_NAME = "AlvaroRomero"
|
|
|
|
# Claves de configuración
|
|
KEY_LANGUAGE = "ui/language"
|
|
KEY_THEME = "ui/theme"
|
|
KEY_UNITS = "ui/units"
|
|
KEY_RECENT_FILES = "project/recentFiles"
|
|
KEY_MAX_RECENT = "project/maxRecentFiles"
|
|
KEY_WINDOW_GEOMETRY = "ui/windowGeometry"
|
|
KEY_WINDOW_STATE = "ui/windowState"
|
|
KEY_HYDRO_DENSITY = "calc/waterDensity"
|
|
KEY_LOG_LEVEL = "system/logLevel"
|
|
|
|
|
|
def get_settings() -> QSettings:
|
|
"""Retorna la instancia de QSettings de la aplicación."""
|
|
return QSettings(ORG_NAME, APP_NAME)
|
|
|
|
|
|
def get_language() -> str:
|
|
s = get_settings()
|
|
return s.value(KEY_LANGUAGE, "es")
|
|
|
|
|
|
def set_language(lang: str) -> None:
|
|
s = get_settings()
|
|
s.setValue(KEY_LANGUAGE, lang)
|
|
|
|
|
|
def get_theme() -> str:
|
|
s = get_settings()
|
|
return s.value(KEY_THEME, "dark")
|
|
|
|
|
|
def set_theme(theme: str) -> None:
|
|
s = get_settings()
|
|
s.setValue(KEY_THEME, theme)
|
|
|
|
|
|
def get_units() -> str:
|
|
"""'si' o 'imperial'"""
|
|
s = get_settings()
|
|
return s.value(KEY_UNITS, "si")
|
|
|
|
|
|
def set_units(units: str) -> None:
|
|
s = get_settings()
|
|
s.setValue(KEY_UNITS, units)
|
|
|
|
|
|
def get_recent_files() -> list[str]:
|
|
s = get_settings()
|
|
val = s.value(KEY_RECENT_FILES, [])
|
|
if isinstance(val, str):
|
|
return [val]
|
|
return list(val) if val else []
|
|
|
|
|
|
def add_recent_file(path: str) -> None:
|
|
s = get_settings()
|
|
recent = get_recent_files()
|
|
if path in recent:
|
|
recent.remove(path)
|
|
recent.insert(0, path)
|
|
max_recent = int(s.value(KEY_MAX_RECENT, 10))
|
|
recent = recent[:max_recent]
|
|
s.setValue(KEY_RECENT_FILES, recent)
|
|
|
|
|
|
def get_water_density() -> float:
|
|
"""Densidad del agua de mar en kg/m³ (por defecto 1025)."""
|
|
s = get_settings()
|
|
return float(s.value(KEY_HYDRO_DENSITY, 1025.0))
|
|
|
|
|
|
def get_log_level() -> str:
|
|
s = get_settings()
|
|
return s.value(KEY_LOG_LEVEL, "INFO")
|