RCAIDE-GUI 1.0.0__py3-none-any.whl

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 (170) hide show
  1. common_widgets/__init__.py +6 -0
  2. common_widgets/animated_toggle.py +141 -0
  3. common_widgets/color.py +17 -0
  4. common_widgets/data_entry_widget.py +337 -0
  5. common_widgets/image_widget.py +21 -0
  6. common_widgets/unit_picker_widget.py +48 -0
  7. main.py +168 -0
  8. rcaide_gui-1.0.0.dist-info/METADATA +96 -0
  9. rcaide_gui-1.0.0.dist-info/RECORD +170 -0
  10. rcaide_gui-1.0.0.dist-info/WHEEL +5 -0
  11. rcaide_gui-1.0.0.dist-info/entry_points.txt +2 -0
  12. rcaide_gui-1.0.0.dist-info/top_level.txt +5 -0
  13. rcaide_io.py +818 -0
  14. tabs/__init__.py +10 -0
  15. tabs/aircraft_configs/__init__.py +3 -0
  16. tabs/aircraft_configs/aircraft_configs.py +301 -0
  17. tabs/analysis/__init__.py +4 -0
  18. tabs/analysis/analysis.py +92 -0
  19. tabs/analysis/widgets/__init__.py +13 -0
  20. tabs/analysis/widgets/aeroacoustics_widget.py +158 -0
  21. tabs/analysis/widgets/aerodynamics_widget.py +108 -0
  22. tabs/analysis/widgets/analysis_data_widget.py +29 -0
  23. tabs/analysis/widgets/atmosphere_widget.py +49 -0
  24. tabs/analysis/widgets/costs_widget.py +35 -0
  25. tabs/analysis/widgets/energy_widget.py +32 -0
  26. tabs/analysis/widgets/geometry_widget.py +55 -0
  27. tabs/analysis/widgets/planets_widget.py +34 -0
  28. tabs/analysis/widgets/propulsion_widget.py +53 -0
  29. tabs/analysis/widgets/stability_widget.py +34 -0
  30. tabs/analysis/widgets/weights_widget.py +94 -0
  31. tabs/geometry/__init__.py +6 -0
  32. tabs/geometry/aircraft_configs.py +232 -0
  33. tabs/geometry/frames/__init__.py +15 -0
  34. tabs/geometry/frames/booms/__init__.py +5 -0
  35. tabs/geometry/frames/booms/boom_frame.py +238 -0
  36. tabs/geometry/frames/cargo_bays/__init__.py +5 -0
  37. tabs/geometry/frames/cargo_bays/cargo_bay_frame.py +159 -0
  38. tabs/geometry/frames/default_frame.py +23 -0
  39. tabs/geometry/frames/energy_network/__init__.py +2 -0
  40. tabs/geometry/frames/energy_network/turbofan_network/__init__.py +3 -0
  41. tabs/geometry/frames/energy_network/turbofan_network/frames/__init__.py +1 -0
  42. tabs/geometry/frames/energy_network/turbofan_network/widgets/__init__.py +1 -0
  43. tabs/geometry/frames/fuselages/__init__.py +5 -0
  44. tabs/geometry/frames/fuselages/fuselage_frame.py +294 -0
  45. tabs/geometry/frames/geometry_frame.py +91 -0
  46. tabs/geometry/frames/landing_gears/__init__.py +5 -0
  47. tabs/geometry/frames/landing_gears/landing_gear_frame.py +189 -0
  48. tabs/geometry/frames/nacelles/__init__.py +1 -0
  49. tabs/geometry/frames/powertrain/__init__.py +6 -0
  50. tabs/geometry/frames/powertrain/converters/__init__.py +5 -0
  51. tabs/geometry/frames/powertrain/converters/converter_frame.py +137 -0
  52. tabs/geometry/frames/powertrain/distributors/__init__.py +5 -0
  53. tabs/geometry/frames/powertrain/distributors/distributor_frame.py +143 -0
  54. tabs/geometry/frames/powertrain/nacelles/__init__.py +5 -0
  55. tabs/geometry/frames/powertrain/nacelles/nacelle_frame.py +283 -0
  56. tabs/geometry/frames/powertrain/powertrain_frame.py +259 -0
  57. tabs/geometry/frames/powertrain/propulsors/__init__.py +5 -0
  58. tabs/geometry/frames/powertrain/propulsors/propulsor_frame.py +146 -0
  59. tabs/geometry/frames/powertrain/sources/__init__.py +6 -0
  60. tabs/geometry/frames/powertrain/sources/energy_source_frame.py +147 -0
  61. tabs/geometry/frames/vehicle_frame.py +171 -0
  62. tabs/geometry/frames/wings/__init__.py +5 -0
  63. tabs/geometry/frames/wings/wings_frame.py +457 -0
  64. tabs/geometry/geometry.py +513 -0
  65. tabs/geometry/widgets/__init__.py +12 -0
  66. tabs/geometry/widgets/booms/__init__.py +6 -0
  67. tabs/geometry/widgets/booms/boom_section_widget.py +109 -0
  68. tabs/geometry/widgets/cargo_bays/__init__.py +1 -0
  69. tabs/geometry/widgets/fuselages/__init__.py +8 -0
  70. tabs/geometry/widgets/fuselages/cabin_class_widget.py +188 -0
  71. tabs/geometry/widgets/fuselages/cabin_widget.py +217 -0
  72. tabs/geometry/widgets/fuselages/fuselage_section_widget.py +190 -0
  73. tabs/geometry/widgets/geometry_data_widget.py +25 -0
  74. tabs/geometry/widgets/landing_gears/__init__.py +6 -0
  75. tabs/geometry/widgets/nacelles/__init__.py +1 -0
  76. tabs/geometry/widgets/powertrain/__init__.py +9 -0
  77. tabs/geometry/widgets/powertrain/converters/__init__.py +5 -0
  78. tabs/geometry/widgets/powertrain/converters/turboelectric_generator_widget.py +74 -0
  79. tabs/geometry/widgets/powertrain/distributors/__init__.py +5 -0
  80. tabs/geometry/widgets/powertrain/distributors/fuel_line_widget.py +81 -0
  81. tabs/geometry/widgets/powertrain/modulators/__init__.py +5 -0
  82. tabs/geometry/widgets/powertrain/modulators/esc_widget.py +58 -0
  83. tabs/geometry/widgets/powertrain/nacelles/__init__.py +5 -0
  84. tabs/geometry/widgets/powertrain/nacelles/nacelle_section_widget.py +115 -0
  85. tabs/geometry/widgets/powertrain/powertrain_connector_widget.py +136 -0
  86. tabs/geometry/widgets/powertrain/powertrain_widget.py +206 -0
  87. tabs/geometry/widgets/powertrain/propulsors/__init__.py +5 -0
  88. tabs/geometry/widgets/powertrain/propulsors/turbofan_widget.py +462 -0
  89. tabs/geometry/widgets/powertrain/sources/__init__.py +6 -0
  90. tabs/geometry/widgets/powertrain/sources/fuel_tank_widget.py +103 -0
  91. tabs/geometry/widgets/powertrain/sources/source_selector_widget.py +35 -0
  92. tabs/geometry/widgets/wings/__init__.py +7 -0
  93. tabs/geometry/widgets/wings/wing_cs_widget.py +198 -0
  94. tabs/geometry/widgets/wings/wing_section_widget.py +298 -0
  95. tabs/home/__init__.py +3 -0
  96. tabs/home/home.py +585 -0
  97. tabs/mission/__init__.py +4 -0
  98. tabs/mission/mission.py +1124 -0
  99. tabs/mission/widgets/__init__.py +3 -0
  100. tabs/mission/widgets/flight_controls_widget.py +186 -0
  101. tabs/mission/widgets/mission_analysis_widget.py +166 -0
  102. tabs/mission/widgets/mission_segment_helper.py +358 -0
  103. tabs/mission/widgets/mission_segment_widget.py +358 -0
  104. tabs/solve/__init__.py +4 -0
  105. tabs/solve/plots/__init__.py +12 -0
  106. tabs/solve/plots/aeroacoustics/__init__.py +6 -0
  107. tabs/solve/plots/aeroacoustics/plot_2D_noise_contour.py +184 -0
  108. tabs/solve/plots/aeroacoustics/plot_3D_noise_contour.py +219 -0
  109. tabs/solve/plots/aeroacoustics/plot_noise_certification_contour.py +115 -0
  110. tabs/solve/plots/aeroacoustics/plot_noise_level.py +118 -0
  111. tabs/solve/plots/aerodynamics/__init__.py +10 -0
  112. tabs/solve/plots/aerodynamics/plot_aerodynamic_coefficients.py +156 -0
  113. tabs/solve/plots/aerodynamics/plot_aerodynamic_forces.py +155 -0
  114. tabs/solve/plots/aerodynamics/plot_aircraft_aerodynamics.py +136 -0
  115. tabs/solve/plots/aerodynamics/plot_drag_components.py +157 -0
  116. tabs/solve/plots/aerodynamics/plot_lift_distribution.py +107 -0
  117. tabs/solve/plots/aerodynamics/plot_rotor_conditions.py +255 -0
  118. tabs/solve/plots/aerodynamics/plot_rotor_disc_performance.py +144 -0
  119. tabs/solve/plots/aerodynamics/plot_rotor_performance.py +124 -0
  120. tabs/solve/plots/common/__init__.py +4 -0
  121. tabs/solve/plots/common/plot_style.py +71 -0
  122. tabs/solve/plots/common/set_axes.py +55 -0
  123. tabs/solve/plots/create_plot_widgets.py +34 -0
  124. tabs/solve/plots/emissions/__init__.py +3 -0
  125. tabs/solve/plots/emissions/plot_emissions.py +167 -0
  126. tabs/solve/plots/energy/__init__.py +12 -0
  127. tabs/solve/plots/energy/plot_altitude_sfc_weight.py +134 -0
  128. tabs/solve/plots/energy/plot_battery_cell_conditions.py +154 -0
  129. tabs/solve/plots/energy/plot_battery_degradation.py +157 -0
  130. tabs/solve/plots/energy/plot_battery_module_C_rates.py +139 -0
  131. tabs/solve/plots/energy/plot_battery_module_conditions.py +157 -0
  132. tabs/solve/plots/energy/plot_battery_pack_conditions.py +164 -0
  133. tabs/solve/plots/energy/plot_battery_ragone_diagram.py +97 -0
  134. tabs/solve/plots/energy/plot_battery_temperature.py +136 -0
  135. tabs/solve/plots/energy/plot_electric_propulsor_efficiencies.py +136 -0
  136. tabs/solve/plots/energy/plot_propulsor_throttles.py +119 -0
  137. tabs/solve/plots/mission/__init__.py +5 -0
  138. tabs/solve/plots/mission/plot_aircraft_velocities.py +145 -0
  139. tabs/solve/plots/mission/plot_flight_conditions.py +236 -0
  140. tabs/solve/plots/mission/plot_flight_trajectory.py +172 -0
  141. tabs/solve/plots/stability/__init__.py +5 -0
  142. tabs/solve/plots/stability/plot_flight_forces_and_moments.py +163 -0
  143. tabs/solve/plots/stability/plot_lateral_stability.py +151 -0
  144. tabs/solve/plots/stability/plot_longitudinal_stability.py +173 -0
  145. tabs/solve/plots/thermal_management/__init__.py +7 -0
  146. tabs/solve/plots/thermal_management/plot_air_cooled_conditions.py +152 -0
  147. tabs/solve/plots/thermal_management/plot_cross_flow_heat_exchanger_conditions.py +185 -0
  148. tabs/solve/plots/thermal_management/plot_reservoir_conditions.py +141 -0
  149. tabs/solve/plots/thermal_management/plot_thermal_management_performance.py +105 -0
  150. tabs/solve/plots/thermal_management/plot_wavy_channel_conditions.py +161 -0
  151. tabs/solve/plots/weights/__init__.py +4 -0
  152. tabs/solve/plots/weights/plot_load_diagram.py +163 -0
  153. tabs/solve/plots/weights/plot_weight_breakdown.py +164 -0
  154. tabs/solve/solve.py +1498 -0
  155. tabs/style_sheet.py +114 -0
  156. tabs/tab_widget.py +14 -0
  157. tabs/visualize_geometry/__init__.py +4 -0
  158. tabs/visualize_geometry/core_3d_viewer.py +253 -0
  159. tabs/visualize_geometry/features/__init__.py +10 -0
  160. tabs/visualize_geometry/features/axes_gizmo.py +173 -0
  161. tabs/visualize_geometry/features/background.py +161 -0
  162. tabs/visualize_geometry/features/blueprint.py +685 -0
  163. tabs/visualize_geometry/features/camera.py +364 -0
  164. tabs/visualize_geometry/features/drag_aircraft.py +219 -0
  165. tabs/visualize_geometry/features/grid.py +194 -0
  166. tabs/visualize_geometry/features/measurement.py +367 -0
  167. tabs/visualize_geometry/features/screenshot.py +91 -0
  168. tabs/visualize_geometry/geometry_helper_functions.py +3 -0
  169. tabs/visualize_geometry/visualize_geometry.py +731 -0
  170. utilities.py +257 -0
