jsbsim-gui 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. jsbsim_gui-0.1.0/.github/copilot-instructions.md +132 -0
  2. jsbsim_gui-0.1.0/.github/dependabot.yml +6 -0
  3. jsbsim_gui-0.1.0/.github/workflows/publish.yml +50 -0
  4. jsbsim_gui-0.1.0/.github/workflows/pythonpackage.yml +41 -0
  5. jsbsim_gui-0.1.0/.gitignore +169 -0
  6. jsbsim_gui-0.1.0/LICENSE +674 -0
  7. jsbsim_gui-0.1.0/PKG-INFO +83 -0
  8. jsbsim_gui-0.1.0/README.md +63 -0
  9. jsbsim_gui-0.1.0/docs/screenshot.png +0 -0
  10. jsbsim_gui-0.1.0/jsbsim_gui/__init__.py +3 -0
  11. jsbsim_gui-0.1.0/jsbsim_gui/__main__.py +53 -0
  12. jsbsim_gui-0.1.0/jsbsim_gui/app.py +269 -0
  13. jsbsim_gui-0.1.0/jsbsim_gui/consoles_panel.py +267 -0
  14. jsbsim_gui-0.1.0/jsbsim_gui/controller.py +240 -0
  15. jsbsim_gui-0.1.0/jsbsim_gui/csv_tree.py +100 -0
  16. jsbsim_gui-0.1.0/jsbsim_gui/edit_actions.py +75 -0
  17. jsbsim_gui-0.1.0/jsbsim_gui/file_state.py +67 -0
  18. jsbsim_gui-0.1.0/jsbsim_gui/find.py +392 -0
  19. jsbsim_gui-0.1.0/jsbsim_gui/hierarchical_tree.py +496 -0
  20. jsbsim_gui-0.1.0/jsbsim_gui/menu_bar.py +149 -0
  21. jsbsim_gui-0.1.0/jsbsim_gui/plot_labels.py +167 -0
  22. jsbsim_gui-0.1.0/jsbsim_gui/plotinfo_list.py +206 -0
  23. jsbsim_gui-0.1.0/jsbsim_gui/plots_view.py +454 -0
  24. jsbsim_gui-0.1.0/jsbsim_gui/property_history.py +87 -0
  25. jsbsim_gui-0.1.0/jsbsim_gui/resources/logo_JSBSIM_globe_410x429.bmp +0 -0
  26. jsbsim_gui-0.1.0/jsbsim_gui/run.py +293 -0
  27. jsbsim_gui-0.1.0/jsbsim_gui/source_editor.py +276 -0
  28. jsbsim_gui-0.1.0/jsbsim_gui/textview.py +406 -0
  29. jsbsim_gui-0.1.0/jsbsim_gui/tree_node.py +100 -0
  30. jsbsim_gui-0.1.0/jsbsim_gui/widget.py +46 -0
  31. jsbsim_gui-0.1.0/pyproject.toml +31 -0
  32. jsbsim_gui-0.1.0/requirements.txt +6 -0
  33. jsbsim_gui-0.1.0/tests/test_consoles_panel.py +134 -0
  34. jsbsim_gui-0.1.0/tests/test_controller_logger.py +308 -0
  35. jsbsim_gui-0.1.0/tests/test_plotinfo_list.py +270 -0
  36. jsbsim_gui-0.1.0/tests/test_property_history.py +203 -0
  37. jsbsim_gui-0.1.0/tests/test_textview_menu_bar.py +114 -0
  38. jsbsim_gui-0.1.0/tests/test_xml_node.py +254 -0
