22
22
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
23
# SOFTWARE.
24
24
25
+ from dataclasses import asdict
26
+ from dataclasses import dataclass
27
+ import os
25
28
from pathlib import Path
29
+ import tkinter
26
30
27
31
import ansys .aedt .core
28
32
from ansys .aedt .core import get_pyaedt_app
34
38
from ansys .aedt .core .extensions .misc import is_student
35
39
from ansys .aedt .core .visualization .advanced .misc import nastran_to_stl
36
40
37
- port = get_port ()
38
- version = get_aedt_version ()
39
- aedt_process_id = get_process_id ()
40
- is_student = is_student ()
41
41
42
- # Extension batch arguments
43
- extension_arguments = {"decimate" : 0.0 , "lightweight" : False , "planar" : True , "file_path" : "" }
44
- extension_description = "Import Nastran or STL file"
42
+ @dataclass
43
+ class ExtensionData :
44
+ decimate : float = 0.0
45
+ lightweight : bool = False
46
+ planar : bool = True
47
+ file_path : str = ""
45
48
46
49
47
- def frontend (): # pragma: no cover
48
- import tkinter
49
- from tkinter import filedialog
50
- from tkinter import ttk
51
-
52
- import PIL .Image
53
- import PIL .ImageTk
54
-
55
- from ansys .aedt .core .extensions .misc import ExtensionTheme
56
-
57
- master = tkinter .Tk ()
58
- master .title ("Import Nastran or STL file" )
50
+ PORT = get_port ()
51
+ VERSION = get_aedt_version ()
52
+ AEDT_PROCESS_ID = get_process_id ()
53
+ IS_STUDENT = is_student ()
54
+ EXTENSION_TITLE = "Import Nastran or STL file"
55
+ EXTENSION_DEFAULT_ARGUMENTS = {"decimate" : 0.0 , "lightweight" : False , "planar" : True , "file_path" : "" }
59
56
60
- # Detect if user closes the UI
61
- master .flag = False
57
+ result = None
62
58
63
- # Load the logo for the main window
64
- icon_path = Path (ansys .aedt .core .extensions .__path__ [0 ]) / "images" / "large" / "logo.png"
65
- im = PIL .Image .open (icon_path )
66
- photo = PIL .ImageTk .PhotoImage (im )
67
59
68
- # Set the icon for the main window
69
- master .iconphoto (True , photo )
70
-
71
- # Configure style for ttk buttons
72
- style = ttk .Style ()
73
- theme = ExtensionTheme ()
74
-
75
- # Apply light theme initially
76
- theme .apply_light_theme (style )
77
- master .theme = "light"
60
+ def create_ui (withdraw = False ):
61
+ from tkinter import filedialog
62
+ from tkinter import ttk
78
63
79
- # Set background color of the window (optional)
80
- master .configure (bg = theme .light ["widget_bg" ])
64
+ from ansys .aedt .core .extensions .misc import create_default_ui
81
65
82
- label2 = ttk . Label ( master , text = "Browse file:" , style = "PyAEDT.TLabel" )
66
+ root , theme , style = create_default_ui ( EXTENSION_TITLE , withdraw = withdraw )
83
67
68
+ label2 = ttk .Label (root , text = "Browse file:" , style = "PyAEDT.TLabel" )
84
69
label2 .grid (row = 0 , column = 0 , pady = 10 )
85
- text = tkinter .Text (master , width = 40 , height = 1 )
70
+
71
+ text = tkinter .Text (root , width = 40 , height = 1 , name = "file_path_text" )
86
72
text .configure (bg = theme .light ["pane_bg" ], foreground = theme .light ["text" ], font = theme .default_font )
87
73
text .grid (row = 0 , column = 1 , pady = 10 , padx = 5 )
88
74
@@ -94,105 +80,97 @@ def browseFiles():
94
80
)
95
81
text .insert (tkinter .END , filename )
96
82
97
- b1 = ttk .Button (master , text = "..." , width = 10 , command = browseFiles , style = "PyAEDT.TButton" )
83
+ b1 = ttk .Button (root , text = "..." , width = 10 , command = browseFiles , style = "PyAEDT.TButton" , name = "browse_button " )
98
84
b1 .grid (row = 0 , column = 2 , pady = 10 )
99
85
100
- label = ttk .Label (master , text = "Decimation factor (0-0.9). It may affect results:" , style = "PyAEDT.TLabel" )
86
+ label = ttk .Label (root , text = "Decimation factor (0-0.9). It may affect results:" , style = "PyAEDT.TLabel" )
101
87
label .grid (row = 1 , column = 0 , pady = 10 )
102
88
103
- check = tkinter .Text (master , width = 20 , height = 1 )
89
+ check = tkinter .Text (root , width = 20 , height = 1 , name = "decimation_text" )
104
90
check .configure (bg = theme .light ["pane_bg" ], foreground = theme .light ["text" ], font = theme .default_font )
105
91
check .insert (tkinter .END , "0.0" )
106
92
check .grid (row = 1 , column = 1 , pady = 10 , padx = 5 )
107
93
108
- label = ttk .Label (master , text = "Import as lightweight (only HFSS):" , style = "PyAEDT.TLabel" )
94
+ label = ttk .Label (root , text = "Import as lightweight (only HFSS):" , style = "PyAEDT.TLabel" )
109
95
label .grid (row = 2 , column = 0 , pady = 10 )
110
- light = tkinter .IntVar ()
111
- check2 = ttk .Checkbutton (master , variable = light , style = "PyAEDT.TCheckbutton" )
96
+ light = tkinter .IntVar (root , name = "var_lightweight" )
97
+ check2 = ttk .Checkbutton (root , variable = light , style = "PyAEDT.TCheckbutton" , name = "check_lightweight " )
112
98
check2 .grid (row = 2 , column = 1 , pady = 10 , padx = 5 )
113
99
114
- label = ttk .Label (master , text = "Enable planar merge:" , style = "PyAEDT.TLabel" )
100
+ label = ttk .Label (root , text = "Enable planar merge:" , style = "PyAEDT.TLabel" )
115
101
label .grid (row = 3 , column = 0 , pady = 10 )
116
- planar = tkinter .IntVar (value = 1 )
117
- check3 = ttk .Checkbutton (master , variable = planar , style = "PyAEDT.TCheckbutton" )
102
+ planar = tkinter .IntVar (root , value = 1 )
103
+ check3 = ttk .Checkbutton (root , variable = planar , style = "PyAEDT.TCheckbutton" , name = "check_planar_merge " )
118
104
check3 .grid (row = 3 , column = 1 , pady = 10 , padx = 5 )
119
105
120
106
def toggle_theme ():
121
- if master .theme == "light" :
107
+ if root .theme == "light" :
122
108
set_dark_theme ()
123
- master .theme = "dark"
109
+ root .theme = "dark"
124
110
else :
125
111
set_light_theme ()
126
- master .theme = "light"
112
+ root .theme = "light"
127
113
128
114
def set_light_theme ():
129
- master .configure (bg = theme .light ["widget_bg" ])
115
+ root .configure (bg = theme .light ["widget_bg" ])
130
116
text .configure (bg = theme .light ["pane_bg" ], foreground = theme .light ["text" ], font = theme .default_font )
131
117
check .configure (bg = theme .light ["pane_bg" ], foreground = theme .light ["text" ], font = theme .default_font )
132
118
theme .apply_light_theme (style )
133
119
change_theme_button .config (text = "\u263d " ) # Sun icon for light theme
134
120
135
121
def set_dark_theme ():
136
- master .configure (bg = theme .dark ["widget_bg" ])
122
+ root .configure (bg = theme .dark ["widget_bg" ])
137
123
text .configure (bg = theme .dark ["pane_bg" ], foreground = theme .dark ["text" ], font = theme .default_font )
138
124
check .configure (bg = theme .dark ["pane_bg" ], foreground = theme .dark ["text" ], font = theme .default_font )
139
125
theme .apply_dark_theme (style )
140
126
change_theme_button .config (text = "\u2600 " ) # Moon icon for dark theme
141
127
142
128
# Create a frame for the toggle button to position it correctly
143
- button_frame = ttk .Frame (master , style = "PyAEDT.TFrame" , relief = tkinter .SUNKEN , borderwidth = 2 )
129
+ button_frame = ttk .Frame (
130
+ root , style = "PyAEDT.TFrame" , relief = tkinter .SUNKEN , borderwidth = 2 , name = "theme_button_frame"
131
+ )
144
132
button_frame .grid (row = 5 , column = 2 , pady = 10 , padx = 10 )
145
133
146
134
# Add the toggle theme button inside the frame
147
135
change_theme_button = ttk .Button (
148
- button_frame , width = 20 , text = "\u263d " , command = toggle_theme , style = "PyAEDT.TButton"
136
+ button_frame , width = 20 , text = "\u263d " , command = toggle_theme , style = "PyAEDT.TButton" , name = "theme_toggle_button"
149
137
)
150
138
151
139
change_theme_button .grid (row = 0 , column = 0 , padx = 0 )
152
140
153
141
def callback ():
154
- master .flag = True
155
- master .decimate_ui = float (check .get ("1.0" , tkinter .END ).strip ())
156
- master .lightweight_ui = True if light .get () == 1 else False
157
- master .planar_ui = True if planar .get () == 1 else False
158
- master .file_path_ui = text .get ("1.0" , tkinter .END ).strip ()
159
- master .destroy ()
142
+ global result
143
+ result = ExtensionData (
144
+ decimate = float (check .get ("1.0" , tkinter .END ).strip ()),
145
+ lightweight = True if light .get () == 1 else False ,
146
+ planar = True if planar .get () == 1 else False ,
147
+ file_path = text .get ("1.0" , tkinter .END ).strip (),
148
+ )
149
+ root .destroy ()
160
150
161
151
def preview ():
162
- master .decimate_ui = float (check .get ("1.0" , tkinter .END ).strip ())
163
- master .lightweight_ui = True if light .get () == 1 else False
164
- master .planar_ui = True if planar .get () == 1 else False
165
- master .file_path_ui = text .get ("1.0" , tkinter .END ).strip ()
152
+ decimate_ui = float (check .get ("1.0" , tkinter .END ).strip ())
153
+ file_path_ui = text .get ("1.0" , tkinter .END ).strip ()
154
+ if not file_path_ui :
155
+ raise ValueError ("Incorrect file path. Please select a valid file." )
156
+
157
+ if not Path (file_path_ui ).is_file ():
158
+ raise FileNotFoundError (f"File ({ file_path_ui } ) not found" )
166
159
167
- if master . file_path_ui .endswith (".nas" ):
168
- nastran_to_stl (input_file = master . file_path_ui , decimation = master . decimate_ui , preview = True )
160
+ if file_path_ui .endswith (".nas" ):
161
+ nastran_to_stl (file_path_ui , decimation = decimate_ui , preview = True )
169
162
else :
170
163
from ansys .aedt .core .visualization .advanced .misc import simplify_stl
171
164
172
- simplify_stl (master . file_path_ui , decimation = master . decimate_ui , preview = True )
165
+ simplify_stl (file_path_ui , decimation = decimate_ui , preview = True )
173
166
174
- b2 = ttk .Button (master , text = "Preview" , width = 40 , command = preview , style = "PyAEDT.TButton" )
167
+ b2 = ttk .Button (root , text = "Preview" , width = 40 , command = preview , style = "PyAEDT.TButton" , name = "preview_button " )
175
168
b2 .grid (row = 5 , column = 0 , pady = 10 , padx = 10 )
176
169
177
- b3 = ttk .Button (master , text = "Ok" , width = 40 , command = callback , style = "PyAEDT.TButton" )
170
+ b3 = ttk .Button (root , text = "Ok" , width = 40 , command = callback , style = "PyAEDT.TButton" , name = "ok_button " )
178
171
b3 .grid (row = 5 , column = 1 , pady = 10 , padx = 10 )
179
172
180
- tkinter .mainloop ()
181
-
182
- decimate_ui = getattr (master , "decimate_ui" , extension_arguments ["decimate" ])
183
- lightweight_ui = getattr (master , "lightweight_ui" , extension_arguments ["lightweight" ])
184
- planar_ui = getattr (master , "planar_ui" , extension_arguments ["planar" ])
185
- file_path_ui = getattr (master , "file_path_ui" , extension_arguments ["file_path" ])
186
-
187
- output_dict = {}
188
- if master .flag :
189
- output_dict = {
190
- "decimate" : decimate_ui ,
191
- "lightweight" : lightweight_ui ,
192
- "planar" : planar_ui ,
193
- "file_path" : file_path_ui ,
194
- }
195
- return output_dict
173
+ return root
196
174
197
175
198
176
def main (extension_args ):
@@ -204,10 +182,10 @@ def main(extension_args):
204
182
if file_path .is_file ():
205
183
app = ansys .aedt .core .Desktop (
206
184
new_desktop = False ,
207
- version = version ,
208
- port = port ,
209
- aedt_process_id = aedt_process_id ,
210
- student_version = is_student ,
185
+ version = VERSION ,
186
+ port = PORT ,
187
+ aedt_process_id = AEDT_PROCESS_ID ,
188
+ student_version = IS_STUDENT ,
211
189
)
212
190
213
191
active_project = app .active_project ()
@@ -233,28 +211,29 @@ def main(extension_args):
233
211
else :
234
212
app = ansys .aedt .core .Desktop (
235
213
new_desktop = False ,
236
- version = version ,
237
- port = port ,
238
- aedt_process_id = aedt_process_id ,
239
- student_version = is_student ,
214
+ version = VERSION ,
215
+ port = PORT ,
216
+ aedt_process_id = AEDT_PROCESS_ID ,
217
+ student_version = IS_STUDENT ,
240
218
)
241
219
app .logger .debug ("Wrong file selected. Select a .nas or .stl file" )
242
220
243
- if not extension_args [ "is_test" ]: # pragma: no cover
221
+ if "PYTEST_CURRENT_TEST" not in os . environ :
244
222
app .release_desktop (False , False )
245
223
return True
246
224
247
225
248
226
if __name__ == "__main__" : # pragma: no cover
249
- args = get_arguments (extension_arguments , extension_description )
227
+ args = get_arguments (EXTENSION_DEFAULT_ARGUMENTS , EXTENSION_TITLE )
250
228
251
229
# Open UI
252
230
if not args ["is_batch" ]: # pragma: no cover
253
- output = frontend ()
254
- if output :
255
- for output_name , output_value in output .items ():
256
- if output_name in extension_arguments :
257
- args [output_name ] = output_value
231
+ root = create_ui ()
232
+
233
+ tkinter .mainloop ()
234
+
235
+ if result :
236
+ args .update (asdict (result ))
258
237
main (args )
259
238
else :
260
239
main (args )
0 commit comments