def on_execute_gencase(self): """ Saves data into disk and uses GenCase to generate the case files.""" self.on_save_case() if not Case.the().executable_paths.gencase: warning_dialog(__("GenCase executable is not set.")) return gencase_full_path = path.abspath(Case.the().executable_paths.gencase) arguments = [ "{path}/{name}_Def".format(path=Case.the().path, name=Case.the().name), "{path}/{name}_out/{name}".format(path=Case.the().path, name=Case.the().name), "-save:+all" ] cmd_string = "{} {}".format(gencase_full_path, " ".join(arguments)) refocus_cwd() process = QtCore.QProcess(get_fc_main_window()) process.setWorkingDirectory(Case.the().path) ensure_process_is_executable_or_fail(gencase_full_path) process.start(gencase_full_path, arguments) debug("Executing -> {}".format(cmd_string)) process.waitForFinished() try: output = str(process.readAllStandardOutput().data(), encoding='utf-8') except UnicodeDecodeError: output = str(process.readAllStandardOutput().data(), encoding='latin1') if process.exitCode(): Case.the().info.is_gencase_done = False error_dialog( __("Error executing GenCase. Did you add objects to the case?. Another reason could be memory issues. View details for more info." ), output) else: try: total_particles_text = output[ output.index("Total particles: "):output.index(" (bound=")] total_particles = int( total_particles_text[total_particles_text.index(": ") + 2:]) Case.the().info.particle_number = total_particles GencaseCompletedDialog(particle_count=total_particles, detail_text=output, cmd_string=cmd_string, parent=get_fc_main_window()).show() Case.the().info.is_gencase_done = True self.on_save_case() Case.the().info.needs_to_run_gencase = False except ValueError: print_exc() Case.the().info.is_gencase_done = False Case.the().info.needs_to_run_gencase = True # Refresh widget enable/disable status as GenCase finishes self.gencase_completed.emit(Case.the().info.is_gencase_done)
def on_add_geo(self): """ Add STL file. Opens a file opener and allows the user to set parameters for the import process """ self.need_refresh.emit() file_name, _ = QtGui.QFileDialog().getOpenFileName( get_fc_main_window(), __("Select GEO to import"), Case.the().info.last_used_directory, "STL Files (*.stl);;PLY Files (*.ply);;VTK Files (*.vtk)") Case.the().info.update_last_used_directory(file_name) if not file_name: return AddGEODialog(file_name, parent=get_fc_main_window())
def on_nnparameters_button(self): """ Defines nnparameters button behaviour""" if Case.the().executable_paths.dsphysics.find('NNewtonian') == -1: warning_dialog( __("DualSPHysics executable is not set as Non-Newtonian!")) else: NonNewtonianDialog(parent=get_fc_main_window()) self.accept()
def on_lsparameters_button(self): """ Defines lsparameters button behaviour""" if Case.the().executable_paths.dsphysics.find('LiquidSediment') == -1: warning_dialog( __("DualSPHysics executable is not set as Liquid-Sediment!")) else: LiquidSedimentDialog(parent=get_fc_main_window()) self.accept()
def __init__(self, parent=None): super().__init__(parent=parent) # Post processing section scaffolding self.main_layout = QtGui.QVBoxLayout() self.main_layout.setContentsMargins(0, 0, 0, 0) self.title_label = QtGui.QLabel("<b>{}</b>".format(__("Post-processing"))) self.title_label.setWordWrap(True) self.first_row_layout = QtGui.QHBoxLayout() self.second_row_layout = QtGui.QHBoxLayout() self.partvtk_button = QtGui.QPushButton(__("PartVTK")) self.computeforces_button = QtGui.QPushButton(__("ComputeForces")) self.isosurface_button = QtGui.QPushButton(__("IsoSurface")) self.floatinginfo_button = QtGui.QPushButton(__("FloatingInfo")) self.measuretool_button = QtGui.QPushButton(__("MeasureTool")) self.flowtool_button = QtGui.QPushButton(__("FlowTool")) self.partvtk_button.setToolTip(__("Opens the PartVTK tool.")) self.computeforces_button.setToolTip(__("Opens the ComputeForces tool.")) self.floatinginfo_button.setToolTip(__("Opens the FloatingInfo tool.")) self.measuretool_button.setToolTip(__("Opens the MeasureTool tool.")) self.isosurface_button.setToolTip(__("Opens the IsoSurface tool.")) self.flowtool_button.setToolTip(__("Opens the FlowTool tool.")) self.partvtk_button.clicked.connect(lambda: PartVTKDialog(self, parent=get_fc_main_window())) self.computeforces_button.clicked.connect(lambda: ComputeForcesDialog(self, parent=get_fc_main_window())) self.floatinginfo_button.clicked.connect(lambda: FloatingInfoDialog(self, parent=get_fc_main_window())) self.measuretool_button.clicked.connect(lambda: MeasureToolDialog(self, parent=get_fc_main_window())) self.isosurface_button.clicked.connect(lambda: IsoSurfaceDialog(self, parent=get_fc_main_window())) self.flowtool_button.clicked.connect(lambda: FlowToolDialog(self, parent=get_fc_main_window())) self.main_layout.addWidget(self.title_label) self.first_row_layout.addWidget(self.partvtk_button) self.first_row_layout.addWidget(self.computeforces_button) self.first_row_layout.addWidget(self.isosurface_button) self.second_row_layout.addWidget(self.floatinginfo_button) self.second_row_layout.addWidget(self.measuretool_button) self.second_row_layout.addWidget(self.flowtool_button) self.main_layout.addLayout(self.first_row_layout) self.main_layout.addLayout(self.second_row_layout) self.setLayout(self.main_layout)
def on_damping_option(self): """ Defines damping button behaviour""" damping_group_name = setup_damping_environment() Case.the().add_damping_group(damping_group_name) DampingConfigDialog(damping_group_name, Case.the(), parent=get_fc_main_window()) self.accept()
def mksmixing_export(obj, post_processing_widget, case) -> None: """ MKsMixing tool export. """ post_processing_widget.adapt_to_export_start() exported_parts: int = get_total_exported_parts_from_disk( case.get_out_folder_path()) export_dialog = ExportProgressDialog(0, exported_parts, parent=get_fc_main_window()) export_dialog.show() case.info.current_output = "" executable_parameters = [ case.get_out_folder_path(), obj["step"], obj["init"], obj["mk"], obj["dp"], obj["cdp"], obj["tout"], obj["n1"], obj["n2"], obj["n3"], obj["calc"], obj["vtk"] ] def on_stdout_ready(): """ Updates the export dialog on every stdout available from the process. """ current_output = str(export_process.readAllStandardOutput().data(), encoding='utf-8') case.info.current_output += current_output try: current_part = int(current_output.split()[1]) except: current_part = export_dialog.get_value() export_dialog.update_data(current_part) def on_cancel(): """ Kills the process and cancels the export dialog. """ export_process.kill() post_processing_widget.adapt_to_export_finished() export_dialog.reject() def on_export_finished(exit_code): """ Closes and displays info/error about the process. """ post_processing_widget.adapt_to_export_finished() export_dialog.accept() detailed_text = "The executed command line was: {} {}\n\n{}".format( case.custom.mksmixing, " ".join(executable_parameters), case.info.current_output) if not exit_code: info_dialog(info_text=__("MKsMixing finished successfully"), detailed_text=detailed_text) if case.custom.mksmixing_plot: MKsMixingPlotDialog( parent=post_processing_widget, paths=[ "{out_path}{file_name}.csv".format( out_path=case.get_out_folder_path(), file_name="MKsMixing") ]) else:
def refresh_movements_table(self): """ Refreshes the movement table. """ self.movement_list_table.clearContents() self.movement_list_table.setRowCount( len(Case.the().info.global_movements) + 1) current_row = 0 for movement in Case.the().info.global_movements: self.movement_list_table.setItem( current_row, 0, QtGui.QTableWidgetItem(movement.name)) try: has_loop = movement.loop except AttributeError: has_loop = False if isinstance(movement, Movement): movement_actions = MovementActions(current_row, movement in self.movements_selected, has_loop, parent=get_fc_main_window()) movement_actions.loop.connect(self.on_loop_movement) elif isinstance(movement, SpecialMovement): movement_actions = WaveMovementActions( current_row, movement in self.movements_selected, parent=get_fc_main_window()) movement_actions.delete.connect(self.on_delete_movement) movement_actions.use.connect(self.on_check_movement) self.movement_list_table.setCellWidget(current_row, 1, movement_actions) current_row += 1 try: self.create_new_movement_button.clicked.disconnect() self.create_new_movement_menu.triggered.disconnect() except RuntimeError: # Nothing connected yet. pass self.create_new_movement_button.clicked.connect(self.on_new_movement) self.create_new_movement_menu.triggered.connect( self.on_new_wave_generator) self.movement_list_table.setCellWidget(current_row, 0, QtGui.QWidget())
def on_accinput_button(self): """ Acceleration input button behaviour.""" accinput_dialog = AccelerationInputDialog( Case.the().acceleration_input, parent=get_fc_main_window()) result = accinput_dialog.exec_() if result == QtGui.QDialog.Accepted: Case.the().acceleration_input = accinput_dialog.get_result() self.accept()
def link_pulley_edit(self, link_pulley_id): """ Edit a link pulley element """ selected_chrono_object_widgets = list( filter(lambda x: x.object_check.isChecked(), self.chrono_object_options_widgets)) LinkPulleyEdit(link_pulley_id=link_pulley_id, bodies_widgets=selected_chrono_object_widgets, parent=get_fc_main_window()) self.refresh_link_pulley()
def link_coulombdamping_edit(self, link_coulombdamping_id): """ Edit a link coulombdamping element """ selected_chrono_object_widgets = list( filter(lambda x: x.object_check.isChecked(), self.chrono_object_options_widgets)) LinkCoulombDampingEdit(link_coulombdamping_id=link_coulombdamping_id, bodies_widgets=selected_chrono_object_widgets, parent=get_fc_main_window()) self.refresh_link_coulombdamping()
def __init__(self, parent=None): super().__init__(parent=parent) self.setObjectName(MAIN_WIDGET_INTERNAL_NAME) self.setWindowTitle("{} {}".format(APP_NAME, str(VERSION))) self.root_widget = QtGui.QWidget() self.main_layout = QtGui.QVBoxLayout() self.main_layout.setContentsMargins(5, 0, 5, 0) self.dock_logo_widget = DockLogoWidget(parent=get_fc_main_window()) self.dock_configuration_widget = DockConfigurationWidget( parent=get_fc_main_window()) self.dp_widget = DockDPWidget(parent=get_fc_main_window()) self.pre_proccessing_widget = DockPreProcessingWidget( parent=get_fc_main_window()) self.simulation_widget = DockSimulationWidget( parent=get_fc_main_window()) self.post_processing_widget = DockPostProcessingWidget( parent=get_fc_main_window()) self.object_list_widget = DockObjectListTableWidget( parent=get_fc_main_window()) self.main_layout.addWidget(self.dock_logo_widget) self.main_layout.addWidget(h_line_generator()) self.main_layout.addWidget(self.dock_configuration_widget) self.main_layout.addWidget(h_line_generator()) self.main_layout.addWidget(self.dp_widget) self.main_layout.addWidget(h_line_generator()) self.main_layout.addWidget(self.pre_proccessing_widget) self.main_layout.addWidget(h_line_generator()) self.main_layout.addWidget(self.simulation_widget) self.main_layout.addWidget(h_line_generator()) self.main_layout.addWidget(self.post_processing_widget) self.main_layout.addWidget(h_line_generator()) self.main_layout.addWidget(self.object_list_widget) self.root_widget.setLayout(self.main_layout) self.setWidget(self.root_widget) self.adapt_to_no_case() # Signal handling self.pre_proccessing_widget.force_pressed.connect( self.on_preprocessing_force_pressed) self.pre_proccessing_widget.need_refresh.connect(self.on_refresh) self.pre_proccessing_widget.update_dp.connect(self.on_signal_update_dp) self.pre_proccessing_widget.case_created.connect( self.adapt_to_new_case) self.pre_proccessing_widget.gencase_completed.connect( self.adapt_to_gencase_done) self.pre_proccessing_widget.simulation_completed.connect( self.adapt_to_simulation_done) self.simulation_widget.simulation_complete.connect( self.adapt_to_simulation_done) self.simulation_widget.simulation_started.connect( self.adapt_to_simulation_start) self.simulation_widget.simulation_cancelled.connect( self.adapt_to_simulation_cancel)
def geo_dialog_browse(self): """ Defines the browse button behaviour.""" file_name_temp, _ = QtGui.QFileDialog().getOpenFileName( get_fc_main_window(), __("Select GEO to import"), Case.the().info.last_used_directory, "STL Files (*.stl);;PLY Files (*.ply);;VTK Files (*.vtk)") Case.the().info.update_last_used_directory(file_name_temp) if file_name_temp: self.geo_file_path.setText(file_name_temp) self.raise_() self.activateWindow() self.geo_button_ok.setFocus()
def boundaryvtk_export(obj, post_processing_widget, case) -> None: """ BoundaryVTK tool export. """ post_processing_widget.adapt_to_export_start() exported_parts: int = get_total_exported_parts_from_disk( case.get_out_folder_path()) export_dialog = ExportProgressDialog(0, exported_parts, parent=get_fc_main_window()) export_dialog.show() case.info.current_output = "" # Eventually clear previous files if os.path.isdir("{out_path}{file_name}".format( out_path=case.get_out_folder_path(), file_name=obj['name'])):
def on_new_from_freecad_document(self, prompt=True): """ Creates a new case based on an existing FreeCAD document. This is specially useful for CAD users that want to use existing geometry for DesignSPHysics. """ file_name, _ = QtGui.QFileDialog().getOpenFileName( get_fc_main_window(), "Select document to import", Case.the().info.last_used_directory) Case.the().info.update_last_used_directory(file_name) if file_name and document_count( ) and not prompt_close_all_documents(prompt): return create_dsph_document_from_fcstd(file_name) Case.the().reset() # Case.the().add_object_to_sim(SimulationObject(CASE_LIMITS_OBJ_NAME, -1, ObjectType.SPECIAL, ObjectFillMode.SPECIAL)) self.update_dp.emit() self.case_created.emit() self.need_refresh.emit()
def on_2d_toggle(self): """ Handles Toggle 3D/2D Button. Changes the Case Limits object accordingly. """ if not valid_document_environment(): error("Not a valid case environment") return fc_object = get_fc_object(CASE_LIMITS_OBJ_NAME) if Case.the().mode3d: # 3D to 2D Case.the().info.last_3d_width = fc_object.Width.Value config_dialog = Mode2DConfigDialog(fc_object.Placement.Base.y, parent=get_fc_main_window()) if config_dialog.exit_status == QtGui.QDialog.Rejected: return fc_object.Placement.Base.y = float(config_dialog.stored_y_value) fc_object.Label = CASE_LIMITS_2D_LABEL Case.the().mode3d = not Case.the().mode3d else: # 2D to 3D Case.the().mode3d = not Case.the().mode3d fc_object.Width = Case.the().info.last_3d_width if Case.the( ).info.last_3d_width > 0.0 else fc_object.Length fc_object.Label = CASE_LIMITS_3D_LABEL
def on_ex_simulate(self): """ Defines what happens on simulation button press. It shows the run window and starts a background process with dualsphysics running. Updates the window with useful info.""" refocus_cwd() if Case.the().info.needs_to_run_gencase: # Warning window about save_case warning_dialog("You should run GenCase again. Otherwise, the obtained results may not be as expected") static_params_exe = [Case.the().get_out_xml_file_path(), Case.the().get_out_folder_path(), "-{device}".format(device=self.device_selector.currentText().lower()), "-svres"] additional_parameters = list() if Case.the().info.run_additional_parameters: additional_parameters = Case.the().info.run_additional_parameters.split(" ") final_params_ex = static_params_exe + additional_parameters cmd_string = "{} {}".format(Case.the().executable_paths.dsphysics, " ".join(final_params_ex)) run_dialog = RunDialog(case_name=Case.the().name, processor=self.device_selector.currentText(), number_of_particles=Case.the().info.particle_number, cmd_string=cmd_string, parent=get_fc_main_window()) run_dialog.set_value(0) run_dialog.run_update(0, 0, None) Case.the().info.is_simulation_done = False run_fs_watcher = QtCore.QFileSystemWatcher() self.simulation_started.emit() # Cancel button handler def on_cancel(): log(__("Stopping simulation")) if process: process.kill() run_dialog.hide_all() Case.the().info.is_simulation_done = True self.simulation_cancelled.emit() run_dialog.cancelled.connect(on_cancel) # Launch simulation and watch filesystem to monitor simulation filelist = [f for f in os.listdir(Case.the().path + "/" + Case.the().name + "_out/") if f.startswith("Part")] for f in filelist: os.remove(Case.the().path + "/" + Case.the().name + "_out/" + f) def on_dsph_sim_finished(exit_code): """ Simulation finish handler. Defines what happens when the process finishes.""" # Reads output and completes the progress bar output = str(process.readAllStandardOutput().data(), encoding='utf-8') run_dialog.set_detail_text(str(output)) run_dialog.run_complete() run_fs_watcher.removePath(Case.the().path + "/" + Case.the().name + "_out/") if exit_code == 0: # Simulation went correctly Case.the().info.is_simulation_done = True Case.the().info.needs_to_run_gencase = False self.simulation_complete.emit(True) else: # In case of an error Case.the().info.needs_to_run_gencase = True if "exception" in str(output).lower(): log("There was an error on the execution. Opening an error dialog for that.") run_dialog.hide() self.simulation_complete.emit(False) error_dialog(__("An error occurred during execution. Make sure that parameters exist and are properly defined. " "You can also check your execution device (update the driver of your GPU). Read the details for more information."), str(output)) save_case(Case.the().path, Case.the()) # Launches a QProcess in background process = QtCore.QProcess(get_fc_main_window()) process.finished.connect(on_dsph_sim_finished) process.start(Case.the().executable_paths.dsphysics, final_params_ex) def on_fs_change(): """ Executed each time the filesystem changes. This updates the percentage of the simulation and its details.""" run_file_data = "" with open(Case.the().path + "/" + Case.the().name + "_out/Run.out", "r") as run_file: run_file_data = run_file.readlines() # Fill details window run_dialog.set_detail_text("".join(run_file_data)) # Set percentage scale based on timemax for l in run_file_data: if Case.the().execution_parameters.timemax == -1: if "TimeMax=" in l: Case.the().execution_parameters.timemax = float(l.split("=")[1]) current_value: float = 0.0 totalpartsout: int = 0 last_estimated_time = None # Update execution metrics last_part_lines = list(filter(lambda x: "Part_" in x and "stored" not in x and " " in x, run_file_data)) if last_part_lines: current_value = (float(last_part_lines[-1].split(None)[1]) * float(100)) / float(Case.the().execution_parameters.timemax) else: current_value = None # Update particles out last_particles_out_lines = list(filter(lambda x: "(total: " in x and "Particles out:" in x, run_file_data)) if last_particles_out_lines: totalpartsout = int(last_particles_out_lines[-1].split("(total: ")[1].split(")")[0]) try: last_estimated_time = str(" ".join(last_part_lines[-1].split(None)[-2:])) except IndexError: last_estimated_time = None # Update run dialog run_dialog.run_update(current_value, totalpartsout, last_estimated_time) # Set filesystem watcher to the out directory. run_fs_watcher.addPath(Case.the().path + "/" + Case.the().name + "_out/") run_fs_watcher.directoryChanged.connect(on_fs_change) # Handle error on simulation start if process.state() == QtCore.QProcess.NotRunning: # Probably error happened. run_fs_watcher.removePath(Case.the().path + "/" + Case.the().name + "_out/") process = None error_dialog("Error on simulation start. Check that the DualSPHysics executable is correctly set.") else: run_dialog.show()
def on_additional_parameters(self): """ Handles additional parameters button for execution """ RunAdditionalParametersDialog(parent=get_fc_main_window())
def box_edit(self, box_id): """ Box edit button behaviour. Opens a dialog to edit the selected FlowTool Box""" FlowToolBoxEditDialog(box_id, parent=get_fc_main_window()) self.refresh_boxlist()
from mod.file_tools import get_total_exported_parts_from_disk, save_measuretool_info from mod.executable_tools import ensure_process_is_executable_or_fail from mod.widgets.postprocessing.export_progress_dialog import ExportProgressDialog def partvtk_export(options, case, post_processing_widget) -> None: """ Export VTK button behaviour. Launches a process while disabling the button. """ post_processing_widget.adapt_to_export_start() save_extension: str = {0: "vtk", 1: "csv", 2: "asc"}[options["save_mode"]] save_flag: str = {0: "-savevtk", 1: "-savecsv", 2: "-saveascii"}[options["save_mode"]] exported_parts: int = get_total_exported_parts_from_disk(case.get_out_folder_path()) export_dialog = ExportProgressDialog(0, exported_parts, parent=get_fc_main_window()) export_dialog.show() case.info.current_output = "" # Build parameters executable_parameters = ["-dirin {}".format(case.get_out_folder_path()), "{save_flag} {out_path}{file_name}".format(save_flag=save_flag, out_path=case.get_out_folder_path(), file_name=options["file_name"]), "-onlytype:{save_types} {additional}".format(save_types=options["save_types"], additional=options["additional_parameters"])] # Information ready handler. def on_stdout_ready(): """ Updates the export dialog on every stdout available from the process. """ current_output = str(export_process.readAllStandardOutput().data(), encoding='utf-8') case.info.current_output += current_output try:
""" Export VTK button behaviour. Launches a process while disabling the button. """ post_processing_widget.adapt_to_export_start() save_extension: str = {0: "vtk", 1: "csv", 2: "asc"}[options["save_mode"]] save_flag: str = { 0: "-savevtk", 1: "-savecsv", 2: "-saveascii" }[options["save_mode"]] exported_parts: int = get_total_exported_parts_from_disk( case.get_out_folder_path()) export_dialog = ExportProgressDialog(0, exported_parts, parent=get_fc_main_window()) export_dialog.show() case.info.current_output = "" # Build parameters executable_parameters = [ "-dirin {}".format(case.get_out_folder_path()), "{save_flag} {out_path}{file_name}".format( save_flag=save_flag, out_path=case.get_out_folder_path(), file_name=options["file_name"]), "-onlytype:{save_types} {additional}".format( save_types=options["save_types"], additional=options["additional_parameters"]) ]
def on_motion_change(self): """ Movement configuration button behaviour. """ MovementDialog(parent=get_fc_main_window())
def on_initials_change(self): """ Initials configuration button behaviour. """ InitialsDialog(parent=get_fc_main_window())
def on_damping_config(self): """ Configures the damping configuration for the selected object """ DampingConfigDialog(FreeCADGui.Selection.getSelection()[0].Name, Case.the(), parent=get_fc_main_window())
def zone_edit(self, io_id): """ Calls a window for edit zones """ debug("Trying to open a zone edit for zone UUID {}".format(io_id)) InletZoneEdit(io_id, parent=get_fc_main_window()) self.refresh_zones()
def boot(): """ Boots the application. """ print_license() check_compatibility() try: master_branch_version = str( urlopen(GITHUB_MASTER_CONSTANTS_URL).read()).split( "VERSION = \"")[-1].split("\"")[0] if VERSION < master_branch_version and NOTIFY_ON_OUTDATED_VERSION: info_dialog( __("Your version of DesignSPHyiscs is outdated. Please go to the Addon Manager and update it. New versions include bug fixes, new features and new DualSPHysics executables, among other things." ), __("The version you're using is {} while the version that you can update to is {}" ).format(VERSION, master_branch_version)) except URLError: log("No network connection or Git repo is down. Skipping version check." ) if document_count() > 0: success = prompt_close_all_documents() if not success: debug( "User chose not to close the currently opened documents. Aborting startup" ) quit() # Tries to delete docks created by a previous execution of DesignSPHysics delete_existing_docks() designsphysics_dock = DesignSPHysicsDock(get_fc_main_window()) properties_widget = PropertiesDockWidget(parent=get_fc_main_window()) get_fc_main_window().addDockWidget(QtCore.Qt.RightDockWidgetArea, designsphysics_dock) get_fc_main_window().addDockWidget(QtCore.Qt.LeftDockWidgetArea, properties_widget) # Subscribe the FreeCAD Objects tree to the item selection change function. # This helps FreeCAD notify DesignSPHysics for the deleted and changed objects to get updated correctly. fc_object_tree: QtGui.QTreeWidget = get_fc_main_window().findChildren( QtGui.QSplitter)[0].findChildren(QtGui.QTreeWidget)[0] fc_object_tree.itemSelectionChanged.connect( lambda p=properties_widget, d=designsphysics_dock: on_tree_item_selection_change(p, d)) debug( "Subscribing selection change monitor handler to freecad object tree item changed." ) properties_widget.need_refresh.connect( lambda p=properties_widget, d=designsphysics_dock: on_tree_item_selection_change(p, d)) designsphysics_dock.need_refresh.connect( lambda p=properties_widget, d=designsphysics_dock: on_tree_item_selection_change(p, d)) # Launch a monitor thread that ensures some things are not changed. monitor_thread = threading.Thread( target=lambda p=properties_widget, d=designsphysics_dock: selection_monitor(p, d)) monitor_thread.start() FreeCADGui.activateWorkbench(DEFAULT_WORKBENCH) log(__("Initialization finished for {} v{}").format(APP_NAME, VERSION))
def on_movement_selected(self, row, _): """ Shows the timeline for the selected movement. """ try: self.currently_selected_movement = Case.the( ).info.global_movements[row] except IndexError: self.timeline_list_table.clearContents() self.timeline_list_table.setEnabled(False) self.timeline_list_table.setRowCount(1) self.timeline_list_table.setCellWidget( 0, 0, MovementTimelinePlaceholder()) return self.timeline_list_table.clearContents() # Reset the notice label if a valid change is made self.notice_label.setText("") if isinstance(self.currently_selected_movement, Movement): self.timeline_list_table.setRowCount( len(self.currently_selected_movement.motion_list)) self.timeline_list_table.setEnabled(True) self.actions_groupbox_table.setEnabled(True) current_row = 0 for motion in self.currently_selected_movement.motion_list: if isinstance(motion, RectMotion): target_to_put = RectilinearMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, WaitMotion): target_to_put = WaitMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, AccRectMotion): target_to_put = AccRectilinearMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, RotMotion): target_to_put = RotationalMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, AccRotMotion): target_to_put = AccRotationalMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, AccCirMotion): target_to_put = AccCircularMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, RotSinuMotion): target_to_put = RotSinuMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, CirSinuMotion): target_to_put = CirSinuMotionTimeline( current_row, motion, parent=get_fc_main_window()) elif isinstance(motion, RectSinuMotion): target_to_put = RectSinuMotionTimeline( current_row, motion, parent=get_fc_main_window()) else: raise NotImplementedError( "The type of movement: {} is not implemented.".format( str(motion.__class__.__name__))) target_to_put.changed.connect(self.on_timeline_item_change) target_to_put.deleted.connect(self.on_timeline_item_delete) target_to_put.order_up.connect(self.on_timeline_item_order_up) target_to_put.order_down.connect( self.on_timeline_item_order_down) self.timeline_list_table.setCellWidget(current_row, 0, target_to_put) if current_row == 0: target_to_put.disable_order_up_button() elif current_row == len( self.currently_selected_movement.motion_list) - 1: target_to_put.disable_order_down_button() current_row += 1 elif isinstance(self.currently_selected_movement, SpecialMovement): self.timeline_list_table.setRowCount(1) self.timeline_list_table.setEnabled(True) self.actions_groupbox_table.setEnabled(False) if isinstance(self.currently_selected_movement.generator, RegularPistonWaveGen): target_to_put = RegularPistonWaveMotionTimeline( self.currently_selected_movement.generator, parent=get_fc_main_window()) elif isinstance(self.currently_selected_movement.generator, IrregularPistonWaveGen): target_to_put = IrregularPistonWaveMotionTimeline( self.currently_selected_movement.generator, parent=get_fc_main_window()) if isinstance(self.currently_selected_movement.generator, RegularFlapWaveGen): target_to_put = RegularFlapWaveMotionTimeline( self.currently_selected_movement.generator, parent=get_fc_main_window()) elif isinstance(self.currently_selected_movement.generator, IrregularFlapWaveGen): target_to_put = IrregularFlapWaveMotionTimeline( self.currently_selected_movement.generator, parent=get_fc_main_window()) elif isinstance(self.currently_selected_movement.generator, FileGen): target_to_put = FileMotionTimeline( self.currently_selected_movement.generator, Case.the().path, parent=get_fc_main_window()) elif isinstance(self.currently_selected_movement.generator, RotationFileGen): target_to_put = RotationFileMotionTimeline( self.currently_selected_movement.generator, Case.the().path, parent=get_fc_main_window()) target_to_put.changed.connect(self.on_timeline_item_change) self.timeline_list_table.setCellWidget(0, 0, target_to_put)
def on_floatstate_change(self): """ Float configuration button behaviour. """ FloatStateDialog(parent=get_fc_main_window())
def on_moorings_button(self): """ Moorings button behaviour.""" MooringsConfigurationDialog(parent=get_fc_main_window()) self.accept()
def on_relaxationzone_menu(self, action): """ Defines Relaxation Zone menu behaviour.""" # Check which type of relaxationzone it is if action.text() == __("Regular waves"): if Case.the().relaxation_zone is not None: if not isinstance(Case.the().relaxation_zone, RelaxationZoneRegular): overwrite_warn = ok_cancel_dialog( __("Relaxation Zone"), __("There's already another type of Relaxation Zone defined. Continuing will overwrite it. Are you sure?" )) if overwrite_warn == QtGui.QMessageBox.Cancel: return Case.the().relaxation_zone = RelaxationZoneRegular() config_dialog = RelaxationZoneRegularConfigDialog( Case.the().relaxation_zone, parent=get_fc_main_window()) # Set the relaxation zone. Can be an object or be None Case.the().relaxation_zone = config_dialog.relaxationzone if action.text() == __("Irregular waves"): if Case.the().relaxation_zone is not None: if not isinstance(Case.the().relaxation_zone, RelaxationZoneIrregular): overwrite_warn = ok_cancel_dialog( __("Relaxation Zone"), __("There's already another type of Relaxation Zone defined. Continuing will overwrite it. Are you sure?" )) if overwrite_warn == QtGui.QMessageBox.Cancel: return Case.the().relaxation_zone = RelaxationZoneIrregular() config_dialog = RelaxationZoneIrregularConfigDialog( Case.the().relaxation_zone, parent=get_fc_main_window()) # Set the relaxation zone. Can be an object or be None Case.the().relaxation_zone = config_dialog.relaxationzone if action.text() == __("External Input"): if Case.the().relaxation_zone is not None: if not isinstance(Case.the().relaxation_zone, RelaxationZoneFile): overwrite_warn = ok_cancel_dialog( __("Relaxation Zone"), __("There's already another type of Relaxation Zone defined. Continuing will overwrite it. Are you sure?" )) if overwrite_warn == QtGui.QMessageBox.Cancel: return Case.the().relaxation_zone = RelaxationZoneFile() config_dialog = RelaxationZoneFileConfigDialog( Case.the().relaxation_zone, parent=get_fc_main_window()) # Set the relaxation zone. Can be an object or be None Case.the().relaxation_zone = config_dialog.relaxationzone if action.text() == __("Uniform velocity"): if Case.the().relaxation_zone is not None: if not isinstance(Case.the().relaxation_zone, RelaxationZoneUniform): overwrite_warn = ok_cancel_dialog( __("Relaxation Zone"), __("There's already another type of Relaxation Zone defined. Continuing will overwrite it. Are you sure?" )) if overwrite_warn == QtGui.QMessageBox.Cancel: return Case.the().relaxation_zone = RelaxationZoneUniform() config_dialog = RelaxationZoneUniformConfigDialog( Case.the().relaxation_zone, parent=get_fc_main_window()) # Set the relaxation zone. Can be an object or be None Case.the().relaxation_zone = config_dialog.relaxationzone self.accept()