setupEM 0.1.2__tar.gz → 0.1.3__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.
- {setupem-0.1.2 → setupem-0.1.3}/PKG-INFO +1 -1
- {setupem-0.1.2 → setupem-0.1.3}/pyproject.toml +1 -1
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM/setupEM.py +109 -42
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM.egg-info/PKG-INFO +1 -1
- {setupem-0.1.2 → setupem-0.1.3}/README.md +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/setup.cfg +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/examples/pcb_lowpass/palace_pcb_lowpass.py +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/examples/sg13_balun_140-170/palace_balun_mesh2.py +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/examples/sg13_microstrip_fast/palace_demo_line.py +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/examples/sg13_rfcmim/palace_rfcmim.py +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM/__init__.py +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM.egg-info/SOURCES.txt +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM.egg-info/dependency_links.txt +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM.egg-info/entry_points.txt +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM.egg-info/requires.txt +0 -0
- {setupem-0.1.2 → setupem-0.1.3}/src/setupEM.egg-info/top_level.txt +0 -0
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
########################################################################
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
import sys, json, os, tempfile, pathlib, ast
|
|
20
|
+
import sys, json, os, tempfile, pathlib, ast, webbrowser
|
|
21
21
|
from PySide6.QtWidgets import (
|
|
22
22
|
QApplication, QMainWindow, QWidget, QHBoxLayout, QVBoxLayout,
|
|
23
23
|
QLabel, QLineEdit,QComboBox,QTableWidget,QHeaderView,
|
|
@@ -123,31 +123,65 @@ def simulation_ports_to_struct (simulation_ports):
|
|
|
123
123
|
return all_ports_list
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
126
|
+
|
|
127
|
+
# ----------------------------------------
|
|
128
|
+
|
|
129
|
+
class FileDropLineEdit(QLineEdit):
|
|
130
|
+
def __init__(self, allowed_extensions=None, on_file_dropped=None):
|
|
131
|
+
super().__init__()
|
|
132
|
+
self.setAcceptDrops(True)
|
|
133
|
+
|
|
134
|
+
# Example: [".png", ".txt"]
|
|
135
|
+
self.allowed_extensions = allowed_extensions or []
|
|
136
|
+
|
|
137
|
+
# Function to execute after a successful drop
|
|
138
|
+
# Signature: callback(path: str)
|
|
139
|
+
self.on_file_dropped = on_file_dropped
|
|
140
|
+
|
|
141
|
+
def dragEnterEvent(self, event):
|
|
142
|
+
if event.mimeData().hasUrls() and self._contains_valid_files(event):
|
|
143
|
+
event.acceptProposedAction()
|
|
144
|
+
else:
|
|
145
|
+
event.ignore()
|
|
146
|
+
|
|
147
|
+
def dragMoveEvent(self, event):
|
|
148
|
+
if event.mimeData().hasUrls() and self._contains_valid_files(event):
|
|
149
|
+
event.acceptProposedAction()
|
|
150
|
+
else:
|
|
151
|
+
event.ignore()
|
|
152
|
+
|
|
153
|
+
def dropEvent(self, event):
|
|
154
|
+
if event.mimeData().hasUrls():
|
|
155
|
+
files = [url.toLocalFile() for url in event.mimeData().urls()]
|
|
156
|
+
valid_files = [f for f in files if self._is_valid(f)]
|
|
157
|
+
|
|
158
|
+
if valid_files:
|
|
159
|
+
file_path = valid_files[0]
|
|
160
|
+
self.setText(file_path)
|
|
161
|
+
event.acceptProposedAction()
|
|
162
|
+
|
|
163
|
+
# 🚀 Call the user function if set
|
|
164
|
+
if self.on_file_dropped:
|
|
165
|
+
self.on_file_dropped(file_path)
|
|
166
|
+
|
|
167
|
+
else:
|
|
168
|
+
self.setText("Invalid file type")
|
|
169
|
+
event.ignore()
|
|
170
|
+
|
|
171
|
+
def _contains_valid_files(self, event):
|
|
172
|
+
for url in event.mimeData().urls():
|
|
173
|
+
if self._is_valid(url.toLocalFile()):
|
|
174
|
+
return True
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
def _is_valid(self, path):
|
|
178
|
+
if not self.allowed_extensions:
|
|
179
|
+
return True
|
|
180
|
+
ext = os.path.splitext(path)[1].lower()
|
|
181
|
+
return ext in self.allowed_extensions
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
151
185
|
|
|
152
186
|
# ---------- FILE INPUT TAB ----------
|
|
153
187
|
class FileInputTab(QWidget):
|
|
@@ -165,7 +199,8 @@ class FileInputTab(QWidget):
|
|
|
165
199
|
self.gds_layout = QVBoxLayout()
|
|
166
200
|
|
|
167
201
|
self.gds_file_layout = QHBoxLayout()
|
|
168
|
-
self.gds_file_edit =
|
|
202
|
+
self.gds_file_edit = FileDropLineEdit([".gds",".GDS"], self.set_gds_file)
|
|
203
|
+
self.gds_file_edit.setText( "Please choose a file ===>")
|
|
169
204
|
self.gds_file_edit.setStyleSheet(EDIT_STYLE_REQUIRED)
|
|
170
205
|
|
|
171
206
|
self.browse_gds_btn = QPushButton("Browse ...")
|
|
@@ -222,7 +257,8 @@ class FileInputTab(QWidget):
|
|
|
222
257
|
self.XML_layout = QVBoxLayout()
|
|
223
258
|
|
|
224
259
|
self.XML_file_layout = QHBoxLayout()
|
|
225
|
-
self.XML_file_edit =
|
|
260
|
+
self.XML_file_edit = FileDropLineEdit([".xml",".XML"], self.set_XML_file)
|
|
261
|
+
self.XML_file_edit.setText("Please choose a file ===>")
|
|
226
262
|
self.XML_file_edit.setStyleSheet(EDIT_STYLE_REQUIRED)
|
|
227
263
|
|
|
228
264
|
self.browse_XML_btn = QPushButton("Browse ...")
|
|
@@ -248,13 +284,18 @@ class FileInputTab(QWidget):
|
|
|
248
284
|
previous_directory = os.path.dirname(previous_file)
|
|
249
285
|
if not os.path.isdir(previous_directory):
|
|
250
286
|
previous_directory = ""
|
|
287
|
+
|
|
288
|
+
filename, _ = QFileDialog.getOpenFileName(self, "Select GDSII File",previous_directory,"*.gds;;*.*")
|
|
289
|
+
if filename:
|
|
290
|
+
self.set_gds_file(filename)
|
|
251
291
|
|
|
252
|
-
file_path, _ = QFileDialog.getOpenFileName(self, "Select GDSII File",previous_directory,"*.gds;;*.*")
|
|
253
|
-
if file_path:
|
|
254
|
-
self.gds_file_edit.setText(file_path)
|
|
255
|
-
saved_values ["GdsFile"] = file_path.replace('\\','/')
|
|
256
292
|
|
|
257
|
-
|
|
293
|
+
def set_gds_file(self, filename):
|
|
294
|
+
# clear model name and target dir if they were auto-generated from previous model
|
|
295
|
+
self.MainWindow.clear_modelname_and_targetdir()
|
|
296
|
+
self.gds_file_edit.setText(filename)
|
|
297
|
+
saved_values ["GdsFile"] = filename.replace('\\','/')
|
|
298
|
+
# file is read when leaving the files tab
|
|
258
299
|
|
|
259
300
|
def browse_XML_file(self):
|
|
260
301
|
# start browsing from previous file location, if valid
|
|
@@ -265,9 +306,13 @@ class FileInputTab(QWidget):
|
|
|
265
306
|
|
|
266
307
|
filename, _ = QFileDialog.getOpenFileName(self, "Select XML Stackup File",previous_directory,"*.xml;;*.*")
|
|
267
308
|
if filename:
|
|
268
|
-
self.
|
|
269
|
-
|
|
270
|
-
|
|
309
|
+
self.set_XML_file(filename)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def set_XML_file (self, filename):
|
|
313
|
+
self.XML_file_edit.setText(filename)
|
|
314
|
+
saved_values ["SubstrateFile"] = filename.replace('\\','/')
|
|
315
|
+
# file is read when leaving the files tab
|
|
271
316
|
|
|
272
317
|
|
|
273
318
|
def load_values(self):
|
|
@@ -1734,6 +1779,8 @@ class CodeEditor(QPlainTextEdit):
|
|
|
1734
1779
|
|
|
1735
1780
|
|
|
1736
1781
|
# ---------- MAIN WINDOW ----------
|
|
1782
|
+
|
|
1783
|
+
|
|
1737
1784
|
class MainWindow(QMainWindow):
|
|
1738
1785
|
TAB_HEADER_COLORS = ["#FFCDD2", "#C8E6C9", "#BBDEFB", "#FFF9C4", "#D1C4E9"]
|
|
1739
1786
|
|
|
@@ -1823,6 +1870,18 @@ class MainWindow(QMainWindow):
|
|
|
1823
1870
|
file_menu.addSeparator()
|
|
1824
1871
|
file_menu.addAction(exit_action)
|
|
1825
1872
|
|
|
1873
|
+
help_menu = menu_bar.addMenu("&Help")
|
|
1874
|
+
self.web_gds2palace_action = QAction("gds2palace", self)
|
|
1875
|
+
self.web_manual_action = QAction("Documentation", self)
|
|
1876
|
+
self.web_examples_action = QAction("Examples", self)
|
|
1877
|
+
self.web_gds2palace_action.triggered.connect(lambda: webbrowser.open("https://github.com/VolkerMuehlhaus/gds2palace_ihp_sg13g2"))
|
|
1878
|
+
self.web_manual_action.triggered.connect(lambda: webbrowser.open("https://github.com/VolkerMuehlhaus/gds2palace_ihp_sg13g2/tree/main/doc"))
|
|
1879
|
+
self.web_examples_action.triggered.connect(lambda: webbrowser.open("https://github.com/VolkerMuehlhaus/gds2palace_ihp_sg13g2/tree/main/workflow"))
|
|
1880
|
+
help_menu.addAction(self.web_gds2palace_action)
|
|
1881
|
+
help_menu.addAction(self.web_manual_action)
|
|
1882
|
+
help_menu.addAction(self.web_examples_action)
|
|
1883
|
+
|
|
1884
|
+
|
|
1826
1885
|
# ---------- Menu actions ----------
|
|
1827
1886
|
|
|
1828
1887
|
|
|
@@ -2021,7 +2080,6 @@ class MainWindow(QMainWindow):
|
|
|
2021
2080
|
QMessageBox.information(self, f"Could not load file {file_path}")
|
|
2022
2081
|
|
|
2023
2082
|
|
|
2024
|
-
|
|
2025
2083
|
def save_user_inputs_to_file(self, filename):
|
|
2026
2084
|
# make sure all tabs save their values
|
|
2027
2085
|
self.save_all_tabs()
|
|
@@ -2066,6 +2124,16 @@ class MainWindow(QMainWindow):
|
|
|
2066
2124
|
QMessageBox.warning(self, "Error", f"Failed to export model code to {file_path}: {e}")
|
|
2067
2125
|
|
|
2068
2126
|
|
|
2127
|
+
def clear_modelname_and_targetdir(self):
|
|
2128
|
+
# clear model name in output settings, to avoid overwriting when changing data
|
|
2129
|
+
saved_values['model_basename']=''
|
|
2130
|
+
# clear target directory if is the gds directory, but keep if other value
|
|
2131
|
+
gds_dir = os.path.dirname(saved_values['GdsFile'])
|
|
2132
|
+
target_dir = saved_values['sim_path']
|
|
2133
|
+
if target_dir.upper()==gds_dir.upper():
|
|
2134
|
+
saved_values['sim_path']=''
|
|
2135
|
+
|
|
2136
|
+
|
|
2069
2137
|
|
|
2070
2138
|
def parse_assignments(file_path):
|
|
2071
2139
|
# parse lines from a Python model code for variable assigments
|
|
@@ -2132,12 +2200,11 @@ def parse_python_ports_definitions (file_path):
|
|
|
2132
2200
|
|
|
2133
2201
|
def main():
|
|
2134
2202
|
app = QApplication(sys.argv)
|
|
2203
|
+
|
|
2135
2204
|
if sys.platform.startswith("win"):
|
|
2136
|
-
app.setStyle("Windows")
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
app.setStyle("Fusion")
|
|
2140
|
-
win = MainWindow()
|
|
2205
|
+
app.setStyle(QStyleFactory.create("Windows"))
|
|
2206
|
+
|
|
2207
|
+
win = MainWindow()
|
|
2141
2208
|
win.show()
|
|
2142
2209
|
sys.exit(app.exec())
|
|
2143
2210
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|