@@ -0,0 +1,132 @@
1
+ # JSBSim GUI - AI Coding Agent Instructions
2
+
3
+ ## Project Overview
4
+ A Tkinter-based GUI for [JSBSim](https://github.com/JSBSim-Team/jsbsim) flight dynamics simulation. The app allows users to load aircraft models/scripts, configure simulations, visualize flight data with real-time plots, and explore/modify JSBSim properties through a hierarchical tree interface.
5
+
6
+ ## Architecture
7
+
8
+ ### Core Components
9
+ - **`app.py`**: Main application window with menu bar and view switching (edit/run modes)
10
+ - **`controller.py`**: Central coordinator wrapping JSBSim's `FGFDMExec`, manages XML parsing, property access, and console output redirection
11
+ - **`run.py`**: Real-time simulation view with property explorer, plots, and drag-n-drop workflow
12
+ - **`source_editor.py`**: XML/source file editor with syntax highlighting and property explorer
13
+ - **`hierarchical_tree.py`**: Reusable tree widgets (`PropertyTree`, `FileTree`, `XMLTree`) with filtering/searching
14
+ - **`plots_view.py`**: Matplotlib-based plotting with interactive hover/crosshair, zoom/pan, and drag-n-drop property selection
15
+ - **`property_history.py`**: Efficient chunked storage (numpy arrays) for time-series property data
16
+ - **`plotinfo_list.py`**: Smart property naming that finds common paths to generate unique, minimal display names
17
+
18
+ ### Key Design Patterns
19
+ 1. **View Switching**: The main window (`App`) replaces `self.main` widget between logo → `SourceEditor` → `Run` modes
20
+ 3. **Drag-n-Drop**: Abstract `DragNDropManager` pattern used for property-to-plot workflow (see `DnDProperties` in `run.py`)
21
+ 4. **XML Tracking**: Custom `XMLNode` tree (built via expat parser) tracks file paths and line numbers for navigation from XML tree to source editor
22
+
23
+ ## Development Workflows
24
+
25
+ ### Running the Application
26
+ ```bash
27
+ python -m jsbsim_gui # Entry point is jsbsim_gui/__main__.py
28
+ python -m jsbsim_gui --root /path/to/jsbsim/data # Override JSBSim root directory
29
+ ```
30
+
31
+ By default, the app uses JSBSim's data directory from the Python library installation. For testing, aircraft/engines/scripts included with JSBSim's Python package are used—no separate data files required.
32
+
33
+ ### Testing
34
+ ```bash
35
+ python -m unittest discover -s tests # Run all tests
36
+ python -m unittest tests.test_plotinfo_list # Specific test module
37
+ ```
38
+ Tests use `jsbsim.FGPropertyManager` for property node mocking. No external fixtures required.
39
+
40
+ ### Dependencies
41
+ - **jsbsim** (≥1.3.0): Python bindings to JSBSim C++ library (includes aircraft/engines/scripts data for testing)
42
+ - **matplotlib**: Plotting with TkAgg backend
43
+ - **PIL/Pillow**: Logo image loading (implicit dependency)
44
+ - **Tkinter**: Ships with Python, not in requirements.txt
45
+
46
+ **Dependency Policy**: ALWAYS prefer Python standard library over PyPI packages. Do NOT add new dependencies without explicit approval. This keeps the project lightweight and reduces maintenance burden.
47
+
48
+ ### Logo Assets
49
+ Logo images are managed via git submodule from `https://github.com/JSBSim-Team/jsbsim-logo.git`:
50
+ ```bash
51
+ git submodule init
52
+ git submodule update
53
+ ```
54
+ Logo path is hardcoded to `logo/wizard_installer/logo_JSBSIM_globe_410x429.bmp` in `app.py`.
55
+
56
+ ## Project-Specific Conventions
57
+
58
+ ### Code Quality Standards
59
+ - **Formatting**: All Python code MUST be formatted with [Black](https://black.readthedocs.io/). Run `black .` before committing.
60
+ - **Type Hints**: Use Python typing annotations for all functions/methods to catch type errors early. Check minimum supported Python version (3.10+) for typing compatibility—avoid newer typing features like `X | Y` union syntax.
61
+ - **No Docstrings**: This is an application, NOT a library. NEVER use docstrings (""" ... """). Instead, use clear, descriptive function and variable names that make the code self-documenting.
62
+ - **Avoid Trivial Micro-functions**: Do not decompose logic into one-line or trivial functions (e.g., `def add_one(x): return x+1`) for the sake of decomposition. Only extract functions when they provide a meaningful, reusable abstraction or significantly improve the clarity of complex logic.
63
+ - **Code Clarity**: Favor readable, straightforward code over convoluted, astute, or "clever" solutions. Simple code that's easy to understand beats smart code that's hard to maintain. Keep trivial logic inline to reduce cognitive load and prevent unnecessary jumping between small function definitions.
64
+ - **Standard Library First**: Strongly prefer `import tkinter`, `import xml.etree`, `import os`, etc. over adding new PyPI dependencies.
65
+ - **Final Review Protocol:** Once the entire task is complete and before providing your final response, you must execute `git diff` and use its output as a mandatory checklist to align your work with the following rules:
66
+ 1. **Analyze & Reconcile:** Read the diff carefully. If any change is not strictly necessary or degrades readability, you must immediately revert or fix those specific lines.
67
+ 2. **Human-Centric Review:** The primary goal is to ensure the final diff is as easy as possible for a human to review. Minimize cognitive load by keeping changes strictly scoped to the task.
68
+ 3. **Whitespace Exception:** Ignore any changes related to 'trailing spaces' removal (handled by IDE). Do not revert these.
69
+ 4. **Scope Enforcement:** If the diff shows that you have touched files or lines unrelated to the given task, revert those specific changes.
70
+ 5. **Validation:** Do not consider the task finished until the `git diff` output perfectly reflects the minimal set of changes required for the given task.
71
+
72
+ ### Property Path Handling
73
+ - Always use forward slashes `/` in property paths, even on Windows (see `get_relative_path()` and `PlotInfoList`)
74
+ - Properties use fully qualified names: `node.get_fully_qualified_name()` returns absolute paths starting with `/`
75
+
76
+ ### Real-Time Update Pattern
77
+ The simulation loop in `Run.update_plots()` uses:
78
+ - **200ms interval** (`REALTIME_UPDATE_INTERVAL_ms`) for UI updates
79
+ - **Batch execution** of JSBSim steps to catch up with real-time, but breaks early if processing exceeds 95% of interval
80
+ - Tracks `initial_seconds` to calculate `sim_lag_time` and maintain real-time pacing
81
+
82
+ ### Matplotlib Integration Gotchas
83
+ - **Blitting for performance**: `canvas.blit()` used with animated artists (crosshair line, value labels)
84
+ - **Inverted y-axis**: `get_axes_at_coordinates()` must flip y-coordinate because Matplotlib's origin is bottom-left, Tkinter's is top-left
85
+ - Last line in each subplot axis is the **animated crosshair** (`ax.lines[-1]`), don't treat it as data
86
+
87
+ ### Property Filtering and Search
88
+ - `HierarchicalTree.filter()` detaches non-matching items but stores them in `_hidden_items` for restoration
89
+ - Always call `update_visible_properties()` after search/filter/collapse operations to update property value display
90
+ - Visible properties drive the update loop—only fetch values for currently displayed items
91
+
92
+ ### XML File Resolution
93
+ JSBSim uses multiple search paths (see `Controller.get_xml_trees()`):
94
+ 1. Aircraft directory
95
+ 2. Aircraft/Systems, Aircraft/systems
96
+ 3. Aircraft/Engines, Aircraft/engines, Aircraft/Engine, Aircraft/engine
97
+ 4. Shared engine_path
98
+ 5. Shared systems_path
99
+
100
+ Include files must be resolved before building the full XML tree for navigation.
101
+
102
+ ### Testing Patterns
103
+ - Property tests use `FGPropertyManager.get_node(path, create=True)` to build test hierarchies
104
+ - Test property naming logic with edge cases: single property, duplicate names, common path trimming
105
+ - Use `np.array_equal()` for numpy array comparisons in property history tests
106
+
107
+ ## Common Tasks
108
+
109
+ ### Adding a New Tree Widget
110
+ 1. Subclass `SearchableTree` (provides search box and collapse button)
111
+ 2. Pass lambda to create underlying `HierarchicalTree` with column definitions
112
+ 3. Bind custom selection handlers with `tree.tree.bind("<<TreeviewSelect>>", ...)`
113
+ 4. Example: `XMLTree` in `source_editor.py`
114
+
115
+ ### Adding a New Plot Feature
116
+ 1. Connect to matplotlib events via `canvas.mpl_connect(event_name, handler)`
117
+ 2. Use `animated=True` for frequently updated artists (lines, text)
118
+ 3. Reset bbox cache (`self.bbox = None`) when layout changes require full redraw
119
+ 4. See `on_scroll()` for zoom implementation pattern
120
+
121
+ ### Extending Property History
122
+ - Chunk size is 100 (`PropertyHistory.CHUNK_SIZE`)
123
+ - Add new properties during init—runtime addition not supported
124
+ - Use `get_property_history()` for full time series, `get_time_snapshot()` for single timestep
125
+
126
+ ## Known Gotchas
127
+
128
+ 1. **Logo path**: Hardcoded relative path `logo/wizard_installer/...` requires running from repo root
129
+ 2. **Window resizing**: Main window starts non-resizable, becomes resizable after file load
130
+ 3. **Trim failures**: JSBSim trim (`simulation/do_simple_trim`) raises `TrimFailureError` exceptions—must catch explicitly
131
+ 4. **Property node lifetime**: JSBSim property nodes are live references; value changes reflect immediately without re-fetching
132
+ 5. **Step vs Run**: `fdm.run_ic()` must be called before `fdm.run()`—UI enforces this via button state management
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -0,0 +1,50 @@
1
+ name: Publish Python distribution to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ jobs:
9
+ build:
10
+ name: Build distribution
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Check out repository
14
+ uses: actions/checkout@v7
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v7
18
+ with:
19
+ python-version: "3.x"
20
+
21
+ - name: Install build tools
22
+ run: python -m pip install --upgrade build
23
+
24
+ - name: Build sdist and wheel
25
+ run: python -m build
26
+
27
+ - name: Store distribution packages
28
+ uses: actions/upload-artifact@v7
29
+ with:
30
+ name: python-package-distributions
31
+ path: dist/
32
+
33
+ publish-to-pypi:
34
+ name: Publish to PyPI
35
+ needs: build
36
+ runs-on: ubuntu-latest
37
+ environment:
38
+ name: pypi
39
+ url: https://pypi.org/p/jsbsim-gui
40
+ permissions:
41
+ id-token: write
42
+ steps:
43
+ - name: Download distribution packages
44
+ uses: actions/download-artifact@v8
45
+ with:
46
+ name: python-package-distributions
47
+ path: dist/
48
+
49
+ - name: Publish package distributions to PyPI
50
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,41 @@
1
+ name: Python package
2
+
3
+ on:
4
+ push:
5
+ tags-ignore:
6
+ - "**"
7
+ pull_request:
8
+
9
+ jobs:
10
+ build:
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.10", 3.11, 3.12, 3.13, 3.14]
14
+ os: [ubuntu-latest]
15
+ include:
16
+ - python-version: "3.10"
17
+ os: windows-latest
18
+ - python-version: "3.10"
19
+ os: macos-latest
20
+ fail-fast: false
21
+ runs-on: ${{ matrix.os }}
22
+
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ - name: Set up Python ${{ matrix.python-version }}
26
+ uses: actions/setup-python@v7
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+ - name: Install dependencies
30
+ run: |
31
+ python -m pip install --upgrade pip
32
+ pip install -r requirements.txt
33
+ - name: Test with unittest
34
+ shell: bash
35
+ run: |
36
+ if [ "${{ runner.os }}" == "Linux" ]; then
37
+ sudo apt-get install -y xvfb
38
+ xvfb-run python -m unittest discover tests
39
+ else
40
+ python -m unittest discover tests
41
+ fi
@@ -0,0 +1,169 @@
1
+ # JSBSim data
2
+ *.csv
3
+
4
+ # Byte-compiled / optimized / DLL files
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+
9
+ # C extensions
10
+ *.so
11
+
12
+ # Distribution / packaging
13
+ .Python
14
+ build/
15
+ develop-eggs/
16
+ dist/
17
+ downloads/
18
+ eggs/
19
+ .eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ wheels/
26
+ share/python-wheels/
27
+ *.egg-info/
28
+ .installed.cfg
29
+ *.egg
30
+ MANIFEST
31
+ .DS_Store
32
+
33
+ # PyInstaller
34
+ # Usually these files are written by a python script from a template
35
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
36
+ *.manifest
37
+ *.spec
38
+
39
+ # Installer logs
40
+ pip-log.txt
41
+ pip-delete-this-directory.txt
42
+
43
+ # Unit test / coverage reports
44
+ htmlcov/
45
+ .tox/
46
+ .nox/
47
+ .coverage
48
+ .coverage.*
49
+ .cache
50
+ nosetests.xml
51
+ coverage.xml
52
+ *.cover
53
+ *.py,cover
54
+ .hypothesis/
55
+ .pytest_cache/
56
+ cover/
57
+
58
+ # Translations
59
+ *.mo
60
+ *.pot
61
+
62
+ # Django stuff:
63
+ *.log
64
+ local_settings.py
65
+ db.sqlite3
66
+ db.sqlite3-journal
67
+
68
+ # Flask stuff:
69
+ instance/
70
+ .webassets-cache
71
+
72
+ # Scrapy stuff:
73
+ .scrapy
74
+
75
+ # Sphinx documentation
76
+ docs/_build/
77
+
78
+ # PyBuilder
79
+ .pybuilder/
80
+ target/
81
+
82
+ # Jupyter Notebook
83
+ .ipynb_checkpoints
84
+
85
+ # IPython
86
+ profile_default/
87
+ ipython_config.py
88
+
89
+ # pyenv
90
+ # For a library or package, you might want to ignore these files since the code is
91
+ # intended to run in multiple environments; otherwise, check them in:
92
+ # .python-version
93
+
94
+ # pipenv
95
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
97
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
98
+ # install all needed dependencies.
99
+ #Pipfile.lock
100
+
101
+ # poetry
102
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
103
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
104
+ # commonly ignored for libraries.
105
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
106
+ #poetry.lock
107
+
108
+ # pdm
109
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
110
+ #pdm.lock
111
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
112
+ # in version control.
113
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
114
+ .pdm.toml
115
+ .pdm-python
116
+ .pdm-build/
117
+
118
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
119
+ __pypackages__/
120
+
121
+ # Celery stuff
122
+ celerybeat-schedule
123
+ celerybeat.pid
124
+
125
+ # SageMath parsed files
126
+ *.sage.py
127
+
128
+ # Environments
129
+ .env
130
+ .venv
131
+ env/
132
+ venv/
133
+ ENV/
134
+ env.bak/
135
+ venv.bak/
136
+
137
+ # Spyder project settings
138
+ .spyderproject
139
+ .spyproject
140
+
141
+ # Rope project settings
142
+ .ropeproject
143
+
144
+ # mkdocs documentation
145
+ /site
146
+
147
+ # mypy
148
+ .mypy_cache/
149
+ .dmypy.json
150
+ dmypy.json
151
+
152
+ # Pyre type checker
153
+ .pyre/
154
+
155
+ # pytype static type analyzer
156
+ .pytype/
157
+
158
+ # Cython debug symbols
159
+ cython_debug/
160
+
161
+ # VS Code
162
+ .vscode/
163
+
164
+ # PyCharm
165
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
166
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
167
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
168
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
169
+ #.idea/