def __init__(self, halcomp, widgets, paths): self.h = halcomp self.w = widgets self.gcodes = GCodes(widgets) self.valid = QtGui.QDoubleValidator(-999.999, 999.999, 3) self.styleeditor = SSE(widgets, paths) KEYBIND.add_call('Key_F4', 'on_keycall_F4') KEYBIND.add_call('Key_F12','on_keycall_F12') KEYBIND.add_call('Key_Pause', 'on_keycall_PAUSE') KEYBIND.add_call('Key_Space', 'on_keycall_PAUSE') # some global variables self.factor = 1.0 self.probe = None self.default_setup = os.path.join(PATH.CONFIGPATH, "default_setup.html") self.start_line = 0 self.run_time = 0 self.time_tenths = 0 self.timer_on = False self.home_all = False self.min_spindle_rpm = INFO.MIN_SPINDLE_SPEED self.max_spindle_rpm = INFO.MAX_SPINDLE_SPEED self.max_spindle_power = INFO.get_error_safe_setting('DISPLAY', 'MAX_SPINDLE_POWER',"0") self.max_linear_velocity = INFO.MAX_TRAJ_VELOCITY self.system_list = ["G54","G55","G56","G57","G58","G59","G59.1","G59.2","G59.3"] self.slow_jog_factor = 10 self.reload_tool = 0 self.last_loaded_program = "" self.first_turnon = True self.unit_label_list = ["ts_height", "tp_height", "zoffset_units", "max_probe_units"] self.lineedit_list = ["work_height", "touch_height", "sensor_height", "laser_x", "laser_y", "sensor_x", "sensor_y", "camera_x", "camera_y", "search_vel", "probe_vel", "max_probe", "eoffset_count"] self.onoff_list = ["frame_program", "frame_tool", "frame_offsets", "frame_dro", "frame_override"] self.axis_a_list = ["label_axis_a", "dro_axis_a", "action_zero_a", "axistoolbutton_a", "action_home_a", "widget_jog_angular", "widget_increments_angular", "a_plus_jogbutton", "a_minus_jogbutton"] STATUS.connect('general', self.dialog_return) STATUS.connect('state-on', lambda w: self.enable_onoff(True)) STATUS.connect('state-off', lambda w: self.enable_onoff(False)) STATUS.connect('mode-auto', lambda w: self.enable_auto(True)) STATUS.connect('gcode-line-selected', lambda w, line: self.set_start_line(line)) STATUS.connect('hard-limits-tripped', self.hard_limit_tripped) STATUS.connect('program-pause-changed', lambda w, state: self.w.btn_pause_spindle.setEnabled(state)) STATUS.connect('user-system-changed', lambda w, data: self.user_system_changed(data)) STATUS.connect('metric-mode-changed', lambda w, mode: self.metric_mode_changed(mode)) STATUS.connect('file-loaded', self.file_loaded) STATUS.connect('all-homed', self.all_homed) STATUS.connect('not-all-homed', self.not_all_homed) STATUS.connect('periodic', lambda w: self.update_runtimer()) STATUS.connect('interp-idle', lambda w: self.stop_timer()) STATUS.connect('actual-spindle-speed-changed',self.update_spindle) STATUS.connect('requested-spindle-speed-changed',self.update_spindle_requested)
def __init__(self, halcomp, widgets, paths): # some global variables self.hal = halcomp self.w = widgets self.PATH = paths self._big_view = -1 self.flag = 0 self.activeStyle = ''' { background-color: white;}''' self.defaultStyle = ''' { background-color: light blue;}''' self.activeWidgetDict = { 'programPage': False, 'userPage': False, 'machinePage': False, 'tooloffsetsPage': False, 'loadPage': False, 'mdiPage': False, 'workoffsetsPage': False, 'setupPage': False } self.current_mode = (None, None) self._last_count = 0 self.run_time = 0 self.time_tenths = 0 self.timerOn = False self.slow_jog_factor = 10 self.STYLEEDITOR = SSE(widgets, paths) self.GCODES = GCodes() STATUS.connect('periodic', lambda w: self.update_runtimer()) STATUS.connect('command-running', lambda w: self.start_timer()) STATUS.connect('command-stopped', lambda w: self.stop_timer()) STATUS.connect("metric-mode-changed", lambda w, d: self.mode_changed(d)) STATUS.connect('state-off', lambda w: self.w.pushbutton_metric.setEnabled(False)) STATUS.connect('state-estop', lambda w: self.w.pushbutton_metric.setEnabled(False)) STATUS.connect( 'interp-idle', lambda w: self.w.pushbutton_metric.setEnabled( self.homed_on_test())) STATUS.connect('interp-run', lambda w: self.w.pushbutton_metric.setEnabled(False)) STATUS.connect('all-homed', lambda w: self.w.pushbutton_metric.setEnabled(True)) STATUS.connect( 'not-all-homed', lambda w, data: self.w.pushbutton_metric.setEnabled(False))
def __init__(self, halcomp, widgets, paths): self.h = halcomp self.w = widgets self.PATHS = paths INIPATH = os.environ.get('INI_FILE_NAME', '/dev/null') self.inifile = linuxcnc.ini(INIPATH) self.STYLEEDITOR = SSE(widgets, paths) self.GCODES = GCodes(widgets) self.valid = QtGui.QDoubleValidator(0.0, 999.999, 3) KEYBIND.add_call('Key_F12', 'on_keycall_F12') KEYBIND.add_call('Key_Pause', 'on_keycall_pause') KEYBIND.add_call('Key_Plus', 'on_keycall_plus') KEYBIND.add_call('Key_Minus', 'on_keycall_minus') STAT.connect('general', self.dialog_return) STAT.connect('state-on', lambda w: self.enable_onoff(True)) STAT.connect('state-off', lambda w: self.enable_onoff(False)) STAT.connect('gcode-line-selected', lambda w, line: self.set_start_line(line)) STAT.connect('hard-limits-tripped', self.hard_limit_tripped) STAT.connect('interp-idle', lambda w: self.set_start_line(0)) STAT.connect('user-system-changed', self.user_system_changed) STAT.connect('file-loaded', self.file_loaded) STAT.connect('all-homed', self.all_homed) STAT.connect('not-all-homed', lambda w, list: self.set_dro_homed(False)) # some global variables self.axis_list = INFO.AVAILABLE_AXES self.max_linear_velocity = INFO.MAX_LINEAR_VELOCITY self.max_spindle_rpm = INFO.MAX_SPINDLE_SPEED self.system_list = [ "G53", "G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3" ] self.slow_jog_factor = 10 self.reload_tool = 0 self.last_loaded_program = "" self.first_turnon = True self.onoff_list = ["frame_program", "frame_tool", "frame_dro"] self.axis_a_list = [ "label_axis_a", "dro_axis_a", "action_zero_a", "axistoolbutton_a", "action_home_a", "widget_jog_angular", "widget_increments_angular", "a_plus_jogbutton", "a_minus_jogbutton" ]
def __init__(self, halcomp, widgets, paths): self.initialized = False self.hal = halcomp self.PATHS = paths self.RODOS_PATH = "/home/mdrives/RODOS4/RODOS4" self.gcodes = GCodes() self.plot_data_buffer = [[], []] self.log_data_buffer = [] self.current_plot_n = 0 self.w = widgets self.init_pins()
class HandlerClass: def __init__(self, halcomp, widgets, paths): self.h = halcomp self.w = widgets self.PATHS = paths INIPATH = os.environ.get('INI_FILE_NAME', '/dev/null') self.inifile = linuxcnc.ini(INIPATH) self.GCODES = GCodes(widgets) self.valid = QtGui.QDoubleValidator(0.0, 999.999, 3) KEYBIND.add_call('Key_F12', 'on_keycall_F12') KEYBIND.add_call('Key_Pause', 'on_keycall_pause') KEYBIND.add_call('Key_Plus', 'on_keycall_plus') KEYBIND.add_call('Key_Minus', 'on_keycall_minus') STATUS.connect('general', self.dialog_return) STATUS.connect('state-on', lambda w: self.enable_onoff(True)) STATUS.connect('state-off', lambda w: self.enable_onoff(False)) STATUS.connect('gcode-line-selected', lambda w, line: self.set_start_line(line)) STATUS.connect('hard-limits-tripped', self.hard_limit_tripped) STATUS.connect('interp-idle', lambda w: self.set_start_line(0)) STATUS.connect('user-system-changed', self.user_system_changed) STATUS.connect('file-loaded', self.file_loaded) STATUS.connect('all-homed', self.all_homed) STATUS.connect('not-all-homed', lambda w, list: self.set_dro_homed(False)) # some global variables self.axis_list = INFO.AVAILABLE_AXES self.max_linear_velocity = INFO.MAX_LINEAR_VELOCITY self.max_spindle_rpm = INFO.MAX_SPINDLE_SPEED self.system_list = [ "G53", "G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3" ] self.slow_jog_factor = 10 self.reload_tool = 0 self.last_loaded_program = "" self.first_turnon = True self.onoff_list = ["frame_program", "frame_tool", "frame_dro"] self.axis_a_list = [ "label_axis_a", "dro_axis_a", "action_zero_a", "axistoolbutton_a", "action_home_a", "widget_jog_angular", "widget_increments_angular", "a_plus_jogbutton", "a_minus_jogbutton" ] def initialized__(self): self.init_pins() self.init_preferences() self.init_widgets() self.GCODES.setup_list() self.w.stackedWidget_log.setCurrentIndex(0) if "A" not in self.axis_list: for i in self.axis_a_list: self.w[i].hide() self.w.lbl_increments_linear.setText("INCREMENTS") ############################# # SPECIAL FUNCTIONS SECTION # ############################# def init_pins(self): pin = self.h.newpin("spindle_speed_fb", hal.HAL_FLOAT, hal.HAL_IN) hal_glib.GPin(pin).connect("value_changed", self.spindle_fb_changed) pin = self.h.newpin("spindle_amps", hal.HAL_FLOAT, hal.HAL_IN) hal_glib.GPin(pin).connect("value_changed", self.spindle_amps_changed) pin = self.h.newpin("spindle_power", hal.HAL_FLOAT, hal.HAL_IN) hal_glib.GPin(pin).connect("value_changed", self.spindle_power_changed) pin = self.h.newpin("spindle_fault", hal.HAL_U32, hal.HAL_IN) hal_glib.GPin(pin).connect("value_changed", self.spindle_fault_changed) pin = self.h.newpin("modbus-errors", hal.HAL_U32, hal.HAL_IN) hal_glib.GPin(pin).connect("value_changed", self.mb_errors_changed) def init_preferences(self): if not self.w.PREFS_: self.add_alarm( "CRITICAL - no preference file found, enable preferences in screenoptions widget" ) return self.last_loaded_program = self.w.PREFS_.getpref( 'last_file_path', None, str, 'BOOK_KEEPING') self.reload_tool = self.w.PREFS_.getpref('Tool to load', 0, int, 'CUSTOM_FORM_ENTRIES') self.w.chk_reload_program.setChecked( self.w.PREFS_.getpref('Reload program', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_reload_tool.setChecked( self.w.PREFS_.getpref('Reload tool', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_keyboard.setChecked( self.w.PREFS_.getpref('Use keyboard', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_run_from_line.setChecked( self.w.PREFS_.getpref('Run from line', False, bool, 'CUSTOM_FORM_ENTRIES')) def closing_cleanup__(self): if not self.w.PREFS_: return self.w.PREFS_.putpref('Tool to load', self.w.statuslabel_tool.text().encode('utf-8'), int, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Reload program', self.w.chk_reload_program.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Reload tool', self.w.chk_reload_tool.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use keyboard', self.w.chk_use_keyboard.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Run from line', self.w.chk_run_from_line.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') def init_widgets(self): self.w.main_tab_widget.setCurrentIndex(0) self.w.slider_jog_linear.setMaximum(self.max_linear_velocity * 60) self.w.slider_jog_linear.setValue(INFO.DEFAULT_LINEAR_JOG_VEL) self.w.slider_jog_angular.setMaximum(INFO.MAX_ANGULAR_JOG_VEL) self.w.slider_jog_angular.setValue(INFO.DEFAULT_ANGULAR_JOG_VEL) self.w.slider_feed_ovr.setMaximum(INFO.MAX_FEED_OVERRIDE) self.w.slider_feed_ovr.setValue(100) self.w.slider_rapid_ovr.setMaximum(100) self.w.slider_rapid_ovr.setValue(100) self.w.slider_spindle_ovr.setMinimum(INFO.MIN_SPINDLE_OVERRIDE) self.w.slider_spindle_ovr.setMaximum(INFO.MAX_SPINDLE_OVERRIDE) self.w.slider_spindle_ovr.setValue(100) self.w.chk_override_limits.setChecked(False) self.w.chk_override_limits.setEnabled(False) self.w.filemanager.show() self.w.gcode_editor.hide() self.w.lbl_max_rapid.setText(str(self.max_linear_velocity * 60)) self.w.lbl_search_vel.setText( self.inifile.find('TOOLSENSOR', 'SEARCH_VEL') or "200") self.w.lbl_probe_vel.setText( self.inifile.find('TOOLSENSOR', 'PROBE_VEL') or "50") self.w.lbl_max_probe.setText( self.inifile.find('TOOLSENSOR', 'MAXPROBE') or "10") self.w.lbl_touch_height.setText( self.inifile.find('TOOLSENSOR', 'TOUCH') or "50") self.w.lbl_laser_x.setText(self.inifile.find('LASER', 'X') or "100") self.w.lbl_laser_y.setText(self.inifile.find('LASER', 'Y') or "-10") self.w.lbl_home_x.setText(self.inifile.find('JOINT_0', 'HOME') or "50") self.w.lbl_home_y.setText(self.inifile.find('JOINT_1', 'HOME') or "50") #set up gcode list self.w.gcode_list.currentRowChanged.connect(self.list_row_changed) titles = mdiText.gcode_titles() for key in sorted(titles.iterkeys()): self.w.gcode_list.addItem(key + ' ' + titles[key]) self.w.gcode_description.setReadOnly(True) TOOLBAR.configure_statusbar(self.w.statusbar, 'message_recall') def processed_key_event__(self, receiver, event, is_pressed, key, code, shift, cntrl): # when typing in MDI, we don't want keybinding to call functions # so we catch and process the events directly. # We do want ESC, F1 and F2 to call keybinding functions though if code not in (QtCore.Qt.Key_Escape, QtCore.Qt.Key_F1, QtCore.Qt.Key_F2): # QtCore.Qt.Key_F3,QtCore.Qt.Key_F4,QtCore.Qt.Key_F5): # search for the top widget of whatever widget received the event # then check if it's one we want the keypress events to go to flag = False receiver2 = receiver while receiver2 is not None and not flag: if isinstance(receiver2, QtWidgets.QDialog): flag = True break if isinstance(receiver2, QtWidgets.QLineEdit): flag = True break if isinstance(receiver2, MDI_WIDGET): flag = True break if isinstance(receiver2, GCODE): flag = True break if isinstance(receiver2, TOOL_TABLE): flag = True break if isinstance(receiver2, OFFSET_VIEW): flag = True break receiver2 = receiver2.parent() if flag: if isinstance(receiver2, GCODE): # if in manual do our keybindings - otherwise # send events to gcode widget if STATUS.is_man_mode() == False: if is_pressed: receiver.keyPressEvent(event) event.accept() return True elif is_pressed: receiver.keyPressEvent(event) event.accept() return True else: event.accept() return True # ok if we got here then try keybindings function calls # KEYBINDING will call functions from handler file as # registered by KEYBIND.add_call(KEY,FUNCTION) above return KEYBIND.manage_function_calls(self, event, is_pressed, key, shift, cntrl) ######################### # CALLBACKS FROM STATUS # ######################### def spindle_fb_changed(self, data): rpm = int(self.h['spindle_speed_fb']) self.w.lbl_spindle_rpm.setText(str(rpm)) if float(self.w.label_spindle_set.text()) > self.max_spindle_rpm: self.w.label_spindle_set.setProperty('overspeed', True) else: self.w.label_spindle_set.setProperty('overspeed', False) self.w.label_spindle_set.setStyle(self.w.label_spindle_set.style()) def spindle_amps_changed(self, data): amps = "{:1.1f}".format(self.h['spindle_amps']) self.w.lbl_spindle_amps.setText(amps) def spindle_power_changed(self, data): power = "{:4.1f}".format(self.h['spindle_power']) self.w.lbl_spindle_power.setText(power) def spindle_fault_changed(self, data): fault = hex(self.h['spindle_fault']) self.w.lbl_spindle_fault.setText(fault) def mb_errors_changed(self, data): errors = self.h['modbus-errors'] self.w.lbl_mb_errors.setText(str(errors)) def dialog_return(self, w, message): rtn = message.get('RETURN') name = message.get('NAME') jog_code = bool(message.get('ID') == '_touchoff_') if jog_code and name == 'MESSAGE' and rtn is True: z_offset = float(self.w.lbl_touch_height.text()) max_probe = self.w.lbl_max_probe.text() search_vel = self.w.lbl_search_vel.text() probe_vel = self.w.lbl_probe_vel.text() ACTION.CALL_MDI("G21 G49") ACTION.CALL_MDI("G10 L20 P0 Z0") ACTION.CALL_MDI("G91") command = "G38.2 Z-{} F{}".format(max_probe, search_vel) if ACTION.CALL_MDI_WAIT(command, 10) == -1: return if ACTION.CALL_MDI_WAIT("G1 Z4.0") == -1: return ACTION.CALL_MDI("G4 P0.5") command = "G38.2 Z-4.4 F{}".format(probe_vel) if ACTION.CALL_MDI_WAIT(command, 10) == -1: return command = "G10 L20 P0 Z{}".format(z_offset) ACTION.CALL_MDI(command) command = "G1 Z10.0 F{}".format(search_vel) ACTION.CALL_MDI_WAIT(command, 10) ACTION.CALL_MDI("G90") def user_system_changed(self, obj, data): sys = self.system_list[int(data)] self.w.actionbutton_rel.setText(sys) def file_loaded(self, obj, filename): if filename is not None: self.w.progressBar.setValue(0) self.last_loaded_program = filename else: self.add_alarm("Filename not valid") def all_homed(self, obj): self.set_dro_homed(True) if self.first_turnon is True: self.first_turnon = False if self.w.chk_reload_tool.isChecked(): command = "M61 Q{}".format(self.reload_tool) ACTION.CALL_MDI(command) if self.last_loaded_program and self.w.chk_reload_program.isChecked( ): ACTION.OPEN_PROGRAM(self.last_loaded_program) self.w.filemanager.updateDirectoryView( self.last_loaded_program) def hard_limit_tripped(self, obj, tripped, list_of_tripped): self.w.chk_override_limits.setEnabled(tripped) if not tripped: self.w.chk_override_limits.setChecked(False) ####################### # CALLBACKS FROM FORM # ####################### # program frame def btn_start_clicked(self): if self.w.main_tab_widget.currentIndex() != 0: return if not STATUS.is_auto_mode(): self.add_alarm("Must be in AUTO mode to run a program") return self.w.btn_start.setProperty('running', True) self.w.btn_start.setStyle(self.w.btn_start.style()) start_line = int(self.w.lbl_start_line.text().encode('utf-8')) self.add_alarm("Started program from line {}".format(start_line)) ACTION.RUN(start_line) def btn_reload_file_clicked(self): if self.last_loaded_program: self.w.progressBar.setValue(0) ACTION.OPEN_PROGRAM(self.last_loaded_program) # tool frame def btn_go_home_clicked(self): ACTION.CALL_MDI_WAIT("G53 G0 Z0") command = "G53 G0 X{} Y{}".format(self.w.lbl_home_x.text(), self.w.lbl_home_y.text()) ACTION.CALL_MDI_WAIT(command, 10) def btn_ref_laser_clicked(self): command = "G10 L20 P0 X{} Y{}".format(self.w.lbl_laser_x.text(), self.w.lbl_laser_y.text()) ACTION.CALL_MDI(command) def btn_touchoff_clicked(self): if self.w.statuslabel_tool.text() == "0": self.add_alarm("Cannot touchoff with no tool loaded") return if not STATUS.is_all_homed(): self.add_alarm("Must be homed to perform tool touchoff") return max_probe = self.w.lbl_max_probe.text() self.add_alarm("Tool touchoff started") # instantiate dialog box info = "Jog to within {} mm of touch plate and click OK".format( max_probe) mess = { 'NAME': 'MESSAGE', 'ID': '_touchoff_', 'MESSAGE': 'TOOL TOUCHOFF', 'MORE': info, 'TYPE': 'OKCANCEL' } ACTION.CALL_DIALOG(mess) # override frame def slow_button_clicked(self, state): slider = self.w.sender().property('slider') current = self.w[slider].value() max = self.w[slider].maximum() if state: self.w.sender().setText("SLOW") self.w[slider].setMaximum(max / self.slow_jog_factor) self.w[slider].setValue(current / self.slow_jog_factor) self.w[slider].setPageStep(10) else: self.w.sender().setText("FAST") self.w[slider].setMaximum(max * self.slow_jog_factor) self.w[slider].setValue(current * self.slow_jog_factor) self.w[slider].setPageStep(100) # file tab def btn_gcode_edit_clicked(self, state): if not STATUS.is_on_and_idle(): return for x in ["load", "next", "prev"]: self.w["btn_file_{}".format(x)].setEnabled(not state) if state: self.w.filemanager.hide() self.w.gcode_editor.show() self.w.gcode_editor.editMode() else: self.w.filemanager.show() self.w.gcode_editor.hide() self.w.gcode_editor.readOnlyMode() # tool tab def btn_m61_clicked(self): checked = self.w.tooloffsetview.get_checked_list() if len(checked) > 1: self.add_alarm("Select only 1 tool to load") elif checked: ACTION.CALL_MDI("M61 Q{}".format(checked[0])) else: self.add_alarm("No tool selected") # alarm tab def btn_clear_alarms_clicked(self): ACTION.UPDATE_MACHINE_LOG('update-machine-log', None, 'DELETE') def btn_save_alarms_clicked(self): text = self.w.machinelog.toPlainText() filename = self.w.lbl_clock.text().encode('utf-8') filename = 'alarms_' + filename.replace(' ', '_') + '.txt' with open(filename, 'w') as f: f.write(text) # gcode tab def list_row_changed(self, row): line = self.w.gcode_list.currentItem().text().encode('utf-8') text = line.split(' ')[0] desc = mdiText.gcode_descriptions(text) or 'No Match' self.w.gcode_description.clear() self.w.gcode_description.insertPlainText(desc) if text != 'null': words = mdiText.gcode_words() if text in words: parm = text + ' ' for index, value in enumerate(words[text], start=0): parm += value self.w.gcode_parameters.setText(parm) else: self.w.gcode_parameters.setText('') # settings tab def chk_override_limits_checked(self, state): if state: print("Override limits set") ACTION.SET_LIMITS_OVERRIDE() else: print("Override limits not set") def chk_run_from_line_checked(self, state): if not state: self.w.lbl_start_line.setText('1') def chk_alpha_mode_checked(self, state): self.w.gcodegraphics.set_alpha_mode(state) def chk_inhibit_display_selection_checked(self, state): self.w.gcodegraphics.set_inhibit_selection(state) ##################### # GENERAL FUNCTIONS # ##################### def kb_jog(self, state, joint, direction, fast=False, linear=True): if not STATUS.is_man_mode() or not STATUS.machine_is_on(): self.add_alarm('Machine must be ON and in Manual mode to jog') return if linear: distance = STATUS.get_jog_increment() rate = STATUS.get_jograte() / 60 else: distance = STATUS.get_jog_increment_angular() rate = STATUS.get_jograte_angular() / 60 if state: if fast: rate = rate * 2 ACTION.JOG(joint, direction, rate, distance) else: ACTION.JOG(joint, 0, 0, 0) def add_alarm(self, message): ACTION.UPDATE_MACHINE_LOG(message, 'TIME') def alarm_added(self): self.w.led_alarm.setState(True) def tab_changed(self, index): self.w.btn_gcode_edit.setChecked(False) self.btn_gcode_edit_clicked(False) if index == 4: self.w.led_alarm.setState(False) def set_dro_homed(self, state): self.w.action_home_all.setProperty('homed', state) self.w.action_home_all.setStyle(self.w.action_home_all.style()) for i in map(str.lower, self.axis_list): self.w["dro_axis_{}".format(i)].setProperty('homed', state) self.w["dro_axis_{}".format(i)].setStyle( self.w["dro_axis_{}".format(i)].style()) def enable_onoff(self, state): for widget in self.onoff_list: self.w[widget].setEnabled(state) def set_start_line(self, line): if self.w.chk_run_from_line.isChecked(): self.w.lbl_start_line.setText(str(line)) else: self.w.lbl_start_line.setText('1') self.add_alarm('Run from line is disabled') def use_keyboard(self): if self.w.chk_use_keyboard.isChecked(): return True else: self.add_alarm('Keyboard shortcuts are disabled') return False ##################### # KEY BINDING CALLS # ##################### def on_keycall_ESTOP(self, event, state, shift, cntrl): if state: ACTION.SET_ESTOP_STATE(True) def on_keycall_POWER(self, event, state, shift, cntrl): if state: ACTION.SET_MACHINE_STATE(False) def on_keycall_ABORT(self, event, state, shift, cntrl): if state: ACTION.ABORT() def on_keycall_HOME(self, event, state, shift, cntrl): if state and not STATUS.is_all_homed() and self.use_keyboard(): ACTION.SET_MACHINE_HOMING(-1) def on_keycall_pause(self, event, state, shift, cntrl): if state and STATUS.is_auto_mode() and self.use_keyboard(): ACTION.PAUSE() def on_keycall_XPOS(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 0, 1, shift) def on_keycall_XNEG(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 0, -1, shift) def on_keycall_YPOS(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 1, 1, shift) def on_keycall_YNEG(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 1, -1, shift) def on_keycall_ZPOS(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 2, 1, shift) def on_keycall_ZNEG(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 2, -1, shift) def on_keycall_plus(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 3, 1, shift, False) def on_keycall_minus(self, event, state, shift, cntrl): if self.use_keyboard(): self.kb_jog(state, 3, -1, shift, False) def on_keycall_F12(self, event, state, shift, cntrl): if state: STYLEEDITOR.load_dialog() ############################## # required class boiler code # ############################## def __getitem__(self, item): return getattr(self, item) def __setitem__(self, item, value): return setattr(self, item, value)
class HandlerClass: def __init__(self, halcomp, widgets, paths): self.h = halcomp self.w = widgets self.gcodes = GCodes(widgets) self.valid = QtGui.QDoubleValidator(-999.999, 999.999, 3) self.styleeditor = SSE(widgets, paths) KEYBIND.add_call('Key_F4', 'on_keycall_F4') KEYBIND.add_call('Key_F12','on_keycall_F12') KEYBIND.add_call('Key_Pause', 'on_keycall_PAUSE') KEYBIND.add_call('Key_Space', 'on_keycall_PAUSE') # some global variables self.factor = 1.0 self.probe = None self.default_setup = os.path.join(PATH.CONFIGPATH, "default_setup.html") self.docs = os.path.join(PATH.SCREENDIR, PATH.BASEPATH,'docs/getting_started.html') self.start_line = 0 self.run_time = 0 self.time_tenths = 0 self.timer_on = False self.home_all = False self.min_spindle_rpm = INFO.MIN_SPINDLE_SPEED self.max_spindle_rpm = INFO.MAX_SPINDLE_SPEED self.max_spindle_power = INFO.get_error_safe_setting('DISPLAY', 'MAX_SPINDLE_POWER',"0") self.max_linear_velocity = INFO.MAX_TRAJ_VELOCITY self.system_list = ["G54","G55","G56","G57","G58","G59","G59.1","G59.2","G59.3"] self.slow_jog_factor = 10 self.reload_tool = 0 self.last_loaded_program = "" self.first_turnon = True self.unit_label_list = ["ts_height", "tp_height", "zoffset_units", "max_probe_units"] self.lineedit_list = ["work_height", "touch_height", "sensor_height", "laser_x", "laser_y", "sensor_x", "sensor_y", "camera_x", "camera_y", "search_vel", "probe_vel", "max_probe", "eoffset_count"] self.onoff_list = ["frame_program", "frame_tool", "frame_offsets", "frame_dro", "frame_override"] self.axis_a_list = ["label_axis_a", "dro_axis_a", "action_zero_a", "axistoolbutton_a", "action_home_a", "widget_jog_angular", "widget_increments_angular", "a_plus_jogbutton", "a_minus_jogbutton"] STATUS.connect('general', self.dialog_return) STATUS.connect('state-on', lambda w: self.enable_onoff(True)) STATUS.connect('state-off', lambda w: self.enable_onoff(False)) STATUS.connect('mode-auto', lambda w: self.enable_auto(True)) STATUS.connect('gcode-line-selected', lambda w, line: self.set_start_line(line)) STATUS.connect('hard-limits-tripped', self.hard_limit_tripped) STATUS.connect('program-pause-changed', lambda w, state: self.w.btn_pause_spindle.setEnabled(state)) STATUS.connect('user-system-changed', lambda w, data: self.user_system_changed(data)) STATUS.connect('metric-mode-changed', lambda w, mode: self.metric_mode_changed(mode)) STATUS.connect('file-loaded', self.file_loaded) STATUS.connect('all-homed', self.all_homed) STATUS.connect('not-all-homed', self.not_all_homed) STATUS.connect('periodic', lambda w: self.update_runtimer()) STATUS.connect('interp-idle', lambda w: self.stop_timer()) STATUS.connect('actual-spindle-speed-changed',self.update_spindle) STATUS.connect('requested-spindle-speed-changed',self.update_spindle_requested) STATUS.connect('override-limits-changed', lambda w, state, data: self._check_override_limits(state, data)) self.html = """<html> <head> <title>Test page for the download:// scheme</title> </head> <body> <h1>Setup Tab</h1> <p>If you select a file with .html as a file ending, it will be shown here..</p> <img src="file://%s" alt="lcnc_swoop" /> <hr /> </body> </html> """ %(os.path.join(paths.IMAGEDIR,'lcnc_swoop.png')) def class_patch__(self): self.old_fman = FM.load FM.load = self.load_code def initialized__(self): self.init_pins() self.init_preferences() self.init_widgets() self.init_probe() self.init_utils() self.w.stackedWidget_log.setCurrentIndex(0) self.w.stackedWidget_dro.setCurrentIndex(0) if self.probe is not None: self.probe.hide() self.w.btn_pause_spindle.setEnabled(False) self.w.btn_dimensions.setChecked(True) self.w.page_buttonGroup.buttonClicked.connect(self.main_tab_changed) self.w.filemanager.onUserClicked() self.w.filemanager_usb.onMediaClicked() # hide widgets for A axis if not present if "A" not in INFO.AVAILABLE_AXES: for i in self.axis_a_list: self.w[i].hide() self.w.lbl_increments_linear.setText("INCREMENTS") # set validators for lineEdit widgets for val in self.lineedit_list: self.w['lineEdit_' + val].setValidator(self.valid) # set unit labels according to machine mode unit = "MM" if INFO.MACHINE_IS_METRIC else "IN" for i in self.unit_label_list: self.w['lbl_' + i].setText(unit) unit = "MM/MIN" if INFO.MACHINE_IS_METRIC else "IN/MIN" for i in ["search_vel_units", "probe_vel_units", "jog_linear"]: self.w['lbl_' + i].setText(unit) self.w.setWindowFlags(QtCore.Qt.FramelessWindowHint) ############################# # SPECIAL FUNCTIONS SECTION # ############################# def init_pins(self): # spindle control pins pin = self.h.newpin("spindle_amps", hal.HAL_FLOAT, hal.HAL_IN) pin.value_changed.connect(self.spindle_pwr_changed) pin = self.h.newpin("spindle_volts", hal.HAL_FLOAT, hal.HAL_IN) pin.value_changed.connect(self.spindle_pwr_changed) pin = self.h.newpin("spindle_fault", hal.HAL_U32, hal.HAL_IN) pin.value_changed.connect(self.spindle_fault_changed) # self.h.newpin("spindle_at_speed", hal.HAL_BIT, hal.HAL_IN) pin = self.h.newpin("modbus-errors", hal.HAL_U32, hal.HAL_IN) pin.value_changed.connect(self.mb_errors_changed) self.h.newpin("spindle_inhibit", hal.HAL_BIT, hal.HAL_OUT) # external offset control pins self.h.newpin("eoffset_enable", hal.HAL_BIT, hal.HAL_OUT) self.h.newpin("eoffset_clear", hal.HAL_BIT, hal.HAL_OUT) self.h.newpin("eoffset_count", hal.HAL_S32, hal.HAL_OUT) pin = self.h.newpin("eoffset_value", hal.HAL_FLOAT, hal.HAL_IN) pin.value_changed.connect(self.eoffset_changed) def init_preferences(self): if not self.w.PREFS_: self.add_status("CRITICAL - no preference file found, enable preferences in screenoptions widget") return self.last_loaded_program = self.w.PREFS_.getpref('last_loaded_file', None, str,'BOOK_KEEPING') self.reload_tool = self.w.PREFS_.getpref('Tool to load', 0, int,'CUSTOM_FORM_ENTRIES') self.w.lineEdit_laser_x.setText(str(self.w.PREFS_.getpref('Laser X', 100, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_laser_y.setText(str(self.w.PREFS_.getpref('Laser Y', -20, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_sensor_x.setText(str(self.w.PREFS_.getpref('Sensor X', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_sensor_y.setText(str(self.w.PREFS_.getpref('Sensor Y', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_camera_x.setText(str(self.w.PREFS_.getpref('Camera X', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_camera_y.setText(str(self.w.PREFS_.getpref('Camera Y', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_work_height.setText(str(self.w.PREFS_.getpref('Work Height', 20, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_touch_height.setText(str(self.w.PREFS_.getpref('Touch Height', 40, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_sensor_height.setText(str(self.w.PREFS_.getpref('Sensor Height', 40, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_search_vel.setText(str(self.w.PREFS_.getpref('Search Velocity', 40, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_probe_vel.setText(str(self.w.PREFS_.getpref('Probe Velocity', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_max_probe.setText(str(self.w.PREFS_.getpref('Max Probe', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_eoffset_count.setText(str(self.w.PREFS_.getpref('Eoffset count', 0, int, 'CUSTOM_FORM_ENTRIES'))) self.w.chk_eoffsets.setChecked(self.w.PREFS_.getpref('External offsets', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_reload_program.setChecked(self.w.PREFS_.getpref('Reload program', False, bool,'CUSTOM_FORM_ENTRIES')) self.w.chk_reload_tool.setChecked(self.w.PREFS_.getpref('Reload tool', False, bool,'CUSTOM_FORM_ENTRIES')) self.w.chk_use_keyboard.setChecked(self.w.PREFS_.getpref('Use keyboard', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_tool_sensor.setChecked(self.w.PREFS_.getpref('Use tool sensor', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_touchplate.setChecked(self.w.PREFS_.getpref('Use tool touchplate', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_run_from_line.setChecked(self.w.PREFS_.getpref('Run from line', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_virtual.setChecked(self.w.PREFS_.getpref('Use virtual keyboard', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_camera.setChecked(self.w.PREFS_.getpref('Use camera', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_alpha_mode.setChecked(self.w.PREFS_.getpref('Use alpha display mode', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_inhibit_selection.setChecked(self.w.PREFS_.getpref('Inhibit display mouse selection', True, bool, 'CUSTOM_FORM_ENTRIES')) def closing_cleanup__(self): if not self.w.PREFS_: return if self.last_loaded_program is not None: self.w.PREFS_.putpref('last_loaded_directory', os.path.dirname(self.last_loaded_program), str, 'BOOK_KEEPING') self.w.PREFS_.putpref('last_loaded_file', self.last_loaded_program, str, 'BOOK_KEEPING') self.w.PREFS_.putpref('Tool to load', STATUS.get_current_tool(), int, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Laser X', self.w.lineEdit_laser_x.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Laser Y', self.w.lineEdit_laser_y.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Sensor X', self.w.lineEdit_sensor_x.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Sensor Y', self.w.lineEdit_sensor_y.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Camera X', self.w.lineEdit_camera_x.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Camera Y', self.w.lineEdit_camera_y.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Work Height', self.w.lineEdit_work_height.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Touch Height', self.w.lineEdit_touch_height.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Sensor Height', self.w.lineEdit_sensor_height.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Search Velocity', self.w.lineEdit_search_vel.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Probe Velocity', self.w.lineEdit_probe_vel.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Max Probe', self.w.lineEdit_max_probe.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Eoffset count', self.w.lineEdit_eoffset_count.text().encode('utf-8'), int, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('External offsets', self.w.chk_eoffsets.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Reload program', self.w.chk_reload_program.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Reload tool', self.w.chk_reload_tool.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use keyboard', self.w.chk_use_keyboard.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use tool sensor', self.w.chk_use_tool_sensor.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use tool touchplate', self.w.chk_use_touchplate.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Run from line', self.w.chk_run_from_line.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use virtual keyboard', self.w.chk_use_virtual.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use camera', self.w.chk_use_camera.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use alpha display mode', self.w.chk_alpha_mode.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Inhibit display mouse selection', self.w.chk_inhibit_selection.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') if self.probe is not None: self.probe.closing_cleanup__() def init_widgets(self): self.w.main_tab_widget.setCurrentIndex(0) self.w.slider_jog_linear.setMaximum(INFO.MAX_LINEAR_JOG_VEL) self.w.slider_jog_linear.setValue(INFO.DEFAULT_LINEAR_JOG_VEL) self.w.slider_jog_angular.setMaximum(INFO.MAX_ANGULAR_JOG_VEL) self.w.slider_jog_angular.setValue(INFO.DEFAULT_ANGULAR_JOG_VEL) self.w.slider_feed_ovr.setMaximum(INFO.MAX_FEED_OVERRIDE) self.w.slider_feed_ovr.setValue(100) self.w.slider_spindle_ovr.setMinimum(INFO.MIN_SPINDLE_OVERRIDE) self.w.slider_spindle_ovr.setMaximum(INFO.MAX_SPINDLE_OVERRIDE) self.w.slider_spindle_ovr.setValue(100) self.w.chk_override_limits.setChecked(False) self.w.chk_override_limits.setEnabled(False) self.w.lbl_maxv_percent.setText("100 %") self.w.lbl_max_rapid.setText(str(self.max_linear_velocity)) self.w.lbl_home_x.setText(INFO.get_error_safe_setting('JOINT_0', 'HOME',"50")) self.w.lbl_home_y.setText(INFO.get_error_safe_setting('JOINT_1', 'HOME',"50")) self.w.cmb_gcode_history.addItem("No File Loaded") self.w.cmb_gcode_history.wheelEvent = lambda event: None self.w.jogincrements_linear.wheelEvent = lambda event: None self.w.jogincrements_angular.wheelEvent = lambda event: None self.w.gcode_editor.hide() self.w.filemanager.table.setShowGrid(False) self.w.filemanager_usb.table.setShowGrid(False) self.w.tooloffsetview.setShowGrid(False) self.w.offset_table.setShowGrid(False) self.w.divider_line.hide() # move clock to statusbar self.w.statusbar.addPermanentWidget(self.w.lbl_clock) #set up gcode list self.gcodes.setup_list() # check for default setup html file try: # web view widget for SETUP page if self.w.web_view: self.toolBar = QtWidgets.QToolBar(self.w) self.w.layout_setup.addWidget(self.toolBar) self.backBtn = QtWidgets.QPushButton(self.w) self.backBtn.setEnabled(True) self.backBtn.setIcon(QtGui.QIcon(':/qt-project.org/styles/commonstyle/images/left-32.png')) self.backBtn.clicked.connect(self.back) self.toolBar.addWidget(self.backBtn) self.forBtn = QtWidgets.QPushButton(self.w) self.forBtn.setEnabled(True) self.forBtn.setIcon(QtGui.QIcon(':/qt-project.org/styles/commonstyle/images/right-32.png')) self.forBtn.clicked.connect(self.forward) self.toolBar.addWidget(self.forBtn) self.writeBtn = QtWidgets.QPushButton('SetUp\n Writer',self.w) self.writeBtn.setEnabled(True) self.writeBtn.clicked.connect(self.writer) self.toolBar.addWidget(self.writeBtn) self.w.layout_setup.addWidget(self.w.web_view) if os.path.exists(self.default_setup): self.w.web_view.load(QtCore.QUrl.fromLocalFile(self.default_setup)) else: self.w.web_view.setHtml(self.html) except Exception as e: print("No default setup file found - {}".format(e)) # set up spindle gauge self.w.gauge_spindle.set_max_value(self.max_spindle_rpm) self.w.gauge_spindle.set_max_reading(self.max_spindle_rpm / 1000) self.w.gauge_spindle.set_threshold(self.min_spindle_rpm) self.w.gauge_spindle.set_label("RPM") def init_probe(self): probe = INFO.get_error_safe_setting('PROBE', 'USE_PROBE', 'none').lower() if probe == 'versaprobe': LOG.info("Using Versa Probe") from qtvcp.widgets.versa_probe import VersaProbe self.probe = VersaProbe() self.probe.setObjectName('versaprobe') elif probe == 'basicprobe': LOG.info("Using Basic Probe") from qtvcp.widgets.basic_probe import BasicProbe self.probe = BasicProbe() self.probe.setObjectName('basicprobe') else: LOG.info("No valid probe widget specified") self.w.btn_probe.hide() return self.w.probe_layout.addWidget(self.probe) self.probe.hal_init() def init_utils(self): from qtvcp.lib.gcode_utility.facing import Facing self.facing = Facing() self.w.layout_facing.addWidget(self.facing) from qtvcp.lib.gcode_utility.hole_circle import Hole_Circle self.hole_circle = Hole_Circle() self.w.layout_hole_circle.addWidget(self.hole_circle) def processed_focus_event__(self, receiver, event): if not self.w.chk_use_virtual.isChecked() or STATUS.is_auto_mode(): return if isinstance(receiver, QtWidgets.QLineEdit): if not receiver.isReadOnly(): self.w.stackedWidget_dro.setCurrentIndex(1) elif isinstance(receiver, QtWidgets.QTableView): self.w.stackedWidget_dro.setCurrentIndex(1) elif isinstance(receiver, QtWidgets.QCommonStyle): return def processed_key_event__(self,receiver,event,is_pressed,key,code,shift,cntrl): # when typing in MDI, we don't want keybinding to call functions # so we catch and process the events directly. # We do want ESC, F1 and F2 to call keybinding functions though if code not in(QtCore.Qt.Key_Escape,QtCore.Qt.Key_F1 ,QtCore.Qt.Key_F2): # QtCore.Qt.Key_F3,QtCore.Qt.Key_F4,QtCore.Qt.Key_F5): # search for the top widget of whatever widget received the event # then check if it's one we want the keypress events to go to flag = False receiver2 = receiver while receiver2 is not None and not flag: if isinstance(receiver2, QtWidgets.QDialog): flag = True break if isinstance(receiver2, QtWidgets.QLineEdit): flag = True break if isinstance(receiver2, MDI_WIDGET): flag = True break if isinstance(receiver2, GCODE): flag = True break if isinstance(receiver2, TOOL_TABLE): flag = True break if isinstance(receiver2, OFFSET_VIEW): flag = True break receiver2 = receiver2.parent() if flag: if isinstance(receiver2, GCODE): # if in manual or in readonly mode do our keybindings - otherwise # send events to gcode widget if STATUS.is_man_mode() == False or not receiver2.isReadOnly(): if is_pressed: receiver.keyPressEvent(event) event.accept() return True if is_pressed: receiver.keyPressEvent(event) event.accept() return True else: event.accept() return True if event.isAutoRepeat():return True # ok if we got here then try keybindings function calls # KEYBINDING will call functions from handler file as # registered by KEYBIND.add_call(KEY,FUNCTION) above return KEYBIND.manage_function_calls(self,event,is_pressed,key,shift,cntrl) ######################### # CALLBACKS FROM STATUS # ######################### def update_spindle(self,w,data): self.w.gauge_spindle.update_value(abs(data)) def update_spindle_requested(self,w,data): self.w.gauge_spindle.set_setpoint(abs(data)) def spindle_pwr_changed(self, data): # this calculation assumes the voltage is line to neutral # that the current reported by the VFD is total current for all 3 phases # and that the synchronous motor spindle has a power factor of 0.9 try: power = float(self.h['spindle_volts'] * self.h['spindle_amps'] * 0.9) # V x I x PF pc_power = (power / float(self.max_spindle_power)) * 100 if pc_power > 100: pc_power = 100 self.w.spindle_power.setValue(int(pc_power)) except: self.w.spindle_power.setValue(0) def spindle_fault_changed(self, data): fault = hex(self.h['spindle_fault']) self.w.lbl_spindle_fault.setText(fault) def mb_errors_changed(self, data): errors = self.h['modbus-errors'] self.w.lbl_mb_errors.setText(str(errors)) def eoffset_changed(self, data): eoffset = "{:2.3f}".format(self.h['eoffset_value']) self.w.lbl_eoffset_value.setText(eoffset) def dialog_return(self, w, message): rtn = message.get('RETURN') name = message.get('NAME') plate_code = bool(message.get('ID') == '_touchplate_') sensor_code = bool(message.get('ID') == '_toolsensor_') wait_code = bool(message.get('ID') == '_wait_resume_') unhome_code = bool(message.get('ID') == '_unhome_') if plate_code and name == 'MESSAGE' and rtn is True: self.touchoff('touchplate') elif sensor_code and name == 'MESSAGE' and rtn is True: self.touchoff('sensor') elif wait_code and name == 'MESSAGE': self.h['eoffset_clear'] = False elif unhome_code and name == 'MESSAGE' and rtn is True: ACTION.SET_MACHINE_UNHOMED(-1) def user_system_changed(self, data): sys = self.system_list[int(data) - 1] self.w.offset_table.selectRow(int(data) + 3) self.w.actionbutton_rel.setText(sys) def metric_mode_changed(self, mode): unit = "MM" if mode else "IN" self.w.lbl_jog_linear.setText(unit + "/MIN") if INFO.MACHINE_IS_METRIC == mode: self.factor = 1.0 rapid = (float(self.w.slider_rapid_ovr.value()) / 100) * self.max_linear_velocity elif mode: self.factor = 25.4 rapid = (float(self.w.slider_rapid_ovr.value()) / 100) * self.max_linear_velocity * 25.4 else: self.factor = 1/25.4 rapid = (float(self.w.slider_rapid_ovr.value()) / 100) * self.max_linear_velocity / 25.4 self.w.lbl_max_rapid.setText("{:4.0f}".format(rapid)) def file_loaded(self, obj, filename): if os.path.basename(filename).count('.') > 1: self.last_loaded_program = "" return if filename is not None: self.add_status("Loaded file {}".format(filename)) self.w.progressBar.reset() self.last_loaded_program = filename self.w.lbl_runtime.setText("00:00:00") else: self.add_status("Filename not valid") def percent_loaded_changed(self, fraction): if fraction < 0: self.w.progressBar.setValue(0) self.w.progressBar.setFormat('PROGRESS') else: self.w.progressBar.setValue(fraction) self.w.progressBar.setFormat('LOADING: {}%'.format(fraction)) def percent_done_changed(self, fraction): self.w.progressBar.setValue(fraction) if fraction < 0: self.w.progressBar.setValue(0) self.w.progressBar.setFormat('PROGRESS') else: self.w.progressBar.setFormat('COMPLETE: {}%'.format(fraction)) def all_homed(self, obj): self.home_all = True self.w.btn_home_all.setText("ALL HOMED") if self.first_turnon is True: self.first_turnon = False if self.w.chk_reload_tool.isChecked(): command = "M61 Q{}".format(self.reload_tool) ACTION.CALL_MDI(command) if self.last_loaded_program is not None and self.w.chk_reload_program.isChecked(): if os.path.isfile(self.last_loaded_program): self.w.cmb_gcode_history.addItem(self.last_loaded_program) self.w.cmb_gcode_history.setCurrentIndex(self.w.cmb_gcode_history.count() - 1) self.w.cmb_gcode_history.setToolTip(fname) ACTION.OPEN_PROGRAM(self.last_loaded_program) ACTION.SET_MANUAL_MODE() self.w.manual_mode_button.setChecked(True) def not_all_homed(self, obj, list): self.home_all = False self.w.btn_home_all.setText("HOME ALL") def hard_limit_tripped(self, obj, tripped, list_of_tripped): self.add_status("Hard limits tripped") self.w.chk_override_limits.setEnabled(tripped) if not tripped: self.w.chk_override_limits.setChecked(False) # keep check button in synch of external changes def _check_override_limits(self,state,data): if 0 in data: self.w.chk_override_limits.setChecked(False) else: self.w.chk_override_limits.setChecked(True) ####################### # CALLBACKS FROM FORM # ####################### # main button bar def main_tab_changed(self, btn): index = btn.property("index") if index is None: return # if in automode still allow settings to show so override linits can be used if STATUS.is_auto_mode() and index != 8: self.add_status("Cannot switch pages while in AUTO mode") # make sure main page is showing self.w.main_tab_widget.setCurrentIndex(0) self.w.btn_main.setChecked(True) return if index == TAB_MAIN: self.w.stackedWidget_dro.setCurrentIndex(0) elif index == TAB_FILE and self.w.btn_gcode_edit.isChecked(): self.w.btn_gcode_edit.setChecked(False) self.w.btn_gcode_edit_clicked(False) if btn == self.w.btn_probe: self.probe.show() self.w.divider_line.show() elif self.probe is not None: self.probe.hide() self.w.divider_line.hide() self.w.main_tab_widget.setCurrentIndex(index) # gcode frame def cmb_gcode_history_clicked(self): if self.w.cmb_gcode_history.currentIndex() == 0: return filename = self.w.cmb_gcode_history.currentText().encode('utf-8') if filename == self.last_loaded_program: self.add_status("Selected program is already loaded") else: ACTION.OPEN_PROGRAM(filename) # program frame def btn_start_clicked(self, obj): if self.w.main_tab_widget.currentIndex() != 0: return if not STATUS.is_auto_mode(): self.add_status("Must be in AUTO mode to run a program") return if STATUS.is_auto_running(): self.add_status("Program is already running") return self.run_time = 0 self.w.lbl_runtime.setText("00:00:00") if self.start_line <= 1: ACTION.RUN(self.start_line) else: # instantiate run from line preset dialog info = '<b>Running From Line: {} <\b>'.format(self.start_line) mess = {'NAME':'RUNFROMLINE', 'TITLE':'Preset Dialog', 'ID':'_RUNFROMLINE', 'MESSAGE':info, 'LINE':self.start_line} ACTION.CALL_DIALOG(mess) self.add_status("Started program from line {}".format(self.start_line)) self.timer_on = True def btn_stop_clicked(self): if not self.w.btn_pause_spindle.isChecked(): return self.w.btn_pause_spindle.setChecked(False) self.btn_pause_spindle_clicked(False) def btn_reload_file_clicked(self): if self.last_loaded_program: self.w.progressBar.reset() self.add_status("Loaded program file {}".format(self.last_loaded_program)) ACTION.OPEN_PROGRAM(self.last_loaded_program) def btn_pause_spindle_clicked(self, state): self.w.action_pause.setEnabled(not state) self.w.action_step.setEnabled(not state) if state: # set external offsets to lift spindle self.h['eoffset_enable'] = self.w.chk_eoffsets.isChecked() fval = float(self.w.lineEdit_eoffset_count.text()) self.h['eoffset_count'] = int(fval) self.h['spindle_inhibit'] = True else: self.h['eoffset_count'] = 0 self.h['eoffset_clear'] = True self.h['spindle_inhibit'] = False if STATUS.is_auto_running(): # instantiate warning box info = "Wait for spindle at speed signal before resuming" mess = {'NAME':'MESSAGE', 'ICON':'WARNING', 'ID':'_wait_resume_', 'MESSAGE':'CAUTION', 'MORE':info, 'TYPE':'OK'} ACTION.CALL_DIALOG(mess) # offsets frame def btn_goto_location_clicked(self): dest = self.w.sender().property('location') if dest == 'home': x = float(self.w.lbl_home_x.text()) y = float(self.w.lbl_home_y.text()) elif dest == 'sensor': x = float(self.w.lineEdit_sensor_x.text()) y = float(self.w.lineEdit_sensor_y.text()) else: return if not STATUS.is_metric_mode(): x = x / 25.4 y = y / 25.4 ACTION.CALL_MDI("G90") ACTION.CALL_MDI_WAIT("G53 G0 Z0") command = "G53 G0 X{:3.4f} Y{:3.4f}".format(x, y) ACTION.CALL_MDI_WAIT(command, 10) def btn_ref_laser_clicked(self): x = float(self.w.lineEdit_laser_x.text()) y = float(self.w.lineEdit_laser_y.text()) if not STATUS.is_metric_mode(): x = x / 25.4 y = y / 25.4 self.add_status("Laser offsets set") command = "G10 L20 P0 X{:3.4f} Y{:3.4f}".format(x, y) ACTION.CALL_MDI(command) def btn_ref_camera_clicked(self): x = float(self.w.lineEdit_camera_x.text()) y = float(self.w.lineEdit_camera_y.text()) if not STATUS.is_metric_mode(): x = x / 25.4 y = y / 25.4 self.add_status("Camera offsets set") command = "G10 L20 P0 X{:3.4f} Y{:3.4f}".format(x, y) ACTION.CALL_MDI(command) def btn_touchoff_clicked(self): if STATUS.get_current_tool() == 0: self.add_status("Cannot touchoff with no tool loaded") return if not STATUS.is_all_homed(): self.add_status("Must be homed to perform tool touchoff") return # instantiate dialog box sensor = self.w.sender().property('sensor') info = "Ensure tooltip is within {} mm of tool sensor and click OK".format(self.w.lineEdit_max_probe.text()) mess = {'NAME':'MESSAGE', 'ID':sensor, 'MESSAGE':'TOOL TOUCHOFF', 'MORE':info, 'TYPE':'OKCANCEL'} ACTION.CALL_DIALOG(mess) def chk_lock_wph_changed(self, state): self.w.lineEdit_work_height.setReadOnly(not state) # DRO frame def btn_home_all_clicked(self, obj): if self.home_all is False: ACTION.SET_MACHINE_HOMING(-1) else: # instantiate dialog box info = "Unhome All Axes?" mess = {'NAME':'MESSAGE', 'ID':'_unhome_', 'MESSAGE':'UNHOME ALL', 'MORE':info, 'TYPE':'OKCANCEL'} ACTION.CALL_DIALOG(mess) def btn_home_clicked(self): joint = self.w.sender().property('joint') axis = INFO.GET_NAME_FROM_JOINT.get(joint).lower() if self.w["dro_axis_{}".format(axis)].property('isHomed') is True: ACTION.SET_MACHINE_UNHOMED(joint) else: ACTION.SET_MACHINE_HOMING(joint) # override frame def slow_button_clicked(self, state): slider = self.w.sender().property('slider') current = self.w[slider].value() max = self.w[slider].maximum() if state: self.w.sender().setText("SLOW") self.w[slider].setMaximum(max / self.slow_jog_factor) self.w[slider].setValue(current / self.slow_jog_factor) self.w[slider].setPageStep(10) else: self.w.sender().setText("FAST") self.w[slider].setMaximum(max * self.slow_jog_factor) self.w[slider].setValue(current * self.slow_jog_factor) self.w[slider].setPageStep(100) def slider_maxv_changed(self, value): maxpc = (float(value) / self.max_linear_velocity) * 100 self.w.lbl_maxv_percent.setText("{:3.0f} %".format(maxpc)) def slider_rapid_changed(self, value): rapid = (float(value) / 100) * self.max_linear_velocity * self.factor self.w.lbl_max_rapid.setText("{:4.0f}".format(rapid)) def btn_maxv_100_clicked(self): self.w.slider_maxv_ovr.setValue(self.max_linear_velocity) def btn_maxv_50_clicked(self): self.w.slider_maxv_ovr.setValue(self.max_linear_velocity / 2) # file tab def btn_gcode_edit_clicked(self, state): if not STATUS.is_on_and_idle(): return if state: self.w.filemanager.hide() self.w.gcode_editor.show() self.w.gcode_editor.editMode() else: self.w.filemanager.show() self.w.gcode_editor.hide() self.w.gcode_editor.readOnlyMode() def btn_load_file_clicked(self): if self.w.btn_gcode_edit.isChecked(): return fname = self.w.filemanager.getCurrentSelected() if fname[1] is True: self.load_code(fname[0]) def btn_copy_file_clicked(self): if self.w.btn_gcode_edit.isChecked(): return if self.w.sender() == self.w.btn_copy_right: source = self.w.filemanager_usb.getCurrentSelected() target = self.w.filemanager.getCurrentSelected() elif self.w.sender() == self.w.btn_copy_left: source = self.w.filemanager.getCurrentSelected() target = self.w.filemanager_usb.getCurrentSelected() else: return if source[1] is False: self.add_status("Specified source is not a file") return if target[1] is True: destination = os.path.join(os.path.dirname(target[0]), os.path.basename(source[0])) else: destination = os.path.join(target[0], os.path.basename(source[0])) try: copyfile(source[0], destination) self.add_status("Copied file from {} to {}".format(source[0], destination)) except Exception as e: self.add_status("Unable to copy file. %s" %e) # tool tab def btn_m61_clicked(self): checked = self.w.tooloffsetview.get_checked_list() if len(checked) > 1: self.add_status("Select only 1 tool to load") elif checked: self.add_status("Loaded tool {}".format(checked[0])) ACTION.CALL_MDI("M61 Q{}".format(checked[0])) else: self.add_status("No tool selected") # status tab def btn_clear_status_clicked(self): STATUS.emit('update-machine-log', None, 'DELETE') def btn_save_status_clicked(self): text = self.w.machinelog.toPlainText() filename = self.w.lbl_clock.text().encode('utf-8') filename = 'status_' + filename.replace(' ','_') + '.txt' self.add_status("Saving Status file to {}".format(filename)) with open(filename, 'w') as f: f.write(text) def btn_dimensions_clicked(self, state): self.w.gcodegraphics.show_extents_option = state self.w.gcodegraphics.clear_live_plotter() # camview tab def cam_zoom_changed(self, value): self.w.camview.scale = float(value) / 10 def cam_dia_changed(self, value): self.w.camview.diameter = value def cam_rot_changed(self, value): self.w.camview.rotation = float(value) / 10 # settings tab def chk_override_limits_checked(self, state): # only toggle override if it's not in synch with the button if state and not STATUS.is_limits_override_set(): self.add_status("Override limits set") ACTION.TOGGLE_LIMITS_OVERRIDE() elif not state and STATUS.is_limits_override_set(): error = ACTION.TOGGLE_LIMITS_OVERRIDE() # if override can't be released set the check button to reflect this if error == False: self.w.chk_override_limits.blockSignals(True) self.w.chk_override_limits.setChecked(True) self.w.chk_override_limits.blockSignals(False) else: self.add_status("Override limits not set") def chk_run_from_line_changed(self, state): if not state: self.w.btn_cycle_start.setText('CYCLE START') def chk_alpha_mode_changed(self, state): self.w.gcodegraphics.set_alpha_mode(state) def chk_inhibit_selection_changed(self, state): self.w.gcodegraphics.set_inhibit_selection(state) def chk_use_camera_changed(self, state): self.w.btn_ref_camera.setEnabled(state) if state : self.w.btn_camera.show() else: self.w.btn_camera.hide() def chk_use_sensor_changed(self, state): self.w.btn_tool_sensor.setEnabled(state) def chk_use_touchplate_changed(self, state): self.w.btn_touchplate.setEnabled(state) def chk_use_virtual_changed(self, state): codestring = "CALCULATOR" if state else "ENTRY" for i in ("x", "y", "z", "a"): self.w["axistoolbutton_" + i].set_dialog_code(codestring) if self.probe: self.probe.dialog_code = codestring if not state: self.w.stackedWidget_dro.setCurrentIndex(0) ##################### # GENERAL FUNCTIONS # ##################### def load_code(self, fname): if fname is None: return filename, file_extension = os.path.splitext(fname) if not file_extension in (".html", '.pdf'): if not (INFO.program_extension_valid(fname)): self.add_status("Unknown or invalid filename extension {}".format(file_extension)) return self.w.cmb_gcode_history.addItem(fname) self.w.cmb_gcode_history.setCurrentIndex(self.w.cmb_gcode_history.count() - 1) self.w.cmb_gcode_history.setToolTip(fname) ACTION.OPEN_PROGRAM(fname) self.add_status("Loaded program file : {}".format(fname)) self.w.main_tab_widget.setCurrentIndex(TAB_MAIN) self.w.filemanager.recordBookKeeping() # adjust ending to check for related HTML setup files fname = filename+'.html' if os.path.exists(fname): self.w.web_view.load(QtCore.QUrl.fromLocalFile(fname)) self.add_status("Loaded HTML file : {}".format(fname)) else: self.w.web_view.setHtml(self.html) # look for PDF setup files # load it with system program fname = filename+'.pdf' if os.path.exists(fname): url = QtCore.QUrl.fromLocalFile(fname) QtGui.QDesktopServices.openUrl(url) self.add_status("Loaded PDF file : {}".format(fname)) return if file_extension == ".html": try: self.w.web_view.load(QtCore.QUrl.fromLocalFile(fname)) self.add_status("Loaded HTML file : {}".format(fname)) self.w.main_tab_widget.setCurrentIndex(TAB_SETUP) self.w.stackedWidget.setCurrentIndex(0) self.w.btn_setup.setChecked(True) self.w.jogging_frame.hide() except Exception as e: print("Error loading HTML file : {}".format(e)) else: # load PDF with system program if os.path.exists(fname): url = QtCore.QUrl.fromLocalFile(fname) QtGui.QDesktopServices.openUrl(url) self.add_status("Loaded PDF file : {}".format(fname)) def disable_spindle_pause(self): self.h['eoffset_count'] = 0 self.h['spindle_inhibit'] = False if self.w.btn_pause_spindle.isChecked(): self.w.btn_pause_spindle.setChecked(False) def touchoff(self, selector): if selector == 'touchplate': z_offset = float(self.w.lineEdit_touch_height.text()) elif selector == 'sensor': z_offset = float(self.w.lineEdit_sensor_height.text()) - float(self.w.lineEdit_work_height.text()) else: self.add_alarm("Unknown touchoff routine specified") return self.add_status("Touchoff to {} started".format(selector)) max_probe = self.w.lineEdit_max_probe.text() search_vel = self.w.lineEdit_search_vel.text() probe_vel = self.w.lineEdit_probe_vel.text() ACTION.CALL_MDI("G21 G49") ACTION.CALL_MDI("G10 L20 P0 Z0") ACTION.CALL_MDI("G91") command = "G38.2 Z-{} F{}".format(max_probe, search_vel) if ACTION.CALL_MDI_WAIT(command, 10) == -1: ACTION.CALL_MDI("G90") return if ACTION.CALL_MDI_WAIT("G1 Z4.0"): ACTION.CALL_MDI("G90") return ACTION.CALL_MDI("G4 P0.5") command = "G38.2 Z-4.4 F{}".format(probe_vel) if ACTION.CALL_MDI_WAIT(command, 10) == -1: ACTION.CALL_MDI("G90") return command = "G10 L20 P0 Z{}".format(z_offset) ACTION.CALL_MDI_WAIT(command) command = "G1 Z10 F{}".format(search_vel) ACTION.CALL_MDI_WAIT(command) ACTION.CALL_MDI("G90") def kb_jog(self, state, joint, direction, fast = False, linear = True): if not STATUS.is_man_mode() or not STATUS.machine_is_on(): self.add_status('Machine must be ON and in Manual mode to jog') return if linear: distance = STATUS.get_jog_increment() rate = STATUS.get_jograte()/60 else: distance = STATUS.get_jog_increment_angular() rate = STATUS.get_jograte_angular()/60 if state: if fast: rate = rate * 2 ACTION.JOG(joint, direction, rate, distance) else: ACTION.JOG(joint, 0, 0, 0) def add_status(self, message): self.w.statusbar.showMessage(message) STATUS.emit('update-machine-log', message, 'TIME') def enable_auto(self, state): if state is True: self.w.btn_main.setChecked(True) self.w.main_tab_widget.setCurrentIndex(TAB_MAIN) if self.probe is not None: self.probe.hide() self.w.stackedWidget_dro.setCurrentIndex(0) def enable_onoff(self, state): if state: self.add_status("Machine ON") else: self.add_status("Machine OFF") self.w.btn_pause_spindle.setChecked(False) self.h['eoffset_count'] = 0 for widget in self.onoff_list: self.w[widget].setEnabled(state) def set_start_line(self, line): if self.w.chk_run_from_line.isChecked(): self.start_line = line self.w.btn_cycle_start.setText("CYCLE START\nLINE {}".format(self.start_line)) else: self.start_line = 1 def use_keyboard(self): if self.w.chk_use_keyboard.isChecked(): return True else: self.add_status('Keyboard shortcuts are disabled') return False def update_rpm(self, speed): rpm = int(speed) if rpm == 0: in_range = True at_speed = False else: in_range = (self.min_spindle_rpm <= int(speed) <= self.max_spindle_rpm) at_speed = self.h['spindle_at_speed'] widget = self.w.lbl_spindle_set widget.setProperty('in_range', in_range) widget.style().unpolish(widget) widget.style().polish(widget) if at_speed is True: self.w.lbl_spindle_atspeed.setText('AT SPEED') else: self.w.lbl_spindle_atspeed.setText('') def update_runtimer(self): if self.timer_on is False or STATUS.is_auto_paused(): return self.time_tenths += 1 if self.time_tenths == 10: self.time_tenths = 0 self.run_time += 1 hours, remainder = divmod(self.run_time, 3600) minutes, seconds = divmod(remainder, 60) self.w.lbl_runtime.setText("{:02d}:{:02d}:{:02d}".format(hours, minutes, seconds)) def stop_timer(self): if self.timer_on: self.timer_on = False self.add_status("Run timer stopped at {}".format(self.w.lbl_runtime.text())) def back(self): if os.path.exists(self.default_setup): self.w.web_view.load(QtCore.QUrl.fromLocalFile(self.default_setup)) else: self.w.web_view.setHtml(self.html) #self.w.web_view.page().triggerAction(QWebEnginePage.Back) def forward(self): self.w.web_view.load(QtCore.QUrl.fromLocalFile(self.docs)) #self.w.web_view.page().triggerAction(QWebEnginePage.Forward) def writer(self): WRITER.show() ##################### # KEY BINDING CALLS # ##################### def on_keycall_ESTOP(self,event,state,shift,cntrl): if state: ACTION.SET_ESTOP_STATE(True) def on_keycall_POWER(self,event,state,shift,cntrl): if state: ACTION.SET_MACHINE_STATE(False) def on_keycall_ABORT(self,event,state,shift,cntrl): if state: ACTION.ABORT() def on_keycall_HOME(self,event,state,shift,cntrl): if state and not STATUS.is_all_homed() and self.use_keyboard(): ACTION.SET_MACHINE_HOMING(-1) def on_keycall_PAUSE(self,event,state,shift,cntrl): if state and STATUS.is_auto_mode() and self.use_keyboard(): ACTION.PAUSE() def on_keycall_XPOS(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 0, 1, shift) def on_keycall_XNEG(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 0, -1, shift) def on_keycall_YPOS(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 1, 1, shift) def on_keycall_YNEG(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 1, -1, shift) def on_keycall_ZPOS(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 2, 1, shift) def on_keycall_ZNEG(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 2, -1, shift) def on_keycall_APOS(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 3, 1, shift, False) def on_keycall_ANEG(self,event,state,shift,cntrl): if self.use_keyboard(): self.kb_jog(state, 3, -1, shift, False) def on_keycall_F4(self,event,state,shift,cntrl): if state: mess = {'NAME':'CALCULATOR', 'TITLE':'Calculator', 'ID':'_calculator_'} ACTION.CALL_DIALOG(mess) def on_keycall_F12(self,event,state,shift,cntrl): if state: self.styleeditor.load_dialog() ############################## # required class boiler code # ############################## def __getitem__(self, item): return getattr(self, item) def __setitem__(self, item, value): return setattr(self, item, value)
def __init__(self, halcomp, widgets, paths): self.h = halcomp self.w = widgets self.gcodes = GCodes(widgets) self.valid = QtGui.QDoubleValidator(-999.999, 999.999, 3) KEYBIND.add_call('Key_F12', 'on_keycall_F12') KEYBIND.add_call('Key_Pause', 'on_keycall_pause') # some global variables self.probe = None self.default_setup = os.path.join(PATH.CONFIGPATH, "default_setup.html") self.docs = os.path.join(PATH.SCREENDIR, PATH.BASEPATH, 'docs/getting_started.html') self.start_line = 0 self.run_time = 0 self.time_tenths = 0 self.timer_on = False self.home_all = False self.min_spindle_rpm = INFO.MIN_SPINDLE_SPEED self.max_spindle_rpm = INFO.MAX_SPINDLE_SPEED self.system_list = [ "G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3" ] self.tab_index_code = (0, 1, 2, 3, 0, 0, 2, 0, 0, 0, 0) self.slow_jog_factor = 10 self.reload_tool = 0 self.last_loaded_program = "" self.first_turnon = True self.lineedit_list = [ "work_height", "touch_height", "sensor_height", "laser_x", "laser_y", "sensor_x", "sensor_y", "camera_x", "camera_y", "search_vel", "probe_vel", "max_probe", "eoffset_count" ] self.onoff_list = [ "frame_program", "frame_tool", "frame_dro", "frame_override", "frame_status" ] self.auto_list = ["chk_eoffsets", "cmb_gcode_history"] self.axis_a_list = [ "label_axis_a", "dro_axis_a", "action_zero_a", "axistoolbutton_a", "action_home_a", "widget_jog_angular", "widget_increments_angular", "a_plus_jogbutton", "a_minus_jogbutton" ] STATUS.connect('general', self.dialog_return) STATUS.connect('state-on', lambda w: self.enable_onoff(True)) STATUS.connect('state-off', lambda w: self.enable_onoff(False)) STATUS.connect('mode-manual', lambda w: self.enable_auto(True)) STATUS.connect('mode-mdi', lambda w: self.enable_auto(True)) STATUS.connect('mode-auto', lambda w: self.enable_auto(False)) STATUS.connect('gcode-line-selected', lambda w, line: self.set_start_line(line)) STATUS.connect('graphics-line-selected', lambda w, line: self.set_start_line(line)) STATUS.connect('hard-limits-tripped', self.hard_limit_tripped) STATUS.connect( 'program-pause-changed', lambda w, state: self.w.btn_spindle_pause.setEnabled(state)) STATUS.connect('actual-spindle-speed-changed', lambda w, speed: self.update_rpm(speed)) STATUS.connect('user-system-changed', lambda w, data: self.user_system_changed(data)) STATUS.connect('metric-mode-changed', lambda w, mode: self.metric_mode_changed(mode)) STATUS.connect('file-loaded', self.file_loaded) STATUS.connect('all-homed', self.all_homed) STATUS.connect('not-all-homed', self.not_all_homed) STATUS.connect('periodic', lambda w: self.update_runtimer()) STATUS.connect('command-stopped', lambda w: self.stop_timer()) STATUS.connect('progress', lambda w, p, t: self.updateProgress(p, t)) STATUS.connect( 'override-limits-changed', lambda w, state, data: self._check_override_limits(state, data)) self.html = """<html> <head> <title>Test page for the download:// scheme</title> </head> <body> <h1>Setup Tab</h1> <p>If you select a file with .html as a file ending, it will be shown here..</p> <img src="file://%s" alt="lcnc_swoop" /> <hr /> </body> </html> """ % (os.path.join(paths.IMAGEDIR, 'lcnc_swoop.png'))
class HandlerClass: ######################## # **** INITIALIZE **** # ######################## # widgets allows access to widgets from the qtvcp files # at this point the widgets and hal pins are not instantiated def __init__(self, halcomp, widgets, paths): # some global variables self.hal = halcomp self.w = widgets self.PATH = paths self._big_view = -1 self.flag = 0 self.activeStyle = ''' { background-color: white;}''' self.defaultStyle = ''' { background-color: light blue;}''' self.activeWidgetDict = { 'programPage': False, 'userPage': False, 'machinePage': False, 'tooloffsetsPage': False, 'loadPage': False, 'mdiPage': False, 'workoffsetsPage': False, 'setupPage': False } self.current_mode = (None, None) self._last_count = 0 self.run_time = 0 self.time_tenths = 0 self.timerOn = False self.slow_jog_factor = 10 self.STYLEEDITOR = SSE(widgets, paths) self.GCODES = GCodes() STATUS.connect('periodic', lambda w: self.update_runtimer()) STATUS.connect('command-running', lambda w: self.start_timer()) STATUS.connect('command-stopped', lambda w: self.stop_timer()) STATUS.connect("metric-mode-changed", lambda w, d: self.mode_changed(d)) STATUS.connect('state-off', lambda w: self.w.pushbutton_metric.setEnabled(False)) STATUS.connect('state-estop', lambda w: self.w.pushbutton_metric.setEnabled(False)) STATUS.connect( 'interp-idle', lambda w: self.w.pushbutton_metric.setEnabled( self.homed_on_test())) STATUS.connect('interp-run', lambda w: self.w.pushbutton_metric.setEnabled(False)) STATUS.connect('all-homed', lambda w: self.w.pushbutton_metric.setEnabled(True)) STATUS.connect( 'not-all-homed', lambda w, data: self.w.pushbutton_metric.setEnabled(False)) ########################################## # Special Functions called from QTVCP ########################################## # For changing functions in widgets we can 'class patch'. # class patching must be done before the class is instantiated. # def class_patch__(self): GCODE.exitCall = self.editor_exit # patch filemanager so we can trap single click loading # (doesn't work well on a touchscreen) # you can only load using a button defined in designer now # keep a reference to the original function as 'superLoad' FILEMGR.superLoad = FILEMGR.load FILEMGR.load = self.FMGRnoop # at this point: # the widgets are instantiated. # the HAL pins are built but HAL is not set ready def initialized__(self): STATUS.emit('play-sound', 'SPEAK This is a test screen for Haas styled QT lathe') KEYBIND.add_call('Key_F3', 'on_keycall_F3') KEYBIND.add_call('Key_F4', 'on_keycall_F4') KEYBIND.add_call('Key_F5', 'on_keycall_F5') KEYBIND.add_call('Key_F6', 'on_keycall_F6') KEYBIND.add_call('Key_F7', 'on_keycall_F7') KEYBIND.add_call('Key_F9', 'on_keycall_F9') KEYBIND.add_call('Key_F11', 'on_keycall_F11') KEYBIND.add_call('Key_F12', 'on_keycall_F12') TOOLBAR.configure_action(self.w.actionCalculatorDialog, 'calculatordialog') TOOLBAR.configure_submenu(self.w.menuGridSize, 'grid_size_submenu') TOOLBAR.configure_action(self.w.actionToolOffsetDialog, 'tooloffsetdialog') TOOLBAR.configure_action(self.w.actionReload, 'Reload') TOOLBAR.configure_statusbar(self.w.statusbar, 'message_controls') self.w.pushbutton_metric.clicked[bool].connect(self.change_mode) # web view widget for SETUP SHEET page self.web_view = QWebView() self.w.verticalLayout_setup.addWidget(self.web_view) self.set_default_html() self.GCODES.setup_list() self.w.gcode_editor.hide() def before_loop__(self): STATUS.connect('state-estop', lambda q: self.w.close()) def processed_key_event__(self, receiver, event, is_pressed, key, code, shift, cntrl): # when typing in MDI, we don't want keybinding to call functions # so we catch and process the events directly. # We do want ESC, F1 and F2 to call keybinding functions though if code not in (QtCore.Qt.Key_Escape, QtCore.Qt.Key_F1, QtCore.Qt.Key_F2, QtCore.Qt.Key_F3, QtCore.Qt.Key_F5, QtCore.Qt.Key_F5, QtCore.Qt.Key_F6, QtCore.Qt.Key_F7, QtCore.Qt.Key_F11, QtCore.Qt.Key_F12): raise if event.isAutoRepeat(): return True # ok if we got here then try keybindings try: return KEYBIND.call(self, event, is_pressed, shift, cntrl) except NameError as e: LOG.debug('Exception in KEYBINDING: {}'.format(e)) except Exception as e: LOG.debug('Exception in KEYBINDING:', exc_info=e) print 'Error in, or no function for: %s in handler file for-%s' % ( KEYBIND.convert(event), key) return False ######################## # callbacks from STATUS # ######################## def runtime_sec_changed(self, data): text = "{:02d}:{:02d}:{:02d}".format(self.h['runtime_hrs'], self.h['runtime_min'], self.h['runtime_sec']) self.w.lbl_runtime.setText(text) def file_loaded(self, obj, filename): if filename is not None: self.w.progressBar.setValue(0) self.last_loaded_program = filename else: self.add_alarm("Filename not valid") def all_homed(self, obj): self.set_dro_homed(True) if self.first_turnon is True: self.first_turnon = False if self.w.chk_reload_tool.isChecked(): STATUS.emit('update-machine-log', 'PreLoad Tool #{}: '.format(self.reload_tool), 'TIME') command = "M61 Q{}".format(self.reload_tool) ACTION.CALL_MDI(command) if self.last_loaded_program is not None and self.w.chk_reload_program.isChecked( ): STATUS.emit('update-machine-log', 'PreLoading NGC: ' + self.last_loaded_program, 'TIME') ACTION.OPEN_PROGRAM(self.last_loaded_program) self.w.filemanager.updateDirectoryView( self.last_loaded_program) def not_all_homed(self, obj, list): self.home_all = False self.w.lbl_home_all.setText("HOME\nALL") for i in INFO.AVAILABLE_JOINTS: if str(i) in list: axis = INFO.GET_NAME_FROM_JOINT.get(i).lower() try: self.w["dro_axis_{}".format(axis)].setProperty( 'homed', False) self.w["dro_axis_{}".format(axis)].setStyle( self.w["dro_axis_{}".format(axis)].style()) except: pass ####################### # callbacks from form # ####################### def percentLoaded(self, fraction): if fraction < 1: self.w.progressBar.setValue(0) self.w.progressBar.setFormat('') else: self.w.progressBar.setValue(fraction) self.w.progressBar.setFormat('Loading: {}%'.format(fraction)) def percentCompleted(self, fraction): self.w.progressBar.setValue(fraction) if fraction < 1: self.w.progressBar.setFormat('') else: self.w.progressBar.setFormat('Completed: {}%'.format(fraction)) def toggle_prog(self): if self.current_mode == ('program', 'run'): self.set_active_mode('program', 'load') else: self.set_active_mode('program', 'run') def toggle_MDI(self): self.set_active_mode('mdi', None) def toggle_setup(self): self.set_active_mode('setup', None) def toggle_dro(self): next = self.w.droPaneStack.currentIndex() + 1 if next == self.w.droPaneStack.count(): self.w.droPaneStack.setCurrentIndex(0) else: self.w.droPaneStack.setCurrentIndex(next) def toggle_offsets(self): self.set_active_mode('offsetPage', None) def set_edit_mode(self, num): if num == 2: self.w.gcodeeditor.editMode() else: self.w.gcodeeditor.readOnlyMode() def toggle_graphics(self): self.set_active_mode('graphics', None) # tool tab def btn_m61_clicked(self): checked = self.w.tooloffsetview.get_checked_list() if len(checked) > 1: self.add_alarm("Select only 1 tool to load") elif checked: ACTION.CALL_MDI("M61 Q{}".format(checked[0])) else: self.add_alarm("No tool selected") # alarm tab def btn_clear_alarms_clicked(self): ACTION.UPDATE_MACHINE_LOG('', 'DELETE') def btn_save_alarms_clicked(self): text = self.w.machinelog.toPlainText() filename = self.w.lbl_clock.text().encode('utf-8') filename = 'alarms_' + filename.replace(' ', '_') + '.txt' with open(filename, 'w') as f: f.write(text) def btn_reload_file_clicked(self): if self.last_loaded_program: self.w.progressBar.setValue(0) ACTION.OPEN_PROGRAM(self.last_loaded_program) def slow_jog_clicked(self, state): slider = self.w.sender().property('slider') current = self.w[slider].value() max = self.w[slider].maximum() if state: self.w.sender().setText("SLOW") self.w[slider].setMaximum(max / self.slow_jog_factor) self.w[slider].setValue(current / self.slow_jog_factor) self.w[slider].setPageStep(1) else: self.w.sender().setText("FAST") self.w[slider].setMaximum(max * self.slow_jog_factor) self.w[slider].setValue(current * self.slow_jog_factor) self.w[slider].setPageStep(1) ##################### # general functions # ##################### def kb_jog(self, state, joint, direction, fast=False, linear=True): if not STATUS.is_man_mode() or not STATUS.machine_is_on(): return if linear: distance = STATUS.get_jog_increment() rate = STATUS.get_jograte() / 60 else: distance = STATUS.get_jog_increment_angular() rate = STATUS.get_jograte_angular() / 60 if state: if fast: rate = rate * 2 ACTION.JOG(joint, direction, rate, distance) else: ACTION.JOG(joint, 0, 0, 0) def editor_exit(self): self.btn_gcode_edit_clicked(False) def set_active_mode(self, mode, index): #print mode,index def update(widget): for key, value in self.activeWidgetDict.iteritems(): #print mode,key,value if key == widget: print widget self.w[key].setStyleSheet('#%s%s' % (key, self.activeStyle)) self.activeWidgetDict[key] = True elif value == True: print 'switch off', key self.w[key].setStyleSheet('#%s%s' % (key, self.defaultStyle)) self.activeWidgetDict[key] = False if mode == 'program': if index == 'run': self.w.mainLeftStack.setCurrentIndex(0) # gcode self.w.mainPaneStack.setCurrentIndex(0) # normal update('programPage') self.w.label_mode.setText('Operation-Run Program') else: self.w.mainLeftStack.setCurrentIndex(0) # gcode self.w.mainPaneStack.setCurrentIndex(1) # load update('loadPage') self.w.label_mode.setText('Operation-Load Program') elif mode == 'setup': self.w.mainPaneStack.setCurrentIndex(0) # normal self.w.widgetswitcher.setCurrentIndex(3) # setup manual self.w.mainLeftStack.setCurrentIndex(1) # setup html update('setupPage') self.w.label_mode.setText('Operation- Manual Setup') elif mode == 'mdi': self.w.mainPaneStack.setCurrentIndex(0) cur = self.w.widgetswitcher.currentIndex() if cur == 4: next = self.w.mdi_tab.currentIndex() + 1 if next > self.w.mdi_tab.count() - 1: next = 0 self.w.mdi_tab.setCurrentIndex(next) else: self.w.widgetswitcher.setCurrentIndex(4) self.w.mdi_tab.setCurrentIndex(0) update('mdiPage') self.w.label_mode.setText('Operation- MDI Control') elif mode == 'offsetPage': self.w.mainPaneStack.setCurrentIndex(0) cur = self.w.widgetswitcher.currentIndex() if cur == 2: self.w.widgetswitcher.setCurrentIndex(0) update('tooloffsetsPage') else: self.w.widgetswitcher.setCurrentIndex(2) update('workoffsetsPage') elif mode == 'graphics': cur = self.w.mainLeftStack.currentIndex() if cur == 0: # gcode if self.w.widgetswitcher.get_current_number() == 0: self.w.widgetswitcher.show_default() self.w.mainLeftStack.setCurrentIndex(2) elif self.w.widgetswitcher.get_current_number() == 1: self.w.widgetswitcher.show_default() self.w.mainLeftStack.setCurrentIndex(0) elif cur == 2: self.w.mainLeftStack.setCurrentIndex(0) self.w.widgetswitcher.show_id_widget(1) else: print('mode/index not recognized') return self.current_mode = (mode, index) def btn_start_macro_clicked(self): self.w.label_mode.setText('Operation- MDI Control') self.w.mditouchy.run_command() return def abort(self, state): if not state: return if STATUS.stat.interp_state == linuxcnc.INTERP_IDLE: self.w.close() else: ACTION.ABORT() def make_progressbar(self): self.w.progressbBar = QtWidgets.QProgressBar() self.w.progressBar.setRange(0, 100) self.w.statusBar.addWidget(self.w.progressBar) def update_runtimer(self): if self.timerOn is False or STATUS.is_auto_paused(): return self.time_tenths += 1 if self.time_tenths == 10: self.time_tenths = 0 self.run_time += 1 hours, remainder = divmod(self.run_time, 3600) minutes, seconds = divmod(remainder, 60) self.w.lbl_runtime.setText("{:02d}:{:02d}:{:02d}".format( hours, minutes, seconds)) def start_timer(self): self.run_time = 0 self.timerOn = True def stop_timer(self): self.timerOn = False def mode_changed(self, data): self._block_signal = True self.w.pushbutton_metric.setChecked(data) # if using state labels option update the labels if self.w.pushbutton_metric._state_text: self.w.pushbutton_metric.setText(None) self._block_signal = False def change_mode(self, data): if self._block_signal: return if data: ACTION.CALL_MDI('G21') else: ACTION.CALL_MDI('G20') def homed_on_test(self): return (STATUS.machine_is_on() and (STATUS.is_all_homed() or INFO.NO_HOME_REQUIRED)) # file tab def btn_gcode_edit_clicked(self, state): if not STATUS.is_on_and_idle(): return for x in ["load", "next", "prev"]: self.w["btn_file_{}".format(x)].setEnabled(not state) if state: self.w.filemanager.hide() self.w.gcode_editor.show() self.w.gcode_editor.editMode() else: self.w.filemanager.show() self.w.gcode_editor.hide() self.w.gcode_editor.readOnlyMode() def btn_load_file_clicked(self): fname = self.w.filemanager.getCurrentSelected() if fname[1] is True: self.load_code(fname[0]) # class patched filemanager to trap single click loading # this makes the original function do nothing def FMGRnoop(self, fname): pass def load_code(self, fname): if fname is None: return if fname.endswith(".ngc") or fname.endswith(".py"): # call original filemanager load function to load program self.w.filemanager.superLoad(fname) # change filepath extension to autoload an html setup page fname = os.path.splitext(fname)[0] + '.html' if fname.endswith(".html"): if os.path.exists(fname): self.web_view.load(QtCore.QUrl.fromLocalFile(fname)) return self.set_default_html(fname) def set_default_html(self, filename=None): if filename is None: filename = 'No program Loaded' print filename self.html = """<html> <head> <title>Test page for the download:// scheme</title> </head> <body> <h1>Setup Tab</h1> <p> tried loading::%s</p> <p>If there was a HTML setup file , it would auto load and be shown here..</p> <img src="file://%s" alt="lcnc_swoop" /> <hr /> <a href="http://linuxcnc.org/docs/html/lathe/lathe-user.html">Lathe User Information link</a> </body> </html> """ % (filename, os.path.join(self.PATH.IMAGEDIR, 'lcnc_swoop.png')) self.web_view.setHtml(self.html) ##################### # KEY BINDING CALLS # ##################### # Machine control def on_keycall_ESTOP(self, event, state, shift, cntrl): if state: ACTION.SET_ESTOP_STATE(STATUS.estop_is_clear()) def on_keycall_POWER(self, event, state, shift, cntrl): if state: ACTION.SET_MACHINE_STATE(not STATUS.machine_is_on()) def on_keycall_HOME(self, event, state, shift, cntrl): if state: if STATUS.is_all_homed(): ACTION.SET_MACHINE_UNHOMED(-1) else: ACTION.SET_MACHINE_HOMING(-1) def on_keycall_ABORT(self, event, state, shift, cntrl): if state: self.abort(state) def on_keycall_pause(self, event, state, shift, cntrl): if state and STATUS.is_auto_mode() and self.use_keyboard(): ACTION.PAUSE() # dialogs def on_keycall_F3(self, event, state, shift, cntrl): if state: STATUS.emit('dialog-request', {'NAME': 'ORIGINOFFSET'}) def on_keycall_F4(self, event, state, shift, cntrl): if state: STATUS.emit('dialog-request', {'NAME': 'CAMVIEW'}) def on_keycall_F6(self, event, state, shift, cntrl): if state: STATUS.emit('dialog-request', {'NAME': 'TOOLOFFSET'}) def on_keycall_F7(self, event, state, shift, cntrl): if state: STATUS.emit('dialog-request', {'NAME': 'VERSAPROBE'}) def on_keycall_F9(self, event, state, shift, cntrl): if state: STATUS.emit('dialog-request', {'NAME': 'Calculator'}) def on_keycall_F11(self, event, state, shift, cntrl): if state: pass def on_keycall_F12(self, event, state, shift, cntrl): if state: self.STYLEEDITOR.load_dialog() # Linear Jogging def on_keycall_XPOS(self, event, state, shift, cntrl): self.kb_jog(state, 0, 1, shift) def on_keycall_XNEG(self, event, state, shift, cntrl): self.kb_jog(state, 0, -1, shift) def on_keycall_YPOS(self, event, state, shift, cntrl): self.kb_jog(state, 1, 1, shift) def on_keycall_YNEG(self, event, state, shift, cntrl): self.kb_jog(state, 1, -1, shift) def on_keycall_ZPOS(self, event, state, shift, cntrl): self.kb_jog(state, 2, 1, shift) def on_keycall_ZNEG(self, event, state, shift, cntrl): self.kb_jog(state, 2, -1, shift) def on_keycall_APOS(self, event, state, shift, cntrl): pass #self.kb_jog(state, 3, 1, shift, False) def on_keycall_ANEG(self, event, state, shift, cntrl): pass #self.kb_jog(state, 3, -1, shift, linear=False) ########################### # **** closing event **** # ########################### def closing_cleanup__(self): pass ############################## # required class boiler code # ############################## def __getitem__(self, item): return getattr(self, item) def __setitem__(self, item, value): return setattr(self, item, value)
def __init__(self, halcomp, widgets, paths): self.h = halcomp self.w = widgets self.PATHS = paths self.gcodes = GCodes(widgets) self._last_count = 0 self.degree = u"\N{DEGREE SIGN}".encode('utf-8') self.valid = QtGui.QDoubleValidator(-999.999, 999.999, 3) self.styleeditor = SSE(widgets, paths) KEYBIND.add_call('Key_F12', 'on_keycall_F12') KEYBIND.add_call('Key_Pause', 'on_keycall_pause') # some global variables self.start_line = 0 self.run_time = 0 self.time_tenths = 0 self.timerOn = False self.home_all = False self.min_spindle_rpm = INFO.MIN_SPINDLE_SPEED self.max_spindle_rpm = INFO.MAX_SPINDLE_SPEED self.max_linear_velocity = INFO.MAX_TRAJ_VELOCITY self.system_list = [ "G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3" ] self.slow_jog_factor = 10 self.reload_tool = 0 self.last_loaded_program = "" self.first_turnon = True self.lineedit_list = [ "work_height", "touch_height", "sensor_height", "laser_x", "laser_y", "sensor_x", "sensor_y", "search_vel", "probe_vel", "max_probe", "eoffset_count" ] self.onoff_list = ["frame_dro"] self.auto_list = ["chk_eoffsets", "cmb_gcode_history"] self.axis_a_list = [ "label_axis_a", "dro_axis_a", "action_zero_a", "axistoolbutton_a", "action_home_a", "slider_jog_angular", "btn_jog_a_slow", "widget_increments_angular", "btn_jog_pos_a", "btn_jog_neg_a", "status_label_jog_angular" ] self.html = """<html> <head> <title>Test page for the download:// scheme</title> </head> <body> <h1>Setup Tab</h1> <p>If you select a file with .html as a file ending, it will be shown here..</p> <img src="file://%s" alt="lcnc_swoop" /> <hr /> <a href="http://www.linuxcnc.org/docs/2.8/html/gui/qtdragon.html">QtDragon Documentation link</a> </body> </html> """ % (os.path.join(paths.IMAGEDIR, 'lcnc_swoop.png')) STATUS.connect('general', self.dialog_return) STATUS.connect('state-on', lambda w: self.enable_onoff(True)) STATUS.connect('state-off', lambda w: self.enable_onoff(False)) STATUS.connect('mode-manual', lambda w: self.enable_auto(True)) STATUS.connect('mode-mdi', lambda w: self.enable_auto(True)) STATUS.connect('mode-auto', lambda w: self.enable_auto(False)) STATUS.connect('gcode-line-selected', lambda w, line: self.set_start_line(line)) STATUS.connect("metric-mode-changed", lambda w, d: self.mode_changed(d)) STATUS.connect('hard-limits-tripped', self.hard_limit_tripped) STATUS.connect('interp-idle', lambda w: self.set_start_line(0)) STATUS.connect('program-pause-changed', lambda w, state: self.w.spindle_pause.setEnabled(state)) STATUS.connect('user-system-changed', self.user_system_changed) STATUS.connect('file-loaded', self.file_loaded) STATUS.connect('homed', self.homed) STATUS.connect('all-homed', self.all_homed) STATUS.connect('not-all-homed', self.not_all_homed) STATUS.connect('periodic', lambda w: self.update_runtimer()) STATUS.connect('command-running', lambda w: self.start_timer()) STATUS.connect('command-stopped', lambda w: self.stop_timer()) self._block_signal = False
class HandlerClass: def __init__(self, halcomp, widgets, paths): self.h = halcomp self.w = widgets self.PATHS = paths self.gcodes = GCodes(widgets) self._last_count = 0 self.degree = u"\N{DEGREE SIGN}".encode('utf-8') self.valid = QtGui.QDoubleValidator(-999.999, 999.999, 3) self.styleeditor = SSE(widgets, paths) KEYBIND.add_call('Key_F12', 'on_keycall_F12') KEYBIND.add_call('Key_Pause', 'on_keycall_pause') # some global variables self.start_line = 0 self.run_time = 0 self.time_tenths = 0 self.timerOn = False self.home_all = False self.min_spindle_rpm = INFO.MIN_SPINDLE_SPEED self.max_spindle_rpm = INFO.MAX_SPINDLE_SPEED self.max_linear_velocity = INFO.MAX_TRAJ_VELOCITY self.system_list = [ "G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3" ] self.slow_jog_factor = 10 self.reload_tool = 0 self.last_loaded_program = "" self.first_turnon = True self.lineedit_list = [ "work_height", "touch_height", "sensor_height", "laser_x", "laser_y", "sensor_x", "sensor_y", "search_vel", "probe_vel", "max_probe", "eoffset_count" ] self.onoff_list = ["frame_dro"] self.auto_list = ["chk_eoffsets", "cmb_gcode_history"] self.axis_a_list = [ "label_axis_a", "dro_axis_a", "action_zero_a", "axistoolbutton_a", "action_home_a", "slider_jog_angular", "btn_jog_a_slow", "widget_increments_angular", "btn_jog_pos_a", "btn_jog_neg_a", "status_label_jog_angular" ] self.html = """<html> <head> <title>Test page for the download:// scheme</title> </head> <body> <h1>Setup Tab</h1> <p>If you select a file with .html as a file ending, it will be shown here..</p> <img src="file://%s" alt="lcnc_swoop" /> <hr /> <a href="http://www.linuxcnc.org/docs/2.8/html/gui/qtdragon.html">QtDragon Documentation link</a> </body> </html> """ % (os.path.join(paths.IMAGEDIR, 'lcnc_swoop.png')) STATUS.connect('general', self.dialog_return) STATUS.connect('state-on', lambda w: self.enable_onoff(True)) STATUS.connect('state-off', lambda w: self.enable_onoff(False)) STATUS.connect('mode-manual', lambda w: self.enable_auto(True)) STATUS.connect('mode-mdi', lambda w: self.enable_auto(True)) STATUS.connect('mode-auto', lambda w: self.enable_auto(False)) STATUS.connect('gcode-line-selected', lambda w, line: self.set_start_line(line)) STATUS.connect("metric-mode-changed", lambda w, d: self.mode_changed(d)) STATUS.connect('hard-limits-tripped', self.hard_limit_tripped) STATUS.connect('interp-idle', lambda w: self.set_start_line(0)) STATUS.connect('program-pause-changed', lambda w, state: self.w.spindle_pause.setEnabled(state)) STATUS.connect('user-system-changed', self.user_system_changed) STATUS.connect('file-loaded', self.file_loaded) STATUS.connect('homed', self.homed) STATUS.connect('all-homed', self.all_homed) STATUS.connect('not-all-homed', self.not_all_homed) STATUS.connect('periodic', lambda w: self.update_runtimer()) STATUS.connect('command-running', lambda w: self.start_timer()) STATUS.connect('command-stopped', lambda w: self.stop_timer()) self._block_signal = False def initialized__(self): self.w.pushbutton_metric.clicked[bool].connect(self.change_mode) self.init_pins() self.init_utils() self.init_preferences() self.init_widgets() self.w.stackedWidget_log.setCurrentIndex(0) self.w.stackedWidget_3.setCurrentIndex(0) self.w.stackedWidget_4.setCurrentIndex(0) self.w.stackedWidget_0.setCurrentIndex(0) self.w.stackedWidget_2.setCurrentIndex(0) self.w.spindle_pause.setEnabled(False) self.w.btn_dimensions.setChecked(True) self.w.btn_touch_sensor.setEnabled self.w.page_buttonGroup.buttonClicked.connect(self.main_tab_changed) self.chk_run_from_line_checked(self.w.chk_run_from_line.isChecked()) self.chk_use_camera_changed(self.w.chk_use_camera.isChecked()) STATUS.connect( 'feed-override-changed', lambda w, data: self.w.pushbutton_fo. setText('FO {0:.0f}%'.format(data))) STATUS.connect( 'rapid-override-changed', lambda w, data: self.w.pushbutton_ro. setText('RO {0:.0f}%'.format(data))) STATUS.connect( 'spindle-override-changed', lambda w, data: self.w.pushbutton_so. setText('SO {0:.0f}%'.format(data))) STATUS.connect('jogincrement-changed', lambda w, incr, label: self.updateIncrementPin(incr)) # hide widgets for A axis if not present if "A" not in INFO.AVAILABLE_AXES: for i in self.axis_a_list: self.w[i].hide() self.w.lbl_increments_linear.setText("INCREMENTS") # set validators for lineEdit widgets for val in self.lineedit_list: self.w['lineEdit_' + val].setValidator(self.valid) # check for default setup html file fname = os.path.join(os.path.expanduser('~'), 'linuxcnc/configs/qtdragon/default_setup.html') if os.path.exists(fname): self.w.setup_webView.load(QtCore.QUrl.fromLocalFile(fname)) ############################# # SPECIAL FUNCTIONS SECTION # ############################# def init_pins(self): # spindle control pins pin = self.h.newpin("spindle_amps", hal.HAL_FLOAT, hal.HAL_IN) pin.value_changed.connect(self.spindle_pwr_changed) pin = self.h.newpin("spindle_volts", hal.HAL_FLOAT, hal.HAL_IN) pin.value_changed.connect(self.spindle_pwr_changed) pin = self.h.newpin("spindle_fault", hal.HAL_U32, hal.HAL_IN) pin.value_changed.connect(self.spindle_fault_changed) pin = self.h.newpin("modbus-errors", hal.HAL_U32, hal.HAL_IN) pin.value_changed.connect(self.mb_errors_changed) # self.h.newpin("spindle_pause", hal.HAL_BIT, hal.HAL_OUT) # external offset control pins self.h.newpin("eoffset_enable", hal.HAL_BIT, hal.HAL_OUT) self.h.newpin("eoffset_clear", hal.HAL_BIT, hal.HAL_OUT) self.h.newpin("eoffset_count", hal.HAL_S32, hal.HAL_OUT) pin = self.h.newpin("eoffset_value", hal.HAL_FLOAT, hal.HAL_IN) pin.value_changed.connect(self.eoffset_changed) self.pin_mpg_in = self.h.newpin('mpg-in', hal.HAL_S32, hal.HAL_IN) self.pin_mpg_in.value_changed.connect(lambda s: self.external_mpg(s)) self.wheel_x = self.h.newpin('jog.wheel.x', hal.HAL_BIT, hal.HAL_OUT) self.wheel_y = self.h.newpin('jog.wheel.y', hal.HAL_BIT, hal.HAL_OUT) self.wheel_z = self.h.newpin('jog.wheel.z', hal.HAL_BIT, hal.HAL_OUT) self.wheel_a = self.h.newpin('jog.wheel.a', hal.HAL_BIT, hal.HAL_OUT) self.jog_increment = self.h.newpin('jog.wheel.incement', hal.HAL_FLOAT, hal.HAL_OUT) def init_preferences(self): if not self.w.PREFS_: self.add_status( "CRITICAL - no preference file found, enable preferences in screenoptions widget" ) return self.last_loaded_program = self.w.PREFS_.getpref( 'last_loaded_file', None, str, 'BOOK_KEEPING') self.reload_tool = self.w.PREFS_.getpref('Tool to load', 0, int, 'CUSTOM_FORM_ENTRIES') self.w.lineEdit_laser_x.setText( str( self.w.PREFS_.getpref('Laser X', 100, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_laser_y.setText( str( self.w.PREFS_.getpref('Laser Y', -20, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_sensor_x.setText( str( self.w.PREFS_.getpref('Sensor X', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_sensor_y.setText( str( self.w.PREFS_.getpref('Sensor Y', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_work_height.setText( str( self.w.PREFS_.getpref('Work Height', 20, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_touch_height.setText( str( self.w.PREFS_.getpref('Touch Height', 40, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_sensor_height.setText( str( self.w.PREFS_.getpref('Sensor Height', 40, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_camera_x.setText( str( self.w.PREFS_.getpref('Camera X', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_camera_y.setText( str( self.w.PREFS_.getpref('Camera Y', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_search_vel.setText( str( self.w.PREFS_.getpref('Search Velocity', 40, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_probe_vel.setText( str( self.w.PREFS_.getpref('Probe Velocity', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_max_probe.setText( str( self.w.PREFS_.getpref('Max Probe', 10, float, 'CUSTOM_FORM_ENTRIES'))) self.w.lineEdit_eoffset_count.setText( str( self.w.PREFS_.getpref('Eoffset count', 0, int, 'CUSTOM_FORM_ENTRIES'))) self.w.chk_eoffsets.setChecked( self.w.PREFS_.getpref('External offsets', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_reload_program.setChecked( self.w.PREFS_.getpref('Reload program', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_reload_tool.setChecked( self.w.PREFS_.getpref('Reload tool', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_keyboard.setChecked( self.w.PREFS_.getpref('Use keyboard', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_run_from_line.setChecked( self.w.PREFS_.getpref('Run from line', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_virtual.setChecked( self.w.PREFS_.getpref('Use virtual keyboard', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.chk_use_tool_sensor.setChecked( self.w.PREFS_.getpref('Use tool sensor', False, bool, 'CUSTOM_FORM_ENTRIES')) self.w.PREFS_.putpref('Use camera', self.w.chk_use_camera.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') def closing_cleanup__(self): if not self.w.PREFS_: return self.w.PREFS_.putpref('last_loaded_directory', os.path.dirname(self.last_loaded_program), str, 'BOOK_KEEPING') self.w.PREFS_.putpref('last_loaded_file', self.last_loaded_program, str, 'BOOK_KEEPING') self.w.PREFS_.putpref('Tool to load', STATUS.get_current_tool(), int, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Laser X', self.w.lineEdit_laser_x.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Laser Y', self.w.lineEdit_laser_y.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Sensor X', self.w.lineEdit_sensor_x.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Sensor Y', self.w.lineEdit_sensor_y.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Camera X', self.w.lineEdit_camera_x.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Camera Y', self.w.lineEdit_camera_y.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref( 'Work Height', self.w.lineEdit_work_height.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref( 'Touch Height', self.w.lineEdit_touch_height.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref( 'Sensor Height', self.w.lineEdit_sensor_height.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref( 'Search Velocity', self.w.lineEdit_search_vel.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Probe Velocity', self.w.lineEdit_probe_vel.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Max Probe', self.w.lineEdit_max_probe.text().encode('utf-8'), float, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref( 'Eoffset count', self.w.lineEdit_eoffset_count.text().encode('utf-8'), int, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('External offsets', self.w.chk_eoffsets.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Reload program', self.w.chk_reload_program.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Reload tool', self.w.chk_reload_tool.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use keyboard', self.w.chk_use_keyboard.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Run from line', self.w.chk_run_from_line.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use virtual keyboard', self.w.chk_use_virtual.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use tool sensor', self.w.chk_use_tool_sensor.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') self.w.PREFS_.putpref('Use camera', self.w.chk_use_camera.isChecked(), bool, 'CUSTOM_FORM_ENTRIES') def init_widgets(self): self.w.main_tab_widget.setCurrentIndex(0) self.w.chk_override_limits.setChecked(False) self.w.chk_override_limits.setEnabled(False) self.w.lbl_maxv_percent.setText("100 %") self.w.lbl_max_rapid.setText(str(self.max_linear_velocity)) self.w.lbl_home_x.setText( INFO.get_error_safe_setting('JOINT_0', 'HOME', "50")) self.w.lbl_home_y.setText( INFO.get_error_safe_setting('JOINT_1', 'HOME', "50")) self.w.cmb_gcode_history.addItem("No File Loaded") self.w.cmb_gcode_history.wheelEvent = lambda event: None self.w.jogincrements_linear.wheelEvent = lambda event: None self.w.jogincrements_angular.wheelEvent = lambda event: None #self.w.spindle_rpm.setValue(0) self.w.gcode_editor.hide() self.w.mdihistory.list.setAlternatingRowColors(False) self.w.filemanager.list.setAlternatingRowColors(False) self.w.runFromLineEdit.setValidator(QtGui.QIntValidator()) #set up gcode list self.gcodes.setup_list() # clickable frames self.w.frame_cycle_start.mousePressEvent = self.btn_start_clicked self.w.frame_home_all.mousePressEvent = self.btn_home_all_clicked # web view widget for SETUP page self.w.verticalLayout_setup.addWidget(self.w.web_view) self.w.web_view.setHtml(self.html) # check for virtual keyboard enabled if self.w.chk_use_virtual.isChecked(): self.w.btn_keyboard.show() else: self.w.btn_keyboard.hide() TOOLBAR.configure_statusbar(self.w.statusbar, 'message_recall') if not INFO.MACHINE_IS_METRIC: self.w.lbl_jog_linear.setText('JOG RATE\nINCH/MIN') self.w.lbl_tool_sensor_B2W.setText('INCH') self.w.lbl_tool_sensor_B2S.setText('INCH') self.w.lbl_touchheight_units.setText('INCH') def init_utils(self): from qtvcp.lib.gcode_utility.facing import Facing self.facing = Facing() self.w.layout_facing.addWidget(self.facing) from qtvcp.lib.gcode_utility.hole_circle import Hole_Circle self.hole_circle = Hole_Circle() self.w.layout_hole_circle.addWidget(self.hole_circle) from qtvcp.widgets.calculator import Calculator self.calculator = Calculator() self.w.layout_calculator.addWidget(self.calculator) self.calculator.bBox.setHidden(True) def processed_focus_event__(self, receiver, event): if not self.w.chk_use_virtual.isChecked() or STATUS.is_auto_mode(): return if isinstance(receiver, QtWidgets.QLineEdit): if not receiver.isReadOnly(): self.w.btn_keyboard.setChecked(True) elif isinstance(receiver, QtWidgets.QTableView): self.w.stackedWidget_2.setCurrentIndex(1) elif isinstance(receiver, QtWidgets.QCommonStyle): return def processed_key_event__(self, receiver, event, is_pressed, key, code, shift, cntrl): # when typing in MDI, we don't want keybinding to call functions # so we catch and process the events directly. # We do want ESC, F1 and F2 to call keybinding functions though if code not in (QtCore.Qt.Key_Escape, QtCore.Qt.Key_F1, QtCore.Qt.Key_F2): # QtCore.Qt.Key_F3,QtCore.Qt.Key_F4,QtCore.Qt.Key_F5): # search for the top widget of whatever widget received the event # then check if it's one we want the keypress events to go to flag = False receiver2 = receiver while receiver2 is not None and not flag: if isinstance(receiver2, QtWidgets.QDialog): flag = True break if isinstance(receiver2, QtWidgets.QLineEdit): flag = True break if isinstance(receiver2, MDI_WIDGET): flag = True break if isinstance(receiver2, GCODE): flag = True break if isinstance(receiver2, TOOL_TABLE): flag = True break if isinstance(receiver2, OFFSET_VIEW): flag = True break receiver2 = receiver2.parent() if flag: if isinstance(receiver2, GCODE): # if in manual or in readonly mode do our keybindings - otherwise # send events to gcode widget if STATUS.is_man_mode( ) == False or not receiver2.editor.isReadOnly(): if is_pressed: receiver.keyPressEvent(event) event.accept() return True elif is_pressed: receiver.keyPressEvent(event) event.accept() return True else: event.accept() return True if event.isAutoRepeat(): return True # ok if we got here then try keybindings try: KEYBIND.call(self, event, is_pressed, shift, cntrl) event.accept() return True except NameError as e: if is_pressed: LOG.debug('Exception in KEYBINDING: {}'.format(e)) self.add_status('Exception in KEYBINDING: {}'.format(e)) except Exception as e: if is_pressed: LOG.debug('Exception in KEYBINDING:', exc_info=e) print( 'Error in, or no function for: %s in handler file for-%s' % (KEYBIND.convert(event), key)) event.accept() return True ######################### # CALLBACKS FROM STATUS # ######################### def updateIncrementPin(self, incr): self.jog_increment.set(incr) def spindle_pwr_changed(self, data): # this calculation assumes the voltage is line to neutral # and that the synchronous motor spindle has a power factor of 0.9 power = self.h['spindle_volts'] * self.h[ 'spindle_amps'] * 2.7 # 3 x V x I x PF amps = "{:1.1f}".format(self.h['spindle_amps']) pwr = "{:1.1f}".format(power) self.w.lbl_spindle_amps.setText(amps) self.w.lbl_spindle_power.setText(pwr) def spindle_fault_changed(self, data): fault = hex(self.h['spindle_fault']) self.w.lbl_spindle_fault.setText(fault) def spindle_faster(self): if STATUS.is_spindle_on(0): ACTION.SET_SPINDLE_FASTER(0) def spindle_slover(self): if STATUS.is_spindle_on(0): ACTION.SET_SPINDLE_SLOWER(0) def mb_errors_changed(self, data): errors = self.h['modbus-errors'] self.w.lbl_mb_errors.setText(str(errors)) def eoffset_changed(self, data): eoffset = "{:2.3f}".format(self.h['eoffset_value']) self.w.lbl_eoffset_value.setText(eoffset) def dialog_return(self, w, message): rtn = message.get('RETURN') name = message.get('NAME') plate_code = bool(message.get('ID') == '_touchplate_') sensor_code = bool(message.get('ID') == '_toolsensor_') wait_code = bool(message.get('ID') == '_wait_resume_') if plate_code and name == 'MESSAGE' and rtn is True: self.touchoff('touchplate') elif sensor_code and name == 'MESSAGE' and rtn is True: self.touchoff('sensor') elif wait_code and name == 'MESSAGE': self.h['eoffset_clear'] = False def user_system_changed(self, obj, data): sys = self.system_list[int(data) - 1] self.w.offset_table.selectRow(int(data) + 3) self.w.actionbutton_rel.setText(sys) def metric_mode_changed(self, mode): if mode is False: self.w.lbl_jog_linear.setText('JOG RATE\nIN/MIN') maxvel = float(self.max_linear_velocity) / 25.4 else: self.w.lbl_jog_linear.setText('JOG RATE\nMM/MIN') maxvel = float(self.max_linear_velocity) self.w.lbl_max_rapid.setText("{:4.0f}".format(maxvel)) def file_loaded(self, obj, filename): if filename is not None: self.add_status("Loaded file {}".format(filename)) self.w.progressBar.setValue(0) self.last_loaded_program = filename self.w.lbl_runtime.setText("00:00:00") else: self.add_status("Filename not valid") def runFromLineClicked(self): text = self.w.runFromLineEdit.text() if text != '': ACTION.RUN(line=int(text)) def btn_start_macro_clicked(self): if STATUS.is_mdi_mode(): self.w.mditouchy.run_command() return def homed(self, obj, joint): i = int(joint) axis = INFO.GET_NAME_FROM_JOINT.get(i).lower() try: self.w["dro_axis_{}".format(axis)].setProperty('homed', True) self.w["dro_axis_{}".format(axis)].setStyle( self.w["dro_axis_{}".format(axis)].style()) except: pass def all_homed(self, obj): self.home_all = True self.w.lbl_home_all.setText("ALL\nHOMED") if self.first_turnon is True: self.first_turnon = False if self.w.chk_reload_tool.isChecked(): command = "M61 Q{}".format(self.reload_tool) ACTION.CALL_MDI(command) if self.last_loaded_program is not None and self.w.chk_reload_program.isChecked( ): if os.path.isfile(self.last_loaded_program): self.w.cmb_gcode_history.addItem(self.last_loaded_program) self.w.cmb_gcode_history.setCurrentIndex( self.w.cmb_gcode_history.count() - 1) ACTION.OPEN_PROGRAM(self.last_loaded_program) ACTION.SET_MANUAL_MODE() self.w.manual_mode_button.setChecked(True) def not_all_homed(self, obj, list): self.home_all = False self.w.lbl_home_all.setText("HOME\nALL") for i in INFO.AVAILABLE_JOINTS: if str(i) in list: axis = INFO.GET_NAME_FROM_JOINT.get(i).lower() try: self.w["dro_axis_{}".format(axis)].setProperty( 'homed', False) self.w["dro_axis_{}".format(axis)].setStyle( self.w["dro_axis_{}".format(axis)].style()) except: pass def hard_limit_tripped(self, obj, tripped, list_of_tripped): self.add_status("Hard limits tripped") self.w.chk_override_limits.setEnabled(tripped) if not tripped: self.w.chk_override_limits.setChecked(False) def update_runtimer(self): if self.timerOn is False or STATUS.is_auto_paused(): return self.time_tenths += 1 if self.time_tenths == 10: self.time_tenths = 0 self.run_time += 1 hours, remainder = divmod(self.run_time, 3600) minutes, seconds = divmod(remainder, 60) self.w.lbl_runtime.setText("{:02d}:{:02d}:{:02d}".format( hours, minutes, seconds)) def start_timer(self): if STATUS.is_auto_running(): self.run_time = 0 self.timerOn = True def stop_timer(self): self.timerOn = False ####################### # CALLBACKS FROM FORM # ####################### def updateJogState(self): state = self.w.pushbutton_jog.isChecked() selected = None if state: ACTION.SET_MANUAL_MODE() selected = STATUS.get_selected_axis() for temp in INFO.AVAILABLE_AXES: if selected == temp: self['wheel_{}'.format(temp.lower())].set(state) else: self['wheel_{}'.format(temp.lower())].set(False) def full_screen(self, state): if state: self.w.stackedWidget_0.setCurrentIndex(1) self.w.widgetswitcher.show_id_widget(1) else: self.w.stackedWidget_0.setCurrentIndex(0) self.w.widgetswitcher.show_id_widget(0) def switch(self, state): #print state if state: self.w.stackedWidget_4.setCurrentIndex(6) self.w.widgetswitcher_2.show_id_widget(1) elif state == 0: self.w.widgetswitcher_2.show_id_widget(0) self.w.main_tab_widget.setCurrentIndex(0) #main button bar def main_tab_changed(self, btn): if STATUS.is_auto_mode(): self.add_status("Cannot switch pages while in AUTO mode") self.w.btn_main.setChecked(True) return index = btn.property("index") if index is None: return self.w.main_tab_widget.setCurrentIndex(index) if index == TAB_MAIN: self.w.btn_keyboard.setChecked(False) self.w.stackedWidget_2.setCurrentIndex(0) self.w.stackedWidget_4.setCurrentIndex(0) elif index == TAB_FILE: self.w.stackedWidget_4.setCurrentIndex(3) elif index == TAB_OFFSETS: self.w.stackedWidget_4.setCurrentIndex(4) elif index == TAB_TOOL: self.w.stackedWidget_4.setCurrentIndex(5) elif index == TAB_PROBE: self.w.stackedWidget_4.setCurrentIndex(6) elif index == TAB_MACRO: self.w.stackedWidget_4.setCurrentIndex(6) elif index == TAB_CAMERA: self.w.stackedWidget_4.setCurrentIndex(4) elif index == TAB_MDI_TOUCHY: self.w.stackedWidget_4.setCurrentIndex(6) else: self.w.stackedWidget_4.setCurrentIndex(0) # gcode frame def cmb_gcode_history_clicked(self): if self.w.cmb_gcode_history.currentIndex() == 0: return filename = self.w.cmb_gcode_history.currentText().encode('utf-8') if filename == self.last_loaded_program: self.add_status("Selected program is already loaded") else: ACTION.OPEN_PROGRAM(filename) # program frame def btn_start_clicked(self, obj): if self.w.main_tab_widget.currentIndex() != 0: return if not STATUS.is_auto_mode(): self.add_status("Must be in AUTO mode to run a program") return start_line = int(self.w.lbl_start_line.text().encode('utf-8')) self.add_status("Started program from line {}".format(start_line)) self.run_time = 0 if start_line == 1: ACTION.RUN(start_line) else: # instantiate preset dialog info = '<b>Running from Line: {} <\b>'.format(start_line) mess = { 'NAME': 'RUNFROMLINE', 'TITLE': 'Preset Dialog', 'ID': '_RUNFROMLINE', 'MESSAGE': info, 'LINE': start_line } ACTION.CALL_DIALOG(mess) def percentLoaded(self, fraction): if fraction < 1: self.w.progressBar.setValue(0) self.w.progressBar.setFormat('') else: self.w.progressBar.setValue(fraction) self.w.progressBar.setFormat('Loading: {}%'.format(fraction)) def percentCompleted(self, fraction): self.w.progressBar.setValue(fraction) if fraction < 1: self.w.progressBar.setFormat('') else: self.w.progressBar.setFormat('Completed: {}%'.format(fraction)) def btn_reload_file_clicked(self): if self.last_loaded_program: self.w.progressBar.setValue(0) self.add_status("Loaded program file {}".format( self.last_loaded_program)) ACTION.OPEN_PROGRAM(self.last_loaded_program) # DRO frame def btn_home_all_clicked(self, obj): if self.home_all is False: ACTION.SET_MACHINE_HOMING(-1) else: # instantiate dialog box info = "Unhome All Axes?" mess = { 'NAME': 'MESSAGE', 'ID': '_unhome_', 'MESSAGE': 'UNHOME ALL', 'MORE': info, 'TYPE': 'OKCANCEL' } ACTION.CALL_DIALOG(mess) ACTION.SET_MACHINE_UNHOMED(-1) def btn_home_clicked(self): joint = self.w.sender().property('joint') axis = INFO.GET_NAME_FROM_JOINT.get(joint).lower() if self.w["dro_axis_{}".format(axis)].property('homed') is True: ACTION.SET_MACHINE_UNHOMED(joint) else: ACTION.SET_MACHINE_HOMING(joint) # tool frame def disable_pause_buttons(self, state): self.w.action_pause.setEnabled(not state) self.w.action_step.setEnabled(not state) if state: # set external offsets to lift spindle self.h['eoffset_enable'] = self.w.chk_eoffsets.isChecked() fval = float(self.w.lineEdit_eoffset_count.text()) self.h['eoffset_count'] = int(fval) self.h['spindle_pause'] = True else: self.h['eoffset_count'] = 0 self.h['eoffset_clear'] = True self.h['spindle_pause'] = False # instantiate warning box info = "Wait for spindle at speed signal before resuming" mess = { 'NAME': 'MESSAGE', 'ICON': 'WARNING', 'ID': '_wait_resume_', 'MESSAGE': 'CAUTION', 'MORE': info, 'TYPE': 'OK' } ACTION.CALL_DIALOG(mess) def btn_go_home_clicked(self): ACTION.CALL_MDI_WAIT("G53 G0 Z0") command = "G53 G0 X{} Y{}".format(self.w.lbl_home_x.text(), self.w.lbl_home_y.text()) ACTION.CALL_MDI_WAIT(command, 10) # override frame def slow_button_clicked(self, state): slider = self.w.sender().property('slider') current = self.w[slider].value() max = self.w[slider].maximum() if state: self.w.sender().setText("SLOW") self.w[slider].setMaximum(max / self.slow_jog_factor) self.w[slider].setValue(current / self.slow_jog_factor) self.w[slider].setPageStep(10) else: self.w.sender().setText("FAST") self.w[slider].setMaximum(max * self.slow_jog_factor) self.w[slider].setValue(current * self.slow_jog_factor) self.w[slider].setPageStep(100) def slider_maxv_changed(self, value): maxpc = (float(value) / self.max_linear_velocity) * 100 self.w.lbl_maxv_percent.setText("{:3.0f} %".format(maxpc)) def slider_rapid_changed(self, value): rapid = (float(value) / 100) * self.max_linear_velocity self.w.lbl_max_rapid.setText("{:4.0f}".format(rapid)) # file tab def btn_gcode_edit_clicked(self, state): if not STATUS.is_on_and_idle(): return if state: self.w.filemanager.hide() self.w.gcode_editor.show() self.w.gcode_editor.editMode() else: self.w.filemanager.show() self.w.gcode_editor.hide() self.w.gcode_editor.readOnlyMode() def btn_load_file_clicked(self): fname = self.w.filemanager.getCurrentSelected() if fname[1] is True: self.load_code(fname[0]) # offsets tab def btn_goto_sensor_clicked(self): x = float(self.w.lineEdit_sensor_x.text()) y = float(self.w.lineEdit_sensor_y.text()) if not STATUS.is_metric_mode(): x = x / 25.4 y = y / 25.4 ACTION.CALL_MDI("G90") ACTION.CALL_MDI_WAIT("G53 G0 Z0") command = "G53 G0 X{:3.4f} Y{:3.4f}".format(x, y) ACTION.CALL_MDI_WAIT(command, 10) def btn_ref_laser_clicked(self): x = float(self.w.lineEdit_laser_x.text()) y = float(self.w.lineEdit_laser_y.text()) if not STATUS.is_metric_mode(): x = x / 25.4 y = y / 25.4 self.add_status("Laser offsets set") command = "G10 L20 P0 X{:3.4f} Y{:3.4f}".format(x, y) ACTION.CALL_MDI(command) def btn_ref_camera_clicked(self): x = float(self.w.lineEdit_camera_x.text()) y = float(self.w.lineEdit_camera_y.text()) if not STATUS.is_metric_mode(): x = x / 25.4 y = y / 25.4 self.add_status("Camera offsets set") command = "G10 L20 P0 X{:3.4f} Y{:3.4f}".format(x, y) ACTION.CALL_MDI(command) # tool tab def btn_m61_clicked(self): checked = self.w.tooloffsetview.get_checked_list() if len(checked) > 1: self.add_status("Select only 1 tool to load") elif checked: self.add_status("Loaded tool {}".format(checked[0])) ACTION.CALL_MDI("M61 Q{}".format(checked[0])) else: self.add_status("No tool selected") def btn_touchoff_clicked(self): if STATUS.get_current_tool() == 0: self.add_status("Cannot touchoff with no tool loaded") return if not STATUS.is_all_homed(): self.add_status("Must be homed to perform tool touchoff") return # instantiate dialog box sensor = self.w.sender().property('sensor') info = "Ensure tooltip is within {} mm of tool sensor and click OK".format( self.w.lineEdit_max_probe.text()) mess = { 'NAME': 'MESSAGE', 'ID': sensor, 'MESSAGE': 'TOOL TOUCHOFF', 'MORE': info, 'TYPE': 'OKCANCEL' } ACTION.CALL_DIALOG(mess) # status tab def btn_clear_status_clicked(self): STATUS.emit('update-machine-log', None, 'DELETE') def btn_save_status_clicked(self): text = self.w.machinelog.toPlainText() filename = self.w.lbl_clock.text().encode('utf-8') filename = 'status_' + filename.replace(' ', '_') + '.txt' self.add_status("Saving Status file to {}".format(filename)) with open(filename, 'w') as f: f.write(text) def btn_dimensions_clicked(self, state): self.w.gcodegraphics.show_extents_option = state self.w.gcodegraphics.updateGL() # DRO def btn_setdro_clicked(self, state): self.w.gcodegraphics.setdro(state) self.w.gcodegraphics.setoverlay(state) def getdro(self): return self.enable_dro # show Offsets def btn_show_offset_clicked(self, state): self.w.gcodegraphics.setShowOffsets(state) self.w.gcodegraphics.setoverlay(state) def getShowOffsets(self): return self.show_offsets # camview tab def cam_zoom_changed(self, value): self.w.camview.scale = float(value) / 10 def cam_dia_changed(self, value): self.w.camview.diameter = value def cam_rot_changed(self, value): self.w.camview.rotation = float(value) / 10 # settings tab def chk_use_virtual_changed(self, state): if state: self.w.btn_keyboard.show() else: self.w.btn_keyboard.hide() def chk_override_limits_checked(self, state): if state: print("Override limits set") ACTION.SET_LIMITS_OVERRIDE() else: print("Override limits not set") def chk_run_from_line_checked(self, state): if not state: self.w.lbl_start_line.setText('1') def chk_use_camera_changed(self, state): self.w.btn_ref_camera.setEnabled(state) if state: self.w.btn_camera.show() else: self.w.btn_camera.hide() def chk_use_tool_sensor_changed(self, state): self.w.btn_touch_sensor.setEnabled(state) def chk_alpha_mode_clicked(self, state): self.w.gcodegraphics.set_alpha_mode(state) def chk_inhibit_display_selection_clicked(self, state): self.w.gcodegraphics.set_inhibit_selection(state) ##################### # GENERAL FUNCTIONS # ##################### def mode_changed(self, data): self._block_signal = True self.w.pushbutton_metric.setChecked(data) # if using state labels option update the labels if self.w.pushbutton_metric._state_text: self.w.pushbutton_metric.setText(None) self._block_signal = False def change_mode(self, data): if self._block_signal: return if data: ACTION.CALL_MDI('G21') else: ACTION.CALL_MDI('G20') def load_code(self, fname): if fname is None: return filename, file_extension = os.path.splitext(fname) if not fname.endswith(".html"): if not (INFO.program_extension_valid(fname)): self.add_status( "Unknown or invalid filename extension {}".format( file_extension)) return self.w.cmb_gcode_history.addItem(fname) self.w.cmb_gcode_history.setCurrentIndex( self.w.cmb_gcode_history.count() - 1) ACTION.OPEN_PROGRAM(fname) self.add_status("Loaded program file : {}".format(fname)) self.w.main_tab_widget.setCurrentIndex(TAB_MAIN) elif fname.endswith(".html"): self.w.web_view.load(QtCore.QUrl.fromLocalFile(fname)) self.add_status("Loaded HTML file : {}".format(fname)) self.w.main_tab_widget.setCurrentIndex(TAB_SETUP) self.w.btn_setup.setChecked(True) else: self.add_status("Unknown or invalid filename") def disable_spindle_pause(self): self.h['eoffset_count'] = 0 if self.w.spindle_pause.isChecked(): self.w.spindle_pause.setChecked(False) def touchoff(self, selector): if selector == 'touchplate': z_offset = float(self.w.lineEdit_touch_height.text()) elif selector == 'sensor': z_offset = float(self.w.lineEdit_sensor_height.text()) - float( self.w.lineEdit_work_height.text()) else: self.add_alarm("Unknown touchoff routine specified") return self.add_status("Touchoff to {} started".format(selector)) max_probe = self.w.lineEdit_max_probe.text() search_vel = self.w.lineEdit_search_vel.text() probe_vel = self.w.lineEdit_probe_vel.text() ACTION.CALL_MDI("G21 G49") ACTION.CALL_MDI("G10 L20 P0 Z0") ACTION.CALL_MDI("G91") command = "G38.2 Z-{} F{}".format(max_probe, search_vel) if ACTION.CALL_MDI_WAIT(command, 10) == -1: ACTION.CALL_MDI("G90") return if ACTION.CALL_MDI_WAIT("G1 Z4.0"): ACTION.CALL_MDI("G90") return ACTION.CALL_MDI("G4 P0.5") command = "G38.2 Z-4.4 F{}".format(probe_vel) if ACTION.CALL_MDI_WAIT(command, 10) == -1: ACTION.CALL_MDI("G90") return command = "G10 L20 P0 Z{}".format(z_offset) ACTION.CALL_MDI_WAIT(command) command = "G1 Z10 F{}".format(search_vel) ACTION.CALL_MDI_WAIT(command) ACTION.CALL_MDI("G90") def kb_jog(self, state, joint, direction, fast=False, linear=True): if not STATUS.is_man_mode() or not STATUS.machine_is_on(): self.add_status('Machine must be ON and in Manual mode to jog') return if linear: distance = STATUS.get_jog_increment() rate = STATUS.get_jograte() / 60 else: distance = STATUS.get_jog_increment_angular() rate = STATUS.get_jograte_angular() / 60 if state: if fast: rate = rate * 2 ACTION.JOG(joint, direction, rate, distance) else: ACTION.JOG(joint, 0, 0, 0) def add_status(self, message): self._m = message print(message) self.w.statusbar.showMessage(self._m, 5000) STATUS.emit('update-machine-log', self._m, 'TIME') def enable_auto(self, state): for widget in self.auto_list: self.w[widget].setEnabled(state) if state is True: self.w.jogging_frame.show() if self.w.chk_use_virtual.isChecked(): self.w.btn_keyboard.show() else: self.w.jogging_frame.hide() self.w.btn_main.setChecked(True) self.w.btn_keyboard.setChecked(False) self.w.btn_keyboard.hide() self.w.main_tab_widget.setCurrentIndex(TAB_MAIN) self.w.stackedWidget_4.setCurrentIndex(3) def enable_onoff(self, state): if state: self.add_status("Machine ON") else: self.add_status("Machine OFF") self.w.spindle_pause.setChecked(False) self.h['eoffset_count'] = 0 for widget in self.onoff_list: self.w[widget].setEnabled(state) def set_start_line(self, line): if line == 0: self.w.lbl_start_line.setText('1') elif self.w.chk_run_from_line.isChecked(): self.w.lbl_start_line.setText(str(line)) else: self.w.lbl_start_line.setText('1') def use_keyboard(self): if self.w.chk_use_keyboard.isChecked(): return True else: self.add_status('Keyboard shortcuts are disabled') return False def update_rpm(self, speed): if int(speed) == 0: in_range = True at_speed = True else: in_range = (self.min_spindle_rpm <= int(speed) <= self.max_spindle_rpm) at_speed = self.h['led_atspeed'] widget = self.w.label_spindle_set widget.setProperty('in_range', in_range) widget.style().unpolish(widget) widget.style().polish(widget) widget = self.w.status_rpm widget.setProperty('at_speed', at_speed) widget.style().unpolish(widget) widget.style().polish(widget) def external_mpg(self, count): diff = count - self._last_count if self.w.pushbutton_fo.isChecked(): scaled = (STATUS.stat.feedrate * 100 + diff) if scaled < 0: scaled = 0 elif scaled > INFO.MAX_FEED_OVERRIDE: scaled = INFO.MAX_FEED_OVERRIDE ACTION.SET_FEED_RATE(scaled) elif self.w.pushbutton_ro.isChecked(): scaled = (STATUS.stat.rapidrate * 100 + diff) if scaled < 0: scaled = 0 elif scaled > 100: scaled = 100 ACTION.SET_RAPID_RATE(scaled) elif self.w.pushbutton_so.isChecked(): scaled = (STATUS.stat.spindle[0]['override'] * 100 + diff) if scaled < INFO.MIN_SPINDLE_OVERRIDE: scaled = INFO.MIN_SPINDLE_OVERRIDE elif scaled > INFO.MAX_SPINDLE_OVERRIDE: scaled = INFO.MAX_SPINDLE_OVERRIDE ACTION.SET_SPINDLE_RATE(scaled) self._last_count = count ##################### # KEY BINDING CALLS # ##################### def on_keycall_ESTOP(self, event, state, shift, cntrl): if state: ACTION.SET_ESTOP_STATE(True) def on_keycall_POWER(self, event, state, shift, cntrl): if state: ACTION.SET_MACHINE_STATE(False) def on_keycall_ABORT(self, event, state, shift, cntrl): if state: ACTION.ABORT() def on_keycall_HOME(self, event, state, shift, cntrl): if state and not STATUS.is_all_homed() and self.use_keyboard(): ACTION.SET_MACHINE_HOMING(-1) def on_keycall_pause(self, event, state, shift, cntrl): if state and STATUS.is_auto_mode() and self.use_keyboard(): ACTION.PAUSE() def on_keycall_XPOS(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 0, 1, shift) def on_keycall_XNEG(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 0, -1, shift) def on_keycall_YPOS(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 1, 1, shift) def on_keycall_YNEG(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 1, -1, shift) def on_keycall_ZPOS(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 2, 1, shift) def on_keycall_ZNEG(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 2, -1, shift) def on_keycall_APOS(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 3, 1, shift, False) def on_keycall_ANEG(self, event, state, shift, cntrl): if self.use_keyboard() and not self.w.btn_keyboard.isChecked(): self.kb_jog(state, 3, -1, shift, False) def on_keycall_F12(self, event, state, shift, cntrl): if state: STYLEEDITOR.load_dialog() ############################## # required class boiler code # ############################## def __getitem__(self, item): return getattr(self, item) def __setitem__(self, item, value): return setattr(self, item, value)