@@ -0,0 +1,259 @@
1
+ # RCAIDE_GUI/tabs/geometry/frames/powertrain/powertrain_frame.py
2
+ #
3
+ # Created: Dec 2025, M. Clarke
4
+
5
+ # ----------------------------------------------------------------------------------------------------------------------
6
+ # IMPORT
7
+ # ----------------------------------------------------------------------------------------------------------------------
8
+ import RCAIDE
9
+ from PyQt6.QtCore import Qt
10
+ from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QScrollArea, QSpacerItem, QSizePolicy, \
11
+ QPushButton, QLineEdit, QComboBox
12
+
13
+ from tabs.geometry.frames import GeometryFrame
14
+ from tabs.geometry.widgets.powertrain.powertrain_widget import PowertrainWidget
15
+ from utilities import show_popup, clear_layout
16
+
17
+
18
+ class PowertrainFrame(GeometryFrame):
19
+ def __init__(self):
20
+ super(PowertrainFrame, self).__init__()
21
+
22
+ self.data_fields = {}
23
+ self.save_function = None
24
+ self.tab_index = -1
25
+ self.index = -1
26
+
27
+ # Create a scroll area
28
+ scroll_area = QScrollArea()
29
+ # Allow the widget inside to resize with the scroll area
30
+ scroll_area.setWidgetResizable(True)
31
+
32
+ # Create a widget to contain the layout
33
+ scroll_content = QWidget()
34
+ # Set the main layout inside the scroll content
35
+ layout = QVBoxLayout(scroll_content)
36
+ self.powertrain_layout = QVBoxLayout()
37
+
38
+ # Create a horizontal layout for the label and buttons
39
+ header_layout = QHBoxLayout()
40
+ header_layout.addWidget(QLabel("<b>Powertrain</b>"))
41
+
42
+ layout.addLayout(header_layout)
43
+ # Create a horizontal line
44
+ line_bar = QFrame()
45
+ line_bar.setFrameShape(QFrame.Shape.HLine)
46
+ line_bar.setFrameShadow(QFrame.Shadow.Sunken)
47
+
48
+ # Add the line bar to the main layout
49
+ layout.addWidget(line_bar)
50
+
51
+ self.main_powertrain_widget = self.make_powertrain_widget()
52
+ # Add the grid layout to the home layout
53
+ layout.addWidget(self.main_powertrain_widget)
54
+
55
+ layout.addWidget(line_bar)
56
+ layout.addLayout(self.powertrain_layout)
57
+
58
+ self.add_buttons_layout()
59
+
60
+ # Adds scroll function
61
+ layout.addItem(QSpacerItem(
62
+ 20, 40, QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding))
63
+
64
+ # Set the scroll content as the widget for the scroll area
65
+ scroll_area.setWidget(scroll_content)
66
+
67
+ # Set the main layout of the scroll area
68
+ layout_scroll = QVBoxLayout(self)
69
+ layout_scroll.addWidget(scroll_area)
70
+
71
+ # Set the layout to the main window/widget
72
+ self.setLayout(layout_scroll)
73
+
74
+ # noinspection PyUnresolvedReferences
75
+ def add_buttons_layout(self):
76
+ # define buttons
77
+ save_button = QPushButton("Save Energy Network Data", self)
78
+ # save_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
79
+ delete_button = QPushButton("Clear Energy Network", self)
80
+ delete_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
81
+
82
+ # define action of buttons
83
+ save_button.clicked.connect(self.save_data)
84
+ delete_button.clicked.connect(self.create_new_structure)
85
+
86
+ # Create a QHBoxLayout to contain the buttons
87
+ buttons_layout = QHBoxLayout()
88
+ buttons_layout.addWidget(save_button)
89
+ buttons_layout.addWidget(delete_button)
90
+
91
+ self.powertrain_layout.addLayout(buttons_layout)
92
+
93
+ def make_powertrain_widget(self):
94
+ """Create a widget for the powertrain section.
95
+
96
+ Returns:
97
+ QWidget: The main powertrain widget."""
98
+ main_powertrain_widget = QWidget()
99
+ main_layout = QVBoxLayout()
100
+ name_layout = QHBoxLayout()
101
+
102
+ # add spacing
103
+ spacer_left = QSpacerItem(
104
+ 50, 5, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
105
+ spacer_right = QSpacerItem(
106
+ 200, 5, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
107
+ name_layout.addItem(spacer_left)
108
+ name_layout.addWidget(QLabel("Name: "))
109
+ self.name_line_edit = QLineEdit(self)
110
+ name_layout.addWidget(self.name_line_edit)
111
+ name_layout.addItem(spacer_right)
112
+
113
+ # Energy Network
114
+ energy_label = QLabel("Energy Network Type:")
115
+ energy_label.setFixedWidth(100) # Adjust width of label
116
+ name_layout.addWidget(energy_label)
117
+ self.powertrain_combo = QComboBox()
118
+ self.powertrain_combo.addItems(["Select Network Type", "Fuel", "Electric", "Hybrid", "Hydrogen"])
119
+ self.powertrain_combo.setFixedWidth(400) # Fix width of combo box
120
+ name_layout.addWidget(self.powertrain_combo, alignment=Qt.AlignmentFlag.AlignLeft)
121
+
122
+ # Connect signal
123
+ self.powertrain_combo.currentIndexChanged.connect(self.display_selected_network)
124
+
125
+ main_layout.addLayout(name_layout)
126
+ main_powertrain_widget.setLayout(main_layout)
127
+ return main_powertrain_widget
128
+
129
+ def set_save_function(self, function):
130
+ self.save_function = function
131
+
132
+ def set_tab_index(self, index):
133
+ self.tab_index = index
134
+
135
+ def get_data_values(self):
136
+ """Retrieve the entered data values from the widgets."""
137
+ selected_network = self.powertrain_combo.currentText()
138
+ data = {"energy network selected": selected_network}
139
+
140
+ assert self.name_line_edit is not None
141
+ data["name"] = self.name_line_edit.text()
142
+
143
+ if selected_network == "Fuel":
144
+ # Add the data values from each fuel line widget to an array
145
+ item = self.powertrain_layout.itemAt(0)
146
+ assert item is not None
147
+ widget = item.widget()
148
+ assert widget is not None and isinstance(widget,PowertrainWidget)
149
+ data_values, net = widget.get_data_values()
150
+
151
+ if isinstance(data_values, bool):
152
+ return False, False
153
+
154
+ # add the fuel line data to the main data
155
+ data["powertrain"] = data_values
156
+
157
+ return data, net
158
+
159
+ def create_rcaide_structure(self):
160
+ selected_network = self.powertrain_combo.currentText()
161
+ if selected_network == "Fuel":
162
+ item = self.powertrain_layout.itemAt(0)
163
+ assert item is not None
164
+ widget = item.widget()
165
+ assert widget is not None and isinstance(widget, PowertrainWidget)
166
+ _, net = widget.get_data_values()
167
+ else:
168
+ return None
169
+
170
+ return net
171
+
172
+ def save_data(self):
173
+ """Call the save function and pass the entered data to it."""
174
+ entered_data, component = self.get_data_values()
175
+ if isinstance(entered_data, bool):
176
+ return
177
+
178
+ if self.save_function:
179
+ if self.index >= 0:
180
+ self.index = self.save_function(
181
+ tab_index=self.tab_index, index=self.index, data=entered_data)
182
+ return
183
+ else:
184
+ self.index = self.save_function(
185
+ tab_index=self.tab_index, vehicle_component=component, data=entered_data, new=True)
186
+
187
+ show_popup("Data Saved!", self)
188
+
189
+ def load_data(self, data, index):
190
+ """Load the data into the widgets.
191
+
192
+ Args:
193
+ data: The data to be loaded into the widgets.
194
+ index: The index of the data in the list.
195
+ """
196
+
197
+ # Load the name into the name line edit
198
+ self.index = index
199
+ assert self.name_line_edit is not None
200
+ self.name_line_edit.setText(data["name"])
201
+
202
+ # Load the selected network into the combo box
203
+ selected_network = data.get("energy network selected", "")
204
+ network_index = self.powertrain_combo.findText(selected_network)
205
+ if network_index != -1:
206
+ self.powertrain_combo.setCurrentIndex(network_index)
207
+
208
+ # Clear existing sections before loading new ones
209
+ clear_layout(self.powertrain_layout)
210
+
211
+ # Load sections based on the selected network
212
+ if selected_network == "Fuel":
213
+ powertrain_widget = PowertrainWidget()
214
+ powertrain_widget.load_data_values(data["powertrain"])
215
+ self.powertrain_layout.addWidget(powertrain_widget)
216
+
217
+ self.add_buttons_layout()
218
+
219
+ def create_new_structure(self):
220
+ """Create a new powertrain structure."""
221
+
222
+ # Clear the main data values
223
+ for data_field in self.data_fields.values():
224
+ line_edit, unit_picker = data_field
225
+ line_edit.clear()
226
+ unit_picker.set_index(0)
227
+
228
+ # Clear the name line edit
229
+ while self.powertrain_layout.count():
230
+ item = self.powertrain_layout.takeAt(0)
231
+ assert item is not None
232
+
233
+ widget = item.widget()
234
+ assert widget is not None
235
+ widget.deleteLater()
236
+
237
+ assert self.name_line_edit is not None
238
+ self.name_line_edit.clear()
239
+ self.index = -1
240
+
241
+ def delete_data(self):
242
+ pass
243
+
244
+ def display_selected_network(self, index):
245
+ selected_network = self.powertrain_combo.currentText()
246
+ # Clear the layout first
247
+ clear_layout(self.powertrain_layout)
248
+
249
+ if selected_network == "Fuel":
250
+ self.main_powertrain_widget = PowertrainWidget()
251
+ self.powertrain_layout.addWidget(self.main_powertrain_widget)
252
+ elif selected_network == "None Selected":
253
+ # Do nothing or add blank widget
254
+ pass
255
+ else:
256
+ # Handle other energy network options here
257
+ pass
258
+
259
+ self.add_buttons_layout()
@@ -0,0 +1,5 @@
1
+ # RCAIDE_GUI/tabs/geometry/frames/powertrain/propulsors/__init__.py
2
+ # ----------------------------------------------------------------------------------------------------------------------
3
+ # IMPORT
4
+ # ----------------------------------------------------------------------------------------------------------------------
5
+ from tabs.geometry.frames.powertrain.propulsors.propulsor_frame import PropulsorFrame
@@ -0,0 +1,146 @@
1
+ # RCAIDE_GUI/tabs/geometry/frames/powertrain/propulsors/propulsor_frame.py
2
+ #
3
+ # Created: Dec 2025, M. Clarke
4
+
5
+ # ----------------------------------------------------------------------------------------------------------------------
6
+ # IMPORT
7
+ # ----------------------------------------------------------------------------------------------------------------------
8
+ # RCAIDE imports
9
+ import RCAIDE
10
+
11
+ # PyQT Imports
12
+ from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton, QLineEdit, QHBoxLayout, \
13
+ QSpacerItem, QSizePolicy, QScrollArea, QFrame
14
+
15
+ # RCAIDE GUI imports
16
+ from tabs.geometry.widgets.powertrain.propulsors.turbofan_widget import TurbofanWidget
17
+ from common_widgets import DataEntryWidget
18
+ from utilities import show_popup, create_line_bar, set_data, Units, create_scroll_area, clear_layout
19
+ import rcaide_io
20
+
21
+ # ---------------------------------------------------------------------------------------------------------------------
22
+ # Propulsor Frame
23
+ # ----------------------------------------------------------------------------------------------------------------------
24
+ class PropulsorFrame(QWidget):
25
+ def __init__(self):
26
+ super(PropulsorFrame, self).__init__()
27
+ self.data_entry_widget: DataEntryWidget | None = None
28
+
29
+ # List to store data values propulsor_ sections
30
+ self.propulsor_sections_layout = QVBoxLayout()
31
+
32
+ # Create a horizontal layout for the label and buttons
33
+ header_layout = QVBoxLayout()
34
+ # label = QLabel("<u><b>Propulsor Frame</b></u>")
35
+
36
+ layout = self.create_scroll_layout()
37
+
38
+ # header_layout.addWidget(label)
39
+
40
+ # Add propulsor_ Section Button
41
+ add_turbofan_button = QPushButton("Add Turbofan", self)
42
+ add_turbofan_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
43
+ add_turbofan_button.setMaximumWidth(200)
44
+ add_turbofan_button.clicked.connect(self.add_turbofan)
45
+ header_layout.addWidget(add_turbofan_button)
46
+
47
+ layout.addLayout(header_layout)
48
+
49
+ # Create a horizontal line
50
+ line_bar = QFrame()
51
+ line_bar.setFrameShape(QFrame.Shape.HLine)
52
+ line_bar.setFrameShadow(QFrame.Shadow.Sunken)
53
+ line_bar.setStyleSheet("background-color: light grey;")
54
+
55
+ # Add the line bar to the main layout
56
+ layout.addWidget(line_bar)
57
+
58
+ # Add the layout for additional propulsor_ sections to the main layout
59
+ layout.addLayout(self.propulsor_sections_layout)
60
+
61
+ # Create a QHBoxLayout to contain the buttons
62
+ button_layout = QHBoxLayout()
63
+
64
+ # Add the button layout to the main layout
65
+ layout.addLayout(button_layout)
66
+
67
+ # Adds scroll function
68
+ layout.addItem(QSpacerItem(20, 40, QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding))
69
+
70
+ def get_data_values(self):
71
+ """Retrieve the entered data values from the dictionary for the propulsor sections."""
72
+
73
+ # Collect data from additional fuselage_widget
74
+ data = []
75
+ propulsors = []
76
+ rcaide_io.propulsor_names = [[]]
77
+ for index in range(self.propulsor_sections_layout.count()):
78
+ item = self.propulsor_sections_layout.itemAt(index)
79
+ assert item is not None
80
+ widget = item.widget()
81
+ assert widget is not None and isinstance(widget, TurbofanWidget)
82
+
83
+ propulsor_data, propulsor = widget.get_data_values()
84
+ data.append(propulsor_data)
85
+ propulsors.append(propulsor)
86
+
87
+ return data, propulsors
88
+
89
+ def load_data(self, data):
90
+ while self.propulsor_sections_layout.count():
91
+ item = self.propulsor_sections_layout.takeAt(0)
92
+ assert item is not None
93
+ widget = item.widget()
94
+ assert widget is not None
95
+
96
+ self.propulsor_sections_layout.removeWidget(widget)
97
+ widget.deleteLater()
98
+
99
+ for propulsor_data in data:
100
+ self.propulsor_sections_layout.addWidget(TurbofanWidget(
101
+ self.propulsor_sections_layout.count(), self.on_delete_button_pressed, propulsor_data))
102
+
103
+ def delete_data(self):
104
+ """Delete the entered data or perform any other action."""
105
+ # TODO: Implement proper deletion of data
106
+
107
+ def add_turbofan(self):
108
+ self.propulsor_sections_layout.addWidget(
109
+ TurbofanWidget(self.propulsor_sections_layout.count(), self.on_delete_button_pressed))
110
+
111
+ def on_delete_button_pressed(self, index):
112
+ propulsor = self.propulsor_sections_layout.itemAt(index)
113
+ if propulsor is None:
114
+ return
115
+
116
+ widget = propulsor.widget()
117
+ if widget is None:
118
+ return
119
+
120
+ widget.deleteLater()
121
+ self.propulsor_sections_layout.removeWidget(widget)
122
+ self.propulsor_sections_layout.update()
123
+
124
+ for i in range(index, self.propulsor_sections_layout.count()):
125
+ propulsor = self.propulsor_sections_layout.itemAt(i)
126
+ if propulsor is None:
127
+ continue
128
+
129
+ widget = propulsor.widget()
130
+ if widget is None or not isinstance(widget, TurbofanWidget):
131
+ continue
132
+
133
+ widget.index = i
134
+
135
+ def update_units(self, line_edit, unit_combobox):
136
+ pass
137
+
138
+ def create_scroll_layout(self):
139
+ # Create a widget to contain the layout
140
+ scroll_content = QWidget()
141
+ layout = QVBoxLayout(scroll_content) # Set the main layout inside the scroll content
142
+
143
+ # Set the main layout of the widget
144
+ self.setLayout(layout)
145
+
146
+ return layout
@@ -0,0 +1,6 @@
1
+ # RCAIDE_GUI/tabs/geometry/frames/powertrain/sources/__init__.py
2
+ # ----------------------------------------------------------------------------------------------------------------------
3
+ # IMPORT
4
+ # ----------------------------------------------------------------------------------------------------------------------
5
+
6
+ from tabs.geometry.frames.powertrain.sources.energy_source_frame import EnergySourceFrame
@@ -0,0 +1,147 @@
1
+ # RCAIDE_GUI/tabs/geometry/frames/powertrain/sources/energy_source_frame.py
2
+ #
3
+ # Created: Dec 2025, M. Clarke
4
+
5
+ # ----------------------------------------------------------------------------------------------------------------------
6
+ # IMPORT
7
+ # ----------------------------------------------------------------------------------------------------------------------
8
+ # RCAIDE imports
9
+ import RCAIDE
10
+
11
+ # PyQT Imports
12
+ from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QHBoxLayout, \
13
+ QSpacerItem, QSizePolicy, QFrame
14
+
15
+ # RCAIDE GUI imports
16
+ from tabs.geometry.widgets.powertrain.sources.fuel_tank_widget import FuelTankWidget
17
+ from common_widgets import DataEntryWidget
18
+
19
+
20
+ # ---------------------------------------------------------------------------------------------------------------------
21
+ # Energy Source Frame
22
+ # ----------------------------------------------------------------------------------------------------------------------
23
+ class EnergySourceFrame(QWidget):
24
+ def __init__(self):
25
+ super(EnergySourceFrame, self).__init__()
26
+
27
+ self.save_function = None
28
+ self.data_entry_widget: DataEntryWidget | None = None
29
+
30
+ # List to store data values source_ sections
31
+ self.source_sections_layout = QVBoxLayout()
32
+
33
+ # Create a horizontal layout for the label and buttons
34
+ header_layout = QVBoxLayout()
35
+ # label = QLabel("<u><b>source Frame</b></u>")
36
+
37
+ layout = self.create_scroll_layout()
38
+
39
+ # header_layout.addWidget(label)
40
+
41
+ # Add source_ Section Button
42
+ add_fuel_tank_button = QPushButton("Add Fuel Tank", self)
43
+ add_fuel_tank_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
44
+ add_fuel_tank_button.setMaximumWidth(200)
45
+ add_fuel_tank_button.clicked.connect(self.add_fuel_tank)
46
+
47
+ header_layout.addWidget(add_fuel_tank_button)
48
+
49
+ layout.addLayout(header_layout)
50
+
51
+ # Create a horizontal line
52
+ line_bar = QFrame()
53
+ line_bar.setFrameShape(QFrame.Shape.HLine)
54
+ line_bar.setFrameShadow(QFrame.Shadow.Sunken)
55
+ line_bar.setStyleSheet("background-color: light grey;")
56
+
57
+ # Add the line bar to the main layout
58
+ layout.addWidget(line_bar)
59
+
60
+ # Add the layout for additional source_ sections to the main layout
61
+ layout.addLayout(self.source_sections_layout)
62
+
63
+ # Create a QHBoxLayout to contain the buttons
64
+ button_layout = QHBoxLayout()
65
+
66
+ # Add the button layout to the main layout
67
+ layout.addLayout(button_layout)
68
+
69
+ # Adds scroll function
70
+ layout.addItem(QSpacerItem(
71
+ 20, 40, QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding))
72
+
73
+ def get_data_values(self):
74
+ data = []
75
+ sources = []
76
+ for index in range(self.source_sections_layout.count()):
77
+ item = self.source_sections_layout.itemAt(index)
78
+ assert item is not None
79
+ widget = item.widget()
80
+ assert widget is not None and isinstance(widget, FuelTankWidget)
81
+
82
+ source_data, fuel_tank = widget.get_data_values()
83
+ data.append(source_data)
84
+ sources.append(fuel_tank)
85
+
86
+ return data, sources
87
+
88
+ def load_data(self, data):
89
+ while self.source_sections_layout.count():
90
+ widget_item = self.source_sections_layout.itemAt(0)
91
+ assert widget_item is not None
92
+ widget = widget_item.widget()
93
+ assert widget is not None
94
+
95
+ self.source_sections_layout.removeWidget(widget)
96
+ widget.deleteLater()
97
+
98
+ for section_data in data:
99
+ self.source_sections_layout.addWidget(FuelTankWidget(
100
+ self.source_sections_layout.count(), self.on_delete_button_pressed, section_data))
101
+
102
+ def delete_data(self):
103
+ # TODO Implement proper deletion of data
104
+ pass
105
+
106
+ def add_fuel_tank(self):
107
+ self.source_sections_layout.addWidget(
108
+ FuelTankWidget(self.source_sections_layout.count(), self.on_delete_button_pressed))
109
+
110
+ def on_delete_button_pressed(self, index):
111
+ tank = self.source_sections_layout.itemAt(index)
112
+ if tank is None:
113
+ return
114
+
115
+ widget = tank.widget()
116
+ if widget is None:
117
+ return
118
+
119
+ widget.deleteLater()
120
+ self.source_sections_layout.removeWidget(widget)
121
+ self.source_sections_layout.update()
122
+
123
+ for i in range(index, self.source_sections_layout.count()):
124
+ tank = self.source_sections_layout.itemAt(i)
125
+ if tank is None:
126
+ continue
127
+
128
+ widget = tank.widget()
129
+ if widget is None or not isinstance(widget, FuelTankWidget):
130
+ continue
131
+
132
+ widget.index = i
133
+
134
+ def set_save_function(self, function):
135
+ self.save_function = function
136
+
137
+ def create_scroll_layout(self):
138
+ # Create a widget to contain the layout
139
+ scroll_content = QWidget()
140
+
141
+ # Set the main layout inside the scroll content
142
+ layout = QVBoxLayout(scroll_content)
143
+
144
+ # Set the main layout of the widget
145
+ self.setLayout(layout)
146
+
147
+ return layout