From fabc7d70c538bd60601deb1dd438afdbc13f6b41 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 16 Aug 2025 11:21:10 -0700 Subject: [PATCH 01/79] add bridgeui folder for HALUI --- lib/python/bridgeui/__init__.py | 3 + lib/python/bridgeui/bridge.py | 302 ++++++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 lib/python/bridgeui/__init__.py create mode 100644 lib/python/bridgeui/bridge.py diff --git a/lib/python/bridgeui/__init__.py b/lib/python/bridgeui/__init__.py new file mode 100644 index 00000000000..b28b04f6431 --- /dev/null +++ b/lib/python/bridgeui/__init__.py @@ -0,0 +1,3 @@ + + + diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py new file mode 100644 index 00000000000..54ea67d225e --- /dev/null +++ b/lib/python/bridgeui/bridge.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python3 + +import os +import sys +import time + +import json +import signal + +import hal +from qtvcp.qt_halobjects import Qhal +from common.iniinfo import _IStat as IStatParent +from common import logger + +# LOG is for running code logging +LOG = logger.initBaseLogger('HAL bridge', log_file=None, + log_level=logger.WARNING, logToFile=False) + +# Force the log level for this module +LOG.setLevel(logger.DEBUG) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL + +try: + import zmq + ZMQ = True +except: + LOG.critical('ZMQ python library problem - Is python3-zmq installed?') + ZMQ = False + +class Info(IStatParent): + _instance = None + _instanceNum = 0 + + def __new__(cls, *args, **kwargs): + if not cls._instance: + cls._instance = IStatParent.__new__(cls, *args, **kwargs) + return cls._instance + +# Instantiate the library with global reference + + +class Bridge(object): + def __init__(self, readAddress = "tcp://127.0.0.1:5690", + writeAddress = "tcp://127.0.0.1:5691"): + super(Bridge, self).__init__() + self.INFO = Info() + + self.currentSelectedAxis = 'None' + self.axesSelected = {'X':0,'Y':0,'Z':0,'A':0,'B':0,'C':0, + 'U':0,'V':0,'W':0} + self.readAddress = readAddress + self.writeAddress = writeAddress + LOG.debug('read port: {}'.format(readAddress)) + LOG.debug('write port: {}'.format(writeAddress)) + + self.readTopic = "" + self.writeTopic = "STATUSREQUEST" + + # catch control c and terminate signals + signal.signal(signal.SIGTERM, self.shutdown) + signal.signal(signal.SIGINT, self.shutdown) + + self.init_hal() + if ZMQ: + self.init_read() + self.init_write() + + def update(self, *arg): + print(self, arg) + raw=arg[0]; row=arg[1];column=arg[2];state=arg[3] + LOG.debug('raw {}, row {}, col {}, state {}'.format(raw,row,column,state)) + print ('raw',raw,'row:',row,'column:',column,'state:',state) + self.writeMsg('set_selected_axis','Y') + self.activeJoint.set(10) + + def init_hal(self): + self.comp = h = hal.component("bridge") + QHAL = Qhal(comp=self.comp, hal=hal) + + self.jogRate = QHAL.newpin("jog-rate", hal.HAL_FLOAT, hal.HAL_OUT) + self.jogRateIn = QHAL.newpin("jog-rate-in", hal.HAL_FLOAT, hal.HAL_IN) + self.jogRateIn.pinValueChanged.connect(self.pinChanged) + + self.jogRateAngular = QHAL.newpin("jog-rate-angular", hal.HAL_FLOAT, hal.HAL_OUT) + self.jogRateAngularIn = QHAL.newpin("jog-rate-angular-in", hal.HAL_FLOAT, hal.HAL_OUT) + self.jogRateAngularIn.pinValueChanged.connect(self.pinChanged) + + self.jogIncrement = QHAL.newpin("jog-increment", hal.HAL_FLOAT, hal.HAL_OUT) + self.jogIncrementAngular = QHAL.newpin("jog-increment-angular", hal.HAL_FLOAT, hal.HAL_OUT) + self.activeJoint = QHAL.newpin('joint-selected', hal.HAL_S32, hal.HAL_OUT) + + for i in (self.INFO.AVAILABLE_AXES): + let = i.lower() + # input + self['axis{}Select'.format(let)] = QHAL.newpin('axis-%s-select'%let, hal.HAL_BIT, hal.HAL_IN) + self['axis{}Select'.format(let)].pinValueChanged.connect(self.pinChanged) + # output + self['Axis{}IsSelected'.format(let)] = QHAL.newpin('axis-%s-is-selected'%let, hal.HAL_BIT, hal.HAL_OUT) + + self.cycle_start = QHAL.newpin('cycle-start-in',QHAL.HAL_BIT, QHAL.HAL_IN) + self.cycle_start.pinValueChanged.connect(self.pinChanged) + self.cycle_pause = QHAL.newpin('cycle-pause-in',QHAL.HAL_BIT, QHAL.HAL_IN) + self.cycle_pause.pinValueChanged.connect(self.pinChanged) + + for i in self.INFO.MDI_COMMAND_DICT: + LOG.debug('{} {}'.format(i,self.INFO.MDI_COMMAND_DICT.get(i))) + self[i] = QHAL.newpin('ini-mdi-cmd-{}'.format(i),QHAL.HAL_BIT, QHAL.HAL_IN) + self[i].pinValueChanged.connect(self.runMacroChanged) + + for i in self.INFO.INI_MACROS: + name = i.split()[0] + LOG.debug('{} {}'.format(name,i)) + self[name] = QHAL.newpin('ini-macro-cmd-{}'.format(name),QHAL.HAL_BIT, QHAL.HAL_IN) + self[name].pinValueChanged.connect(self.runMacroChanged) + + QHAL.setUpdateRate(100) + h.ready() + + def init_write(self): + context = zmq.Context() + self.writeSocket = context.socket(zmq.PUB) + self.writeSocket.bind(self.writeAddress) + + def init_read(self): + # ZeroMQ Context + self.readContext = zmq.Context() + + # Define the socket using the "Context" + self.readSocket = self.readContext.socket(zmq.SUB) + + # Define subscription and messages with topic to accept. + self.readSocket.setsockopt_string(zmq.SUBSCRIBE, self.readTopic) + self.readSocket.connect(self.readAddress) + + # callback from ZMQ read socket + def readMsg(self, msg): + if self.readSocket.getsockopt(zmq.EVENTS) & zmq.POLLIN: + while self.readSocket.getsockopt(zmq.EVENTS) & zmq.POLLIN: + # get raw message + topic, data = self.readSocket.recv_multipart() + # convert from json object to python object + y = json.loads(data) + self. action(y.get('MESSAGE'),y.get('ARGS')) + + # set our output HAL pins from messages from hal_glib + def action(self, msg, data): + LOG.debug('{} {}'.format(msg, data)) + if msg == 'jograte-changed': + self.jogRate.set(float(data[0])) + elif msg == 'jograte-angular-changed': + self.jogRateAngular.set(float(data[0])) + elif msg == 'jogincrements-changed': + self.jogIncrement.set(float(data[0][0])) + elif msg == 'jogincrement-angular-changed': + self.jogIncremtAngular.set(float(data[0][0])) + elif msg == 'joint-selection-changed': + self.activeJoint.set(int(data[0])) + elif msg == 'axis-selection-changed': + flag = 1 + for i in(self.INFO.AVAILABLE_AXES): + if data[0] == i: + state = True + self.currentSelectedAxis = data[0] + flag = 0 + else: + state = False + self['Axis{}IsSelected'.format(i.lower())].set(state) + self.axesSelected[i] = int(state) + if flag: + self.currentSelectedAxis = 'None' + #print ('axis state', self.axesSelected) + + # send msg to hal_glib + def writeMsg(self, msg, data): + print('Write Msg called') + if ZMQ: + topic = self.writeTopic + message = json.dumps({'FUNCTION':msg,'ARGS':data}) + LOG.debug('Sending ZMQ Message:{} {}'.format(topic, message)) + self.writeSocket.send_multipart( + [bytes(topic.encode('utf-8')), + bytes((message).encode('utf-8'))]) + + # callback from HAL input pins + def pinChanged(self, pinObject, value): + LOG.debug('Pin name:{} changed value to {}'.format(pinObject.text(), value)) + #print(type(value)) + # Axis selction change request + if 'select' in pinObject.text(): + if bool(value) == False: + pass + #print('Not true state') + return + for i in (self.INFO.AVAILABLE_AXES): + if '-{}-'.format(i.lower()) in pinObject.text(): + self.writeMsg('set_selected_axis', i) + break + else: + if 'None' in pinObject.text(): + self.writeMsg('set_selected_axis', '') + + # cycle start + elif self.cycle_start == pinObject: + if value: + self.writeMsg('request_cycle_start', value) + + # cycle pause + elif self.cycle_pause == pinObject: + #if value: + self.writeMsg('request_cycle_pause', value) + + # linear jog rate + elif self.jogRateIn == pinObject: + self.writeMsg('set_jograte', value) + + # angular jog rate + elif self.jogRateAngularIn == pinObject: + self.writeMsg('set_jograte_angular', value) + + # catch all default + else: + self.writeMsg(pinObject.text(),value) + + # callback; request to run a specific macro + def runMacroChanged(self, pinObject, value): + LOG.debug('Macro Pin name:{} changed value to {}'.format(pinObject.text(), value)) + #LOG.debug(type(value)) + name = pinObject.text().strip('macro-cmd-') + if value: + self.writeMsg('request_macro_call', name) + + def shutdown(self,signum=None,stack_frame=None): + LOG.debug('shutdown') + global app + app.quit() + + def getJogRate(self): + return self.jogRate.get() + def setJogRate(self, value): + self.writeMsg('set_jograte', value) + + def getJogRateAngular(self): + return self.jogRateAngular.get() + def setJogRateAngular(self, value): + self.writeMsg('set_jograte_angular', value) + + def getSelectedAxis(self): + name = self.currentSelectedAxis + if name == 'None': + index = -1 + else: + index = 'XYZABCUVW'.index(name) + return index + def setSelectedAxis(self, value): + if value < 0: + letter = 'None' + else: + letter ='XYZABCUVW'[value] + self.writeMsg('set_selected_axis', letter) + + def isAxisSelected(self, index): + letter = 'XYZABCUVW'[index] + return int(self.axesSelected[letter]) + + def __getitem__(self, item): + return getattr(self, item) + def __setitem__(self, item, value): + return setattr(self, item, value) + +if __name__ == "__main__": + import sys + import getopt + from PyQt5.QtWidgets import QApplication + + letters = 'dh' # the : means an argument needs to be passed after the letter + keywords = ['readport=', 'writeport=' ] # the = means that a value is expected after + # the keyword + + opts, extraparam = getopt.getopt(sys.argv[1:],letters,keywords) + # starts at the second element of argv since the first one is the script name + # extraparms are extra arguments passed after all option/keywords are assigned + # opts is a list containing the pair "option"/"value" + + readport = "tcp://127.0.0.1:5690" + writeport = "tcp://127.0.0.1:5691" + + for o,p in opts: + if o in ['-d']: + LOG.setLevel(logger.DEBUG) + elif o in ['--readport']: + readport = p + elif o in ['--writeport']: + writeport = p + elif o in ['-h','--help']: + print('HAL bridge: GUI to HAL interface using ZMQ') + print('option "-d" = debug print mode') + print('option "--readport=" read socket address') + print('option "--writeport=" write socket address') + print('example: hal_bridge -d --readport=tcp://127.0.0.1:5692') + + app = QApplication(sys.argv) + test = Bridge(readport, writeport) + sys.exit(app.exec_()) From e8272af56a3340d2f6e2b493dccaf3cb8d19eb9a Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 2 Aug 2025 19:38:15 -0700 Subject: [PATCH 02/79] halui initial testing of embedded python halui --- .../qtdragon/qtdragon_xyz/qtdragon_metric.ini | 2 +- src/emc/usr_intf/Submakefile | 3 +- src/emc/usr_intf/halui.cc | 244 ++++++++++++++++-- 3 files changed, 226 insertions(+), 23 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini index 7e5d56e05aa..f437be0811a 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini @@ -151,7 +151,7 @@ SPINDLES = 1 [HAL] HALUI = halui -HALBRIDGE = hal_bridge +#HALBRIDGE = hal_bridge # loads the HAL machine simulation HALFILE = core_sim.hal diff --git a/src/emc/usr_intf/Submakefile b/src/emc/usr_intf/Submakefile index b914e30ffe1..4dbd9ec9afb 100644 --- a/src/emc/usr_intf/Submakefile +++ b/src/emc/usr_intf/Submakefile @@ -42,5 +42,6 @@ TARGETS += ../bin/linuxcnclcd ../bin/halui: $(call TOOBJS, $(HALUISRCS)) ../lib/liblinuxcnc.a ../lib/liblinuxcncini.so.1 ../lib/libnml.so.0 ../lib/liblinuxcnchal.so.0 ../lib/libtooldata.so.0 $(ECHO) Linking $(notdir $@) - $(Q)$(CXX) $(CXXFLAGS) -o $@ $(ULFLAGS) $^ $(LDFLAGS) + $(Q)$(CXX) $(CXXFLAGS) -o $@ $(ULFLAGS) $^ $(LDFLAGS) $(PYTHON_LIBS) $(PYTHON_EXTRA_LIBS) TARGETS += ../bin/halui + diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 4e1761f64d9..544a435236a 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -43,6 +43,10 @@ using namespace linuxcnc; +#define PY_SSIZE_T_CLEAN +#include +#include + /* Using halui: see the man page */ static int axis_mask = 0; @@ -234,9 +238,16 @@ typedef halui_str_base halui_str; typedef halui_str_base local_halui_str; #pragma GCC diagnostic pop +PyObject *pModule, *pFuncRead, *pFuncWrite, *pInstance, *pClass; +PyObject *pValue; + static halui_str *halui_data; static local_halui_str old_halui_data; +static double lastjogspeed = 0; +static double internaljogspeed = 0; +static int lastaxis = -1; + static char *mdi_commands[MDI_MAX]; static int num_mdi_commands=0; static int have_home_all = 0; @@ -1600,7 +1611,101 @@ static bool jogging_selected_axis(local_halui_str &hal) { return (hal.ajog_plus[EMCMOT_MAX_AXIS] || hal.ajog_minus[EMCMOT_MAX_AXIS]); } +static double write_msg_axis_get_jogspeed() { + double jspd = 0; + // check socket messages for jogspeed + pFuncRead = PyObject_GetAttrString(pInstance, "getJogRate"); + if (pFuncRead && PyCallable_Check(pFuncRead)) { + pValue = PyObject_CallNoArgs(pFuncRead); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: getJogRate function failed: returned NULL\n"); + jspd = 0; + }else{ + if (PyFloat_Check(pValue)) { + jspd = PyFloat_AsDouble(pValue); + if (PyErr_Occurred()) { + jspd = 0; + // Handle conversion error + PyErr_Print(); + // Clear the error state if needed + PyErr_Clear(); + } + } + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncRead); + return jspd; +} + +static void write_msg_axis_jogspeed(double speed) +{ + pFuncWrite = PyObject_GetAttrString(pInstance, "setJogRate"); + + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallFunction(pFuncWrite, "d", speed); + if (pValue == NULL){ + fprintf(stderr, "halui bridge: writeMsg function failed: returned NULL\n"); + if (PyErr_Occurred()) PyErr_Print(); + }else{ + Py_DECREF(pValue); + } + + }else{ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "halui Bridge: Failed python function"); + } + Py_DECREF(pFuncWrite); +} + +static int write_msg_get_axis_selected() { + int value = 0; + // check socket messages for jogspeed + pFuncRead = PyObject_GetAttrString(pInstance, "getSelectedAxis"); + if (pFuncRead && PyCallable_Check(pFuncRead)) { + pValue = PyObject_CallNoArgs(pFuncRead); + if (pValue == NULL){ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "Halui Bridge: getSelectAxis function failed: returned NULL\n"); + value = -1; + }else{ + if (PyLong_Check(pValue)) { + value = (int) PyLong_AsLong(pValue); + //fprintf(stderr, "axis value %d\n",value); + if (PyErr_Occurred()) { + value = -1; + // Handle conversion error + PyErr_Print(); + // Clear the error state if needed + PyErr_Clear(); + } + } + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncRead); + return value; +} + +static void write_msg_axis_changed( int axis) +{ + pFuncWrite = PyObject_GetAttrString(pInstance, "setSelectedAxis"); + + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallFunction(pFuncWrite, "i", axis); + if (pValue == NULL){ + fprintf(stderr, "halui bridge: writeMsg function failed: returned NULL\n"); + if (PyErr_Occurred()) PyErr_Print(); + }else{ + Py_DECREF(pValue); + } + }else{ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "halui Bridge: Failed python function"); + } + Py_DECREF(pFuncWrite); +} // this function looks if any of the hal pins has changed // and sends appropriate messages if so static void check_hal_changes() @@ -1611,13 +1716,30 @@ static void check_hal_changes() hal_bit_t bit; int js; hal_float_t floatt; + double jogspeed; int jjog_speed_changed; int ajog_speed_changed; + int is_any_axis_selected, deselected; local_halui_str new_halui_data_mutable; copy_hal_data(*halui_data, new_halui_data_mutable); const local_halui_str &new_halui_data = new_halui_data_mutable; + // read socket messages + pFuncRead = PyObject_GetAttrString(pInstance, "readMsg"); + if (pFuncRead && PyCallable_Check(pFuncRead)) { + pValue = PyObject_CallFunction(pFuncRead, "O", pClass); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: readMsg function failed: returned NULL\n"); + } + if (PyErr_Occurred()) PyErr_Print(); + }else{ + if (PyErr_Occurred()){ + PyErr_Print(); + } + fprintf(stderr, "Bridge: Failed python function"); + exit(1); + } //check if machine_on pin has changed (the rest work exactly the same) if (check_bit_changed(new_halui_data.machine_on, old_halui_data.machine_on) != 0) @@ -1833,11 +1955,23 @@ static void check_hal_changes() // re-start the jog with the new speed if (fabs(old_halui_data.ajog_speed - new_halui_data.ajog_speed) > 0.00001) { old_halui_data.ajog_speed = new_halui_data.ajog_speed; + internaljogspeed = new_halui_data.ajog_speed; ajog_speed_changed = 1; + write_msg_axis_jogspeed(internaljogspeed); } else { ajog_speed_changed = 0; } + // check socket messages for jogspeed + jogspeed = write_msg_axis_get_jogspeed(); + if (fabs(jogspeed - lastjogspeed) > 0.00001) { + ajog_speed_changed = 1; + lastjogspeed = jogspeed; + internaljogspeed = jogspeed; + fprintf(stderr, "JogRate value = %f\n", jogspeed ); + } + + for (joint=0; joint < num_joints; joint++) { if (check_bit_changed(new_halui_data.joint_home[joint], old_halui_data.joint_home[joint]) != 0) sendHome(joint); @@ -1917,47 +2051,57 @@ static void check_hal_changes() } } + + // check thru axes + is_any_axis_selected = 0; + deselected = 0; for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) { if ( !(axis_mask & (1 << axis_num)) ) { continue; } + + // axis jog - bit = new_halui_data.ajog_minus[axis_num]; if ((bit != old_halui_data.ajog_minus[axis_num]) || (bit && ajog_speed_changed)) { if (bit != 0) - sendJogCont(axis_num,-new_halui_data.ajog_speed,JOGTELEOP); + sendJogCont(axis_num,-internaljogspeed,JOGTELEOP); else sendJogStop(axis_num,JOGTELEOP); old_halui_data.ajog_minus[axis_num] = bit; } + // axis jog + bit = new_halui_data.ajog_plus[axis_num]; if ((bit != old_halui_data.ajog_plus[axis_num]) || (bit && ajog_speed_changed)) { if (bit != 0) - sendJogCont(axis_num,new_halui_data.ajog_speed,JOGTELEOP); + sendJogCont(axis_num,internaljogspeed,JOGTELEOP); else sendJogStop(axis_num,JOGTELEOP); old_halui_data.ajog_plus[axis_num] = bit; } + // axis jog analog floatt = new_halui_data.ajog_analog[axis_num]; bit = (fabs(floatt) > new_halui_data.ajog_deadband); if ((floatt != old_halui_data.ajog_analog[axis_num]) || (bit && ajog_speed_changed)) { if (bit) - sendJogCont(axis_num,(new_halui_data.ajog_speed) * (new_halui_data.ajog_analog[axis_num]),JOGTELEOP); + sendJogCont(axis_num,(internaljogspeed) * (new_halui_data.ajog_analog[axis_num]),JOGTELEOP); else sendJogStop(axis_num,JOGTELEOP); old_halui_data.ajog_analog[axis_num] = floatt; } + // axis jog + increment bit = new_halui_data.ajog_increment_plus[axis_num]; if (bit != old_halui_data.ajog_increment_plus[axis_num]) { if (bit) - sendJogIncr(axis_num, new_halui_data.ajog_speed, new_halui_data.ajog_increment[axis_num],JOGTELEOP); + sendJogIncr(axis_num, internaljogspeed, new_halui_data.ajog_increment[axis_num],JOGTELEOP); old_halui_data.ajog_increment_plus[axis_num] = bit; } + // jog a- increment bit = new_halui_data.ajog_increment_minus[axis_num]; if (bit != old_halui_data.ajog_increment_minus[axis_num]) { if (bit) - sendJogIncr(axis_num, new_halui_data.ajog_speed, -(new_halui_data.ajog_increment[axis_num]),JOGTELEOP); + sendJogIncr(axis_num, internaljogspeed, -(new_halui_data.ajog_increment[axis_num]),JOGTELEOP); old_halui_data.ajog_increment_minus[axis_num] = bit; } @@ -1965,30 +2109,46 @@ static void check_hal_changes() bit = new_halui_data.axis_nr_select[axis_num]; if (bit != old_halui_data.axis_nr_select[axis_num]) { if (bit != 0) { + is_any_axis_selected = 1; *halui_data->axis_selected = axis_num; + write_msg_axis_changed(axis_num); aselect_changed = axis_num; // flag that we changed the selected axis - } + }else{ + deselected = 1; + } old_halui_data.axis_nr_select[axis_num] = bit; - } + } + } + // last axis has been deselected - no axis is selected now + if (is_any_axis_selected == 0 and deselected == 1) { + write_msg_axis_changed(-1); + } + + // check socket messages for axis selection change + int value = write_msg_get_axis_selected(); + if (value != lastaxis){ + aselect_changed = lastaxis = value; } if (aselect_changed >= 0) { - for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) { - if ( !(axis_mask & (1 << axis_num)) ) { continue; } - if (axis_num != aselect_changed) { - *(halui_data->axis_is_selected[axis_num]) = 0; + fprintf(stderr, "halui Bridge: axis selected %d\n",aselect_changed); + for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) { + if ( !(axis_mask & (1 << axis_num)) ) { continue; } + if (axis_num != aselect_changed) { + *(halui_data->axis_is_selected[axis_num]) = 0; if (jogging_selected_axis(old_halui_data) && !jogging_axis(old_halui_data, axis_num)) { - sendJogStop(axis_num,JOGTELEOP); + sendJogStop(axis_num,JOGTELEOP); } } else { - *(halui_data->axis_is_selected[axis_num]) = 1; + *(halui_data->axis_is_selected[axis_num]) = 1; if (*halui_data->ajog_plus[num_axes]) { - sendJogCont(axis_num, new_halui_data.ajog_speed,JOGTELEOP); + fprintf(stderr, "halui: jog plus: %d\n",num_axes); + sendJogCont(axis_num, internaljogspeed,JOGTELEOP); } else if (*halui_data->ajog_minus[num_axes]) { - sendJogCont(axis_num, -new_halui_data.ajog_speed,JOGTELEOP); + sendJogCont(axis_num, -internaljogspeed,JOGTELEOP); } - } - } + } + } } if (check_bit_changed(new_halui_data.joint_home[num_joints], old_halui_data.joint_home[num_joints]) != 0) @@ -2037,7 +2197,7 @@ static void check_hal_changes() js = new_halui_data.axis_selected; if ((bit != old_halui_data.ajog_minus[EMCMOT_MAX_AXIS]) || (bit && ajog_speed_changed)) { if (bit != 0) - sendJogCont(js, -new_halui_data.ajog_speed,JOGTELEOP); + sendJogCont(js, -internaljogspeed,JOGTELEOP); else sendJogStop(js,JOGTELEOP); old_halui_data.ajog_minus[EMCMOT_MAX_AXIS] = bit; @@ -2047,7 +2207,7 @@ static void check_hal_changes() js = new_halui_data.axis_selected; if ((bit != old_halui_data.ajog_plus[EMCMOT_MAX_AXIS]) || (bit && ajog_speed_changed)) { if (bit != 0) - sendJogCont(js,new_halui_data.ajog_speed,JOGTELEOP); + sendJogCont(js,internaljogspeed,JOGTELEOP); else sendJogStop(js,JOGTELEOP); old_halui_data.ajog_plus[EMCMOT_MAX_AXIS] = bit; @@ -2057,7 +2217,7 @@ static void check_hal_changes() js = new_halui_data.axis_selected; if (bit != old_halui_data.ajog_increment_plus[EMCMOT_MAX_AXIS]) { if (bit) - sendJogIncr(js, new_halui_data.ajog_speed, new_halui_data.ajog_increment[EMCMOT_MAX_AXIS],JOGTELEOP); + sendJogIncr(js, internaljogspeed, new_halui_data.ajog_increment[EMCMOT_MAX_AXIS],JOGTELEOP); old_halui_data.ajog_increment_plus[EMCMOT_MAX_AXIS] = bit; } @@ -2065,7 +2225,7 @@ static void check_hal_changes() js = new_halui_data.axis_selected; if (bit != old_halui_data.ajog_increment_minus[EMCMOT_MAX_AXIS]) { if (bit) - sendJogIncr(js, new_halui_data.ajog_speed, -(new_halui_data.ajog_increment[EMCMOT_MAX_AXIS]),JOGTELEOP); + sendJogIncr(js, internaljogspeed, -(new_halui_data.ajog_increment[EMCMOT_MAX_AXIS]),JOGTELEOP); old_halui_data.ajog_increment_minus[EMCMOT_MAX_AXIS] = bit; } @@ -2310,6 +2470,46 @@ int main(int argc, char *argv[]) //initialize safe values hal_init_pins(); + + /* import the python module and get references for needed function */ + + PyConfig config; + PyConfig_InitPythonConfig(&config); + char name[] = "halui"; + wchar_t *wname = Py_DecodeLocale(name, NULL); + PyConfig_SetString(&config, &config.program_name, wname); + Py_Initialize(); + + PyRun_SimpleString("print('PYTHON EMBEDDED!!')\n" + ); + pModule = PyImport_ImportModule("bridgeui.bridge"); + if (pModule != NULL) { + pClass = PyObject_GetAttrString(pModule, "Bridge"); + pInstance = PyObject_CallObject(pClass, NULL); + pFuncWrite = PyObject_GetAttrString(pInstance, "update"); + + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallFunction(pFuncWrite, "Olllh", pClass, 0, 0, 0, 0); + if (pValue == NULL){ + fprintf(stderr, "Panelui: update function failed: returned NULL\n"); + } + if (PyErr_Occurred()) PyErr_Print(); + }else{ + if (PyErr_Occurred()){ + PyErr_Print(); + } + fprintf(stderr, "Bridge: Failed python function"); + exit(1); + Py_DECREF(pValue); + } + Py_DECREF(pFuncWrite); + }else{ + PyErr_Print(); + fprintf(stderr, "bridge: Failed to load \"%s\"\n", "pyui"); + exit(1); + } + + // init NML if (0 != tryNml()) { rcs_print_error("can't connect to emc\n"); @@ -2345,6 +2545,8 @@ int main(int argc, char *argv[]) } } check_hal_changes(); //if anything changed send NML messages + + modify_hal_pins(); //if status changed modify HAL too esleep(0.02); //sleep for a while updateStatus(); From 5210645d3fd1d69ac91c4e3f5160504381495ef5 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 16 Aug 2025 10:13:59 -0700 Subject: [PATCH 03/79] halui -inject socket axis selection --- src/emc/usr_intf/halui.cc | 53 ++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 544a435236a..a6a50f27d69 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -1272,6 +1272,9 @@ static void sendJogStop(int ja, int jjogmode) static void sendJogCont(int ja, double speed, int jjogmode) { + // no selected axis/joint + if (ja < 0) { return; } + EMC_JOG_CONT emc_jog_cont_msg; if (emcStatus->task.state != EMC_TASK_STATE::ON) { return; } @@ -1556,7 +1559,7 @@ static void hal_init_pins() *(halui_data->ajog_speed) = 0; *(halui_data->joint_selected) = 0; // select joint 0 by default - *(halui_data->axis_selected) = 0; // select axis 0 by default + *(halui_data->axis_selected) = -1; // select no axis by default *(halui_data->fo_scale) = old_halui_data.fo_scale = 0.1; //sane default *(halui_data->ro_scale) = old_halui_data.ro_scale = 0.1; //sane default @@ -1721,11 +1724,7 @@ static void check_hal_changes() int ajog_speed_changed; int is_any_axis_selected, deselected; - local_halui_str new_halui_data_mutable; - copy_hal_data(*halui_data, new_halui_data_mutable); - const local_halui_str &new_halui_data = new_halui_data_mutable; - - // read socket messages + // get python to process socket messages pFuncRead = PyObject_GetAttrString(pInstance, "readMsg"); if (pFuncRead && PyCallable_Check(pFuncRead)) { pValue = PyObject_CallFunction(pFuncRead, "O", pClass); @@ -1741,6 +1740,29 @@ static void check_hal_changes() exit(1); } + // check socket messages for current axis selection + int value = write_msg_get_axis_selected(); + + local_halui_str new_halui_data_mutable; + + if (value != lastaxis) { + // inject socket axis selection over hal data + for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) { + if ( !(axis_mask & (1 << axis_num)) ) { continue; } + + if (axis_num == value) { + *(halui_data->axis_nr_select[axis_num]) = 1; + }else{ + *(halui_data->axis_nr_select[axis_num]) = 0; + } + } + lastaxis = value; + } + + copy_hal_data(*halui_data, new_halui_data_mutable); + const local_halui_str &new_halui_data = new_halui_data_mutable; + + //check if machine_on pin has changed (the rest work exactly the same) if (check_bit_changed(new_halui_data.machine_on, old_halui_data.machine_on) != 0) sendMachineOn(); //send MachineOn NML command @@ -2109,25 +2131,20 @@ static void check_hal_changes() bit = new_halui_data.axis_nr_select[axis_num]; if (bit != old_halui_data.axis_nr_select[axis_num]) { if (bit != 0) { - is_any_axis_selected = 1; - *halui_data->axis_selected = axis_num; - write_msg_axis_changed(axis_num); - aselect_changed = axis_num; // flag that we changed the selected axis + is_any_axis_selected = 1; + *halui_data->axis_selected = axis_num; + write_msg_axis_changed(axis_num); + aselect_changed = axis_num; // flag that we changed the selected axis }else{ deselected = 1; - } - old_halui_data.axis_nr_select[axis_num] = bit; } + old_halui_data.axis_nr_select[axis_num] = bit; + } } // last axis has been deselected - no axis is selected now if (is_any_axis_selected == 0 and deselected == 1) { write_msg_axis_changed(-1); - } - - // check socket messages for axis selection change - int value = write_msg_get_axis_selected(); - if (value != lastaxis){ - aselect_changed = lastaxis = value; + *halui_data->axis_selected = -1; } if (aselect_changed >= 0) { From 56a24c0760b0118fbe6b544da60c9c9a38351dcb Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 16 Aug 2025 11:12:19 -0700 Subject: [PATCH 04/79] gladevcp -speedcontrol: put Gstat status in the loop Gstat sends out socket messages for jog rate --- lib/python/gladevcp/speedcontrol.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/python/gladevcp/speedcontrol.py b/lib/python/gladevcp/speedcontrol.py index 332f025ab0d..5dda24b65a3 100755 --- a/lib/python/gladevcp/speedcontrol.py +++ b/lib/python/gladevcp/speedcontrol.py @@ -35,6 +35,8 @@ else: from .hal_widgets import _HalSpeedControlBase +from gladevcp.core import Status, Action + class SpeedControl(Gtk.Box, _HalSpeedControlBase): ''' The SpeedControl Widget serves as a slider with button to increment od decrease @@ -98,6 +100,8 @@ class SpeedControl(Gtk.Box, _HalSpeedControlBase): "%.1f", GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT), 'do_hide_button' : ( GObject.TYPE_BOOLEAN, 'Hide the button', 'Display the button + and - to alter the values', False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT), + 'type' : ( GObject.TYPE_INT, 'Type of adjustment', 'Set to -1 for general, 0 for jograte', + -1, 0, -1, GObject.ParamFlags.READWRITE|GObject.ParamFlags.CONSTRUCT), } __gproperties = __gproperties__ @@ -112,6 +116,9 @@ class SpeedControl(Gtk.Box, _HalSpeedControlBase): def __init__(self, size = 36, value = 0, min = 0, max = 100, inc_speed = 100, unit = "", color = "#FF8116", template = "%.1f"): super(SpeedControl, self).__init__() + self._action = Action() + self._status = Status() + # basic settings self._size = size self._value = value @@ -123,6 +130,7 @@ def __init__(self, size = 36, value = 0, min = 0, max = 100, inc_speed = 100, un self._increment = (self._max - self._min) / 100.0 self._template = template self._speed = inc_speed + self.type_linear_jog = False self.adjustment = Gtk.Adjustment(value = self._value, lower = self._min, upper = self._max, step_increment = self._increment, page_increment = 0) self.adjustment.connect("value_changed", self._on_value_changed) @@ -175,6 +183,10 @@ def _hal_init(self): self.hal_pin_decrease = self.hal.newpin(self.hal_name+".decrease", hal.HAL_BIT, hal.HAL_IN) self.hal_pin_decrease.connect("value-changed", self._on_minus_changed) + if self.type_linear_jog: + print('->>',self.type_linear_jog) + self._status.connect('jograte-changed', lambda w, data: self.set_value(data)) + # this draws our widget on the screen def expose(self, widget, event): # create the cairo window @@ -269,6 +281,9 @@ def get_value(self): # we are not sync, so def _on_value_changed(self, widget): value = widget.get_value() + if self.type_linear_jog: + self._action.SET_JOG_RATE(value) + if value != self._value: self._value = value self.set_value(self._value) @@ -453,6 +468,10 @@ def do_set_property(self, property, value): self._template = value if name == "do_hide_button": self.hide_button(value) + if name == "type": + print(name,value) + if value == 0: + self.type_linear_jog = True self._draw_widget() else: raise AttributeError('unknown property %s' % property.name) From 38e70d634de6ed7cabfa4d17b82101336e04011c Mon Sep 17 00:00:00 2001 From: CMorley Date: Tue, 19 Aug 2025 20:18:49 -0700 Subject: [PATCH 05/79] bridge -remove HAL pin code, get MDI commands working --- lib/python/bridgeui/bridge.py | 98 ++++++++++++++--------------------- 1 file changed, 38 insertions(+), 60 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index 54ea67d225e..32cc74b8440 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -8,7 +8,6 @@ import signal import hal -from qtvcp.qt_halobjects import Qhal from common.iniinfo import _IStat as IStatParent from common import logger @@ -59,7 +58,7 @@ def __init__(self, readAddress = "tcp://127.0.0.1:5690", signal.signal(signal.SIGTERM, self.shutdown) signal.signal(signal.SIGINT, self.shutdown) - self.init_hal() + self.init() if ZMQ: self.init_read() self.init_write() @@ -72,48 +71,14 @@ def update(self, *arg): self.writeMsg('set_selected_axis','Y') self.activeJoint.set(10) - def init_hal(self): - self.comp = h = hal.component("bridge") - QHAL = Qhal(comp=self.comp, hal=hal) + def init(self): + self.jogRate = 0 + self.jogRateAngular = 0 - self.jogRate = QHAL.newpin("jog-rate", hal.HAL_FLOAT, hal.HAL_OUT) - self.jogRateIn = QHAL.newpin("jog-rate-in", hal.HAL_FLOAT, hal.HAL_IN) - self.jogRateIn.pinValueChanged.connect(self.pinChanged) + self.jogIncrement = 0 + self.jogIncrementAngular = 0 - self.jogRateAngular = QHAL.newpin("jog-rate-angular", hal.HAL_FLOAT, hal.HAL_OUT) - self.jogRateAngularIn = QHAL.newpin("jog-rate-angular-in", hal.HAL_FLOAT, hal.HAL_OUT) - self.jogRateAngularIn.pinValueChanged.connect(self.pinChanged) - - self.jogIncrement = QHAL.newpin("jog-increment", hal.HAL_FLOAT, hal.HAL_OUT) - self.jogIncrementAngular = QHAL.newpin("jog-increment-angular", hal.HAL_FLOAT, hal.HAL_OUT) - self.activeJoint = QHAL.newpin('joint-selected', hal.HAL_S32, hal.HAL_OUT) - - for i in (self.INFO.AVAILABLE_AXES): - let = i.lower() - # input - self['axis{}Select'.format(let)] = QHAL.newpin('axis-%s-select'%let, hal.HAL_BIT, hal.HAL_IN) - self['axis{}Select'.format(let)].pinValueChanged.connect(self.pinChanged) - # output - self['Axis{}IsSelected'.format(let)] = QHAL.newpin('axis-%s-is-selected'%let, hal.HAL_BIT, hal.HAL_OUT) - - self.cycle_start = QHAL.newpin('cycle-start-in',QHAL.HAL_BIT, QHAL.HAL_IN) - self.cycle_start.pinValueChanged.connect(self.pinChanged) - self.cycle_pause = QHAL.newpin('cycle-pause-in',QHAL.HAL_BIT, QHAL.HAL_IN) - self.cycle_pause.pinValueChanged.connect(self.pinChanged) - - for i in self.INFO.MDI_COMMAND_DICT: - LOG.debug('{} {}'.format(i,self.INFO.MDI_COMMAND_DICT.get(i))) - self[i] = QHAL.newpin('ini-mdi-cmd-{}'.format(i),QHAL.HAL_BIT, QHAL.HAL_IN) - self[i].pinValueChanged.connect(self.runMacroChanged) - - for i in self.INFO.INI_MACROS: - name = i.split()[0] - LOG.debug('{} {}'.format(name,i)) - self[name] = QHAL.newpin('ini-macro-cmd-{}'.format(name),QHAL.HAL_BIT, QHAL.HAL_IN) - self[name].pinValueChanged.connect(self.runMacroChanged) - - QHAL.setUpdateRate(100) - h.ready() + self.activeJoint = 0 def init_write(self): context = zmq.Context() @@ -141,19 +106,19 @@ def readMsg(self, msg): y = json.loads(data) self. action(y.get('MESSAGE'),y.get('ARGS')) - # set our output HAL pins from messages from hal_glib + # set our variables from messages from hal_glib def action(self, msg, data): LOG.debug('{} {}'.format(msg, data)) if msg == 'jograte-changed': - self.jogRate.set(float(data[0])) + self.jogRate = float(data[0]) elif msg == 'jograte-angular-changed': - self.jogRateAngular.set(float(data[0])) + self.jogRateAngular = float(data[0]) elif msg == 'jogincrements-changed': - self.jogIncrement.set(float(data[0][0])) + self.jogIncrement = float(data[0][0]) elif msg == 'jogincrement-angular-changed': - self.jogIncremtAngular.set(float(data[0][0])) + self.jogIncremtAngular = float(data[0][0]) elif msg == 'joint-selection-changed': - self.activeJoint.set(int(data[0])) + self.activeJoint = int(data[0]) elif msg == 'axis-selection-changed': flag = 1 for i in(self.INFO.AVAILABLE_AXES): @@ -163,7 +128,6 @@ def action(self, msg, data): flag = 0 else: state = False - self['Axis{}IsSelected'.format(i.lower())].set(state) self.axesSelected[i] = int(state) if flag: self.currentSelectedAxis = 'None' @@ -183,8 +147,7 @@ def writeMsg(self, msg, data): # callback from HAL input pins def pinChanged(self, pinObject, value): LOG.debug('Pin name:{} changed value to {}'.format(pinObject.text(), value)) - #print(type(value)) - # Axis selction change request + # Axis selection change request if 'select' in pinObject.text(): if bool(value) == False: pass @@ -220,26 +183,41 @@ def pinChanged(self, pinObject, value): else: self.writeMsg(pinObject.text(),value) - # callback; request to run a specific macro - def runMacroChanged(self, pinObject, value): - LOG.debug('Macro Pin name:{} changed value to {}'.format(pinObject.text(), value)) - #LOG.debug(type(value)) - name = pinObject.text().strip('macro-cmd-') - if value: - self.writeMsg('request_macro_call', name) def shutdown(self,signum=None,stack_frame=None): LOG.debug('shutdown') global app app.quit() + def getMdiName(self, num): + if num >len(self.INFO.MDI_COMMAND_DICT)-1: + return 'None' + temp = list(self.INFO.MDI_COMMAND_DICT.keys())[num] + LOG.debug('{} {}'.format(num,temp)) + return temp + + def getMacroNames(self): + for i in self.INFO.INI_MACROS: + name = i.split()[0] + LOG.debug('{} {}'.format(name,i)) + + def runIndexedMacro(self, num): + name = self.getMdiName(num) + LOG.debug('Macro name:{} ,index: {}'.format(name, num)) + if name != 'None': + self.writeMsg('request_macro_call', name) + + def getMdiCount(self): + print(len(self.INFO.MDI_COMMAND_DICT)) + return len(self.INFO.MDI_COMMAND_DICT) + def getJogRate(self): - return self.jogRate.get() + return self.jogRate def setJogRate(self, value): self.writeMsg('set_jograte', value) def getJogRateAngular(self): - return self.jogRateAngular.get() + return self.jogRateAngular def setJogRateAngular(self, value): self.writeMsg('set_jograte_angular', value) From 87592b4a309524a2a68a880fc842c464a4707c4a Mon Sep 17 00:00:00 2001 From: CMorley Date: Tue, 19 Aug 2025 20:19:38 -0700 Subject: [PATCH 06/79] halui -code clenup, GUI based MDI command feature --- src/emc/usr_intf/halui.cc | 176 ++++++++++++++++++++++++++++---------- 1 file changed, 132 insertions(+), 44 deletions(-) diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index a6a50f27d69..7e809130e41 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -207,6 +207,7 @@ static int axis_mask = 0; FIELD(hal_bit_t,home_all) /* pin for homing all joints in sequence */ \ FIELD(hal_bit_t,abort) /* pin for aborting */ \ ARRAY(hal_bit_t,mdi_commands,MDI_MAX) \ + ARRAY(hal_bit_t,gui_mdi_commands,MDI_MAX) \ \ FIELD(hal_float_t,units_per_mm) \ @@ -250,6 +251,9 @@ static int lastaxis = -1; static char *mdi_commands[MDI_MAX]; static int num_mdi_commands=0; + +static char *gui_mdi_commands[MDI_MAX]; +static int num_gui_mdi_commands = 0; static int have_home_all = 0; static int comp_id, done; /* component ID, main while loop */ @@ -542,6 +546,65 @@ int halui_export_pin_OUT_bit(hal_bit_t **pin, const char *name) return 0; } +static int py_call_get_mdi_count() { + int value = 0; + // check socket messages for jogspeed + pFuncRead = PyObject_GetAttrString(pInstance, "getMdiCount"); + if (pFuncRead && PyCallable_Check(pFuncRead)) { + pValue = PyObject_CallNoArgs(pFuncRead); + if (pValue == NULL){ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "Halui Bridge: getMdiCountfunction failed: returned NULL\n"); + value = -1; + }else{ + if (PyLong_Check(pValue)) { + value = (int) PyLong_AsLong(pValue); + //fprintf(stderr, "axis value %d\n",value); + if (PyErr_Occurred()) { + value = -1; + // Handle conversion error + PyErr_Print(); + // Clear the error state if needed + PyErr_Clear(); + } + } + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncRead); + return value; +} + +// turns a undex number into a macro name +static char* py_call_get_mdi_name( int num) { + pFuncWrite = PyObject_GetAttrString(pInstance, "getMdiName"); + + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallFunction(pFuncWrite, "i", num); + + if (pValue != NULL) { + if (PyUnicode_Check(pValue)) { + PyObject *pBytes = PyUnicode_AsUTF8String(pValue); + char *result_string = PyBytes_AsString(pBytes); + Py_XDECREF(pBytes); + printf("Python function returned: %s %i\n", result_string,num); + Py_DECREF(pValue); + Py_DECREF(pFuncWrite); + return result_string; + } else { + fprintf(stderr, "Return value is not a string. %i\n", num); + } + } else { + PyErr_Print(); // Print Python error if call failed + } + Py_DECREF(pValue); + }else{ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "halui Bridge: Failed python function"); + } + Py_DECREF(pFuncWrite); + return NULL; +} /******************************************************************** * @@ -932,6 +995,12 @@ int halui_hal_init(void) if (retval < 0) return retval; } + for (int n=0; ngui_mdi_commands[n]), comp_id, "halui.mdi-command-%s", py_call_get_mdi_name(n)); + if (retval < 0) return retval; + } + hal_ready(comp_id); return 0; } @@ -1503,6 +1572,12 @@ static int iniLoad(const char *filename) mdi_commands[num_mdi_commands++] = strdup(mc->c_str()); } + int temp = py_call_get_mdi_count(); + for (int n=0; n 0.00001) { ajog_speed_changed = 1; lastjogspeed = jogspeed; @@ -2133,7 +2229,7 @@ static void check_hal_changes() if (bit != 0) { is_any_axis_selected = 1; *halui_data->axis_selected = axis_num; - write_msg_axis_changed(axis_num); + py_call_axis_changed(axis_num); aselect_changed = axis_num; // flag that we changed the selected axis }else{ deselected = 1; @@ -2143,7 +2239,7 @@ static void check_hal_changes() } // last axis has been deselected - no axis is selected now if (is_any_axis_selected == 0 and deselected == 1) { - write_msg_axis_changed(-1); + py_call_axis_changed(-1); *halui_data->axis_selected = -1; } @@ -2246,10 +2342,19 @@ static void check_hal_changes() old_halui_data.ajog_increment_minus[EMCMOT_MAX_AXIS] = bit; } + // run HALUI commands for(int n = 0; n < num_mdi_commands; n++) { if (check_bit_changed(new_halui_data.mdi_commands[n], old_halui_data.mdi_commands[n]) != 0) sendMdiCommand(n); } + + // request GUI ti run MDI commands + for(int n = 0; n < num_gui_mdi_commands; n++) { + if (check_bit_changed(new_halui_data.gui_mdi_commands[n], old_halui_data.gui_mdi_commands[n]) != 0){ + printf("GUI MDI command called index: %i\n", n); + py_call_request_MDI(n); + } + } } // this function looks at the received NML status message @@ -2472,22 +2577,6 @@ int main(int argc, char *argv[]) exit(1); } - // get configuration information - if (0 != iniLoad(emc_inifile)) { - rcs_print_error("iniLoad error\n"); - exit(2); - } - - //init HAL and export pins - if (0 != halui_hal_init()) { - rcs_print_error("hal_init error\n"); - exit(1); - } - - //initialize safe values - hal_init_pins(); - - /* import the python module and get references for needed function */ PyConfig config; @@ -2497,35 +2586,34 @@ int main(int argc, char *argv[]) PyConfig_SetString(&config, &config.program_name, wname); Py_Initialize(); - PyRun_SimpleString("print('PYTHON EMBEDDED!!')\n" - ); + PyRun_SimpleString("print('PYTHON EMBEDDED!!')\n"); pModule = PyImport_ImportModule("bridgeui.bridge"); if (pModule != NULL) { pClass = PyObject_GetAttrString(pModule, "Bridge"); pInstance = PyObject_CallObject(pClass, NULL); - pFuncWrite = PyObject_GetAttrString(pInstance, "update"); - - if (pFuncWrite && PyCallable_Check(pFuncWrite)) { - pValue = PyObject_CallFunction(pFuncWrite, "Olllh", pClass, 0, 0, 0, 0); - if (pValue == NULL){ - fprintf(stderr, "Panelui: update function failed: returned NULL\n"); - } - if (PyErr_Occurred()) PyErr_Print(); - }else{ - if (PyErr_Occurred()){ - PyErr_Print(); - } - fprintf(stderr, "Bridge: Failed python function"); - exit(1); - Py_DECREF(pValue); - } - Py_DECREF(pFuncWrite); }else{ PyErr_Print(); fprintf(stderr, "bridge: Failed to load \"%s\"\n", "pyui"); exit(1); } + // get configuration information + if (0 != iniLoad(emc_inifile)) { + rcs_print_error("iniLoad error\n"); + exit(2); + } + + //init HAL and export pins + if (0 != halui_hal_init()) { + rcs_print_error("hal_init error\n"); + exit(1); + } + + //initialize safe values + hal_init_pins(); + + + // init NML if (0 != tryNml()) { From 09f788a6d5f27272d57c65bd7fdd3d8f1a84cd8a Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 22 Aug 2025 15:32:30 -0700 Subject: [PATCH 07/79] halui -add cycle start cycle pause pins calls these functions in a GUI --- lib/python/bridgeui/bridge.py | 47 ++++++----------------------------- src/emc/usr_intf/halui.cc | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index 32cc74b8440..862ae0244d9 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -144,51 +144,18 @@ def writeMsg(self, msg, data): [bytes(topic.encode('utf-8')), bytes((message).encode('utf-8'))]) - # callback from HAL input pins - def pinChanged(self, pinObject, value): - LOG.debug('Pin name:{} changed value to {}'.format(pinObject.text(), value)) - # Axis selection change request - if 'select' in pinObject.text(): - if bool(value) == False: - pass - #print('Not true state') - return - for i in (self.INFO.AVAILABLE_AXES): - if '-{}-'.format(i.lower()) in pinObject.text(): - self.writeMsg('set_selected_axis', i) - break - else: - if 'None' in pinObject.text(): - self.writeMsg('set_selected_axis', '') - - # cycle start - elif self.cycle_start == pinObject: - if value: - self.writeMsg('request_cycle_start', value) - - # cycle pause - elif self.cycle_pause == pinObject: - #if value: - self.writeMsg('request_cycle_pause', value) - - # linear jog rate - elif self.jogRateIn == pinObject: - self.writeMsg('set_jograte', value) - - # angular jog rate - elif self.jogRateAngularIn == pinObject: - self.writeMsg('set_jograte_angular', value) - - # catch all default - else: - self.writeMsg(pinObject.text(),value) - - def shutdown(self,signum=None,stack_frame=None): LOG.debug('shutdown') global app app.quit() + def cycleStart(self): + # cycle start + self.writeMsg('request_cycle_start', True) + + def cyclePause(self): + self.writeMsg('request_cycle_pause', True) + def getMdiName(self, num): if num >len(self.INFO.MDI_COMMAND_DICT)-1: return 'None' diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 7e809130e41..914e3644f67 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -90,6 +90,8 @@ static int axis_mask = 0; FIELD(hal_bit_t,program_is_running) /* pin for notifying user that program is running */ \ FIELD(hal_bit_t,halui_mdi_is_running) /* pin for notifying user that halui MDI commands is running */ \ FIELD(hal_bit_t,program_is_paused) /* pin for notifying user that program is paused */ \ + FIELD(hal_bit_t,cycle_start) /* pin for running program */ \ + FIELD(hal_bit_t,cycle_pause) /* pin for running program */ \ FIELD(hal_bit_t,program_run) /* pin for running program */ \ FIELD(hal_bit_t,program_pause) /* pin for pausing program */ \ FIELD(hal_bit_t,program_resume) /* pin for resuming program */ \ @@ -546,6 +548,36 @@ int halui_export_pin_OUT_bit(hal_bit_t **pin, const char *name) return 0; } +static void py_call_cycleStart() { + + // check socket messages for jogspeed + pFuncWrite = PyObject_GetAttrString(pInstance, "cycleStart"); + if (pFuncRead && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallNoArgs(pFuncWrite); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: cycleStart function failed: returned NULL\n"); + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncWrite); + return ; +} + +static void py_call_cyclePause() { + + // check socket messages for jogspeed + pFuncWrite = PyObject_GetAttrString(pInstance, "cyclePause"); + if (pFuncRead && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallNoArgs(pFuncWrite); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: cyclePause function failed: returned NULL\n"); + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncWrite); + return ; +} + static int py_call_get_mdi_count() { int value = 0; // check socket messages for jogspeed @@ -837,6 +869,10 @@ int halui_hal_init(void) if (retval < 0) return retval; retval = halui_export_pin_IN_bit(&(halui_data->flood_off), "halui.flood.off"); if (retval < 0) return retval; + retval = halui_export_pin_IN_bit(&(halui_data->cycle_start), "halui.cycle.start"); + if (retval < 0) return retval; + retval = halui_export_pin_IN_bit(&(halui_data->cycle_pause), "halui.cycle.pause"); + if (retval < 0) return retval; retval = halui_export_pin_IN_bit(&(halui_data->program_run), "halui.program.run"); if (retval < 0) return retval; retval = halui_export_pin_IN_bit(&(halui_data->program_pause), "halui.program.pause"); @@ -1899,6 +1935,16 @@ static void check_hal_changes() if (check_bit_changed(new_halui_data.flood_off, old_halui_data.flood_off) != 0) sendFloodOff(); + if (check_bit_changed(new_halui_data.cycle_start, old_halui_data.cycle_start) != 0){ + fprintf(stderr, "cycle-start value = %i\n", new_halui_data.cycle_start ); + py_call_cycleStart(); + } + + if (check_bit_changed(new_halui_data.cycle_pause, old_halui_data.cycle_pause) != 0){ + fprintf(stderr, "cycle-pause value = %i\n", new_halui_data.cycle_pause ); + py_call_cyclePause(); + } + if (check_bit_changed(new_halui_data.program_run, old_halui_data.program_run) != 0) sendProgramRun(0); From 36dd08df8b5b8e20e001317ad59e5c0a54907290 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 22 Aug 2025 15:33:19 -0700 Subject: [PATCH 08/79] qtdragon -adjust external pause message to toggle --- share/qtvcp/screens/qtdragon/qtdragon_handler.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index 8280b2b8291..787728bdb2d 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -153,7 +153,7 @@ def __init__(self, halcomp, widgets, paths): STATUS.connect('status-message', lambda w, d, o: self.add_external_status(d,o)) STATUS.connect('runstop-line-changed', lambda w, l :self.lastRunLine(l)) STATUS.connect('cycle-start-request', lambda w, state :self.btn_start_clicked(state)) - STATUS.connect('cycle-pause-request', lambda w, state: self.btn_pause_clicked(state)) + STATUS.connect('cycle-pause-request', lambda w, state: self.ext_pause_toggled(state)) STATUS.connect('macro-call-request', lambda w, name: self.request_macro_call(name)) STATUS.connect('ok-request', lambda w, state: self.dialog_ext_control(w,1,1)) STATUS.connect('cancel-request', lambda w, state: self.dialog_ext_control(w,1,0)) @@ -1314,6 +1314,12 @@ def btn_spindle_z_down_clicked(self): if self.h['eoffset-clear'] != True: self.h['eoffset-spindle-count'] = int(fval) + def ext_pause_toggled(self, state): + if STATUS.is_auto_paused(): + self.btn_pause_clicked(False) + return + self.btn_pause_clicked(True) + def btn_pause_clicked(self, data): # pause request From fb5d94d596da1f9b043c4ed410448e64beb3fc1c Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 27 Jul 2025 14:05:58 -0700 Subject: [PATCH 09/79] gmoccapy/hal_bridge -allow hal_bridge to call macros in gmoccapy This is a proof of concept to allow 3rd party (hal_bridge) to call macros. The macros are run from Gmoccapy so no timing problems should occur and and pre checks or post changes can be covered. There needs to be agreement on where to put macro definitions in the INI. Gmoccapy puts them under [MACROS], iniinfo under [DISPLAY] python ZMQ module package must be available for this to work --- configs/sim/gmoccapy/gmoccapy_right_panel.ini | 8 +++- src/emc/usr_intf/gmoccapy/getiniinfo.py | 2 +- src/emc/usr_intf/gmoccapy/gmoccapy.py | 42 ++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/configs/sim/gmoccapy/gmoccapy_right_panel.ini b/configs/sim/gmoccapy/gmoccapy_right_panel.ini index 62213d687d5..7b4c5981da8 100644 --- a/configs/sim/gmoccapy/gmoccapy_right_panel.ini +++ b/configs/sim/gmoccapy/gmoccapy_right_panel.ini @@ -31,6 +31,12 @@ INTRO_TIME = 5 # list of selectable jog increments INCREMENTS = 1mm, 0.1mm, 0.01mm, 0.001mm, 1.2345in +MACRO = i_am_lost +MACRO = halo_world +MACRO = jog_around +MACRO = increment xinc yinc +MACRO = go_to_position X-pos Y-pos Z-pos + [FILTER] PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image PROGRAM_EXTENSION = .py Python Script @@ -75,7 +81,7 @@ HALFILE = simulated_home.hal POSTGUI_HALFILE = gmoccapy_postgui.hal HALUI = halui - +HALBRIDGE = hal_bridge -d # Trajectory planner section -------------------------------------------------- [HALUI] #No Content diff --git a/src/emc/usr_intf/gmoccapy/getiniinfo.py b/src/emc/usr_intf/gmoccapy/getiniinfo.py index 20be167976e..8d45c6ccec8 100644 --- a/src/emc/usr_intf/gmoccapy/getiniinfo.py +++ b/src/emc/usr_intf/gmoccapy/getiniinfo.py @@ -377,7 +377,7 @@ def get_tool_sensor_data(self): def get_macros(self): # lets look in the INI file, if there are any entries - macros = self.inifile.findall("MACROS", "MACRO") + macros = self.inifile.findall("DISPLAY", "MACRO") # If there are no entries we will return False if not macros: return False diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index c7afde2fcbf..ebeb1bd3255 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -431,6 +431,7 @@ def __init__(self, argv): self.GSTAT = Status() self.GSTAT.connect("graphics-gcode-properties", self.on_gcode_properties) self.GSTAT.connect("file-loaded", self.on_hal_status_file_loaded) + self.GSTAT.connect('macro-call-request', lambda w, name: self.request_macro_call(name)) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) @@ -1314,6 +1315,33 @@ def _make_joints_button(self): self.joints_button_dic[name] = btn + # call INI macro (from hal_glib message) + def request_macro_call(self, data): + + # some error checking + if not self.GSTAT.is_mdi_mode(): + message = _("You must be in MDI mode to run macros") + self.dialogs.warning_dialog(self, _("Important Warning!"), message) + return + + # look thru the INI macros + macros = self.get_ini_info.get_macros() + num_macros = len(macros) + if num_macros > 14: + num_macros = 14 + for pos in range(0, num_macros): + # extract just the macro name + name = macros[pos].split()[0] + if data == name: + # get the button instance and click it + button = self["button_macro_{0}".format(pos)] + button.emit("clicked") + break + else: + # didn't match a name - give a hint + message = _("Macro {} not found ".format(data)) + self.dialogs.warning_dialog(self, _("Important Warning!"), message) + # check if macros are in the INI file and add them to MDI Button List def _make_macro_button(self): LOG.debug("Entering make macro button") @@ -1355,7 +1383,9 @@ def _make_macro_button(self): btn.set_halign(Gtk.Align.CENTER) btn.set_valign(Gtk.Align.CENTER) btn.set_property("name","macro_{0}".format(pos)) - btn.set_property("tooltip-text", _("Press to run macro {0}").format(name)) + # keep a reference of the button + self["button_macro_{0}".format(pos)] = btn + btn.set_property("tooltip-text", _("Press to run macro {0}".format(name))) btn.connect("clicked", self._on_btn_macro_pressed, name) btn.position = pos btn.show() @@ -6513,6 +6543,16 @@ def _make_hal_pins(self): hal_glib.GPin(pin).connect("value_changed", self._blockdelete) + ############################## + # required class boiler code # + # for subscriptable objects # + ############################## + def __getitem__(self, item): + return getattr(self, item) + + def __setitem__(self, item, value): + return setattr(self, item, value) + # Hal Pin Handling End # ========================================================= From 06a7c0397fa8a7139320154696fde2dcd3368f59 Mon Sep 17 00:00:00 2001 From: CMorley Date: Wed, 30 Jul 2025 20:50:47 -0700 Subject: [PATCH 10/79] gmoccapy -ability to run INI MDI commands using HAL bridge --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index ebeb1bd3255..22e6e6a7dd5 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -198,7 +198,8 @@ def __init__(self, argv): self.error_channel.poll() # set INI path for INI info class before widgets are loaded - INFO = Info(ini=argv[2]) + self.INFO = Info(ini=argv[2]) + self.ACTION = Action() self.builder = Gtk.Builder() # translation of the glade file will be done with @@ -1317,7 +1318,17 @@ def _make_joints_button(self): # call INI macro (from hal_glib message) def request_macro_call(self, data): + # if MDI command change to MDI and run + cmd = self.INFO.get_ini_mdi_command(data) + print('MDI command:',data,cmd) + if not cmd is None: + self.ACTION.RECORD_CURRENT_MODE() + LOG.debug("INI MDI COMMAND #: {} = {}".format(data, cmd)) + self.ACTION.CALL_INI_MDI(data) + self.ACTION.RESTORE_RECORDED_MODE() + return + # run Macros # some error checking if not self.GSTAT.is_mdi_mode(): message = _("You must be in MDI mode to run macros") @@ -6592,6 +6603,7 @@ def __setitem__(self, item, value): # Some of these libraries log when imported so logging level must already be set. import gladevcp.makepins from gladevcp.core import Info, Status + from gladevcp.core import Info, Status, Action from gladevcp.combi_dro import Combi_DRO # we will need it to make the DRO from gmoccapy import widgets # a class to handle the widgets From aeb737bb8e065a816b65812238eab512cea02d06 Mon Sep 17 00:00:00 2001 From: CMorley Date: Wed, 30 Jul 2025 20:51:51 -0700 Subject: [PATCH 11/79] gmoccapy -sample config: add INI MDI commands to test with --- configs/sim/gmoccapy/gmoccapy_right_panel.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configs/sim/gmoccapy/gmoccapy_right_panel.ini b/configs/sim/gmoccapy/gmoccapy_right_panel.ini index 7b4c5981da8..01312384c08 100644 --- a/configs/sim/gmoccapy/gmoccapy_right_panel.ini +++ b/configs/sim/gmoccapy/gmoccapy_right_panel.ini @@ -37,6 +37,11 @@ MACRO = jog_around MACRO = increment xinc yinc MACRO = go_to_position X-pos Y-pos Z-pos +[MDI_COMMAND_LIST] +# for macro buttons on main oage up to 10 possible +MDI_COMMAND = G0 Z1;X0 Y0;Z0, Goto\nUser\nZero +MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero + [FILTER] PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image PROGRAM_EXTENSION = .py Python Script From 9ef481c9526cdebd7f3182117331455a2b824c0c Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 23 Aug 2025 06:37:17 -0700 Subject: [PATCH 12/79] halui -add gui ok/canel pins --- lib/python/bridgeui/bridge.py | 6 ++++ src/emc/usr_intf/halui.cc | 52 +++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index 862ae0244d9..27397528660 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -156,6 +156,12 @@ def cycleStart(self): def cyclePause(self): self.writeMsg('request_cycle_pause', True) + def ok(self): + self.writeMsg('request_ok', True) + + def cancel(self): + self.writeMsg('request_cancel', True) + def getMdiName(self, num): if num >len(self.INFO.MDI_COMMAND_DICT)-1: return 'None' diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 914e3644f67..585ea12b916 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -208,8 +208,12 @@ static int axis_mask = 0; \ FIELD(hal_bit_t,home_all) /* pin for homing all joints in sequence */ \ FIELD(hal_bit_t,abort) /* pin for aborting */ \ +\ ARRAY(hal_bit_t,mdi_commands,MDI_MAX) \ ARRAY(hal_bit_t,gui_mdi_commands,MDI_MAX) \ +\ + FIELD(hal_bit_t,gui_ok) /* pin for acknowledging dialog ok */ \ + FIELD(hal_bit_t,gui_cancel) /* pin for acknowledging dialog cancel */ \ \ FIELD(hal_float_t,units_per_mm) \ @@ -578,6 +582,34 @@ static void py_call_cyclePause() { return ; } +static void py_call_ok() { + + // check socket messages for gui ok message + pFuncWrite = PyObject_GetAttrString(pInstance, "ok"); + if (pFuncRead && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallNoArgs(pFuncWrite); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: ok function failed: returned NULL\n"); + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncWrite); + return ; +} +static void py_call_cancel() { + + // check socket messages for gui cancel message + pFuncWrite = PyObject_GetAttrString(pInstance, "cancel"); + if (pFuncRead && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallNoArgs(pFuncWrite); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: cancel function failed: returned NULL\n"); + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncWrite); + return ; +} static int py_call_get_mdi_count() { int value = 0; // check socket messages for jogspeed @@ -1033,10 +1065,16 @@ int halui_hal_init(void) for (int n=0; ngui_mdi_commands[n]), comp_id, "halui.mdi-command-%s", py_call_get_mdi_name(n)); + retval = hal_pin_bit_newf(HAL_IN, &(halui_data->gui_mdi_commands[n]), comp_id, "halui.gui.mdi-command-%s", py_call_get_mdi_name(n)); if (retval < 0) return retval; } + retval = halui_export_pin_IN_bit(&(halui_data->gui_ok), "halui.gui.ok"); + if (retval < 0) return retval; + + retval = halui_export_pin_IN_bit(&(halui_data->gui_cancel), "halui.gui.cancel"); + if (retval < 0) return retval; + hal_ready(comp_id); return 0; } @@ -2397,10 +2435,20 @@ static void check_hal_changes() // request GUI ti run MDI commands for(int n = 0; n < num_gui_mdi_commands; n++) { if (check_bit_changed(new_halui_data.gui_mdi_commands[n], old_halui_data.gui_mdi_commands[n]) != 0){ - printf("GUI MDI command called index: %i\n", n); + fprintf(stderr,"GUI MDI command called index: %i\n", n); py_call_request_MDI(n); } } + + if (check_bit_changed(new_halui_data.gui_ok, old_halui_data.gui_ok) != 0) { + fprintf(stderr,"GUI OK command called\n"); + py_call_ok(); + } + + if (check_bit_changed(new_halui_data.gui_cancel, old_halui_data.gui_cancel) != 0) { + fprintf(stderr,"GUI CANCEL command called\n"); + py_call_cancel(); + } } // this function looks at the received NML status message From 435e2b766d9e933737b6ed3af591a9938e63107c Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 23 Aug 2025 13:57:34 -0700 Subject: [PATCH 13/79] qtdragon metric -add a control panel --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 17 ++ configs/sim/qtdragon/qtdragon_xyz/panel.ui | 237 ++++++++++++++++++ .../qtdragon/qtdragon_xyz/qtdragon_metric.ini | 3 +- 3 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 configs/sim/qtdragon/qtdragon_xyz/panel.hal create mode 100644 configs/sim/qtdragon/qtdragon_xyz/panel.ui diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal new file mode 100644 index 00000000000..e9407a91feb --- /dev/null +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -0,0 +1,17 @@ +net rate halui.axis.jog-speed panel.Jog-rate-f + +net sx halui.axis.x.select panel.axis-x +net sy halui.axis.y.select panel.axis-y +net sz halui.axis.z.select panel.axis-z + +net jog-p halui.axis.selected.plus +net jog-m halui.axis.selected.minus +net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 +net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 + +net pause halui.cycle.start panel.cycle-start +net start halui.cycle.pause panel.cycle-pause + +net cancel halui.gui.cancel panel.cancel +net ok halui.gui.ok panel.ok + diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui new file mode 100644 index 00000000000..d9200fc614e --- /dev/null +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -0,0 +1,237 @@ + + + MainWindow + + + + 0 + 0 + 313 + 467 + + + + MainWindow + + + + + + + + + Axis Selection + + + + + + X + + + axis-x + + + + + + + Y + + + axis-y + + + + + + + Z + + + axis-z + + + + + + + + + + Axis Jog + + + + + + + + + + jog-pos + + + + + + + - + + + jog-neg + + + + + + + + + + jog rate + + + + + + 300 + + + Qt::Horizontal + + + Jog-rate + + + + + + + + + + MDI Comands + + + + + + 0 + + + mdi-0 + + + + + + + 1 + + + mdi-1 + + + + + + + 2 + + + mdi-2 + + + + + + + + + + program control + + + + + + start + + + cycle-start + + + + + + + pause + + + cycle-pause + + + + + + + + + + dialog control + + + + + + ok + + + ok + + + + + + + cancel + + + cancel + + + + + + + + + + + + + + 0 + 0 + 313 + 22 + + + + + + + + PushButton + QPushButton +
qtvcp.widgets.simple_widgets
+
+ + Slider + QSlider +
qtvcp.widgets.simple_widgets
+
+
+ + +
diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini index f437be0811a..c62a2dd16a9 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini @@ -166,7 +166,8 @@ POSTGUI_HALFILE = qtdragon_postgui.hal # you can add multiple entries # uncomment this one to print all HAL pins that start with qt #POSTGUI_HALCMD = show pin qt - +POSTGUI_HALCMD = show pin halui.gui +POSTGUI_HALCMD = loadusr qtvcp -H panel.hal panel [HALUI] # no content From 13b1e7daf4fe8a47d0a8466361dcfa26a2312c51 Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 10:04:00 -0700 Subject: [PATCH 14/79] iniinfo -parse ini commands in a better way mdi commands with a comma in it (ie MSG, text) would not be interpeted properly --- lib/python/common/iniinfo.py | 45 ++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/python/common/iniinfo.py b/lib/python/common/iniinfo.py index 57b78707bd7..c81118f6e37 100644 --- a/lib/python/common/iniinfo.py +++ b/lib/python/common/iniinfo.py @@ -18,7 +18,7 @@ def __init__(self, ini=None): global LOG LOG = logger.getLogger(__name__) # Force the log level for this module only - #LOG.setLevel(logger.DEBUG) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL + LOG.setLevel(logger.DEBUG) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL inipath = os.environ.get('INI_FILE_NAME', '/dev/null') self.LINUXCNC_IS_RUNNING = bool(inipath != '/dev/null') @@ -570,7 +570,7 @@ def update(self): if self.INI.hassection('MDI_COMMAND_LIST'): try: for key,value in self.INI.getvariables('MDI_COMMAND_LIST'): - + #print(f'key:{key},value:{value}') # legacy way: list of repeat 'MDI_COMMAND=XXXX' # in this case order matters in the INI if key == 'MDI_COMMAND': @@ -597,24 +597,51 @@ def update(self): # new way: 'MDI_COMMAND_SSS = XXXX' (SSS being any string) # order of commands doesn't matter in the INI + + # here are some samples, the last three are difficult + # the third is invalid + # MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero + # cmd: G53 G0 Z0;G53 G0 X0 Y0 label: Goto\nMachn\nZero + + # MDI_COMMAND_MACRO2 = (MSG, macro 2); + # cmd: (MSG, macro 2); label: + + # MDI_COMMAND_MACRO3 = (MSG, macro 2) + # cmd: (MSG label: macro 2) + + # MDI_COMMAND_MACRO4 = (MSG, macro 2),test + # cmd: (MSG, macro 2) label: test + else: self.MDI_COMMAND_LIST.append(None) self.MDI_COMMAND_LABEL_LIST.append(None) try: name = (key.replace('MDI_COMMAND_','')) mdidatadict = {} - for num,k in enumerate(value.split(',')): - if num == 0: - mdidatadict['cmd'] = k - if len(value.split(',')) <2: - mdidatadict['label'] = None - else: - mdidatadict['label'] = k + #print(f'name:{name}') + # find the last colon in string or 0 + lastCmd = value.rfind(';') + #print('l ;:',lastCmd) + if lastCmd == -1: lastCmd = 0 + + # find the last colon in string or use the string length + lastComma = value.rfind(',', lastCmd) + #print('l comma:',lastComma,lastCmd) + if lastComma == -1: lastComma = len(value) + + label = value[lastComma+1:] + cmd = value[:lastComma] + #print(value,' cmd:',cmd,' label:',label) + + mdidatadict['cmd'] = cmd + mdidatadict['label'] = label self.MDI_COMMAND_DICT[name] = mdidatadict + except Exception as e: LOG.error('INI MDI command parse error:{}'.format(e)) except Exception as e: LOG.error('INI MDI command parse error:{}'.format(e)) + print(self.MDI_COMMAND_DICT) ################ # MACRO commands # From 88d16a3d8ce667e63dd26ad8c7e59ad150d74e19 Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 10:05:52 -0700 Subject: [PATCH 15/79] gladevcp -gth_action: add ability to run new style INI MDI commands named INI MDI commands were not recognised. --- lib/python/gladevcp/gtk_action.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/python/gladevcp/gtk_action.py b/lib/python/gladevcp/gtk_action.py index 247d9df4e93..97a6fc442c5 100644 --- a/lib/python/gladevcp/gtk_action.py +++ b/lib/python/gladevcp/gtk_action.py @@ -191,14 +191,23 @@ def CALL_MDI_WAIT(self, code, time=5, mode_return=False): self.ensure_mode(premode) return 0 - def CALL_INI_MDI(self, number): + def CALL_INI_MDI(self, key): try: - mdi = INFO.MDI_COMMAND_LIST[number] + # prefer named INI MDI commands + mdi = INFO.get_ini_mdi_command(key) + LOG.debug('COMMAND= {}'.format(mdi)) + if mdi is None: raise Exception except: - msg = 'MDI_COMMAND= # {} Not found under [MDI_COMMAND_LIST] in INI file'.format(number) - LOG.error(msg) - self.SET_ERROR_MESSAGE(msg) - return + # fallback to legacy nth line + try: + mdi = INFO.MDI_COMMAND_LIST[key] + except: + msg = 'MDI_COMMAND_{} Not found under [MDI_COMMAND_LIST] in INI file'.format(key) + LOG.error(msg) + self.SET_ERROR_MESSAGE(msg) + return + + mdi_list = mdi.split(';') self.ensure_mode(linuxcnc.MODE_MDI) for code in (mdi_list): From a953040d7f88c6e9087ebe64b1783eec1bc29eb6 Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 10:07:38 -0700 Subject: [PATCH 16/79] qtvcp -dialog widget: add status message control of tool change dialog you can use STATUS messages to 'press' ok or cancel --- lib/python/qtvcp/widgets/dialog_widget.py | 46 +++++++++++++++++------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/python/qtvcp/widgets/dialog_widget.py b/lib/python/qtvcp/widgets/dialog_widget.py index e0f9735afb9..25a7e3f5452 100644 --- a/lib/python/qtvcp/widgets/dialog_widget.py +++ b/lib/python/qtvcp/widgets/dialog_widget.py @@ -416,6 +416,7 @@ def __init__(self, parent=None): class ToolDialog(LcncDialog, GeometryMixin): def __init__(self, parent=None): super(ToolDialog, self).__init__(parent) + self._request_name = 'TOOLCHANGE' self.setText('Manual Tool Change Request') self.setInformativeText('Please Insert Tool 0') self.setStandardButtons(QMessageBox.Ok) @@ -458,6 +459,8 @@ def _hal_init(self): self.sound_type = self.PREFS_.getpref('toolDialog_sound_type', 'READY', str, 'DIALOG_OPTIONS') else: self.play_sound = False + # can acknowledge from status messages too + STATUS.connect('dialog-update', self._status_update) # process callback from 'change' HAL pin def tool_change(self, change): @@ -508,7 +511,7 @@ def tool_change(self, change): # process callback for 'change-button' HAL pin # hide the message dialog or desktop notify message def external_acknowledge(self, state): - #print('external acklnowledge: {}'.format(state)) + #print('external acknowledge: {}'.format(state)) if state: if self._useDesktopNotify: self.deskNotice.close() @@ -516,10 +519,29 @@ def external_acknowledge(self, state): self.hide() self._processChange(True) + # callback from status 'update-dialog' + def _status_update(self, w, message): + print(message) + if message.get('NAME') == self._request_name: + if not self.isVisible(): return + print(self._request_name) + response = message.get('response') + if not response is None: + # 'ok' + if response == 1: + if self._useDesktopNotify: + self.deskNotice.close() + elif self.isVisible(): + self.hide() + self._processChange(True) + # 'cancel' + elif response == 0: + self.hide() + self._processChange(False) # This also is called from DesktopDialog def _processChange(self,answer): - #print('proces change: {}'.format(answer)) + print('process change: {}'.format(answer)) if answer == -1: self.changed.set(True) ACTION.ABORT() @@ -535,6 +557,16 @@ def _processChange(self,answer): self.record_geometry() STATUS.emit('focus-overlay-changed', False, None, None) + # decode button presses + def msgbtn(self, i): + LOG.debug('Button pressed is: {}'.format(i.text())) + if self.clickedButton() == self._actionbutton: + self._processChange(-1) + elif self.standardButton(self.clickedButton()) == QMessageBox.Ok: + self._processChange(True) + else: + self._processChange(False) + ###### overridden functions ################ def showdialog(self, message, more_info=None, details=None, @@ -576,16 +608,6 @@ def showEvent(self, event): self.set_geometry() super(LcncDialog, self).showEvent(event) - # decode button presses - def msgbtn(self, i): - LOG.debug('Button pressed is: {}'.format(i.text())) - if self.clickedButton() == self._actionbutton: - self._processChange(-1) - elif self.standardButton(self.clickedButton()) == QMessageBox.Ok: - self._processChange(True) - else: - self._processChange(False) - ############################################ # ********************** From bc27954e6794c73f0cf17881d71e86302718449e Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 10:16:35 -0700 Subject: [PATCH 17/79] gmoccapy -add gstat message control of start and pause --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 22e6e6a7dd5..073490d6f46 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -433,6 +433,8 @@ def __init__(self, argv): self.GSTAT.connect("graphics-gcode-properties", self.on_gcode_properties) self.GSTAT.connect("file-loaded", self.on_hal_status_file_loaded) self.GSTAT.connect('macro-call-request', lambda w, name: self.request_macro_call(name)) + self.GSTAT.connect('cycle-start-request', lambda w, state :self.request_start(state)) + self.GSTAT.connect('cycle-pause-request', lambda w, state: self.request_pause(state)) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) @@ -1316,6 +1318,14 @@ def _make_joints_button(self): self.joints_button_dic[name] = btn + def request_start(self,data): + print('start') + self.widgets.btn_run.emit('clicked') + + def request_pause(self,data): + print('pause') + self.widgets.tbtn_pause.emit('clicked') + # call INI macro (from hal_glib message) def request_macro_call(self, data): # if MDI command change to MDI and run From 8281a081771b4f58f439e6e92c34790c7782d862 Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 10:19:59 -0700 Subject: [PATCH 18/79] gmoccapy -add a halui test config with a sim test panel --- configs/sim/gmoccapy/gmoccapy_halui_test.ini | 225 ++++++++++++ configs/sim/gmoccapy/panel.hal | 24 ++ configs/sim/gmoccapy/panel.ui | 365 +++++++++++++++++++ 3 files changed, 614 insertions(+) create mode 100644 configs/sim/gmoccapy/gmoccapy_halui_test.ini create mode 100644 configs/sim/gmoccapy/panel.hal create mode 100644 configs/sim/gmoccapy/panel.ui diff --git a/configs/sim/gmoccapy/gmoccapy_halui_test.ini b/configs/sim/gmoccapy/gmoccapy_halui_test.ini new file mode 100644 index 00000000000..27579c0b389 --- /dev/null +++ b/configs/sim/gmoccapy/gmoccapy_halui_test.ini @@ -0,0 +1,225 @@ +# EMC controller parameters for a simulated machine. +# General note: Comments can either be preceded with a # or ; - either is +# acceptable, although # is in keeping with most linux config files. + +# General section ------------------------------------------------------------- +[EMC] +VERSION = 1.1 +MACHINE = gmoccapy +DEBUG = 0 + +# Sections for display options ------------------------------------------------ +[DISPLAY] +DISPLAY = gmoccapy -i +# Log level: +# DEBUG -d +# INFO -i +# VERBOSE -v +# ERROR -q + +# Cycle time, in milliseconds, that display will sleep between polls +CYCLE_TIME = 100 + +# Values that will be allowed for override, 1.0 = 100% +MAX_FEED_OVERRIDE = 1.5 +MAX_SPINDLE_OVERRIDE = 1.2 +MIN_SPINDLE_OVERRIDE = 0.5 + +# Initial value for spindle speed +DEFAULT_SPINDLE_SPEED = 450 + +# The following are not used, added here to suppress warnings (from qt_istat/logger). +DEFAULT_LINEAR_VELOCITY = 35 +MIN_LINEAR_VELOCITY = 0 +MAX_LINEAR_VELOCITY = 234 +DEFAULT_SPINDLE_0_SPEED = 500 +MIN_SPINDLE_0_SPEED = 0 +MAX_SPINDLE_0_SPEED = 3000 +MAX_SPINDLE_0_OVERRIDE = 1.2 +MIN_SPINDLE_0_OVERRIDE = 0.5 + +# Prefix to be used +PROGRAM_PREFIX = ../../nc_files/ + +# Introductory graphic +INTRO_GRAPHIC = linuxcnc.gif +INTRO_TIME = 5 + +# list of selectable jog increments +INCREMENTS = 1.000 mm, 0.100 mm, 0.010 mm, 0.001 mm, 1.2345 inch + +# for details see nc_files/subroutines/maco_instructions.txt +[FILTER] +PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image +PROGRAM_EXTENSION = .py Python Script +png = image-to-gcode +gif = image-to-gcode +jpg = image-to-gcode +py = python3 + +# Task controller section ----------------------------------------------------- +[RS274NGC] +RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.005 G80 G90 G94 G97 M5 M9 +PARAMETER_FILE = sim.var +SUBROUTINE_PATH = ./macros +REMAP=M6 modalgroup=6 prolog=change_prolog ngc=change_g43 epilog=change_epilog +REMAP=M61 modalgroup=6 prolog=settool_prolog ngc=settool_g43 epilog=settool_epilog + +# the Python plugins serves interpreter and task +[PYTHON] +PATH_PREPEND = ./python +TOPLEVEL = ./python/toplevel.py +LOG_LEVEL = 0 + +# Motion control section ------------------------------------------------------ +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 1.0 +BASE_PERIOD = 100000 +SERVO_PERIOD = 1000000 + +# Hardware Abstraction Layer section -------------------------------------------------- +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +# Part program interpreter section -------------------------------------------- +[HAL] +HALFILE = core_sim.hal +HALFILE = spindle_sim.hal +HALFILE = simulated_home.hal + +# Single file that is executed after the GUI has started. +POSTGUI_HALFILE = gmoccapy_postgui.hal +POSTGUI_HALCMD = loadusr qtvcp -a -H panel.hal panel + +HALUI = halui + +# Trajectory planner section -------------------------------------------------- +[HALUI] +#No Content + +[MDI_COMMAND_LIST] +# for macro buttons on main oage up to 10 possible +MDI_COMMAND_MACRO0 = G0 Z1;X0 Y0;Z0, Goto\nUser\nZero +MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero +MDI_COMMAND_MACRO2 = (MSG, macro 2); +MDI_COMMAND_MACRO3 = (MSG, macro 2) +MDI_COMMAND_MACRO4 = (MSG, macro 2),test +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = mm +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 35 +MAX_LINEAR_VELOCITY = 234 +POSITION_FILE = position.txt +#NO_FORCE_HOMING = 1 + +[EMCIO] +# tool table file +TOOL_TABLE = tool.tbl +TOOL_CHANGE_POSITION = 100 100 -10 +TOOL_CHANGE_QUILL_UP = 1 + +[KINS] +KINEMATICS = trivkins coordinates=xyz +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 + +[JOINT_0] +TYPE = LINEAR +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_OFFSET = 0.0 +HOME = 10 +HOME_SEARCH_VEL = 200.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 1 +HOME_IS_SHARED = 1 + +# Second axis +[AXIS_Y] +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 + +[JOINT_1] +TYPE = LINEAR +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_OFFSET = 0.0 +HOME = 10 +HOME_SEARCH_VEL = 200.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 1 + +# Third axis +[AXIS_Z] +MIN_LIMIT = -400.0 +MAX_LIMIT = 0.001 +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 + +[JOINT_2] +TYPE = LINEAR +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -400.0 +MAX_LIMIT = 0.001 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_OFFSET = 1.0 +HOME = -10 +HOME_SEARCH_VEL = 200.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 0 +HOME_IS_SHARED = 1 + +# section for main IO controller parameters ----------------------------------- +[MACROS] +MACRO = go_to_position x-pos y-pos z-pos +MACRO = i_am_lost +MACRO = increment x-incr y-incr +MACRO = macro_4 +MACRO = macro_5 +MACRO = macro_6 +MACRO = macro_7 +MACRO = macro_8 +MACRO = macro_9 +MACRO = macro_10 +MACRO = macro_11 +MACRO = macro_12 +MACRO = macro_13 +MACRO = macro_14 +MACRO = macro_15 + + diff --git a/configs/sim/gmoccapy/panel.hal b/configs/sim/gmoccapy/panel.hal new file mode 100644 index 00000000000..d48117a20ff --- /dev/null +++ b/configs/sim/gmoccapy/panel.hal @@ -0,0 +1,24 @@ +net rate halui.axis.jog-speed panel.Jog-rate-f + +net sx halui.axis.x.select panel.axis-x +net sy halui.axis.y.select panel.axis-y +net sz halui.axis.z.select panel.axis-z + +net jog-p halui.axis.selected.plus panel.jog-pos +net jog-m halui.axis.selected.minus panel.jog-neg + +net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 +net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 +net m2 halui.gui.mdi-command-MACRO2 panel.mdi-2 + +net man panel.manual-mode halui.mode.manual +net mdi panel.mdi-mode halui.mode.mdi +net auto panel.auto-mode halui.mode.auto + +net pause halui.cycle.start panel.cycle-start +net start halui.cycle.pause panel.cycle-pause +net abort halui.abort panel.cycle-abort + +net cancel halui.gui.cancel panel.cancel +net ok halui.gui.ok panel.ok + diff --git a/configs/sim/gmoccapy/panel.ui b/configs/sim/gmoccapy/panel.ui new file mode 100644 index 00000000000..c671b279767 --- /dev/null +++ b/configs/sim/gmoccapy/panel.ui @@ -0,0 +1,365 @@ + + + MainWindow + + + + 0 + 0 + 313 + 467 + + + + MainWindow + + + + + + + + + Axis Selection + + + + + + None + + + true + + + true + + + axis-none + + + + + + + X + + + true + + + true + + + axis-x + + + + + + + Y + + + true + + + true + + + axis-y + + + + + + + Z + + + true + + + true + + + axis-z + + + + + + + + + + Axis Jog + + + + + + + + + + jog-pos + + + + + + + - + + + jog-neg + + + + + + + + + + jog rate + + + + + + 300 + + + Qt::Horizontal + + + Jog-rate + + + + + + + + + + MDI Comands + + + + + + 0 + + + mdi-0 + + + + + + + 1 + + + mdi-1 + + + + + + + 2 + + + mdi-2 + + + + + + + + + + Mode Comands + + + + + + Manual + + + true + + + true + + + manual-mode + + + true + + + true + + + true + + + + + + + MDI + + + true + + + true + + + mdi-mode + + + true + + + true + + + true + + + + + + + Auto + + + true + + + true + + + auto-mode + + + true + + + true + + + true + + + + + + + + + + program control + + + + + + start + + + cycle-start + + + + + + + pause + + + cycle-pause + + + + + + + Abort + + + cycle-abort + + + + + + + + + + dialog control + + + + + + ok + + + ok + + + + + + + cancel + + + cancel + + + + + + + + + + + + + + 0 + 0 + 313 + 22 + + + + + + + + PushButton + QPushButton +
qtvcp.widgets.simple_widgets
+
+ + Slider + QSlider +
qtvcp.widgets.simple_widgets
+
+
+ + +
From 476c13aba4a648556fd21e986debbd7c9a96618e Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 10:24:15 -0700 Subject: [PATCH 19/79] qtdragon -update test config test panel --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 24 ++-- configs/sim/qtdragon/qtdragon_xyz/panel.ui | 130 +++++++++++++++++- .../qtdragon/qtdragon_xyz/qtdragon_metric.ini | 4 +- 3 files changed, 144 insertions(+), 14 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal index e9407a91feb..a5c68d8da0c 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.hal +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -1,17 +1,19 @@ -net rate halui.axis.jog-speed panel.Jog-rate-f +net rate halui.axis.jog-speed panel.Jog-rate-f -net sx halui.axis.x.select panel.axis-x -net sy halui.axis.y.select panel.axis-y -net sz halui.axis.z.select panel.axis-z +net sx halui.axis.x.select panel.axis-x +net sy halui.axis.y.select panel.axis-y +net sz halui.axis.z.select panel.axis-z -net jog-p halui.axis.selected.plus -net jog-m halui.axis.selected.minus -net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 -net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 +net jog-p halui.axis.selected.plus panel.jog-pos +net jog-m halui.axis.selected.minus panel.jog-neg -net pause halui.cycle.start panel.cycle-start -net start halui.cycle.pause panel.cycle-pause +#net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 +#net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 +#net m2 halui.gui.mdi-command-0 panel.mdi-2 -net cancel halui.gui.cancel panel.cancel +net pause halui.cycle.start panel.cycle-start +net start halui.cycle.pause panel.cycle-pause + +net cancel halui.gui.cancel panel.cancel net ok halui.gui.ok panel.ok diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index d9200fc614e..c671b279767 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -23,11 +23,33 @@ Axis Selection + + + + None + + + true + + + true + + + axis-none + + + X + + true + + + true + axis-x @@ -38,6 +60,12 @@ Y + + true + + + true + axis-y @@ -48,6 +76,12 @@ Z + + true + + + true + axis-z @@ -146,6 +180,90 @@ + + + + Mode Comands + + + + + + Manual + + + true + + + true + + + manual-mode + + + true + + + true + + + true + + + + + + + MDI + + + true + + + true + + + mdi-mode + + + true + + + true + + + true + + + + + + + Auto + + + true + + + true + + + auto-mode + + + true + + + true + + + true + + + + + + @@ -163,7 +281,7 @@ - + pause @@ -172,6 +290,16 @@ + + + + Abort + + + cycle-abort + + + diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini index c62a2dd16a9..7dce4b83a04 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini @@ -10,7 +10,7 @@ DEBUG = 0x00000000 # sets qtdragon as screen. for debug output to terminal add -d or -v # sets window title # sets icon in task manager -DISPLAY = qtvcp qtdragon +DISPLAY = qtvcp -d qtdragon TITLE = QtDragon XYZ Metric ICON = silver_dragon.png @@ -167,7 +167,7 @@ POSTGUI_HALFILE = qtdragon_postgui.hal # uncomment this one to print all HAL pins that start with qt #POSTGUI_HALCMD = show pin qt POSTGUI_HALCMD = show pin halui.gui -POSTGUI_HALCMD = loadusr qtvcp -H panel.hal panel +POSTGUI_HALCMD = loadusr qtvcp -a -H panel.hal panel [HALUI] # no content From 2debd42b76e812a91f3b3075ab7416d3f3caca4e Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 18:10:59 -0700 Subject: [PATCH 20/79] qtvcp/gladevcp -action: add ability; return to mode after INI mdi --- lib/python/gladevcp/gtk_action.py | 12 +++++++++++- lib/python/qtvcp/qt_action.py | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/python/gladevcp/gtk_action.py b/lib/python/gladevcp/gtk_action.py index 97a6fc442c5..ae56852891a 100644 --- a/lib/python/gladevcp/gtk_action.py +++ b/lib/python/gladevcp/gtk_action.py @@ -191,7 +191,7 @@ def CALL_MDI_WAIT(self, code, time=5, mode_return=False): self.ensure_mode(premode) return 0 - def CALL_INI_MDI(self, key): + def CALL_INI_MDI(self, key, mode_return = False): try: # prefer named INI MDI commands mdi = INFO.get_ini_mdi_command(key) @@ -209,11 +209,21 @@ def CALL_INI_MDI(self, key): mdi_list = mdi.split(';') + if mode_return: + self.RECORD_CURRENT_MODE() + self._a = STATUS.connect('command-stopped', lambda w: self.return_mode_after_finish()) self.ensure_mode(linuxcnc.MODE_MDI) for code in (mdi_list): LOG.debug('CALL_INI_MDI command:{}'.format(code)) self.cmd.mdi('%s' % code) + # when command stops - we try to continue the generator. + # if generator is done - return to recorded mode. + def return_mode_after_finish(self): + print('ini command end') + self.RESTORE_RECORDED_MODE() + STATUS.handler_disconnect(self._a) + def CALL_OWORD(self, code, time=5): LOG.debug('OWORD_COMMAND= {}'.format(code)) self.ensure_mode(linuxcnc.MODE_MDI) diff --git a/lib/python/qtvcp/qt_action.py b/lib/python/qtvcp/qt_action.py index afe02a62b89..a30f852bbe8 100644 --- a/lib/python/qtvcp/qt_action.py +++ b/lib/python/qtvcp/qt_action.py @@ -228,7 +228,7 @@ def CALL_MDI_WAIT(self, code, time=5, mode_return=False): self.ensure_mode(premode) return 0 - def CALL_INI_MDI(self, key): + def CALL_INI_MDI(self, key, mode_return = False): try: # prefer named INI MDI commands mdi = INFO.get_ini_mdi_command(key) @@ -245,6 +245,9 @@ def CALL_INI_MDI(self, key): return mdi_list = mdi.split(';') + if mode_return: + self.RECORD_CURRENT_MODE() + self._a = STATUS.connect('command-stopped', lambda w: self.return_mode_after_finish()) self.ensure_mode(linuxcnc.MODE_MDI) for code in (mdi_list): LOG.debug('CALL_INI_MDI command:{}'.format(code)) @@ -283,6 +286,13 @@ def RUN_MACRO( self, data): self.CALL_MDI(command) return + # when command stops - we try to continue the generator. + # if generator is done - return to recorded mode. + def return_mode_after_finish(self): + print('ini command end') + self.RESTORE_RECORDED_MODE() + STATUS.handler_disconnect(self._a) + def CALL_OWORD(self, code, time=5): LOG.debug('OWORD_COMMAND= {}'.format(code)) self.ensure_mode(linuxcnc.MODE_MDI) From 0defcc27d4af650780ba90dc1ab3b306e494d039 Mon Sep 17 00:00:00 2001 From: CMorley Date: Mon, 1 Sep 2025 21:27:49 -0700 Subject: [PATCH 21/79] gmoccapy -used new mode return INI MDI function --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 073490d6f46..3c2c43bfc04 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -1332,10 +1332,8 @@ def request_macro_call(self, data): cmd = self.INFO.get_ini_mdi_command(data) print('MDI command:',data,cmd) if not cmd is None: - self.ACTION.RECORD_CURRENT_MODE() LOG.debug("INI MDI COMMAND #: {} = {}".format(data, cmd)) - self.ACTION.CALL_INI_MDI(data) - self.ACTION.RESTORE_RECORDED_MODE() + self.ACTION.CALL_INI_MDI(data,mode_return = True) return # run Macros From 654d0a4e221e9cedcdc7926bdfc9da777de3bb88 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 5 Sep 2025 20:39:53 -0700 Subject: [PATCH 22/79] halui -fix memory leaks --- lib/python/bridgeui/bridge.py | 2 +- src/emc/usr_intf/halui.cc | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index 27397528660..f2377f26100 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -97,7 +97,7 @@ def init_read(self): self.readSocket.connect(self.readAddress) # callback from ZMQ read socket - def readMsg(self, msg): + def readMsg(self): if self.readSocket.getsockopt(zmq.EVENTS) & zmq.POLLIN: while self.readSocket.getsockopt(zmq.EVENTS) & zmq.POLLIN: # get raw message diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 585ea12b916..244155d699f 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -1799,9 +1799,8 @@ static void py_call_axis_jogspeed(double speed) if (pValue == NULL){ fprintf(stderr, "halui bridge: writeMsg function failed: returned NULL\n"); if (PyErr_Occurred()) PyErr_Print(); - }else{ - Py_DECREF(pValue); } + Py_DECREF(pValue); }else{ if (PyErr_Occurred()) PyErr_Print(); @@ -1848,9 +1847,8 @@ static void py_call_axis_changed( int axis) if (pValue == NULL){ fprintf(stderr, "halui bridge: writeMsg function failed: returned NULL\n"); if (PyErr_Occurred()) PyErr_Print(); - }else{ - Py_DECREF(pValue); } + Py_DECREF(pValue); }else{ if (PyErr_Occurred()) PyErr_Print(); @@ -1868,9 +1866,8 @@ static void py_call_request_MDI( int index) if (pValue == NULL){ fprintf(stderr, "halui bridge: runIndexedMacro function failed: returned NULL\n"); if (PyErr_Occurred()) PyErr_Print(); - }else{ - Py_DECREF(pValue); } + Py_DECREF(pValue); }else{ if (PyErr_Occurred()) PyErr_Print(); @@ -1896,8 +1893,9 @@ static void check_hal_changes() // get python to process socket messages pFuncRead = PyObject_GetAttrString(pInstance, "readMsg"); + if (pFuncRead && PyCallable_Check(pFuncRead)) { - pValue = PyObject_CallFunction(pFuncRead, "O", pClass); + pValue = PyObject_CallNoArgs(pFuncRead); if (pValue == NULL){ fprintf(stderr, "Halui Bridge: readMsg function failed: returned NULL\n"); } @@ -1909,6 +1907,8 @@ static void check_hal_changes() fprintf(stderr, "Bridge: Failed python function"); exit(1); } + Py_DECREF(pFuncRead); + Py_DECREF(pValue); // check socket messages for current axis selection int value = py_call_get_axis_selected(); @@ -2690,6 +2690,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "bridge: Failed to load \"%s\"\n", "pyui"); exit(1); } + Py_DECREF(pClass); // get configuration information if (0 != iniLoad(emc_inifile)) { From 1ca090b5ca535da6f9b073901d8b41efda148bed Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 5 Sep 2025 20:40:47 -0700 Subject: [PATCH 23/79] qtdragon -test files update --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 11 ++++++++--- configs/sim/qtdragon/qtdragon_xyz/panel.ui | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal index a5c68d8da0c..04bc14e8e26 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.hal +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -1,4 +1,4 @@ -net rate halui.axis.jog-speed panel.Jog-rate-f +net rate halui.axis.jog-speed panel.jog-rate net sx halui.axis.x.select panel.axis-x net sy halui.axis.y.select panel.axis-y @@ -7,12 +7,17 @@ net sz halui.axis.z.select panel.axis-z net jog-p halui.axis.selected.plus panel.jog-pos net jog-m halui.axis.selected.minus panel.jog-neg -#net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 -#net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 +net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 +net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 #net m2 halui.gui.mdi-command-0 panel.mdi-2 +net man panel.manual-mode halui.mode.manual +net mdi panel.mdi-mode halui.mode.mdi +net auto panel.auto-mode halui.mode.auto + net pause halui.cycle.start panel.cycle-start net start halui.cycle.pause panel.cycle-pause +net abort halui.abort panel.cycle-abort net cancel halui.gui.cancel panel.cancel net ok halui.gui.ok panel.ok diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index c671b279767..74a4afbef7d 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -6,8 +6,8 @@ 0 0 - 313 - 467 + 404 + 560 @@ -126,15 +126,15 @@ - - - 300 - + Qt::Horizontal - Jog-rate + jog-rate + + + true @@ -341,7 +341,7 @@ 0 0 - 313 + 404 22 @@ -355,9 +355,9 @@
qtvcp.widgets.simple_widgets
- Slider + StatusSlider QSlider -
qtvcp.widgets.simple_widgets
+
qtvcp.widgets.status_slider
From 9881fade558920f561e5b4aab4ca0a6fff721d6a Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 26 Sep 2025 22:09:20 -0700 Subject: [PATCH 24/79] hal_glib -add a function to run the gobject mainloop once so GUIs not basd in gobject can run the message system --- lib/python/common/hal_glib.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/python/common/hal_glib.py b/lib/python/common/hal_glib.py index 864bf95b0ec..caa00c6ba75 100644 --- a/lib/python/common/hal_glib.py +++ b/lib/python/common/hal_glib.py @@ -353,6 +353,11 @@ def __init__(self, stat = None): def set_timer(self): GLib.timeout_add(CYCLE_TIME, self.update) + # used to run the Gobject mainloop once + # allows a GUI that is not GLib based to update the mainloop + def run_iteration(self): + GLib.MainContext.default().iteration (True) + # open a zmq socket for writing out data def init_write_socket(self): context = zmq.Context() @@ -363,6 +368,7 @@ def init_write_socket(self): self.write_available = True except Exception as e: LOG.debug('hal_glib write socket not available: {}'.format(e)) + LOG.debug('hal_glib write socket not available\n {}'.format(e)) self.write_available = False # convert and actually send out the message From 31ace239d9c58e65b9814c4647dbf1da905fd919 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 26 Sep 2025 22:27:26 -0700 Subject: [PATCH 25/79] axis sinm -add a sim test for halui messages --- configs/sim/axis/axis_halui_test.ini | 225 +++++++++++++++++ configs/sim/axis/gstatmessages.py | 66 +++++ configs/sim/axis/panel.hal | 24 ++ configs/sim/axis/panel.ui | 365 +++++++++++++++++++++++++++ 4 files changed, 680 insertions(+) create mode 100644 configs/sim/axis/axis_halui_test.ini create mode 100644 configs/sim/axis/gstatmessages.py create mode 100644 configs/sim/axis/panel.hal create mode 100644 configs/sim/axis/panel.ui diff --git a/configs/sim/axis/axis_halui_test.ini b/configs/sim/axis/axis_halui_test.ini new file mode 100644 index 00000000000..877a91db9d8 --- /dev/null +++ b/configs/sim/axis/axis_halui_test.ini @@ -0,0 +1,225 @@ +# EMC controller parameters for a simulated machine. + +# General note: Comments can either be preceded with a # or ; - either is +# acceptable, although # is in keeping with most linux config files. + +# General section ------------------------------------------------------------- +[EMC] + +# Version of this INI file +VERSION = 1.1 + +# Name of machine, for use with display, etc. +MACHINE = LinuxCNC-HAL-SIM-AXIS + +# Debug level, 0 means no messages. See src/emc/nml_int/emcglb.h for others +#DEBUG = 0x7FFFFFFF +DEBUG = 0 + +# Sections for display options ------------------------------------------------ +[DISPLAY] + +# Name of display program, e.g., axis +DISPLAY = axis + +# Cycle time, in seconds, that display will sleep between polls +CYCLE_TIME = 0.100 + +# Path to help file +HELP_FILE = doc/help.txt + +# Initial display setting for position, RELATIVE or MACHINE +POSITION_OFFSET = RELATIVE + +# Initial display setting for position, COMMANDED or ACTUAL +POSITION_FEEDBACK = ACTUAL + +# Highest value that will be allowed for feed override, 1.0 = 100% +MAX_FEED_OVERRIDE = 1.2 +MAX_SPINDLE_OVERRIDE = 1.0 + +MAX_LINEAR_VELOCITY = 5 +DEFAULT_LINEAR_VELOCITY = .25 +DEFAULT_SPINDLE_SPEED = 200 +# Prefix to be used +PROGRAM_PREFIX = ../../nc_files/ + +# Introductory graphic +INTRO_GRAPHIC = linuxcnc.gif +INTRO_TIME = 5 + +#EDITOR = geany +TOOL_EDITOR = tooledit + +INCREMENTS = 1 in, 0.1 in, 10 mil, 1 mil, 1mm, .1mm, 1/8000 in + +USER_COMMAND_FILE=gstatmessages.py + +[FILTER] +PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image +PROGRAM_EXTENSION = .py Python Script + +png = image-to-gcode +gif = image-to-gcode +jpg = image-to-gcode +py = python3 + +# Task controller section ----------------------------------------------------- +[TASK] + +# Name of task controller program, e.g., milltask +TASK = milltask + +# Cycle time, in seconds, that task controller will sleep between polls +CYCLE_TIME = 0.001 + +# Part program interpreter section -------------------------------------------- +[RS274NGC] + +# File containing interpreter variables +PARAMETER_FILE = sim.var + +# Motion control section ------------------------------------------------------ +[EMCMOT] + +EMCMOT = motmod + +# Timeout for comm to emcmot, in seconds +COMM_TIMEOUT = 1.0 + +# BASE_PERIOD is unused in this configuration but specified in core_sim.hal +BASE_PERIOD = 0 +# Servo task period, in nano-seconds +SERVO_PERIOD = 1000000 + +# section for main IO controller parameters ----------------------------------- +[EMCIO] +# tool table file +TOOL_TABLE = sim.tbl +TOOL_CHANGE_POSITION = 0 0 0 +TOOL_CHANGE_QUILL_UP = 1 + +# Hardware Abstraction Layer section -------------------------------------------------- +[HAL] + +# The run script first uses halcmd to execute any HALFILE +# files, and then to execute any individual HALCMD commands. +# + +# list of hal config files to run through halcmd +# files are executed in the order in which they appear +HALFILE = core_sim.hal +HALFILE = sim_spindle_encoder.hal +HALFILE = axis_manualtoolchange.hal +HALFILE = simulated_home.hal +HALFILE = check_xyz_constraints.hal +HALFILE = cooling.hal + +# list of halcmd commands to execute +# commands are executed in the order in which they appear +#HALCMD = save neta + +# Single file that is executed after the GUI has started. Only supported by +# AXIS at this time (only AXIS creates a HAL component of its own) +#POSTGUI_HALFILE = test_postgui.hal +POSTGUI_HALCMD = loadusr qtvcp -a -H panel.hal panel + +HALUI = halui + +# Trajectory planner section -------------------------------------------------- +[TRAJ] +COORDINATES = X Y Z +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +MAX_LINEAR_VELOCITY = 4 +DEFAULT_LINEAR_ACCELERATION = 100 +MAX_LINEAR_ACCELERATION = 100 +POSITION_FILE = position.txt + +[KINS] +KINEMATICS = trivkins +JOINTS = 3 + +# Axes sections --------------- +[AXIS_X] +MAX_VELOCITY = 4 +MAX_ACCELERATION = 100.0 +MIN_LIMIT = -10.0 +MAX_LIMIT = 10.0 + +[AXIS_Y] +MAX_VELOCITY = 4 +MAX_ACCELERATION = 100.0 +MIN_LIMIT = -10.0 +MAX_LIMIT = 10.0 + +[AXIS_Z] +MAX_VELOCITY = 4 +MAX_ACCELERATION = 100.0 +MIN_LIMIT = -8.0 +MAX_LIMIT = 0.12 + +# Joints sections ------------- +[JOINT_0] +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 5 +MAX_ACCELERATION = 50.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +FERROR = 0.050 +MIN_FERROR = 0.010 +MIN_LIMIT = -10.0 +MAX_LIMIT = 10.0 +HOME_OFFSET = 0.0 +HOME_SEARCH_VEL = 20.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 1 +HOME_IS_SHARED = 1 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 5 +MAX_ACCELERATION = 50.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +FERROR = 0.050 +MIN_FERROR = 0.010 +MIN_LIMIT = -10.0 +MAX_LIMIT = 10.0 +HOME_OFFSET = 0.0 +HOME_SEARCH_VEL = 20.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 1 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 5 +MAX_ACCELERATION = 50.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -8.0 + +# Normally the Z max should be 0.000! +# The only reason it's greater than 0 here is so that the splash screen +# gcode will run. +MAX_LIMIT = 0.12 + +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_OFFSET = 1.0 +HOME_SEARCH_VEL = 20.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 0 +HOME_IS_SHARED = 1 diff --git a/configs/sim/axis/gstatmessages.py b/configs/sim/axis/gstatmessages.py new file mode 100644 index 00000000000..5c9e1e95d16 --- /dev/null +++ b/configs/sim/axis/gstatmessages.py @@ -0,0 +1,66 @@ + +from hal_glib import GStat +GSTAT = GStat() +GSTAT.forced_update() +GSTAT.connect('jograte-changed', lambda w, data: vars.jog_speed.set(data)) +GSTAT.connect('axis-selection-changed', lambda w,data: select_axis(data)) +GSTAT.connect('cycle-start-request', lambda w, state : cycle_start_request(state)) +GSTAT.connect('cycle-pause-request', lambda w, state: pause_request(state)) +GSTAT.connect('ok-request', lambda w, state: dialog_ext_control(w,1,1)) +GSTAT.connect('cancel-request', lambda w, state: dialog_ext_control(w,1,0)) +GSTAT.connect('macro-call-request', lambda w, name: request_macro_call(name)) +def user_live_update(): + GSTAT.run_iteration() + +def select_axis(data): + if data is None: return + widget = getattr(widgets, "axis_%s" % data.lower()) + widget.focus() + widget.invoke() + +def cycle_start_request(state): + print('cycle start',state) + commands.task_run(None) + +def pause_request(state): + print('cycle pause',state) + commands.task_pauseresume(None) + +def dialog_ext_control(widget,t,state): + print('dialog control',widget,state) + + flag = False + for child in root_window.winfo_children(): + #print(child) + if isinstance(child, Tkinter.Toplevel): + #print(f"Found a Toplevel window: {child}") + if '.!toplevel' in str(child): + #print('sending command:',child) + for child2 in child.winfo_children(): + #print(child2) + if isinstance(child2, Tkinter.Frame): + for child3 in child2.winfo_children(): + #print(child3) + if isinstance(child3, Tkinter.Button): + #print(dir(child3)) + txt = child3.cget("text") + if txt.lower() == 'ok' and state: + #print('Ok') + child3.invoke() + flag = True + break + elif txt.lower() == 'cancel' and not state: + #print('Cancel') + child3.invoke() + flag = True + break + if flag: break + if flag: break + else: + #print('No window') + # remove one error message + if state == 0: + notifications.clear_one() + +def request_macro_call(name): + print('request macro:',name) diff --git a/configs/sim/axis/panel.hal b/configs/sim/axis/panel.hal new file mode 100644 index 00000000000..5db03ed71da --- /dev/null +++ b/configs/sim/axis/panel.hal @@ -0,0 +1,24 @@ +net rate halui.axis.jog-speed panel.jog-rate + +net sx halui.axis.x.select panel.axis-x +net sy halui.axis.y.select panel.axis-y +net sz halui.axis.z.select panel.axis-z + +net jog-p halui.axis.selected.plus panel.jog-pos +net jog-m halui.axis.selected.minus panel.jog-neg + +#net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 +#net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 +#net m2 halui.gui.mdi-command-0 panel.mdi-2 + +net man panel.manual-mode halui.mode.manual +net mdi panel.mdi-mode halui.mode.mdi +net auto panel.auto-mode halui.mode.auto + +net pause halui.cycle.start panel.cycle-start +net start halui.cycle.pause panel.cycle-pause +net abort halui.abort panel.cycle-abort + +net cancel halui.gui.cancel panel.cancel +net ok halui.gui.ok panel.ok + diff --git a/configs/sim/axis/panel.ui b/configs/sim/axis/panel.ui new file mode 100644 index 00000000000..74a4afbef7d --- /dev/null +++ b/configs/sim/axis/panel.ui @@ -0,0 +1,365 @@ + + + MainWindow + + + + 0 + 0 + 404 + 560 + + + + MainWindow + + + + + + + + + Axis Selection + + + + + + None + + + true + + + true + + + axis-none + + + + + + + X + + + true + + + true + + + axis-x + + + + + + + Y + + + true + + + true + + + axis-y + + + + + + + Z + + + true + + + true + + + axis-z + + + + + + + + + + Axis Jog + + + + + + + + + + jog-pos + + + + + + + - + + + jog-neg + + + + + + + + + + jog rate + + + + + + Qt::Horizontal + + + jog-rate + + + true + + + + + + + + + + MDI Comands + + + + + + 0 + + + mdi-0 + + + + + + + 1 + + + mdi-1 + + + + + + + 2 + + + mdi-2 + + + + + + + + + + Mode Comands + + + + + + Manual + + + true + + + true + + + manual-mode + + + true + + + true + + + true + + + + + + + MDI + + + true + + + true + + + mdi-mode + + + true + + + true + + + true + + + + + + + Auto + + + true + + + true + + + auto-mode + + + true + + + true + + + true + + + + + + + + + + program control + + + + + + start + + + cycle-start + + + + + + + pause + + + cycle-pause + + + + + + + Abort + + + cycle-abort + + + + + + + + + + dialog control + + + + + + ok + + + ok + + + + + + + cancel + + + cancel + + + + + + + + + + + + + + 0 + 0 + 404 + 22 + + + + + + + + PushButton + QPushButton +
qtvcp.widgets.simple_widgets
+
+ + StatusSlider + QSlider +
qtvcp.widgets.status_slider
+
+
+ + +
From e12ecff4b51dca33e37c68813118f36ee81d2edc Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 26 Sep 2025 22:34:12 -0700 Subject: [PATCH 26/79] qtdragon -add halui test sim --- .../qtdragon_xyz/qtdragon_halui_test.ini | 267 ++++++++++++++++++ .../qtdragon/qtdragon_xyz/qtdragon_metric.ini | 5 +- 2 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini new file mode 100644 index 00000000000..e7a674f81b2 --- /dev/null +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini @@ -0,0 +1,267 @@ +# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47 +# Changes to most things are ok and will be read by the wizard + +[EMC] +VERSION = 1.1 +MACHINE = qtdragon_metric +DEBUG = 0x00000000 + +[DISPLAY] +# sets qtdragon as screen. for debug output to terminal add -d or -v +# sets window title +# sets icon in task manager +DISPLAY = qtvcp -d qtdragon +TITLE = QtDragon XYZ Metric +ICON = silver_dragon.png + +# qtdragon saves most preference to this file +PREFERENCE_FILE_PATH = WORKINGFOLDER/qtdragon.pref + +# min/max percentage overrides allowed in qtdragon 1 = 100% +MAX_FEED_OVERRIDE = 1.2 +MIN_SPINDLE_0_OVERRIDE = 0.5 +MAX_SPINDLE_0_OVERRIDE = 1.2 + +# manual spindle speed will start at this RPM +DEFAULT_SPINDLE_0_SPEED = 12000 + +# spindle up/down increment in RPM +SPINDLE_INCREMENT = 200 + +# min max apindle speed manually allowed +MIN_SPINDLE_0_SPEED = 1000 +MAX_SPINDLE_0_SPEED = 20000 + +# max spindle power in Watts +MAX_SPINDLE_POWER = 2000 + +# min/max/default jog velocities in qtdragon in units/sec +MIN_LINEAR_VELOCITY = 0 +MAX_LINEAR_VELOCITY = 60.00 +DEFAULT_LINEAR_VELOCITY = 50.0 + +# incremental jog step length options +INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch + +# Display grid increments +GRIDS = 0, .1 mm, 1 mm, 2 mm, 5 mm, 10 mm, .25 in, .5 in + +CYCLE_TIME = 100 +INTRO_GRAPHIC = silver_dragon.png +INTRO_TIME = 2 + +# default program search path +PROGRAM_PREFIX = ~/linuxcnc/nc_files + +# NGCGUI subroutine path. +# Thr path must also be in [RS274NGC] SUBROUTINE_PATH +NGCGUI_SUBFILE_PATH = ../../../nc_files/ngcgui_lib/ +# pre selected programs tabs +# specify filenames only, files must be in the NGCGUI_SUBFILE_PATH +NGCGUI_SUBFILE = slot.ngc +NGCGUI_SUBFILE = qpocket.ngc + +# qtdragon saves MDI cxommands to this file +MDI_HISTORY_FILE = mdi_history.dat +# qtdragon saves rnning logs to this file +LOG_FILE = qtdragon.log + +# optional user dialogs (3), controlled by HAL pins +MESSAGE_BOLDTEXT = Critical and Persistent +MESSAGE_TEXT = This is a persistent dialog test +MESSAGE_DETAILS = There seems to be something wrong\n You must fix it to clear message +MESSAGE_TYPE = nonedialog +MESSAGE_PINNAME = nonedialogtest +MESSAGE_ICON = CRITICAL + +MESSAGE_BOLDTEXT = Do You Want To Make A Choice? +MESSAGE_TEXT = This is a yes no dialog test +MESSAGE_DETAILS = Y/N DETAILS +MESSAGE_TYPE = yesnodialog +MESSAGE_PINNAME = yndialogtest +MESSAGE_ICON = QUESTION + +MESSAGE_BOLDTEXT = This is an information message +MESSAGE_TEXT = This is low priority +MESSAGE_DETAILS = press ok to clear +MESSAGE_TYPE = okdialog status +MESSAGE_PINNAME = bothtest +MESSAGE_ICON = INFO + +# optional tab showing an external qtvcp panel +EMBED_TAB_NAME=Vismach demo +EMBED_TAB_COMMAND=qtvcp vismach_mill_xyz +EMBED_TAB_LOCATION=tabWidget_utilities + +[MDI_COMMAND_LIST] +# for macro buttons on main oage up to 10 possible +MDI_COMMAND_MACRO0 = G0 Z25;X0 Y0;Z0, Goto\nUser\nZero +MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero + +[FILTER] +# Controls what programs are shown inqtdragon file manager +PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap) +PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image +PROGRAM_EXTENSION = .py Python Script + +# specifies what special 'filter' programs runs based on program ending +png = image-to-gcode +gif = image-to-gcode +jpg = image-to-gcode +py = python3 + +[KINS] +KINEMATICS = trivkins coordinates=XYZ +JOINTS = 3 + +[EMCIO] +TOOL_TABLE = tool.tbl + +[RS274NGC] +# motion controller saves parameters to this file +PARAMETER_FILE = qtdragon.var + +# start up G/M codes when first loaded +RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.0127 G80 G90 G94 G97 M5 M9 + +# subroutine/remap path list +SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs + +# on abort, this ngc file is called. required for basic/versa probe +ON_ABORT_COMMAND=O call + +[EMCMOT] +EMCMOT = motmod +SERVO_PERIOD = 1000000 +COMM_TIMEOUT = 1.0 +COMM_WAIT = 0.010 +BASE_PERIOD = 100000 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.010 + +[TRAJ] +COORDINATES = XYZ +LINEAR_UNITS = metric +ANGULAR_UNITS = degree +MAX_LINEAR_VELOCITY = 60.00 +DEFAULT_LINEAR_VELOCITY = 50.00 +SPINDLES = 1 + +[HAL] +HALUI = halui +#HALBRIDGE = hal_bridge + +# loads the HAL machine simulation +HALFILE = core_sim.hal +HALFILE = simulated_home.hal + +# this file is loaded after qtdragon has made it's HAl pins +# you can add multiple entries +POSTGUI_HALFILE = qtdragon_postgui.hal + +# this command is run after qtdragon has made it's HAl pins +# any HAL conmmand can be used +# you can add multiple entries +# uncomment this one to print all HAL pins that start with qt +#POSTGUI_HALCMD = show pin qt +POSTGUI_HALCMD = show pin halui.gui +POSTGUI_HALCMD = loadusr qtvcp -a -H panel.hal panel +[HALUI] +# no content + +[PROBE] +# pick basic probe or versa probe or remove for none +#USE_PROBE = versaprobe +USE_PROBE = basicprobe + +[AXIS_X] +MIN_LIMIT = -0.001 +MAX_LIMIT = 520.0 +MAX_VELOCITY = 60.0 +MAX_ACCELERATION = 500.0 + +[AXIS_Y] +MIN_LIMIT = -0.001 +MAX_LIMIT = 630.0 +MAX_VELOCITY = 60.0 +MAX_ACCELERATION = 500.0 + +[AXIS_Z] +# used by external offsets for auto spindle lift +OFFSET_AV_RATIO = 0.2 +MIN_LIMIT = -115.0 +MAX_LIMIT = 10.0 +MAX_VELOCITY = 40.0 +MAX_ACCELERATION = 500.0 + +[JOINT_0] +AXIS = X +MIN_LIMIT = -0.001 +MAX_LIMIT = 520.0 +MAX_VELOCITY = 60.0 +MAX_ACCELERATION = 500.0 +TYPE = LINEAR +SCALE = 160.0 +STEPGEN_MAX_VEL = 72.0 +STEPGEN_MAX_ACC = 600.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +MAX_OUTPUT = 0 +MAX_ERROR = 0.0127 +HOME = 20.0 +HOME_OFFSET = 0.00000 +HOME_SEARCH_VEL = 20.000000 +HOME_LATCH_VEL = 10.000 +HOME_SEQUENCE = 1 +HOME_USE_INDEX = False +HOME_IGNORE_LIMITS = False +HOME_IS_SHARED = 1 + +[JOINT_1] +AXIS = Y +MIN_LIMIT = -0.001 +MAX_LIMIT = 630.0 +MAX_VELOCITY = 60.0 +MAX_ACCELERATION = 500.0 +TYPE = LINEAR +SCALE = 160.0 +STEPGEN_MAX_VEL = 72.0 +STEPGEN_MAX_ACC = 600.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +MAX_OUTPUT = 0 +MAX_ERROR = 0.0127 +HOME = 20.0 +HOME_OFFSET = 0.000000 +HOME_SEARCH_VEL = 20.00 +HOME_LATCH_VEL = 10.00 +HOME_SEQUENCE = 2 +HOME_USE_INDEX = False +HOME_IGNORE_LIMITS = False + +[JOINT_2] +AXIS = Z +MIN_LIMIT = -115.0 +MAX_LIMIT = 10.0 +MAX_VELOCITY = 40.0 +MAX_ACCELERATION = 500.0 +TYPE = LINEAR +SCALE = 160.0 +STEPGEN_MAX_VEL = 48.0 +STEPGEN_MAX_ACC = 600.0 +FERROR = 1.0 +MIN_FERROR = 0.5 +MAX_OUTPUT = 0 +MAX_ERROR = 0.0127 +HOME = -10.0 +HOME_OFFSET = 0.000000 +HOME_SEARCH_VEL = 20.000000 +HOME_LATCH_VEL = 10.00 +HOME_SEQUENCE = 0 +HOME_USE_INDEX = False +HOME_IGNORE_LIMITS = False +HOME_IS_SHARED = 1 + + diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini index 7dce4b83a04..f437be0811a 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_metric.ini @@ -10,7 +10,7 @@ DEBUG = 0x00000000 # sets qtdragon as screen. for debug output to terminal add -d or -v # sets window title # sets icon in task manager -DISPLAY = qtvcp -d qtdragon +DISPLAY = qtvcp qtdragon TITLE = QtDragon XYZ Metric ICON = silver_dragon.png @@ -166,8 +166,7 @@ POSTGUI_HALFILE = qtdragon_postgui.hal # you can add multiple entries # uncomment this one to print all HAL pins that start with qt #POSTGUI_HALCMD = show pin qt -POSTGUI_HALCMD = show pin halui.gui -POSTGUI_HALCMD = loadusr qtvcp -a -H panel.hal panel + [HALUI] # no content From 64754b4f562979941a97cbc0753182e7648caad6 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 17 Oct 2025 21:47:47 -0700 Subject: [PATCH 27/79] test panel - make mode buttons not checkable The indicator shows state, so we don't need to chow checked state. in a real panel the buttons would be momentary buttons anyways --- configs/sim/axis/panel.ui | 6 +++--- configs/sim/gmoccapy/panel.ui | 12 ++++++------ configs/sim/qtdragon/qtdragon_xyz/panel.ui | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/configs/sim/axis/panel.ui b/configs/sim/axis/panel.ui index 74a4afbef7d..7264d58f6d0 100644 --- a/configs/sim/axis/panel.ui +++ b/configs/sim/axis/panel.ui @@ -192,7 +192,7 @@ Manual - true + false true @@ -217,7 +217,7 @@ MDI - true + false true @@ -242,7 +242,7 @@ Auto - true + false true diff --git a/configs/sim/gmoccapy/panel.ui b/configs/sim/gmoccapy/panel.ui index c671b279767..6ed71542f13 100644 --- a/configs/sim/gmoccapy/panel.ui +++ b/configs/sim/gmoccapy/panel.ui @@ -6,8 +6,8 @@ 0 0 - 313 - 467 + 404 + 537 @@ -195,7 +195,7 @@ true - true + false manual-mode @@ -220,7 +220,7 @@ true - true + false mdi-mode @@ -242,7 +242,7 @@ Auto - true + false true @@ -341,7 +341,7 @@ 0 0 - 313 + 404 22 diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index 74a4afbef7d..7264d58f6d0 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -192,7 +192,7 @@ Manual - true + false true @@ -217,7 +217,7 @@ MDI - true + false true @@ -242,7 +242,7 @@ Auto - true + false true From dfba671c958e0703a74ce399f8f6e435620a3a74 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 17 Oct 2025 21:50:03 -0700 Subject: [PATCH 28/79] gmoccapy -getinfo.py: fix macro search title this must have been fix in master after I branched --- src/emc/usr_intf/gmoccapy/getiniinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emc/usr_intf/gmoccapy/getiniinfo.py b/src/emc/usr_intf/gmoccapy/getiniinfo.py index 8d45c6ccec8..20be167976e 100644 --- a/src/emc/usr_intf/gmoccapy/getiniinfo.py +++ b/src/emc/usr_intf/gmoccapy/getiniinfo.py @@ -377,7 +377,7 @@ def get_tool_sensor_data(self): def get_macros(self): # lets look in the INI file, if there are any entries - macros = self.inifile.findall("DISPLAY", "MACRO") + macros = self.inifile.findall("MACROS", "MACRO") # If there are no entries we will return False if not macros: return False From 574ac222ba1de1936f1024804780081bfc5eb344 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 15 Nov 2025 14:50:23 -0800 Subject: [PATCH 29/79] halui switch u32 to s32 s32 is more common the u32 (easier to connect to) also axis select uses -1 as 'unselected' --- src/emc/usr_intf/halui.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 244155d699f..47ddb514b3b 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -104,7 +104,7 @@ static int axis_mask = 0; FIELD(hal_bit_t,program_bd_off) /* pin for setting block delete off */ \ FIELD(hal_bit_t,program_bd_is_on) /* status pin that block delete is on */ \ \ - FIELD(hal_u32_t,tool_number) /* pin for current selected tool */ \ + FIELD(hal_s32_t,tool_number) /* pin for current selected tool */ \ FIELD(hal_float_t,tool_length_offset_x) /* current applied x tool-length-offset */ \ FIELD(hal_float_t,tool_length_offset_y) /* current applied y tool-length-offset */ \ FIELD(hal_float_t,tool_length_offset_z) /* current applied z tool-length-offset */ \ @@ -139,8 +139,8 @@ static int axis_mask = 0; ARRAY(hal_bit_t,joint_on_hard_max_limit,EMCMOT_MAX_JOINTS+1) /* status pin that the joint is on the hardware max limit */ \ ARRAY(hal_bit_t,joint_override_limits,EMCMOT_MAX_JOINTS+1) /* status pin that the joint is on the hardware max limit */ \ ARRAY(hal_bit_t,joint_has_fault,EMCMOT_MAX_JOINTS+1) /* status pin that the joint has a fault */ \ - FIELD(hal_u32_t,joint_selected) /* status pin for the joint selected */ \ - FIELD(hal_u32_t,axis_selected) /* status pin for the axis selected */ \ + FIELD(hal_s32_t,joint_selected) /* status pin for the joint selected */ \ + FIELD(hal_s32_t,axis_selected) /* status pin for the axis selected */ \ \ ARRAY(hal_bit_t,joint_nr_select,EMCMOT_MAX_JOINTS) /* nr. of pins to select a joint */ \ ARRAY(hal_bit_t,axis_nr_select,EMCMOT_MAX_AXIS) /* nr. of pins to select a axis */ \ @@ -846,11 +846,11 @@ int halui_hal_init(void) if (retval < 0) return retval; retval = hal_pin_float_newf(HAL_OUT, &(halui_data->ro_value), comp_id, "halui.rapid-override.value"); if (retval < 0) return retval; - retval = hal_pin_u32_newf(HAL_OUT, &(halui_data->joint_selected), comp_id, "halui.joint.selected"); + retval = hal_pin_s32_newf(HAL_OUT, &(halui_data->joint_selected), comp_id, "halui.joint.selected"); if (retval < 0) return retval; - retval = hal_pin_u32_newf(HAL_OUT, &(halui_data->axis_selected), comp_id, "halui.axis.selected"); + retval = hal_pin_s32_newf(HAL_OUT, &(halui_data->axis_selected), comp_id, "halui.axis.selected"); if (retval < 0) return retval; - retval = hal_pin_u32_newf(HAL_OUT, &(halui_data->tool_number), comp_id, "halui.tool.number"); + retval = hal_pin_s32_newf(HAL_OUT, &(halui_data->tool_number), comp_id, "halui.tool.number"); if (retval < 0) return retval; retval = hal_pin_float_newf(HAL_OUT, &(halui_data->tool_length_offset_x), comp_id, "halui.tool.length_offset.x"); if (retval < 0) return retval; From fee6dfe2469a8b5f9d741b91356a1f5164a322b9 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 12 Dec 2025 20:13:10 -0800 Subject: [PATCH 30/79] halui -add mpg_select0 pin Some GUIs use the MPG for other things then jogging. Qtdragon uses MPG for scrolling and needs a selected pin. --- lib/python/bridgeui/bridge.py | 23 +++++++++++++++++++---- src/emc/usr_intf/halui.cc | 28 +++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index f2377f26100..56577ebb664 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -45,7 +45,7 @@ def __init__(self, readAddress = "tcp://127.0.0.1:5690", self.currentSelectedAxis = 'None' self.axesSelected = {'X':0,'Y':0,'Z':0,'A':0,'B':0,'C':0, - 'U':0,'V':0,'W':0} + 'U':0,'V':0,'W':0,'MPG0':0} self.readAddress = readAddress self.writeAddress = writeAddress LOG.debug('read port: {}'.format(readAddress)) @@ -108,7 +108,7 @@ def readMsg(self): # set our variables from messages from hal_glib def action(self, msg, data): - LOG.debug('{} {}'.format(msg, data)) + LOG.debug('{} -> {} -> {}'.format(msg, data, data[0])) if msg == 'jograte-changed': self.jogRate = float(data[0]) elif msg == 'jograte-angular-changed': @@ -120,7 +120,14 @@ def action(self, msg, data): elif msg == 'joint-selection-changed': self.activeJoint = int(data[0]) elif msg == 'axis-selection-changed': + print ('pre axis state', self.axesSelected,self.currentSelectedAxis) flag = 1 + if data[0] == 'MPG0': + self.currentSelectedAxis = data[0] + flag = 0 + self.axesSelected['MPG0'] = True + else: + self.axesSelected['MPG0'] = False for i in(self.INFO.AVAILABLE_AXES): if data[0] == i: state = True @@ -129,9 +136,10 @@ def action(self, msg, data): else: state = False self.axesSelected[i] = int(state) + if flag: self.currentSelectedAxis = 'None' - #print ('axis state', self.axesSelected) + print ('axis state', self.axesSelected,self.currentSelectedAxis) # send msg to hal_glib def writeMsg(self, msg, data): @@ -198,18 +206,25 @@ def getSelectedAxis(self): name = self.currentSelectedAxis if name == 'None': index = -1 + elif name =='MPG0': + index = 100 else: index = 'XYZABCUVW'.index(name) return index def setSelectedAxis(self, value): if value < 0: letter = 'None' + elif value == 100: + letter = 'MPG0' else: letter ='XYZABCUVW'[value] self.writeMsg('set_selected_axis', letter) def isAxisSelected(self, index): - letter = 'XYZABCUVW'[index] + if index == 100: + letter = 'MPG0' + else: + letter = 'XYZABCUVW'[index] return int(self.axesSelected[letter]) def __getitem__(self, item): diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 47ddb514b3b..638b2d46b1f 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -144,6 +144,7 @@ static int axis_mask = 0; \ ARRAY(hal_bit_t,joint_nr_select,EMCMOT_MAX_JOINTS) /* nr. of pins to select a joint */ \ ARRAY(hal_bit_t,axis_nr_select,EMCMOT_MAX_AXIS) /* nr. of pins to select a axis */ \ + FIELD(hal_bit_t,mpg_select0)\ \ ARRAY(hal_bit_t,joint_is_selected,EMCMOT_MAX_JOINTS) /* nr. of status pins for joint selected */ \ ARRAY(hal_bit_t,axis_is_selected,EMCMOT_MAX_AXIS) /* nr. of status pins for axis selected */ \ @@ -1023,6 +1024,9 @@ int halui_hal_init(void) if (retval < 0) return retval; } + retval = halui_export_pin_IN_bit(&(halui_data->mpg_select0), "halui.mpg-select.0"); + if (retval < 0) return retval; + retval = hal_pin_bit_newf(HAL_IN, &(halui_data->joint_home[num_joints]), comp_id, "halui.joint.selected.home"); if (retval < 0) return retval; retval = hal_pin_bit_newf(HAL_IN, &(halui_data->joint_unhome[num_joints]), comp_id, "halui.joint.selected.unhome"); @@ -1683,6 +1687,7 @@ static void hal_init_pins() for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) { if ( !(axis_mask & (1 << axis_num)) ) { continue; } *(halui_data->axis_nr_select[axis_num]) = old_halui_data.axis_nr_select[axis_num] = 0; + *(halui_data->mpg_select0) = old_halui_data.mpg_select0 = 0; *(halui_data->ajog_minus[axis_num]) = old_halui_data.ajog_minus[axis_num] = 0; *(halui_data->ajog_plus[axis_num]) = old_halui_data.ajog_plus[axis_num] = 0; *(halui_data->ajog_analog[axis_num]) = old_halui_data.ajog_analog[axis_num] = 0; @@ -1926,6 +1931,11 @@ static void check_hal_changes() *(halui_data->axis_nr_select[axis_num]) = 0; } } + if (value == 100) { + *(halui_data->mpg_select0) = 1; + }else{ + *(halui_data->mpg_select0) = 0; + } lastaxis = value; } @@ -2258,6 +2268,7 @@ static void check_hal_changes() is_any_axis_selected = 0; deselected = 0; for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) { + if ( !(axis_mask & (1 << axis_num)) ) { continue; } // axis jog - @@ -2321,7 +2332,22 @@ static void check_hal_changes() old_halui_data.axis_nr_select[axis_num] = bit; } } - // last axis has been deselected - no axis is selected now + + // is MPG0 selected? + bit = new_halui_data.mpg_select0; + if (bit != old_halui_data.mpg_select0) { + if (bit != 0) { + is_any_axis_selected = 1; + py_call_axis_changed(100); + *halui_data->axis_selected = 100; + }else{ + deselected = 1; + } + old_halui_data.mpg_select0 = bit; + } + + + // last axis has been deselected - no axis is selected now if (is_any_axis_selected == 0 and deselected == 1) { py_call_axis_changed(-1); *halui_data->axis_selected = -1; From 53db204c911fcd7fec48a231a270b182882c0865 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 12 Dec 2025 20:15:21 -0800 Subject: [PATCH 31/79] qtdragon -add mpg_select button logic control --- share/qtvcp/screens/qtdragon/qtdragon_handler.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index 787728bdb2d..372dc60a49f 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -1465,9 +1465,12 @@ def MPG_select_changed(self, button): if button == self.w.btn_mpg_scroll: self.removeMPGFocusBorder() + if not self.w.btn_mpg_scroll.isChecked(): + ACTION.SET_SELECTED_AXIS('None') return if button == self.w.btn_mpg_scroll: if self.w.btn_mpg_scroll.isChecked(): + ACTION.SET_SELECTED_AXIS('MPG0') self.recolorMPGFocusBorder() else: self.removeMPGFocusBorder() From ab168280be76e40b77d353cfbd20b3f2e627a47f Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 12 Dec 2025 22:06:22 -0800 Subject: [PATCH 32/79] sim panel -add scale buttons and MPG dial --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 13 ++ configs/sim/qtdragon/qtdragon_xyz/panel.ui | 243 ++++++++++++++++---- 2 files changed, 206 insertions(+), 50 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal index 04bc14e8e26..7c7b85458c9 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.hal +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -1,8 +1,21 @@ net rate halui.axis.jog-speed panel.jog-rate net sx halui.axis.x.select panel.axis-x +net sx axis.x.jog-enable net sy halui.axis.y.select panel.axis-y +net sy axis.y.jog-enable net sz halui.axis.z.select panel.axis-z +net sz axis.z.jog-enable + +net mpg-scale axis.x.jog-scale panel.mpg-scale +net mpg-scale axis.y.jog-scale +net mpg-scale axis.z.jog-scale + +net mpg-count panel.mpg-wheel-s +net mpg-count qtdragon.mpg-in +net mpg-count axis.x.jog-counts +net mpg-count axis.y.jog-counts +net mpg-count axis.z.jog-counts net jog-p halui.axis.selected.plus panel.jog-pos net jog-m halui.axis.selected.minus panel.jog-neg diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index 7264d58f6d0..c5447316fb4 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -6,8 +6,8 @@ 0 0 - 404 - 560 + 418 + 587 @@ -91,55 +91,190 @@ - - - Axis Jog - - - - - - + - - - jog-pos - - - - - - - - - - - jog-neg - - - - - + + + + + Axis Jog + + + + + + + + + + jog-pos + + + + + + + - + + + jog-neg + + + + + + + + + + jog rate + + + + + + Qt::Horizontal + + + jog-rate + + + true + + + + + + + - - - jog rate - - - - - - Qt::Horizontal - - - jog-rate - - - true - - - - - + + + + + MPG + + + + + + .001 + + + true + + + true + + + true + + + mpg-scale-small + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.001000000000000 + + + buttonGroup_mpgscale + + + + + + + .01 + + + true + + + true + + + mpg-scale-med + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.010000000000000 + + + buttonGroup_mpgscale + + + + + + + .1 + + + true + + + true + + + mpg-scale-large + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.100000000000000 + + + buttonGroup_mpgscale + + + + + + + + + + + 0 + 74 + + + + false + + + true + + + false + + + mpg-wheel + + + + @@ -341,7 +476,7 @@ 0 0 - 404 + 418 22 @@ -354,6 +489,11 @@ QPushButton
qtvcp.widgets.simple_widgets
+ + Dial + QDial +
qtvcp.widgets.simple_widgets
+
StatusSlider QSlider @@ -362,4 +502,7 @@ + + + From 0cc845476af3de3356dc15b6ab2ae96b705521aa Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 13 Dec 2025 20:42:40 -0800 Subject: [PATCH 33/79] qtvcp -baseclass: register dialogs for later checks like if you want to send responses to the current showing dialog --- lib/python/qtvcp/widgets/widget_baseclass.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/python/qtvcp/widgets/widget_baseclass.py b/lib/python/qtvcp/widgets/widget_baseclass.py index 23bfa396f45..d2012fe8f82 100644 --- a/lib/python/qtvcp/widgets/widget_baseclass.py +++ b/lib/python/qtvcp/widgets/widget_baseclass.py @@ -17,6 +17,7 @@ # the other subclasses are for simple HAL widget functionality import hal + from qtpy.QtCore import Property from qtpy.QtWidgets import QDialog From a9e5c0e7224b784d835b0e5959e4948ee7507c16 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 13 Dec 2025 20:46:51 -0800 Subject: [PATCH 34/79] qtdragon -find the currently visible dialog to send messages to halui 'ok' or 'cancel' messages --- share/qtvcp/screens/qtdragon/qtdragon_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index 372dc60a49f..dabd7ddd854 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -783,7 +783,7 @@ def dialog_return(self, w, message): self.touchoff('touchplate') elif sensor_code and name == 'MESSAGE' and rtn is True: self.touchoff('sensor') - elif wait_code and name == 'MESSAGE': + elif wait_code and name == 'MESSAGE' and rtn is True: self.lowerSpindle() elif unhome_code and name == 'MESSAGE' and rtn is True: ACTION.SET_MACHINE_UNHOMED(-1) From bfcc91fe9eed47eca99262666fc2946876e50a13 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 14 Dec 2025 01:10:17 -0800 Subject: [PATCH 35/79] gmoccapy -change system dialog to accept halui messages ok and cancel are used by the system unlock dialog as an example. To do this properly for all dialogs would require some more thought. --- src/emc/usr_intf/gmoccapy/dialogs.py | 46 +++++++++++++++++++++------ src/emc/usr_intf/gmoccapy/gmoccapy.py | 29 +++++++++++++++-- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/emc/usr_intf/gmoccapy/dialogs.py b/src/emc/usr_intf/gmoccapy/dialogs.py index 08a16ee7249..ab06d809965 100644 --- a/src/emc/usr_intf/gmoccapy/dialogs.py +++ b/src/emc/usr_intf/gmoccapy/dialogs.py @@ -36,10 +36,19 @@ class Dialogs(GObject.GObject): __gsignals__ = { 'play_sound': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)), + 'system-dialog-result': (GObject.SignalFlags.RUN_FIRST , GObject.TYPE_NONE, (GObject.TYPE_INT,)) } - def __init__(self): + def __init__(self, caller): GObject.GObject.__init__(self) + self.sys_dialog = self.system_dialog(caller) + + def dialog_ext_control(self, answer): + if self.sys_dialog.get_visible(): + if answer: + self.sys_dialog.response(Gtk.ResponseType.ACCEPT) + else: + self.sys_dialog.response(Gtk.ResponseType.CANCEL) # This dialog is for unlocking the system tab # The unlock code number is defined at the top of the page @@ -47,9 +56,12 @@ def system_dialog(self, caller): dialog = Gtk.Dialog(_("Enter System Unlock Code"), caller.widgets.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT) + dialog.set_modal(True) label = Gtk.Label(_("Enter System Unlock Code")) label.modify_font(Pango.FontDescription("sans 20")) calc = gladevcp.Calculator() + dialog._calc = calc + dialog._caller = caller dialog.vbox.pack_start(label, False, False, 0) dialog.vbox.add(calc) calc.set_value("") @@ -57,18 +69,32 @@ def system_dialog(self, caller): calc.set_editable(True) calc.integer_entry_only(True) calc.num_pad_only(True) - calc.entry.connect("activate", lambda w : dialog.emit("response", Gtk.ResponseType.ACCEPT)) + calc.entry.connect("activate", lambda w : self.on_system_response(dialog,Gtk.ResponseType.ACCEPT)) dialog.parse_geometry("360x400") dialog.set_decorated(True) - dialog.show_all() + dialog.connect("response", self.on_system_response) + return dialog + + def show_system_dialog(self): + self.sys_dialog._calc.set_value("") + self.sys_dialog.show_all() self.emit("play_sound", "alert") - response = dialog.run() - code = calc.get_value() - dialog.destroy() - if response == Gtk.ResponseType.ACCEPT: - if code == int(caller.unlock_code): - return True - return False + + def on_system_response(self, dialog, result): + code = dialog._calc.get_value() + print('Code:',code) + rtn = -1 + if result == Gtk.ResponseType.ACCEPT: + if code == int(dialog._caller.unlock_code): + print('Yes') + rtn = 1 + else: + print('No') + rtn = 0 + else: + print('Cancelled') + self.emit('system-dialog-result',rtn) + dialog.hide() def entry_dialog(self, caller, data = None, header = _("Enter value") , label = _("Enter the value to set"), integer = False): dialog = Gtk.Dialog(header, diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 3c2c43bfc04..a2a9aac5196 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -272,8 +272,9 @@ def __init__(self, argv): self.icon_theme.append_search_path(ICON_THEME_DIR) self.icon_theme.append_search_path(USER_ICON_THEME_DIR) - self.dialogs = dialogs.Dialogs() + self.dialogs = dialogs.Dialogs(caller = self) self.dialogs.connect("play_sound", self._on_play_sound) + self.dialogs.connect('system-dialog-result', self.system_dialog_return) # check the arguments given from the command line (Ini file) self.user_mode = False @@ -435,6 +436,8 @@ def __init__(self, argv): self.GSTAT.connect('macro-call-request', lambda w, name: self.request_macro_call(name)) self.GSTAT.connect('cycle-start-request', lambda w, state :self.request_start(state)) self.GSTAT.connect('cycle-pause-request', lambda w, state: self.request_pause(state)) + self.GSTAT.connect('ok-request', lambda w, state: self.dialogs.dialog_ext_control(1)) + self.GSTAT.connect('cancel-request', lambda w, state: self.dialogs.dialog_ext_control(0)) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) @@ -4278,8 +4281,9 @@ def on_tbtn_setup_toggled(self, widget, data=None): code = True # else we ask for the code using the system.dialog if self.widgets.rbt_use_unlock.get_active(): - if self.dialogs.system_dialog(self): - code = True + self.dialogs.show_system_dialog() + # we will wait for response + return # Lets see if the user has the right to enter settings if code: self.widgets.ntb_main.set_current_page(1) @@ -4329,6 +4333,25 @@ def on_tbtn_setup_toggled(self, widget, data=None): widget.set_image(self.widgets.img_settings) + # return code from system dialog + def system_dialog_return(self,widget,result): + print(widget,result) + # Lets see if the user has the right to enter settings + if result == 1: + self.widgets.ntb_main.set_current_page(1) + self.widgets.ntb_setup.set_current_page(0) + self.widgets.ntb_button.set_current_page(_BB_SETUP) + #widget.set_image(self.widgets.img_settings_on) + elif result == 0: + if self.widgets.rbt_hal_unlock.get_active(): + message = _("Hal Pin is low, Access denied") + else: + message = _("wrong code entered, Access denied") + self.dialogs.warning_dialog(self, _("Just to warn you"), message) + self.widgets.tbtn_setup.set_active(False) + #widget.set_image(self.widgets.img_settings) + + # Show or hide the user tabs def on_tbtn_user_tabs_toggled(self, widget, data=None): if widget.get_active(): From 128f2c8c7f522af00e786784f7b30c164eecd5e1 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 26 Dec 2025 19:48:56 -0800 Subject: [PATCH 36/79] gmoccapy -change warning dialogs to accept HALUI messages --- src/emc/usr_intf/gmoccapy/dialogs.py | 38 +++++-- src/emc/usr_intf/gmoccapy/gmoccapy.py | 152 ++++++++++++++++---------- 2 files changed, 122 insertions(+), 68 deletions(-) diff --git a/src/emc/usr_intf/gmoccapy/dialogs.py b/src/emc/usr_intf/gmoccapy/dialogs.py index ab06d809965..a28408d9abe 100644 --- a/src/emc/usr_intf/gmoccapy/dialogs.py +++ b/src/emc/usr_intf/gmoccapy/dialogs.py @@ -36,19 +36,20 @@ class Dialogs(GObject.GObject): __gsignals__ = { 'play_sound': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)), - 'system-dialog-result': (GObject.SignalFlags.RUN_FIRST , GObject.TYPE_NONE, (GObject.TYPE_INT,)) + 'system-dialog-result': (GObject.SignalFlags.RUN_FIRST , GObject.TYPE_NONE, (GObject.TYPE_INT,)), + 'warning-dialog-result': (GObject.SignalFlags.RUN_FIRST , GObject.TYPE_NONE, (GObject.TYPE_INT, GObject.TYPE_STRING)) } def __init__(self, caller): GObject.GObject.__init__(self) self.sys_dialog = self.system_dialog(caller) + self.warn_dialog = self.warning_dialog(caller) def dialog_ext_control(self, answer): if self.sys_dialog.get_visible(): - if answer: - self.sys_dialog.response(Gtk.ResponseType.ACCEPT) - else: - self.sys_dialog.response(Gtk.ResponseType.CANCEL) + self.sys_dialog.response(answer) + elif self.warn_dialog.get_visible(): + self.warn_dialog.response(answer) # This dialog is for unlocking the system tab # The unlock code number is defined at the top of the page @@ -134,7 +135,7 @@ def entry_dialog(self, caller, data = None, header = _("Enter value") , label = return "CANCEL" # display warning dialog - def warning_dialog(self, caller, message, secondary = None, title = _("Operator Message"),\ + def warning_dialog(self, caller, message = '', secondary = None, title = _("Operator Message"),\ sound = True, confirm_pin = 'warning-confirm', active_pin = None): dialog = Gtk.MessageDialog(caller.widgets.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, @@ -149,11 +150,10 @@ def warning_dialog(self, caller, message, secondary = None, title = _("Operator box.add(ok_button) dialog.action_area.add(box) dialog.set_border_width(5) - dialog.show_all() if sound: self.emit("play_sound", "alert") dialog.set_title(title) - + dialog.context = [] def periodic(): if caller.halcomp[confirm_pin]: dialog.response(Gtk.ResponseType.OK) @@ -164,10 +164,26 @@ def periodic(): return False return True GLib.timeout_add(100, periodic) + dialog.connect("response", self.on_warning_response) + return dialog - response = dialog.run() - dialog.destroy() - return response == Gtk.ResponseType.OK + def show_warning_dialog(self, title, message, context=None, sound=True,\ + confirm_pin = 'warning-confirm', active_pin = None): + print(message,context) + self.warn_dialog.context.append(context) + self.warn_dialog.set_title(title) + self.warn_dialog.format_secondary_text(message) + self.warn_dialog.set_markup(message) + self.warn_dialog.show_all() + if sound: + self.emit("play_sound", "alert") + print(self.warn_dialog.context) + + def on_warning_response(self, dialog, rtn): + context = dialog.context.pop() + print(context) + self.emit('warning-dialog-result', rtn, context) + dialog.hide() def yesno_dialog(self, caller, message, title = _("Operator Message")): dialog = Gtk.MessageDialog(caller.widgets.window1, diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index a2a9aac5196..84771469140 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -272,10 +272,6 @@ def __init__(self, argv): self.icon_theme.append_search_path(ICON_THEME_DIR) self.icon_theme.append_search_path(USER_ICON_THEME_DIR) - self.dialogs = dialogs.Dialogs(caller = self) - self.dialogs.connect("play_sound", self._on_play_sound) - self.dialogs.connect('system-dialog-result', self.system_dialog_return) - # check the arguments given from the command line (Ini file) self.user_mode = False self.logofile = None @@ -354,6 +350,11 @@ def __init__(self, argv): self.builder.connect_signals(self) + self.dialogs = dialogs.Dialogs(caller = self) + self.dialogs.connect("play_sound", self._on_play_sound) + self.dialogs.connect('system-dialog-result', self.system_dialog_return) + self.dialogs.connect('warning-dialog-result', self.warning_dialog_return) + # this are settings to be done before window show self._init_preferences() @@ -436,8 +437,8 @@ def __init__(self, argv): self.GSTAT.connect('macro-call-request', lambda w, name: self.request_macro_call(name)) self.GSTAT.connect('cycle-start-request', lambda w, state :self.request_start(state)) self.GSTAT.connect('cycle-pause-request', lambda w, state: self.request_pause(state)) - self.GSTAT.connect('ok-request', lambda w, state: self.dialogs.dialog_ext_control(1)) - self.GSTAT.connect('cancel-request', lambda w, state: self.dialogs.dialog_ext_control(0)) + self.GSTAT.connect('ok-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.ACCEPT)) + self.GSTAT.connect('cancel-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.CANCEL)) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) @@ -1343,7 +1344,8 @@ def request_macro_call(self, data): # some error checking if not self.GSTAT.is_mdi_mode(): message = _("You must be in MDI mode to run macros") - self.dialogs.warning_dialog(self, _("Important Warning!"), message) + self.dialogs.show_warning_dialog( _("Important Warning!"), + message, context=None) return # look thru the INI macros @@ -1362,7 +1364,8 @@ def request_macro_call(self, data): else: # didn't match a name - give a hint message = _("Macro {} not found ".format(data)) - self.dialogs.warning_dialog(self, _("Important Warning!"), message) + self.dialogs.show_warning_dialog( _("Important Warning!"), + message, context=None) # check if macros are in the INI file and add them to MDI Button List def _make_macro_button(self): @@ -1540,8 +1543,9 @@ def _make_lathe(self): message += _("this is not a lathe, as a lathe must have at least\n") message += _("an X and an Z axis\n") message += _("Wrong lathe configuration, we will leave here") - self.dialogs.warning_dialog(self, _("Very critical situation"), message, sound = False) - sys.exit() + self.dialogs.show_warning_dialog( _("Very critical situation"), + message, context='systemexit') + return else: if not len(self.axis_list) == 2 and not len(self.axis_list) < 6: self._arrange_jog_button_by_axis() @@ -1991,8 +1995,9 @@ def _init_tooleditor(self): if not tooltable: message = _("Did not find a toolfile file in [EMCIO] TOOL_TABLE") LOG.error(message) - self.dialogs.warning_dialog(self, _("Very critical situation"), message, sound = False) - sys.exit() + self.dialogs.show_warning_dialog( _("Very critical situation"), + message, context='systemexit') + return toolfile = os.path.join(CONFIGPATH, tooltable) self.widgets.tooledit1.set_filename(toolfile) # first we hide all the axis columns the unhide the ones we want @@ -2451,8 +2456,9 @@ def _init_offsetpage(self): if not parameterfile: message = _("Did not find a parameter file in [RS274NGC] PARAMETER_FILE") LOG.error(message) - self.dialogs.warning_dialog(self, _("Very critical situation"), message, sound = False) - sys.exit() + self.dialogs.show_warning_dialog( _("Very critical situation"), + message, context='systemexit') + return path = os.path.join(CONFIGPATH, parameterfile) self.widgets.offsetpage1.set_filename(path) @@ -4335,21 +4341,48 @@ def on_tbtn_setup_toggled(self, widget, data=None): # return code from system dialog def system_dialog_return(self,widget,result): - print(widget,result) + print('System ->',widget,result) # Lets see if the user has the right to enter settings if result == 1: self.widgets.ntb_main.set_current_page(1) self.widgets.ntb_setup.set_current_page(0) self.widgets.ntb_button.set_current_page(_BB_SETUP) - #widget.set_image(self.widgets.img_settings_on) + self.widgets.tbtn_setup.set_image(self.widgets.img_settings_on) elif result == 0: if self.widgets.rbt_hal_unlock.get_active(): message = _("Hal Pin is low, Access denied") else: message = _("wrong code entered, Access denied") - self.dialogs.warning_dialog(self, _("Just to warn you"), message) + self.dialogs.show_warning_dialog( _("Just to warn you"), message, context='sytemunlockfail') + # we will wait for response + + + + # return code from system dialog + def warning_dialog_return(self,widget,result,context): + print('Warning ->',widget,result,context) + if context is None: + return + + if context == 'systemunlockfail': self.widgets.tbtn_setup.set_active(False) - #widget.set_image(self.widgets.img_settings) + self.widgets.tbtn_setup.set_image(self.widgets.img_settings) + elif context == 'systemexit': + sys.exit() + + elif context == 'mantoolchange': + if result: + self.halcomp["toolchange-changed"] = True + else: + LOG.debug("toolchange abort {0} {1}".format(self.stat.tool_in_spindle, self.halcomp['toolchange-number'])) + self.command.abort() + self.halcomp['toolchange-number'] = self.stat.tool_in_spindle + self.halcomp['toolchange-change'] = False + self.halcomp['toolchange-changed'] = True + message = _("Tool Change has been aborted!\n") + message += _("The old tool will remain set!") + self.dialogs.show_warning_dialog( _("Just to warn you"), + message, context=None) # Show or hide the user tabs @@ -4470,8 +4503,8 @@ def on_btn_classicladder_clicked(self, widget, data=None): if hal.component_exists("classicladder_rt"): p = os.popen("classicladder &", "w") else: - self.dialogs.warning_dialog(self, _("INFO:"), - _("Classicladder real-time component not detected")) + self.dialogs.show_warning_dialog(_("INFO:"), + _("Classicladder real-time component not detected"), context='classicfail') # ========================================================= # spindle stuff @@ -4786,8 +4819,8 @@ def on_btn_show_calc_clicked(self, widget): integer=False) if value == "ERROR": LOG.debug("conversion error") - self.dialogs.warning_dialog(self, _("Conversion error !"), - ("Please enter only numerical values\nValues have not been applied")) + self.dialogs.show_warning_dialog(_("INFO:"), + _("Please enter only numerical values\nValues have not been applied"), context=None) elif value == "CANCEL": return else: @@ -4812,8 +4845,8 @@ def on_btn_show_calc_clicked(self, widget): integer=False) if value == "ERROR": LOG.debug("conversion error") - self.dialogs.warning_dialog(self, _("Conversion error !"), - ("Please enter only numerical values\nValues have not been applied")) + self.dialogs.show_warning_dialog(_("INFO:"), + _("Please enter only numerical values\nValues have not been applied"), context=None) elif value == "CANCEL": return else: @@ -4999,8 +5032,8 @@ def _on_btn_set_value_clicked(self, widget, data=None): return elif offset == "ERROR": LOG.debug("Conversion error in btn_set_value") - self.dialogs.warning_dialog(self, _("Conversion error in btn_set_value!"), - _("Please enter only numerical values. Values have not been applied")) + self.dialogs.show_warning_dialog(_("Conversion error in btn_set_value!"), + _("Please enter only numerical values\nValues have not been applied"), context=None) else: self.command.mode(linuxcnc.MODE_MDI) self.command.wait_complete() @@ -5021,7 +5054,8 @@ def _on_btn_set_selected_clicked(self, widget, data=None): system, name = self.widgets.offsetpage1.get_selected() if system not in ["G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3"]: message = _("You did not select a system to be changed to, so nothing will be changed") - self.dialogs.warning_dialog(self, _("Important Warning!"), message) + self.dialogs.show_warning_dialog(_("Important Warning!"), + message, context=None) return if system == self.system_list[self.stat.g5x_index]: return @@ -5084,8 +5118,8 @@ def on_btn_block_height_clicked(self, widget, data=None): else: self.prefs.putpref("blockheight", 0.0, float) self.prefs.putpref("probeheight", 0.0, float) - self.dialogs.warning_dialog(self, _("Conversion error in btn_block_height!"), - _("Please enter only numerical values\nValues have not been applied")) + self.dialogs.show_warning_dialog(_("Conversion error in btn_block_height!"), + _("Please enter only numerical values\nValues have not been applied"), context=None) # set coordinate system to new origin origin = self.get_ini_info.get_axis_2_min_limit() + blockheight @@ -5113,7 +5147,9 @@ def _set_icon_theme(self, name): if name is None or name == "none": # Switching to none required a restart (skip entire icon theme stuff) message = "Change to no icon theme requires a restart to take effect." - self.dialogs.warning_dialog(self, _("Just to warn you"), message) + self.dialogs.show_warning_dialog( _("Just to warn you"), + message, context=None) + else: self.icon_theme.set_custom_theme(name) self.notification.set_property('icon_theme_name', name) @@ -5657,28 +5693,20 @@ def on_tool_change(self, widget): except: message = _("Tool\n\n# {0:d}\n\n not in the tool table!").format(toolnumber) - result = self.dialogs.warning_dialog(self, message, title=_("Manual Tool change"),\ - confirm_pin = 'toolchange-confirm', active_pin = 'toolchange-change') - if result: - self.halcomp["toolchange-changed"] = True - else: - LOG.debug("toolchange abort {0} {1}".format(self.stat.tool_in_spindle, self.halcomp['toolchange-number'])) - self.command.abort() - self.halcomp['toolchange-number'] = self.stat.tool_in_spindle - self.halcomp['toolchange-change'] = False - self.halcomp['toolchange-changed'] = True - message = _("Tool Change has been aborted!\n") - message += _("The old tool will remain set!") - self.dialogs.warning_dialog(self, message) + self.dialogs.show_warning_dialog( _("Manual Tool change"), + message, context='mantoolchange', + confirm_pin = 'toolchange-confirm', + active_pin = 'toolchange-change') else: self.halcomp['toolchange-changed'] = False def on_btn_delete_tool_clicked(self, widget, data=None): selected_tool = self.widgets.tooledit1.get_selected_row() if self.stat.tool_in_spindle == selected_tool: - message = _("You are trying to delete the tool mounted in the spindle.\n" - "This is not allowed, please change tool prior to delete it.") - self.dialogs.warning_dialog(self, _("Warning Tool can not be deleted!"), message) + message = _("You are trying to delete the tool mounted in the spindle\n") + message += _("This is not allowed, please change tool prior to delete it") + self.dialogs.show_warning_dialog( _("Warning Tool can not be deleted!"), + message, context=None) return self.widgets.tooledit1.delete_selected_row(widget) self.widgets.tooledit1.edited = True @@ -5706,13 +5734,15 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): if not tool: message = _("No tool selected in the tool table. ") message += _("Please select only one tool in the table!") - self.dialogs.warning_dialog(self, _("Warning Tool Touch off not possible!"), message) + self.dialogs.show_warning_dialog( _("Warning Tool Touch off not possible!"), + message, context=None) return if tool != self.stat.tool_in_spindle: message = _("You can not touch off a tool, which is not mounted in the spindle! ") message += _("Your selection has been reset to the tool in spindle.") - self.dialogs.warning_dialog(self, _("Warning Tool Touch off not possible!"), message) + self.dialogs.show_warning_dialog( _("Warning Tool Touch off not possible!"), + message, context=None) self.widgets.tooledit1.reload(self) self.widgets.tooledit1.set_selected_tool(self.stat.tool_in_spindle) return @@ -5720,7 +5750,8 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): if "G41" in self.active_gcodes or "G42" in self.active_gcodes: message = _("Tool touch off is not possible with cutter radius compensation switched on!\n") message += _("Please emit an G40 before tool touch off.") - self.dialogs.warning_dialog(self, _("Warning Tool Touch off not possible!"), message) + self.dialogs.show_warning_dialog( _("Warning Tool Touch off not possible!"), + message, context=None) return if widget == self.widgets.btn_tool_touchoff_x: @@ -5728,8 +5759,8 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): elif widget == self.widgets.btn_tool_touchoff_z: axis = "z" else: - self.dialogs.warning_dialog(self, _("Real big error!"), - _("You managed to come to a place that is not possible in on_btn_tool_touchoff")) + self.dialogs.show_warning_dialog(_("Real big error!"), + _("You managed to come to a place that is not possible in on_btn_tool_touchoff"), context=None) return value = self.dialogs.entry_dialog(self, data=None, @@ -5739,7 +5770,8 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): if value == "ERROR": message = _("Conversion error because of wrong entry for touch off axis {0}").format(axis.upper()) - self.dialogs.warning_dialog(self, _("Conversion error !"), message) + self.dialogs.show_warning_dialog( _("Conversion error !"), + message, context=None) return elif value == "CANCEL": return @@ -5767,13 +5799,15 @@ def on_btn_select_tool_by_no_clicked(self, widget, data=None): if value == "ERROR": message = _("Conversion error because of wrong entry for tool number.\n") message += _("Enter only integer numbers!") - self.dialogs.warning_dialog(self, _("Conversion error !"), message) + self.dialogs.show_warning_dialog( _("Conversion error !"), + message, context=None) return elif value == "CANCEL": return elif int(value) == self.stat.tool_in_spindle: message = _("Selected tool is already in spindle, no change needed.") - self.dialogs.warning_dialog(self, _("Important Warning!"), message) + self.dialogs.show_warning_dialog( _("Important Warning!"), + message, context=None) return else: self.tool_change = True @@ -5794,11 +5828,13 @@ def on_btn_selected_tool_clicked(self, widget, data=None): tool = self.widgets.tooledit1.get_selected_row() if tool == None: message = _("you selected no or more than one tool, the tool selection must be unique") - self.dialogs.warning_dialog(self, _("Important Warning!"), message) + self.dialogs.show_warning_dialog( _("Important Warning!"), + message, context=None) return if tool == self.stat.tool_in_spindle: message = _("Selected tool is already in spindle, no change needed.") - self.dialogs.warning_dialog(self, _("Important Warning!"), message) + self.dialogs.show_warning_dialog( _("Important Warning!"), + message, context=None) return if tool or tool == 0: self.tool_change = True @@ -5816,7 +5852,9 @@ def on_btn_selected_tool_clicked(self, widget, data=None): self.command.mdi(command) else: message = _("Could not understand the entered tool number. Will not change anything!") - self.dialogs.warning_dialog(self, _("Important Warning!"), message) + self.dialogs.show_warning_dialog( _("Important Warning!"), + message, context=None) + # ========================================================= # gremlin relevant calls From 745cdbdb543a9da49df560604112817094070082 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 1 Feb 2026 00:00:35 -0800 Subject: [PATCH 37/79] gmoccapy -set jog speed control widget to use messages Sends out a jog rate gobject message --- src/emc/usr_intf/gmoccapy/gmoccapy.glade | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.glade b/src/emc/usr_intf/gmoccapy/gmoccapy.glade index 049c965ed4f..efe301beca8 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.glade +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.glade @@ -1,5 +1,5 @@ - + @@ -1410,6 +1410,7 @@ uncomment selection False rgb(255,129,22) 10500 + 0 mm/min 1500 @@ -1456,6 +1457,7 @@ uncomment selection rgb(255,129,22) 3600 %.d + 0 °/min 360 From 912c066e3a6b8bb482cbe39aacaf3ea36ef33a25 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 1 Feb 2026 00:25:59 -0800 Subject: [PATCH 38/79] gmoccapy -use halui message to cancel notifications --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 84771469140..2fb03eec134 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -439,6 +439,7 @@ def __init__(self, argv): self.GSTAT.connect('cycle-pause-request', lambda w, state: self.request_pause(state)) self.GSTAT.connect('ok-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.ACCEPT)) self.GSTAT.connect('cancel-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.CANCEL)) + self.GSTAT.connect('cancel-request', lambda w, state: self._del_notification()) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) @@ -6348,6 +6349,9 @@ def _on_message_deleted(self, widget, messages, checkbox_checked): def _del_message_changed(self, pin): if pin.get(): + self._del_notification() + + def _del_notification(self): if self.halcomp["error"] == True: number = [] messages = self.notification.messages From 1ce04733406530eb77c481b660bb1160d44bf0b3 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 1 Feb 2026 17:45:44 -0800 Subject: [PATCH 39/79] add python3-zmq package for halui --- debian/configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/configure b/debian/configure index 096b3f4a5ed..635bf664ecb 100755 --- a/debian/configure +++ b/debian/configure @@ -121,7 +121,7 @@ PYTHON_GST=python3-gst-1.0,gstreamer1.0-plugins-base TCLTK_VERSION=8.6 PYTHON_IMAGING=python3-pil PYTHON_IMAGING_TK=python3-pil.imagetk -QTVCP_DEPENDS="python3-qtpy,\n python3-pyqt5,\n python3-pyqt5.qsci,\n python3-pyqt5.qtsvg,\n python3-pyqt5.qtopengl,\n python3-opencv,\n python3-dbus,\n python3-espeak,\n python3-dbus.mainloop.pyqt5,\n python3-pyqt5.qtwebengine,\n espeak-ng,\n pyqt5-dev-tools,\n gstreamer1.0-tools,\n espeak,\n sound-theme-freedesktop" +QTVCP_DEPENDS="python3-qtpy,\n python3-pyqt5,\n python3-pyqt5.qsci,\n python3-pyqt5.qtsvg,\n python3-pyqt5.qtopengl,\n python3-opencv,\n python3-dbus,\n python3-espeak,\n python3-dbus.mainloop.pyqt5,\n python3-pyqt5.qtwebengine,\n espeak-ng,\n pyqt5-dev-tools,\n gstreamer1.0-tools,\n espeak,\n sound-theme-freedesktop,\n python3-zmq" YAPPS_RUNTIME="python3-yapps" DEBHELPER="debhelper (>= 12)" COMPAT="12" From ee7e7569a047a8a43ccf28af7a365062f7d95626 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 7 Feb 2026 14:45:11 -0800 Subject: [PATCH 40/79] gmoccapy -can submit the current MDI command from HALUI Pressing HALUI's cycle start when in MDI mode will call the current MDI command in gmoccapy's MDI history widget. --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 2fb03eec134..3c5bd167d5b 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -1323,12 +1323,21 @@ def _make_joints_button(self): self.joints_button_dic[name] = btn + # halui/external cycle start request def request_start(self,data): - print('start') - self.widgets.btn_run.emit('clicked') + print('start request') + if self.stat.task_mode == linuxcnc.MODE_MDI: + print('Submit MDI') + self.widgets.hal_mdihistory.submit() + elif self.stat.task_mode == linuxcnc.MODE_MANUAL: + self._show_error((13, _("Can't start cycles or submit MDI commands in manual Mode"))) + else: + print('Cycle Start') + self.widgets.btn_run.emit('clicked') + # halui/external pause request def request_pause(self,data): - print('pause') + print('pause request') self.widgets.tbtn_pause.emit('clicked') # call INI macro (from hal_glib message) From 44fa90c96b11585e8b928366b0634b681723b7d9 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 7 Feb 2026 16:39:36 -0800 Subject: [PATCH 41/79] add python3-zmq to python3 depends --- debian/control.main-pkg.in | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control.main-pkg.in b/debian/control.main-pkg.in index 56653dc0827..2af4d385f91 100644 --- a/debian/control.main-pkg.in +++ b/debian/control.main-pkg.in @@ -22,6 +22,7 @@ Depends: python3-opengl, python3-configobj, python3-xlib, + python3-zmq, libgtksourceview-4-dev, tcl@TCLTK_VERSION@, tk@TCLTK_VERSION@, From 4675fdbd56d74e5052da9d286fee1d5769136b1f Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 8 Feb 2026 16:42:51 -0800 Subject: [PATCH 42/79] makefile -add halui brideui --- src/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile b/src/Makefile index c95d6d3473c..20af2d46d2a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -779,6 +779,7 @@ install-python: install-dirs $(DIR) $(DESTDIR)$(SITEPY)/pyui $(DIR) $(DESTDIR)$(SITEPY)/plasmac $(FILE) ../lib/python/*.py ../lib/python/*.so $(DESTDIR)$(SITEPY) + $(FILE) ../lib/python/bridgeui/*.py $(DESTDIR)$(SITEPY)/bridgeui $(FILE) ../lib/python/common/*.py $(DESTDIR)$(SITEPY)/common $(FILE) ../lib/python/rs274/*.py $(DESTDIR)$(SITEPY)/rs274 $(FILE) ../lib/python/touchy/*.py $(DESTDIR)$(SITEPY)/touchy From 4255aa9786c54a073a23b431058b87b85ed70f7a Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 8 Feb 2026 22:46:56 -0800 Subject: [PATCH 43/79] makefile -finish adding bridgeui folder --- src/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile b/src/Makefile index 20af2d46d2a..b0f46de708e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -756,6 +756,7 @@ install-kernel-indep: install-dirs install-kernel-indep: install-python install-python: install-dirs $(DIR) $(DESTDIR)$(SITEPY) $(DESTDIR)$(SITEPY)/rs274 + $(DIR) $(DESTDIR)$(SITEPY)/bridgeui $(DIR) $(DESTDIR)$(SITEPY)/common $(DIR) $(DESTDIR)$(SITEPY)/touchy $(DIR) $(DESTDIR)$(SITEPY)/gscreen From 43ecd747d76e99e2c2b57c6d8f11e5da9c88a527 Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 14 Mar 2026 18:57:07 -0700 Subject: [PATCH 44/79] sim - add MPG button on VCP panel --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 2 ++ configs/sim/qtdragon/qtdragon_xyz/panel.ui | 22 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal index 7c7b85458c9..c630fcf6d87 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.hal +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -6,6 +6,8 @@ net sy halui.axis.y.select panel.axis-y net sy axis.y.jog-enable net sz halui.axis.z.select panel.axis-z net sz axis.z.jog-enable +net sgui halui.mpg-select.0 panel.select-gui0 + net mpg-scale axis.x.jog-scale panel.mpg-scale net mpg-scale axis.y.jog-scale diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index c5447316fb4..50da9ae96f1 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -6,7 +6,7 @@ 0 0 - 418 + 495 587 @@ -25,6 +25,22 @@ + + GUI + + + true + + + true + + + select-gui0 + + + + + None @@ -148,7 +164,7 @@ - + MPG @@ -476,7 +492,7 @@ 0 0 - 418 + 495 22 From 0ddfb30e06887a11757067af59a96ba03007e34e Mon Sep 17 00:00:00 2001 From: CMorley Date: Sat, 14 Mar 2026 19:03:05 -0700 Subject: [PATCH 45/79] try to get qtdragon MPG scrolling button to work on vcp --- lib/python/qtvcp/widgets/axis_tool_button.py | 9 ++++++++- share/qtvcp/screens/qtdragon/qtdragon_handler.py | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/python/qtvcp/widgets/axis_tool_button.py b/lib/python/qtvcp/widgets/axis_tool_button.py index d2c58f7a55b..7168a3dc0a7 100644 --- a/lib/python/qtvcp/widgets/axis_tool_button.py +++ b/lib/python/qtvcp/widgets/axis_tool_button.py @@ -226,6 +226,7 @@ def _a_from_j(self, axis): return axis, r[jnum] def selectJoint(self): + print(self.objectName(),'select',self._joint,self._axis,self.isChecked()) if self._block_signal or self._joint == -1 or self._axis == '': return if self.isChecked() == True: if STATUS.is_joint_mode(): @@ -251,7 +252,7 @@ def selectJoint(self): self.hal_pin_axis.set(False) def ChangeState(self, joint = None, axis = None): - #print(self.objectName(),'change',joint,axis,self._axis) + print(self.objectName(),'change',joint,axis,self._axis,self.isChecked()) # joint mode if STATUS.is_joint_mode(): if int(joint) != self._joint: @@ -269,12 +270,18 @@ def ChangeState(self, joint = None, axis = None): # axis mode else: if str(axis) != self._axis and self.isChecked(): + print(self.objectName(),'Set false') + if not self.group() == 0: + self.group().setExclusive(False) self._block_signal = True self.setChecked(False) self._block_signal = False + if not self.group() == 0: + self.group().setExclusive(True) if self._halpin_option and self._axis != '': self.hal_pin_joint.set(False) elif str(axis) == self._axis and not self.isChecked(): + print(self.objectName(),'Set True') self._block_signal = True self.setChecked(True) self._block_signal = False diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index dabd7ddd854..781e838e1a9 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -157,6 +157,7 @@ def __init__(self, halcomp, widgets, paths): STATUS.connect('macro-call-request', lambda w, name: self.request_macro_call(name)) STATUS.connect('ok-request', lambda w, state: self.dialog_ext_control(w,1,1)) STATUS.connect('cancel-request', lambda w, state: self.dialog_ext_control(w,1,0)) + STATUS.connect('axis-selection-changed', lambda w,data: self.mpg_selection_changed(data)) self.swoopPath = os.path.join(paths.IMAGEDIR,'lcnc_swoop.png') self.swoopURL = QtCore.QUrl.fromLocalFile(self.swoopPath) @@ -1453,6 +1454,16 @@ def btn_systemtool_toggled(self, state): if state: STATUS.emit('dro-reference-change-request', 1) + def mpg_selection_changed(self, data): + if data =='MPG0': + self.w.btn_mpg_scroll.setChecked(True) + self.recolorMPGFocusBorder() + elif data == 'None': + self.w.btn_mpg_scroll.group().setExclusive(False) + self.w.btn_mpg_scroll.setChecked(False) + self.w.btn_mpg_scroll.group().setExclusive(True) + self.removeMPGFocusBorder() + def MPG_select_changed(self, button): #print(button) # Auto exclusive doesn't allow unchecking all buttons @@ -1472,8 +1483,10 @@ def MPG_select_changed(self, button): if self.w.btn_mpg_scroll.isChecked(): ACTION.SET_SELECTED_AXIS('MPG0') self.recolorMPGFocusBorder() - else: + else: self.removeMPGFocusBorder() + else: + self.removeMPGFocusBorder() #self.set_statusbar('MPG output Selected: {}'.format(cmd.toolTip()),DEFAULT,noLog=True) self._lastSelectButton = button From 49bcfe7a2ea6048533c2050e4ed1114836df1024 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 3 Apr 2026 18:34:43 -0700 Subject: [PATCH 46/79] gmoccapy -update external pause/start behavior fix pausing in MDI don't toggle pause (only pause not unpause) cycle start will unpause if paused --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 3c5bd167d5b..05a42ba45d4 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -1326,7 +1326,9 @@ def _make_joints_button(self): # halui/external cycle start request def request_start(self,data): print('start request') - if self.stat.task_mode == linuxcnc.MODE_MDI: + if self.GSTAT.is_auto_paused(): + self.command.auto(linuxcnc.AUTO_RESUME) + elif self.stat.task_mode == linuxcnc.MODE_MDI: print('Submit MDI') self.widgets.hal_mdihistory.submit() elif self.stat.task_mode == linuxcnc.MODE_MANUAL: @@ -1338,7 +1340,15 @@ def request_start(self,data): # halui/external pause request def request_pause(self,data): print('pause request') - self.widgets.tbtn_pause.emit('clicked') + + # don't toggle + if self.GSTAT.is_auto_paused(): + return + + if self.stat.task_mode == linuxcnc.MODE_AUTO: + self.widgets.tbtn_pause.emit('clicked') + else: + self.command.auto(linuxcnc.AUTO_PAUSE) # call INI macro (from hal_glib message) def request_macro_call(self, data): From f489432dadc3c9fe604ca5797bd63aef4df87de3 Mon Sep 17 00:00:00 2001 From: CMorley Date: Thu, 9 Apr 2026 17:00:26 -0700 Subject: [PATCH 47/79] gmoccapy -more dialog work wait but don't block code added. entry dialogs now can use halui yes and no responses --- src/emc/usr_intf/gmoccapy/dialogs.py | 172 +++++++++++++++-------- src/emc/usr_intf/gmoccapy/gmoccapy.py | 190 +++++++++++--------------- 2 files changed, 194 insertions(+), 168 deletions(-) diff --git a/src/emc/usr_intf/gmoccapy/dialogs.py b/src/emc/usr_intf/gmoccapy/dialogs.py index a28408d9abe..dc9418f37ad 100644 --- a/src/emc/usr_intf/gmoccapy/dialogs.py +++ b/src/emc/usr_intf/gmoccapy/dialogs.py @@ -36,20 +36,27 @@ class Dialogs(GObject.GObject): __gsignals__ = { 'play_sound': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)), - 'system-dialog-result': (GObject.SignalFlags.RUN_FIRST , GObject.TYPE_NONE, (GObject.TYPE_INT,)), - 'warning-dialog-result': (GObject.SignalFlags.RUN_FIRST , GObject.TYPE_NONE, (GObject.TYPE_INT, GObject.TYPE_STRING)) } def __init__(self, caller): GObject.GObject.__init__(self) self.sys_dialog = self.system_dialog(caller) self.warn_dialog = self.warning_dialog(caller) + self.ent_dialog = self.entry_dialog(caller) + self.yn_dialog = self.yesno_dialog(caller) + # sent from Gstat messages + # first one found visibly gets the answer + # maybe we should check focus? def dialog_ext_control(self, answer): if self.sys_dialog.get_visible(): self.sys_dialog.response(answer) elif self.warn_dialog.get_visible(): self.warn_dialog.response(answer) + elif self.ent_dialog.get_visible(): + self.ent_dialog.response(answer) + elif self.yn_dialog.get_visible(): + self.yn_dialog.response(answer) # This dialog is for unlocking the system tab # The unlock code number is defined at the top of the page @@ -77,66 +84,94 @@ def system_dialog(self, caller): return dialog def show_system_dialog(self): - self.sys_dialog._calc.set_value("") - self.sys_dialog.show_all() + dialog = self.sys_dialog + dialog._calc.set_value("") + dialog.show_all() self.emit("play_sound", "alert") - def on_system_response(self, dialog, result): + # wait but don't block event loop + dialog.RESPONSE = None + while dialog.RESPONSE is None: + while Gtk.events_pending(): + Gtk.main_iteration() + + dialog.hide() + code = dialog._calc.get_value() - print('Code:',code) rtn = -1 - if result == Gtk.ResponseType.ACCEPT: + if dialog.RESPONSE == Gtk.ResponseType.ACCEPT: if code == int(dialog._caller.unlock_code): - print('Yes') rtn = 1 else: - print('No') rtn = 0 - else: - print('Cancelled') - self.emit('system-dialog-result',rtn) - dialog.hide() - def entry_dialog(self, caller, data = None, header = _("Enter value") , label = _("Enter the value to set"), integer = False): - dialog = Gtk.Dialog(header, + return rtn + + def on_system_response(self, dialog, rtn): + dialog.RESPONSE = rtn + + def entry_dialog(self, caller): + dialog = Gtk.Dialog('', caller.widgets.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT) - label = Gtk.Label(label) - label.modify_font(Pango.FontDescription("sans 20")) - label.set_margin_top(15) - calc = gladevcp.Calculator() + dialog.label = Gtk.Label('') + dialog.label.modify_font(Pango.FontDescription("sans 20")) + dialog.label.set_margin_top(15) + dialog.calc = gladevcp.Calculator() content_area = dialog.get_content_area() - content_area.pack_start(child=label, expand=False, fill=False, padding=0) - content_area.add(calc) - if data != None: - calc.set_value(data) - else: - calc.set_value("") - calc.set_property("font", "sans 20") - calc.set_editable(True) - calc.entry.connect("activate", lambda w : dialog.emit("response", Gtk.ResponseType.ACCEPT)) + content_area.pack_start(child=dialog.label, expand=False, fill=False, padding=0) + content_area.add(dialog.calc) + dialog.calc.set_property("font", "sans 20") + dialog.calc.set_editable(True) + dialog.calc.entry.connect("activate", lambda w : self.on_entry_response(dialog, Gtk.ResponseType.ACCEPT)) dialog.parse_geometry("460x400") dialog.set_decorated(True) + dialog.connect("response", self.on_entry_response) + return dialog + + def show_entry_dialog(self, data = None, header = _("Enter value") , + label = _("Enter the value to set"), integer = False): + + dialog = self.ent_dialog + if data != None: + dialog.calc.set_value(data) + else: + dialog.calc.set_value("") if integer: # The user is only allowed to enter integer values, we hide some button - calc.integer_entry_only(True) - calc.num_pad_only(True) + dialog.calc.integer_entry_only(True) + dialog.calc.num_pad_only(True) + dialog.label.set_text(label) + dialog.set_title(header) dialog.show_all() - response = dialog.run() - value = calc.get_value() - dialog.destroy() - if response == Gtk.ResponseType.ACCEPT: + + # wait but don't block event loop + dialog.RESPONSE = None + while dialog.RESPONSE is None: + while Gtk.events_pending(): + Gtk.main_iteration() + + dialog.hide() + + value = dialog.calc.get_value() + if dialog.RESPONSE == Gtk.ResponseType.ACCEPT: if value != None: - if integer: - return int(value) + if dialog.calc.integer_only: + qv = int(value) else: - return float(value) + qv = float(value) else: - return "ERROR" - return "CANCEL" + qv = "ERROR" + else: + qv = "CANCEL" + return qv + + def on_entry_response(self, dialog, rtn): + dialog.RESPONSE = rtn # display warning dialog def warning_dialog(self, caller, message = '', secondary = None, title = _("Operator Message"),\ sound = True, confirm_pin = 'warning-confirm', active_pin = None): + dialog = Gtk.MessageDialog(caller.widgets.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.NONE, message) @@ -167,32 +202,34 @@ def periodic(): dialog.connect("response", self.on_warning_response) return dialog - def show_warning_dialog(self, title, message, context=None, sound=True,\ + def show_warning_dialog(self, title, message, sound=True, confirm_pin = 'warning-confirm', active_pin = None): - print(message,context) - self.warn_dialog.context.append(context) - self.warn_dialog.set_title(title) - self.warn_dialog.format_secondary_text(message) - self.warn_dialog.set_markup(message) - self.warn_dialog.show_all() + dialog = self.warn_dialog + dialog.set_title(title) + dialog.format_secondary_text(message) + dialog.set_markup(message) + dialog.show_all() if sound: self.emit("play_sound", "alert") - print(self.warn_dialog.context) - def on_warning_response(self, dialog, rtn): - context = dialog.context.pop() - print(context) - self.emit('warning-dialog-result', rtn, context) + # wait but don't block event loop + dialog.RESPONSE = None + while dialog.RESPONSE is None: + while Gtk.events_pending(): + Gtk.main_iteration() + dialog.hide() - def yesno_dialog(self, caller, message, title = _("Operator Message")): + return dialog.RESPONSE + + def on_warning_response(self, dialog, rtn): + dialog.RESPONSE = rtn + + def yesno_dialog(self, caller): dialog = Gtk.MessageDialog(caller.widgets.window1, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE) - if title: - dialog.set_title(str(title)) - dialog.set_markup(message) yes_button = Gtk.Button.new_with_mnemonic(_("_Yes")) no_button = Gtk.Button.new_with_mnemonic(_("_No")) yes_button.set_size_request(-1, 56) @@ -206,11 +243,30 @@ def yesno_dialog(self, caller, message, title = _("Operator Message")): box.set_layout(Gtk.ButtonBoxStyle.CENTER) dialog.action_area.add(box) dialog.set_border_width(5) + dialog.connect("response", self.on_yn_response) + return dialog + + def show_yesno_dialog(self, caller, message, title = _("Operator Message")): + dialog = self.yn_dialog + dialog.set_markup(message) + if title: + dialog.set_title(str(title)) dialog.show_all() self.emit("play_sound", "alert") - response = dialog.run() - dialog.destroy() - return response == Gtk.ResponseType.YES + + # wait but don't block event loop + dialog.RESPONSE = None + while dialog.RESPONSE is None: + while Gtk.events_pending(): + Gtk.main_iteration() + + rtn = dialog.RESPONSE + dialog.hide() + return bool(rtn in(Gtk.ResponseType.YES, Gtk.ResponseType.ACCEPT)) + + # update internal variable so dialog will respond + def on_yn_response(self,dialog, rtn): + dialog.RESPONSE = rtn def show_user_message(self, caller, message, title = _("Operator Message")): dialog = Gtk.MessageDialog(caller.widgets.window1, diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 05a42ba45d4..ab27cab9123 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -352,8 +352,6 @@ def __init__(self, argv): self.dialogs = dialogs.Dialogs(caller = self) self.dialogs.connect("play_sound", self._on_play_sound) - self.dialogs.connect('system-dialog-result', self.system_dialog_return) - self.dialogs.connect('warning-dialog-result', self.warning_dialog_return) # this are settings to be done before window show self._init_preferences() @@ -1365,7 +1363,7 @@ def request_macro_call(self, data): if not self.GSTAT.is_mdi_mode(): message = _("You must be in MDI mode to run macros") self.dialogs.show_warning_dialog( _("Important Warning!"), - message, context=None) + message) return # look thru the INI macros @@ -1385,7 +1383,7 @@ def request_macro_call(self, data): # didn't match a name - give a hint message = _("Macro {} not found ".format(data)) self.dialogs.show_warning_dialog( _("Important Warning!"), - message, context=None) + message) # check if macros are in the INI file and add them to MDI Button List def _make_macro_button(self): @@ -1564,8 +1562,8 @@ def _make_lathe(self): message += _("an X and an Z axis\n") message += _("Wrong lathe configuration, we will leave here") self.dialogs.show_warning_dialog( _("Very critical situation"), - message, context='systemexit') - return + message) + sys.exit() else: if not len(self.axis_list) == 2 and not len(self.axis_list) < 6: self._arrange_jog_button_by_axis() @@ -2016,8 +2014,8 @@ def _init_tooleditor(self): message = _("Did not find a toolfile file in [EMCIO] TOOL_TABLE") LOG.error(message) self.dialogs.show_warning_dialog( _("Very critical situation"), - message, context='systemexit') - return + message) + sys.exit() toolfile = os.path.join(CONFIGPATH, tooltable) self.widgets.tooledit1.set_filename(toolfile) # first we hide all the axis columns the unhide the ones we want @@ -2173,15 +2171,15 @@ def on_tool_col_edit_started(self, widget, filtered_path, new_text, col): toolpage = self.widgets.tooledit1 toolview = toolpage.view1 model, treeiter = toolview.get_selection().get_selected() - value = self.dialogs.entry_dialog(self, - data=model[treeiter][col], + value = self.dialogs.show_entry_dialog(data=model[treeiter][col], header=_("Enter value"), label=_("Tool") + f" {model[treeiter][1]}, {captations[col]}:", integer=col in [1,2,15]) + if value == "ERROR": LOG.debug("conversion error") - self.dialogs.warning_dialog(self, _("Conversion error !"), - ("Please enter only numerical values\nValues have not been applied")) + self.dialogs.warning_dialog(_("Conversion error !"), + ("Please enter only numerical values\nValues have not been applied")) elif value == "CANCEL": pass else: @@ -2477,8 +2475,8 @@ def _init_offsetpage(self): message = _("Did not find a parameter file in [RS274NGC] PARAMETER_FILE") LOG.error(message) self.dialogs.show_warning_dialog( _("Very critical situation"), - message, context='systemexit') - return + message) + sys.exit() path = os.path.join(CONFIGPATH, parameterfile) self.widgets.offsetpage1.set_filename(path) @@ -2576,12 +2574,13 @@ def on_offset_col_edit_started(self, widget, filtered_path, new_text, col): path = offsetpage.modelfilter.get_path(treeiter) (store_path,) = offsetpage.modelfilter.convert_path_to_child_path(path) row = store_path - if self.widgets.offsetpage1.btn_edit_offsets.get_active(): - offset = self.dialogs.entry_dialog(self, - data=offsetpage.store[row][col], + if self.widgets.offsetpage1.btn_edit_offsets.get_active() or \ + if self.touch_button_dic["edit_offsets"].get_active(): + value = self.dialogs.show_entry_dialog(data=offsetpage.store[row][col], header=_("Enter value for offset"), label=f"{offsetpage.store[row][0]} {AXISLIST[col]}-" + _("offset:"), integer=False) + if offset == "ERROR": LOG.debug("conversion error") self.dialogs.warning_dialog(self, _("Conversion error !"), @@ -2733,7 +2732,7 @@ def _show_user_message(self, pin, message): self.halcomp["messages." + message[2] + "-waiting"] = 1 self.halcomp["messages." + message[2] + "-response"] = 0 title = "Pin " + message[2] + " message" - response = self.dialogs.yesno_dialog(self, message[0], title) + response = self.dialogs.show_yesno_dialog(self, message[0], title) self.halcomp["messages." + message[2] + "-waiting"] = 0 self.halcomp["messages." + message[2] + "-response"] = response else: @@ -3241,13 +3240,14 @@ def on_hal_status_mode_mdi(self, widget): self.last_key_event = None, 0 def on_mdi_calculation_start(self, *args): - position = self.widgets.hal_mdihistory.entry.get_position() - print("position: ", position) - value = self.dialogs.entry_dialog(self, + value = self.dialogs.show_entry_dialog( data=self.widgets.hal_mdihistory.entry.get_text(), header=_("Enter value"), label=_("Calculate value to insert"), integer=False) + + position = self.widgets.hal_mdihistory.entry.get_position() + if value == "ERROR": LOG.debug("conversion error") self.dialogs.warning_dialog(self, _("Conversion error !"), @@ -3453,8 +3453,9 @@ def _on_btn_macro_pressed( self, widget = None, data = None ): command = str( "O<" + o_codes[0] + "> call" ) for code in o_codes[1:]: - parameter = self.dialogs.entry_dialog(self, data=None, header=_("Enter value:"), + parameter = self.dialogs.show_entry_dialog(data=None, header=_("Enter value:"), label=f"{code}:", integer=False) + if parameter == "ERROR": LOG.debug("conversion error") self.dialogs.warning_dialog(self, _("Conversion error !"), @@ -4307,9 +4308,12 @@ def on_tbtn_setup_toggled(self, widget, data=None): code = True # else we ask for the code using the system.dialog if self.widgets.rbt_use_unlock.get_active(): - self.dialogs.show_system_dialog() - # we will wait for response - return + code = self.dialogs.show_system_dialog() + # cancelled? + if code == -1: + self.widgets.tbtn_setup.set_active(False) + widget.set_image(self.widgets.img_settings) + return # Lets see if the user has the right to enter settings if code: self.widgets.ntb_main.set_current_page(1) @@ -4321,7 +4325,7 @@ def on_tbtn_setup_toggled(self, widget, data=None): message = _("Hal Pin is low, Access denied") else: message = _("wrong code entered, Access denied") - self.dialogs.warning_dialog(self, _("Just to warn you"), message) + self.dialogs.show_warning_dialog(_("Just to warn you"), message) self.widgets.tbtn_setup.set_active(False) widget.set_image(self.widgets.img_settings) else: @@ -4359,52 +4363,6 @@ def on_tbtn_setup_toggled(self, widget, data=None): widget.set_image(self.widgets.img_settings) - # return code from system dialog - def system_dialog_return(self,widget,result): - print('System ->',widget,result) - # Lets see if the user has the right to enter settings - if result == 1: - self.widgets.ntb_main.set_current_page(1) - self.widgets.ntb_setup.set_current_page(0) - self.widgets.ntb_button.set_current_page(_BB_SETUP) - self.widgets.tbtn_setup.set_image(self.widgets.img_settings_on) - elif result == 0: - if self.widgets.rbt_hal_unlock.get_active(): - message = _("Hal Pin is low, Access denied") - else: - message = _("wrong code entered, Access denied") - self.dialogs.show_warning_dialog( _("Just to warn you"), message, context='sytemunlockfail') - # we will wait for response - - - - # return code from system dialog - def warning_dialog_return(self,widget,result,context): - print('Warning ->',widget,result,context) - if context is None: - return - - if context == 'systemunlockfail': - self.widgets.tbtn_setup.set_active(False) - self.widgets.tbtn_setup.set_image(self.widgets.img_settings) - elif context == 'systemexit': - sys.exit() - - elif context == 'mantoolchange': - if result: - self.halcomp["toolchange-changed"] = True - else: - LOG.debug("toolchange abort {0} {1}".format(self.stat.tool_in_spindle, self.halcomp['toolchange-number'])) - self.command.abort() - self.halcomp['toolchange-number'] = self.stat.tool_in_spindle - self.halcomp['toolchange-change'] = False - self.halcomp['toolchange-changed'] = True - message = _("Tool Change has been aborted!\n") - message += _("The old tool will remain set!") - self.dialogs.show_warning_dialog( _("Just to warn you"), - message, context=None) - - # Show or hide the user tabs def on_tbtn_user_tabs_toggled(self, widget, data=None): if widget.get_active(): @@ -4524,7 +4482,7 @@ def on_btn_classicladder_clicked(self, widget, data=None): p = os.popen("classicladder &", "w") else: self.dialogs.show_warning_dialog(_("INFO:"), - _("Classicladder real-time component not detected"), context='classicfail') + _("Classicladder real-time component not detected")) # ========================================================= # spindle stuff @@ -4818,7 +4776,7 @@ def on_btn_delete_clicked(self, widget, data=None): message = _("Do you really want to delete the MDI history?\n") message += _("This will not delete the MDI History file, but will\n" "delete the listbox entries for this session.") - result = self.dialogs.yesno_dialog(self, message, _("Attention!!")) + result = self.dialogs.show_yesno_dialog(self, message, _("Attention!!")) if result: self.widgets.hal_mdihistory.model.clear() @@ -4832,15 +4790,14 @@ def on_btn_show_calc_clicked(self, widget): text = mdi_entry.get_text() data = text[bounds[0]:bounds[1]] has_selection = True - value = self.dialogs.entry_dialog(self, - data=data, + value = self.dialogs.show_entry_dialog(data=data, header=_("Enter value"), label=_("Calculate value to insert"), integer=False) if value == "ERROR": LOG.debug("conversion error") - self.dialogs.show_warning_dialog(_("INFO:"), - _("Please enter only numerical values\nValues have not been applied"), context=None) + self.dialogs.show_warning_dialog(_("Conversion error !"), + ("Please enter only numerical values\nValues have not been applied")) elif value == "CANCEL": return else: @@ -4858,15 +4815,14 @@ def on_btn_show_calc_clicked(self, widget): bounds = buffer.get_selection_bounds() data = buffer.get_text(bounds[0],bounds[1],False) has_selection = True - value = self.dialogs.entry_dialog(self, - data=data, + value = self.dialogs.show_entry_dialog(data=data, header=_("Enter value"), label=_("Calculate value to insert"), integer=False) if value == "ERROR": LOG.debug("conversion error") - self.dialogs.show_warning_dialog(_("INFO:"), - _("Please enter only numerical values\nValues have not been applied"), context=None) + self.dialogs.show_warning_dialog(_("Conversion error !"), + ("Please enter only numerical values\nValues have not been applied")) elif value == "CANCEL": return else: @@ -4925,7 +4881,7 @@ def on_btn_back_clicked(self, widget, data=None): if self.widgets.ntb_button.get_current_page() == _BB_EDIT: # edit mode, go back to auto_buttons if self.file_changed: message = _("Exit and discard changes?") - result = self.dialogs.yesno_dialog(self, message, _("Attention!")) + result = self.dialogs.show_yesno_dialog(self, message, _("Attention!")) if not result: # user says no, he want to save return self.widgets.ntb_button.set_current_page(_BB_AUTO) @@ -4938,7 +4894,7 @@ def on_btn_back_clicked(self, widget, data=None): else: # else we go to main button on manual if self.widgets.tooledit1.edited: message = _("Discard unsaved changes and exit?") - result = self.dialogs.yesno_dialog(self, message, _("Attention!")) + result = self.dialogs.show_yesno_dialog(self, message, _("Attention!")) if not result: # user says no, he want to save return # check if offset values for current tool have been changed @@ -4960,7 +4916,7 @@ def on_btn_back_clicked(self, widget, data=None): "Do you want to activate tool compensation (G43)\n" \ "using the currently active tool offset?") if message: - result = self.dialogs.yesno_dialog(self, message, _("Attention!")) + result = self.dialogs.show_yesno_dialog(self, message, _("Attention!")) if result: # user says YES self.command.mode(linuxcnc.MODE_MDI) self.command.wait_complete() @@ -5038,22 +4994,22 @@ def _on_btn_set_value_clicked(self, widget, data=None): if self.lathe_mode and axis =="x": if self.diameter_mode: preset = self.prefs.getpref("diameter offset_axis_{0}".format(axis), 0, float) - offset = self.dialogs.entry_dialog(self, data=preset, header=_("Enter value for diameter"), + offset = self.dialogs.show_entry_dialog(data=preset, header=_("Enter value for diameter"), label=_("Set diameter to:"), integer=False) else: preset = self.prefs.getpref("radius offset_axis_{0}".format(axis), 0, float) - offset = self.dialogs.entry_dialog(self, data=preset, header=_("Enter value for radius"), + offset = self.dialogs.show_entry_dialog(data=preset, header=_("Enter value for radius"), label=_("Set radius to:"), integer=False) else: preset = self.prefs.getpref("offset_axis_{0}".format(axis), 0, float) - offset = self.dialogs.entry_dialog(self, data=preset, header=_("Enter value for axis {0}").format(axis.upper()), + offset = self.dialogs.show_entry_dialog(data=preset, header=_("Enter value for axis {0}").format(axis.upper()), label=_("Set axis {0} to:").format(axis.upper()), integer=False) if offset == "CANCEL": return elif offset == "ERROR": LOG.debug("Conversion error in btn_set_value") self.dialogs.show_warning_dialog(_("Conversion error in btn_set_value!"), - _("Please enter only numerical values\nValues have not been applied"), context=None) + _("Please enter only numerical values\nValues have not been applied")) else: self.command.mode(linuxcnc.MODE_MDI) self.command.wait_complete() @@ -5075,7 +5031,7 @@ def _on_btn_set_selected_clicked(self, widget, data=None): if system not in ["G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3"]: message = _("You did not select a system to be changed to, so nothing will be changed") self.dialogs.show_warning_dialog(_("Important Warning!"), - message, context=None) + message) return if system == self.system_list[self.stat.g5x_index]: return @@ -5125,7 +5081,7 @@ def on_chk_reload_tool_toggled(self, widget, data=None): def on_btn_block_height_clicked(self, widget, data=None): probeheight = self.widgets.spbtn_probe_height.get_value() preset = self.prefs.getpref("blockheight", 0.0, float) - blockheight = self.dialogs.entry_dialog(self, data=preset, header=_("Enter the block height"), + blockheight = self.dialogs.show_entry_dialog(data=preset, header=_("Enter the block height"), label=_("Block height measured from base table"), integer=False) if blockheight == "CANCEL" or blockheight == "ERROR": @@ -5139,7 +5095,7 @@ def on_btn_block_height_clicked(self, widget, data=None): self.prefs.putpref("blockheight", 0.0, float) self.prefs.putpref("probeheight", 0.0, float) self.dialogs.show_warning_dialog(_("Conversion error in btn_block_height!"), - _("Please enter only numerical values\nValues have not been applied"), context=None) + _("Please enter only numerical values\nValues have not been applied")) # set coordinate system to new origin origin = self.get_ini_info.get_axis_2_min_limit() + blockheight @@ -5168,7 +5124,7 @@ def _set_icon_theme(self, name): # Switching to none required a restart (skip entire icon theme stuff) message = "Change to no icon theme requires a restart to take effect." self.dialogs.show_warning_dialog( _("Just to warn you"), - message, context=None) + message) else: self.icon_theme.set_custom_theme(name) @@ -5713,10 +5669,24 @@ def on_tool_change(self, widget): except: message = _("Tool\n\n# {0:d}\n\n not in the tool table!").format(toolnumber) - self.dialogs.show_warning_dialog( _("Manual Tool change"), + result = self.dialogs.show_warning_dialog( _("Manual Tool change"), message, context='mantoolchange', confirm_pin = 'toolchange-confirm', active_pin = 'toolchange-change') + + if result: + self.halcomp["toolchange-changed"] = True + else: + LOG.debug("toolchange abort {0} {1}".format(self.stat.tool_in_spindle, self.halcomp['toolchange-number'])) + self.command.abort() + self.halcomp['toolchange-number'] = self.stat.tool_in_spindle + self.halcomp['toolchange-change'] = False + self.halcomp['toolchange-changed'] = True + message = _("Tool Change has been aborted!\n") + message += _("The old tool will remain set!") + self.dialogs.show_warning_dialog( _("Just to warn you"), + message) + else: self.halcomp['toolchange-changed'] = False @@ -5726,7 +5696,7 @@ def on_btn_delete_tool_clicked(self, widget, data=None): message = _("You are trying to delete the tool mounted in the spindle\n") message += _("This is not allowed, please change tool prior to delete it") self.dialogs.show_warning_dialog( _("Warning Tool can not be deleted!"), - message, context=None) + message) return self.widgets.tooledit1.delete_selected_row(widget) self.widgets.tooledit1.edited = True @@ -5738,7 +5708,7 @@ def on_btn_add_tool_clicked(self, widget, data=None): def on_btn_reload_tooltable_clicked(self, widget, data=None): if self.widgets.tooledit1.edited: message = _("Discard unsaved changes and reload the table?") - result = self.dialogs.yesno_dialog(self, message, _("Attention!")) + result = self.dialogs.show_yesno_dialog(self, message, _("Attention!")) if not result: # user says no, he want to save return self.widgets.tooledit1.reload(None) @@ -5755,14 +5725,14 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): message = _("No tool selected in the tool table. ") message += _("Please select only one tool in the table!") self.dialogs.show_warning_dialog( _("Warning Tool Touch off not possible!"), - message, context=None) + message) return if tool != self.stat.tool_in_spindle: message = _("You can not touch off a tool, which is not mounted in the spindle! ") message += _("Your selection has been reset to the tool in spindle.") self.dialogs.show_warning_dialog( _("Warning Tool Touch off not possible!"), - message, context=None) + message) self.widgets.tooledit1.reload(self) self.widgets.tooledit1.set_selected_tool(self.stat.tool_in_spindle) return @@ -5771,7 +5741,7 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): message = _("Tool touch off is not possible with cutter radius compensation switched on!\n") message += _("Please emit an G40 before tool touch off.") self.dialogs.show_warning_dialog( _("Warning Tool Touch off not possible!"), - message, context=None) + message) return if widget == self.widgets.btn_tool_touchoff_x: @@ -5780,10 +5750,10 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): axis = "z" else: self.dialogs.show_warning_dialog(_("Real big error!"), - _("You managed to come to a place that is not possible in on_btn_tool_touchoff"), context=None) + _("You managed to come to a place that is not possible in on_btn_tool_touchoff")) return - value = self.dialogs.entry_dialog(self, data=None, + value = self.dialogs.show_entry_dialog(data=None, header=_("Enter value for axis {0} to set:").format(axis.upper()), label=_("Set parameter of tool {0:d} and axis {1} to:").format(self.stat.tool_in_spindle, axis.upper()), integer=False) @@ -5791,7 +5761,7 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): if value == "ERROR": message = _("Conversion error because of wrong entry for touch off axis {0}").format(axis.upper()) self.dialogs.show_warning_dialog( _("Conversion error !"), - message, context=None) + message) return elif value == "CANCEL": return @@ -5811,23 +5781,23 @@ def on_btn_tool_touchoff_clicked(self, widget, data=None): def on_btn_select_tool_by_no_clicked(self, widget, data=None): if self.widgets.tooledit1.edited: message = _("Discard unsaved changes and change tool?") - result = self.dialogs.yesno_dialog(self, message, _("Attention!")) + result = self.dialogs.show_yesno_dialog(self, message, _("Attention!")) if not result: # user says no, he want to save return - value = self.dialogs.entry_dialog(self, data=None, header=_("Enter the tool number as integer "), + value = self.dialogs.show_entry_dialog(data=None, header=_("Enter the tool number as integer "), label=_("Select the tool to change"), integer=True) if value == "ERROR": message = _("Conversion error because of wrong entry for tool number.\n") message += _("Enter only integer numbers!") self.dialogs.show_warning_dialog( _("Conversion error !"), - message, context=None) + message) return elif value == "CANCEL": return elif int(value) == self.stat.tool_in_spindle: message = _("Selected tool is already in spindle, no change needed.") self.dialogs.show_warning_dialog( _("Important Warning!"), - message, context=None) + message) return else: self.tool_change = True @@ -5842,19 +5812,19 @@ def on_btn_select_tool_by_no_clicked(self, widget, data=None): def on_btn_selected_tool_clicked(self, widget, data=None): if self.widgets.tooledit1.edited: message = _("Discard unsaved changes and change tool?") - result = self.dialogs.yesno_dialog(self, message, _("Attention!")) + result = self.dialogs.show_yesno_dialog(self, message, _("Attention!")) if not result: # user says no, he want to save return tool = self.widgets.tooledit1.get_selected_row() if tool == None: message = _("you selected no or more than one tool, the tool selection must be unique") self.dialogs.show_warning_dialog( _("Important Warning!"), - message, context=None) + message) return if tool == self.stat.tool_in_spindle: message = _("Selected tool is already in spindle, no change needed.") self.dialogs.show_warning_dialog( _("Important Warning!"), - message, context=None) + message) return if tool or tool == 0: self.tool_change = True @@ -5873,7 +5843,7 @@ def on_btn_selected_tool_clicked(self, widget, data=None): else: message = _("Could not understand the entered tool number. Will not change anything!") self.dialogs.show_warning_dialog( _("Important Warning!"), - message, context=None) + message) # ========================================================= From f730ecf32a9e3b8811c4fa971b444691ad58fba2 Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 10 Apr 2026 13:38:30 -0700 Subject: [PATCH 48/79] halui -add an angular jograte pin and send angular jograte messages halui doesn't use the angular jograte in it's jogging yet but will tell the gui the jograte has changed --- src/emc/usr_intf/halui.cc | 79 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 638b2d46b1f..8d18f0cecda 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -162,6 +162,7 @@ static int axis_mask = 0; ARRAY(hal_bit_t,jjog_increment_minus,EMCMOT_MAX_JOINTS+1) /* Incremental jogging, negative direction */ \ \ FIELD(hal_float_t,ajog_speed) /* pin for setting the jog speed (halui internal) */ \ + FIELD(hal_float_t,ajog_speed_angular) /* pin for setting the angular jog speed (halui internal) */ \ ARRAY(hal_bit_t,ajog_minus,EMCMOT_MAX_AXIS+1) /* pin to jog in positive direction */ \ ARRAY(hal_bit_t,ajog_plus,EMCMOT_MAX_AXIS+1) /* pin to jog in negative direction */ \ ARRAY(hal_float_t,ajog_analog,EMCMOT_MAX_AXIS+1) /* pin for analog jogging (-1..0..1) */ \ @@ -254,6 +255,8 @@ static local_halui_str old_halui_data; static double lastjogspeed = 0; static double internaljogspeed = 0; +static double lastangularjogspeed = 0; +static double internalangularjogspeed = 0; static int lastaxis = -1; static char *mdi_commands[MDI_MAX]; @@ -1059,6 +1062,8 @@ int halui_hal_init(void) retval = halui_export_pin_IN_float(&(halui_data->ajog_speed), "halui.axis.jog-speed"); if (retval < 0) return retval; + retval = halui_export_pin_IN_float(&(halui_data->ajog_speed_angular), "halui.axis.jog-speed-angular"); + if (retval < 0) return retval; retval = halui_export_pin_IN_float(&(halui_data->ajog_deadband), "halui.axis.jog-deadband"); if (retval < 0) return retval; @@ -1711,6 +1716,7 @@ static void hal_init_pins() *(halui_data->ajog_increment_minus[EMCMOT_MAX_AXIS]) = old_halui_data.ajog_increment_minus[EMCMOT_MAX_AXIS] = 0; *(halui_data->ajog_deadband) = 0.2; *(halui_data->ajog_speed) = 0; + *(halui_data->ajog_speed_angular) = 0; *(halui_data->joint_selected) = 0; // select joint 0 by default *(halui_data->axis_selected) = -1; // select no axis by default @@ -1814,9 +1820,55 @@ static void py_call_axis_jogspeed(double speed) Py_DECREF(pFuncWrite); } +static double py_call_axis_get_angular_jogspeed() { + double jspd = 0; + // check socket messages for angular jogspeed + pFuncRead = PyObject_GetAttrString(pInstance, "getJogRateAngular"); + if (pFuncRead && PyCallable_Check(pFuncRead)) { + pValue = PyObject_CallNoArgs(pFuncRead); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: getJogRateAngular function failed: returned NULL\n"); + jspd = 0; + }else{ + if (PyFloat_Check(pValue)) { + jspd = PyFloat_AsDouble(pValue); + if (PyErr_Occurred()) { + jspd = 0; + // Handle conversion error + PyErr_Print(); + // Clear the error state if needed + PyErr_Clear(); + } + } + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncRead); + return jspd; +} + +static void py_call_axis_angular_jogspeed(double speed) +{ + pFuncWrite = PyObject_GetAttrString(pInstance, "setJogRateAngular"); + + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallFunction(pFuncWrite, "d", speed); + if (pValue == NULL){ + fprintf(stderr, "halui bridge: setJogRateAngular function failed: returned NULL\n"); + if (PyErr_Occurred()) PyErr_Print(); + } + Py_DECREF(pValue); + + }else{ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "halui Bridge: Failed python function"); + } + Py_DECREF(pFuncWrite); +} + static int py_call_get_axis_selected() { int value = 0; - // check socket messages for jogspeed + // check socket messages for selected axis pFuncRead = PyObject_GetAttrString(pInstance, "getSelectedAxis"); if (pFuncRead && PyCallable_Check(pFuncRead)) { pValue = PyObject_CallNoArgs(pFuncRead); @@ -1892,8 +1944,10 @@ static void check_hal_changes() int js; hal_float_t floatt; double jogspeed; + double angularjogspeed; int jjog_speed_changed; int ajog_speed_changed; + int ajog_speed_angular_changed; int is_any_axis_selected, deselected; // get python to process socket messages @@ -2160,6 +2214,7 @@ static void check_hal_changes() } else { jjog_speed_changed = 0; } + // axis stuff (selection, homing..) aselect_changed = -1; // flag to see if the selected joint changed @@ -2183,7 +2238,27 @@ static void check_hal_changes() fprintf(stderr, "JogRate value = %f\n", jogspeed ); } - + // if the ANGULAR jog-speed changes while in a continuous jog, we want to + // re-start the jog with the new speed + if (fabs(old_halui_data.ajog_speed_angular - new_halui_data.ajog_speed_angular) > 0.00001) { + old_halui_data.ajog_speed_angular = new_halui_data.ajog_speed_angular; + internalangularjogspeed = new_halui_data.ajog_speed_angular; + ajog_speed_angular_changed = 1; + py_call_axis_angular_jogspeed(internalangularjogspeed); + } else { + ajog_speed_angular_changed = 0; + } + + // check socket messages for ANGULAR jogspeed + angularjogspeed = py_call_axis_get_angular_jogspeed(); + if (fabs(angularjogspeed - lastangularjogspeed) > 0.00001) { + ajog_speed_angular_changed = 1; + lastangularjogspeed = angularjogspeed; + internalangularjogspeed = angularjogspeed; + fprintf(stderr, "angular JogRate value = %f\n", angularjogspeed ); + } + + for (joint=0; joint < num_joints; joint++) { if (check_bit_changed(new_halui_data.joint_home[joint], old_halui_data.joint_home[joint]) != 0) sendHome(joint); From 4729efa99c3fc2ded64fa2a7aef4092f71771caf Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 10 Apr 2026 13:40:16 -0700 Subject: [PATCH 49/79] gladevcp -speedcontrol -add angular jograte type automatically sends and responds to jograte messages --- lib/python/gladevcp/speedcontrol.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/python/gladevcp/speedcontrol.py b/lib/python/gladevcp/speedcontrol.py index 5dda24b65a3..a30cc26dd3b 100755 --- a/lib/python/gladevcp/speedcontrol.py +++ b/lib/python/gladevcp/speedcontrol.py @@ -100,8 +100,8 @@ class SpeedControl(Gtk.Box, _HalSpeedControlBase): "%.1f", GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT), 'do_hide_button' : ( GObject.TYPE_BOOLEAN, 'Hide the button', 'Display the button + and - to alter the values', False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT), - 'type' : ( GObject.TYPE_INT, 'Type of adjustment', 'Set to -1 for general, 0 for jograte', - -1, 0, -1, GObject.ParamFlags.READWRITE|GObject.ParamFlags.CONSTRUCT), + 'type' : ( GObject.TYPE_INT, 'Type of adjustment', 'Set to -1 for general, 0 for jograte, 1 for angular jograte', + -1, 1, -1, GObject.ParamFlags.READWRITE|GObject.ParamFlags.CONSTRUCT), } __gproperties = __gproperties__ @@ -131,6 +131,7 @@ def __init__(self, size = 36, value = 0, min = 0, max = 100, inc_speed = 100, un self._template = template self._speed = inc_speed self.type_linear_jog = False + self.type_angular_jog = False self.adjustment = Gtk.Adjustment(value = self._value, lower = self._min, upper = self._max, step_increment = self._increment, page_increment = 0) self.adjustment.connect("value_changed", self._on_value_changed) @@ -184,8 +185,11 @@ def _hal_init(self): self.hal_pin_decrease.connect("value-changed", self._on_minus_changed) if self.type_linear_jog: - print('->>',self.type_linear_jog) + print('linear jograte ->>',self.type_linear_jog) self._status.connect('jograte-changed', lambda w, data: self.set_value(data)) + elif self.type_angular_jog: + print('Angular jograte ->>',self.type_angular_jog) + self._status.connect('jograte-angular-changed', lambda w, data: self.set_value(data)) # this draws our widget on the screen def expose(self, widget, event): @@ -472,6 +476,10 @@ def do_set_property(self, property, value): print(name,value) if value == 0: self.type_linear_jog = True + self.type_angular_jog = False + elif value == 1: + self.type_linear_jog = False + self.type_angular_jog = True self._draw_widget() else: raise AttributeError('unknown property %s' % property.name) From b899b46c5c0cc750c9ef5c61c81d0b858ee1939d Mon Sep 17 00:00:00 2001 From: CMorley Date: Fri, 10 Apr 2026 13:41:47 -0700 Subject: [PATCH 50/79] gmoccapy -update the angular speedcontrol to new angular type --- src/emc/usr_intf/gmoccapy/gmoccapy.glade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.glade b/src/emc/usr_intf/gmoccapy/gmoccapy.glade index efe301beca8..622a1cc2c4c 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.glade +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.glade @@ -1457,7 +1457,7 @@ uncomment selection rgb(255,129,22) 3600 %.d - 0 + 1 °/min 360 From c957a2df1ecbc92c81816863d8774199c458aaba Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 12 Apr 2026 10:07:58 -0700 Subject: [PATCH 51/79] gladevcp -speedcontrol: add angular jograte command forgot to add the command to output the rate whenn \the widget is changed --- lib/python/gladevcp/speedcontrol.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/python/gladevcp/speedcontrol.py b/lib/python/gladevcp/speedcontrol.py index a30cc26dd3b..36cde39a08e 100755 --- a/lib/python/gladevcp/speedcontrol.py +++ b/lib/python/gladevcp/speedcontrol.py @@ -285,8 +285,11 @@ def get_value(self): # we are not sync, so def _on_value_changed(self, widget): value = widget.get_value() + if self.type_linear_jog: self._action.SET_JOG_RATE(value) + elif self.type_angular_jog: + self._action.SET_JOG_RATE_ANGULAR(value) if value != self._value: self._value = value From 00a064aba360c124f882129882e8af7351300c9e Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 12 Apr 2026 10:15:33 -0700 Subject: [PATCH 52/79] halui -use angular jograte pin/messages for angular axis now checks for axis type and uses the apropriate jograte --- lib/python/bridgeui/bridge.py | 9 ++++ src/emc/usr_intf/halui.cc | 98 ++++++++++++++++++++++++++++------- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index 56577ebb664..1d0edfaeddd 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -227,6 +227,15 @@ def isAxisSelected(self, index): letter = 'XYZABCUVW'[index] return int(self.axesSelected[letter]) + def getAxisIndexType(self, axis): + try: + num = self.INFO.GET_JOINT_NUM_FROM_AXIS_INDEX[axis] + flag = self.INFO.JOINT_TYPE_INT[num] + return flag + except: + return 1 + + def __getitem__(self, item): return getattr(self, item) def __setitem__(self, item, value): diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 8d18f0cecda..c9daf4ae1a0 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -257,6 +257,7 @@ static double lastjogspeed = 0; static double internaljogspeed = 0; static double lastangularjogspeed = 0; static double internalangularjogspeed = 0; +static double tempjogspeed = 0; static int lastaxis = -1; static char *mdi_commands[MDI_MAX]; @@ -643,7 +644,7 @@ static int py_call_get_mdi_count() { return value; } -// turns a undex number into a macro name +// turns a index number into a macro name static char* py_call_get_mdi_name( int num) { pFuncWrite = PyObject_GetAttrString(pInstance, "getMdiName"); @@ -1933,6 +1934,35 @@ static void py_call_request_MDI( int index) Py_DECREF(pFuncWrite); } +static int py_call_get_axis_type( int index) { + int value = 0; + // check socket messages for selected axis + pFuncRead = PyObject_GetAttrString(pInstance, "getAxisIndexType"); + if (pFuncRead && PyCallable_Check(pFuncRead)) { + pValue = PyObject_CallFunction(pFuncRead, "i", index); + if (pValue == NULL){ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "Halui Bridge: getSelectAxis function failed: returned NULL\n"); + value = -1; + }else{ + if (PyLong_Check(pValue)) { + value = (int) PyLong_AsLong(pValue); + //fprintf(stderr, "axis value %d\n",value); + if (PyErr_Occurred()) { + value = -1; + // Handle conversion error + PyErr_Print(); + // Clear the error state if needed + PyErr_Clear(); + } + } + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncRead); + return value; +} + // this function looks if any of the hal pins has changed // and sends appropriate messages if so static void check_hal_changes() @@ -1947,7 +1977,6 @@ static void check_hal_changes() double angularjogspeed; int jjog_speed_changed; int ajog_speed_changed; - int ajog_speed_angular_changed; int is_any_axis_selected, deselected; // get python to process socket messages @@ -2243,16 +2272,16 @@ static void check_hal_changes() if (fabs(old_halui_data.ajog_speed_angular - new_halui_data.ajog_speed_angular) > 0.00001) { old_halui_data.ajog_speed_angular = new_halui_data.ajog_speed_angular; internalangularjogspeed = new_halui_data.ajog_speed_angular; - ajog_speed_angular_changed = 1; + ajog_speed_changed = 1; py_call_axis_angular_jogspeed(internalangularjogspeed); } else { - ajog_speed_angular_changed = 0; + ajog_speed_changed = 0; } // check socket messages for ANGULAR jogspeed angularjogspeed = py_call_axis_get_angular_jogspeed(); if (fabs(angularjogspeed - lastangularjogspeed) > 0.00001) { - ajog_speed_angular_changed = 1; + ajog_speed_changed = 1; lastangularjogspeed = angularjogspeed; internalangularjogspeed = angularjogspeed; fprintf(stderr, "angular JogRate value = %f\n", angularjogspeed ); @@ -2346,11 +2375,18 @@ static void check_hal_changes() if ( !(axis_mask & (1 << axis_num)) ) { continue; } + // check for axis type: linear/rotary + if (py_call_get_axis_type(axis_num) == 1){ + tempjogspeed = internaljogspeed; + }else{ + tempjogspeed = internalangularjogspeed; + } + // axis jog - bit = new_halui_data.ajog_minus[axis_num]; if ((bit != old_halui_data.ajog_minus[axis_num]) || (bit && ajog_speed_changed)) { if (bit != 0) - sendJogCont(axis_num,-internaljogspeed,JOGTELEOP); + sendJogCont(axis_num,-tempjogspeed,JOGTELEOP); else sendJogStop(axis_num,JOGTELEOP); old_halui_data.ajog_minus[axis_num] = bit; @@ -2360,7 +2396,7 @@ static void check_hal_changes() bit = new_halui_data.ajog_plus[axis_num]; if ((bit != old_halui_data.ajog_plus[axis_num]) || (bit && ajog_speed_changed)) { if (bit != 0) - sendJogCont(axis_num,internaljogspeed,JOGTELEOP); + sendJogCont(axis_num,tempjogspeed,JOGTELEOP); else sendJogStop(axis_num,JOGTELEOP); old_halui_data.ajog_plus[axis_num] = bit; @@ -2371,7 +2407,7 @@ static void check_hal_changes() bit = (fabs(floatt) > new_halui_data.ajog_deadband); if ((floatt != old_halui_data.ajog_analog[axis_num]) || (bit && ajog_speed_changed)) { if (bit) - sendJogCont(axis_num,(internaljogspeed) * (new_halui_data.ajog_analog[axis_num]),JOGTELEOP); + sendJogCont(axis_num,(tempjogspeed) * (new_halui_data.ajog_analog[axis_num]),JOGTELEOP); else sendJogStop(axis_num,JOGTELEOP); old_halui_data.ajog_analog[axis_num] = floatt; @@ -2381,7 +2417,7 @@ static void check_hal_changes() bit = new_halui_data.ajog_increment_plus[axis_num]; if (bit != old_halui_data.ajog_increment_plus[axis_num]) { if (bit) - sendJogIncr(axis_num, internaljogspeed, new_halui_data.ajog_increment[axis_num],JOGTELEOP); + sendJogIncr(axis_num, tempjogspeed, new_halui_data.ajog_increment[axis_num],JOGTELEOP); old_halui_data.ajog_increment_plus[axis_num] = bit; } @@ -2389,7 +2425,7 @@ static void check_hal_changes() bit = new_halui_data.ajog_increment_minus[axis_num]; if (bit != old_halui_data.ajog_increment_minus[axis_num]) { if (bit) - sendJogIncr(axis_num, internaljogspeed, -(new_halui_data.ajog_increment[axis_num]),JOGTELEOP); + sendJogIncr(axis_num, tempjogspeed, -(new_halui_data.ajog_increment[axis_num]),JOGTELEOP); old_halui_data.ajog_increment_minus[axis_num] = bit; } @@ -2438,12 +2474,20 @@ static void check_hal_changes() sendJogStop(axis_num,JOGTELEOP); } } else { + + // check for axis type: linear/rotary + if (py_call_get_axis_type(axis_num) == 1){ + tempjogspeed = internaljogspeed; + }else{ + tempjogspeed = internalangularjogspeed; + } + *(halui_data->axis_is_selected[axis_num]) = 1; if (*halui_data->ajog_plus[num_axes]) { fprintf(stderr, "halui: jog plus: %d\n",num_axes); - sendJogCont(axis_num, internaljogspeed,JOGTELEOP); + sendJogCont(axis_num, tempjogspeed,JOGTELEOP); } else if (*halui_data->ajog_minus[num_axes]) { - sendJogCont(axis_num, -internaljogspeed,JOGTELEOP); + sendJogCont(axis_num, -tempjogspeed,JOGTELEOP); } } } @@ -2494,8 +2538,17 @@ static void check_hal_changes() bit = new_halui_data.ajog_minus[EMCMOT_MAX_AXIS]; js = new_halui_data.axis_selected; if ((bit != old_halui_data.ajog_minus[EMCMOT_MAX_AXIS]) || (bit && ajog_speed_changed)) { - if (bit != 0) - sendJogCont(js, -internaljogspeed,JOGTELEOP); + if (bit != 0){ + + // check for axis type: linear/rotary + if (py_call_get_axis_type(js) == 1){ + tempjogspeed = internaljogspeed; + }else{ + tempjogspeed = internalangularjogspeed; + } + + sendJogCont(js, -tempjogspeed,JOGTELEOP); + } else sendJogStop(js,JOGTELEOP); old_halui_data.ajog_minus[EMCMOT_MAX_AXIS] = bit; @@ -2504,8 +2557,17 @@ static void check_hal_changes() bit = new_halui_data.ajog_plus[EMCMOT_MAX_AXIS]; js = new_halui_data.axis_selected; if ((bit != old_halui_data.ajog_plus[EMCMOT_MAX_AXIS]) || (bit && ajog_speed_changed)) { - if (bit != 0) - sendJogCont(js,internaljogspeed,JOGTELEOP); + if (bit != 0){ + + // check for axis type: linear/rotary + if (py_call_get_axis_type(js) == 1){ + tempjogspeed = internaljogspeed; + }else{ + tempjogspeed = internalangularjogspeed; + } + + sendJogCont(js,tempjogspeed,JOGTELEOP); + } else sendJogStop(js,JOGTELEOP); old_halui_data.ajog_plus[EMCMOT_MAX_AXIS] = bit; @@ -2515,7 +2577,7 @@ static void check_hal_changes() js = new_halui_data.axis_selected; if (bit != old_halui_data.ajog_increment_plus[EMCMOT_MAX_AXIS]) { if (bit) - sendJogIncr(js, internaljogspeed, new_halui_data.ajog_increment[EMCMOT_MAX_AXIS],JOGTELEOP); + sendJogIncr(js, tempjogspeed, new_halui_data.ajog_increment[EMCMOT_MAX_AXIS],JOGTELEOP); old_halui_data.ajog_increment_plus[EMCMOT_MAX_AXIS] = bit; } @@ -2523,7 +2585,7 @@ static void check_hal_changes() js = new_halui_data.axis_selected; if (bit != old_halui_data.ajog_increment_minus[EMCMOT_MAX_AXIS]) { if (bit) - sendJogIncr(js, internaljogspeed, -(new_halui_data.ajog_increment[EMCMOT_MAX_AXIS]),JOGTELEOP); + sendJogIncr(js, tempjogspeed, -(new_halui_data.ajog_increment[EMCMOT_MAX_AXIS]),JOGTELEOP); old_halui_data.ajog_increment_minus[EMCMOT_MAX_AXIS] = bit; } From 5eb33b5eacaa65556fce21f0c2024f201a8ee42a Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 12 Apr 2026 10:43:09 -0700 Subject: [PATCH 53/79] gmoccapy -update vcp panel for angular axes --- configs/sim/gmoccapy/panel.hal | 2 +- configs/sim/gmoccapy/panel.ui | 127 +++++++++++++++++++++++++++++---- 2 files changed, 113 insertions(+), 16 deletions(-) diff --git a/configs/sim/gmoccapy/panel.hal b/configs/sim/gmoccapy/panel.hal index d48117a20ff..e93020bc83f 100644 --- a/configs/sim/gmoccapy/panel.hal +++ b/configs/sim/gmoccapy/panel.hal @@ -1,4 +1,4 @@ -net rate halui.axis.jog-speed panel.Jog-rate-f +net rate halui.axis.jog-speed panel.jog-rate-f net sx halui.axis.x.select panel.axis-x net sy halui.axis.y.select panel.axis-y diff --git a/configs/sim/gmoccapy/panel.ui b/configs/sim/gmoccapy/panel.ui index 6ed71542f13..73215dec2cd 100644 --- a/configs/sim/gmoccapy/panel.ui +++ b/configs/sim/gmoccapy/panel.ui @@ -6,8 +6,8 @@ 0 0 - 404 - 537 + 389 + 600 @@ -22,11 +22,26 @@ Axis Selection - - - + + + 0 + + + 3 + + + 0 + + + 0 + + + 4 + + + - None + Z true @@ -35,11 +50,11 @@ true - axis-none + axis-z - + X @@ -55,7 +70,23 @@ - + + + + None + + + true + + + true + + + axis-none + + + + Y @@ -71,10 +102,10 @@ - - + + - Z + C true @@ -83,7 +114,39 @@ true - axis-z + axis-c + + + + + + + B + + + true + + + true + + + axis-b + + + + + + + A + + + true + + + true + + + axis-a @@ -96,6 +159,18 @@ Axis Jog + + 0 + + + 3 + + + 0 + + + 0 + @@ -134,7 +209,29 @@ Qt::Horizontal - Jog-rate + jog-rate + + + + + + + + + + jAngular jog rate + + + + + + 1800 + + + Qt::Horizontal + + + jog-rate-angular @@ -341,7 +438,7 @@ 0 0 - 404 + 389 22 From 037b62563f8f9c8ca3afbf745634e87f029344ff Mon Sep 17 00:00:00 2001 From: CMorley Date: Sun, 12 Apr 2026 10:44:31 -0700 Subject: [PATCH 54/79] gmoccapy -add a 4 axis halui test config to confirm angular jograte works --- .../gmoccapy/gmoccapy_halui_test_4_axis.ini | 218 ++++++++++++++++++ configs/sim/gmoccapy/panel-4axis.hal | 26 +++ 2 files changed, 244 insertions(+) create mode 100644 configs/sim/gmoccapy/gmoccapy_halui_test_4_axis.ini create mode 100644 configs/sim/gmoccapy/panel-4axis.hal diff --git a/configs/sim/gmoccapy/gmoccapy_halui_test_4_axis.ini b/configs/sim/gmoccapy/gmoccapy_halui_test_4_axis.ini new file mode 100644 index 00000000000..f722d2e6654 --- /dev/null +++ b/configs/sim/gmoccapy/gmoccapy_halui_test_4_axis.ini @@ -0,0 +1,218 @@ +# General section ------------------------------------------------------------- +[EMC] +VERSION = 1.1 +MACHINE = gmoccapy 4 axis +DEBUG = 0 + +# for details see nc_files/subroutines/maco_instructions.txt +[DISPLAY] +DISPLAY = gmoccapy + +# Cycle time, in milliseconds, that display will sleep between polls +CYCLE_TIME = 100 + +# Highest value that will be allowed for feed override, 1.0 = 100% +MAX_FEED_OVERRIDE = 1.5 +MAX_SPINDLE_OVERRIDE = 1.2 +MIN_SPINDLE_OVERRIDE = .5 + +# Prefix to be used +PROGRAM_PREFIX = ../../nc_files/ + +# Introductory graphic +INTRO_GRAPHIC = linuxcnc.gif +INTRO_TIME = 5 + +# list of selectable jog increments +INCREMENTS = 1.000 mm, 0.100 mm, 0.010 mm, 0.001 mm, 90.000 ° + +[FILTER] +PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image +PROGRAM_EXTENSION = .py Python Script +png = image-to-gcode +gif = image-to-gcode +jpg = image-to-gcode +py = python3 + +# Task controller section ----------------------------------------------------- +[RS274NGC] +RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.005 G80 G90 G94 G97 M5 M9 +PARAMETER_FILE = sim.var +SUBROUTINE_PATH = ./macros +REMAP=M6 modalgroup=6 prolog=change_prolog ngc=change_g43 epilog=change_epilog +REMAP=M61 modalgroup=6 prolog=settool_prolog ngc=settool_g43 epilog=settool_epilog + +# the Python plugins serves interpreter and task +[PYTHON] +PATH_PREPEND = ./python +TOPLEVEL = ./python/toplevel.py +LOG_LEVEL = 0 + +# Motion control section ------------------------------------------------------ +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 1.0 +BASE_PERIOD = 100000 +SERVO_PERIOD = 1000000 + +# Hardware Abstraction Layer section -------------------------------------------------- +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +# Part program interpreter section -------------------------------------------- +[HAL] +HALFILE = core_sim4.hal +HALFILE = spindle_sim.hal +HALFILE = simulated_home.hal + +# Single file that is executed after the GUI has started. +POSTGUI_HALFILE = gmoccapy_postgui.hal +POSTGUI_HALCMD = loadusr qtvcp -a -H panel-4axis.hal panel +HALUI = halui + +# Trajectory planner section -------------------------------------------------- +[HALUI] +#No Content +[MDI_COMMAND_LIST] +# for macro buttons on main oage up to 10 possible +MDI_COMMAND_MACRO0 = G0 Z1;X0 Y0;Z0, Goto\nUser\nZero +MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero +MDI_COMMAND_MACRO2 = (MSG, macro 2); +MDI_COMMAND_MACRO3 = (MSG, macro 2) +MDI_COMMAND_MACRO4 = (MSG, macro 2),test + + +[TRAJ] +COORDINATES = X Y Z C +LINEAR_UNITS = mm +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 50 +MAX_LINEAR_VELOCITY = 234 +POSITION_FILE = position.txt + +# First axis = X +[EMCIO] +# tool table file +TOOL_TABLE = tool.tbl +TOOL_CHANGE_POSITION = 100 100 -10 +TOOL_CHANGE_QUILL_UP = 1 + +[KINS] +KINEMATICS = trivkins coordinates=xyzc +JOINTS = 4 + +[AXIS_X] +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 + +[JOINT_0] +TYPE = LINEAR +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_OFFSET = 0.0 +HOME = 10 +HOME_SEARCH_VEL = 200.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 1 +HOME_IS_SHARED = 1 + +# Second axis = Y +[AXIS_Y] +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 + +[JOINT_1] +TYPE = LINEAR +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -400.0 +MAX_LIMIT = 400.0 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_OFFSET = 0.0 +HOME = 10 +HOME_SEARCH_VEL = 200.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 1 +HOME_IS_SHARED = 1 + +# Third axis = Z +[AXIS_Z] +MIN_LIMIT = -400.0 +MAX_LIMIT = 0.001 +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 + +[JOINT_2] +TYPE = LINEAR +MAX_VELOCITY = 166 +MAX_ACCELERATION = 1500.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -400.0 +MAX_LIMIT = 0.001 +FERROR = 0.050 +MIN_FERROR = 0.010 +HOME_OFFSET = 1.0 +HOME = -10 +HOME_SEARCH_VEL = 200.0 +HOME_LATCH_VEL = 20.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 0 +HOME_IS_SHARED = 1 + +# Fourth axis = A +# Fifth axis = B + +# Sixt axis = C +[AXIS_C] +MAX_VELOCITY = 90.0 +MAX_ACCELERATION = 1200.0 + +[JOINT_3] +TYPE = ANGULAR +HOME = 0.0 +MAX_VELOCITY = 90.0 +MAX_ACCELERATION = 1200.0 +BACKLASH = 0.000 +INPUT_SCALE = 40 +OUTPUT_SCALE = 1.000 +FERROR = 5.0 +MIN_FERROR = 1.0 +HOME_OFFSET = 0.0 +HOME_SEARCH_VEL = 0.0 +HOME_LATCH_VEL = 0.0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = NO +HOME_SEQUENCE = 1 + +# section for main IO controller parameters ----------------------------------- +[MACROS] +MACRO = i_am_lost +MACRO = halo_world +MACRO = jog_around +MACRO = increment xinc yinc +MACRO = go_to_position X-pos Y-pos Z-pos + +# Sections for display options ------------------------------------------------ diff --git a/configs/sim/gmoccapy/panel-4axis.hal b/configs/sim/gmoccapy/panel-4axis.hal new file mode 100644 index 00000000000..d1dde2dcefb --- /dev/null +++ b/configs/sim/gmoccapy/panel-4axis.hal @@ -0,0 +1,26 @@ +net rate halui.axis.jog-speed panel.jog-rate-f +net angular-rate halui.axis.jog-speed-angular panel.jog-rate-angular-f + +net sx halui.axis.x.select panel.axis-x +net sy halui.axis.y.select panel.axis-y +net sz halui.axis.z.select panel.axis-z +net sc halui.axis.c.select panel.axis-c + +net jog-p halui.axis.selected.plus panel.jog-pos +net jog-m halui.axis.selected.minus panel.jog-neg + +net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 +net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 +net m2 halui.gui.mdi-command-MACRO2 panel.mdi-2 + +net man panel.manual-mode halui.mode.manual +net mdi panel.mdi-mode halui.mode.mdi +net auto panel.auto-mode halui.mode.auto + +net pause halui.cycle.start panel.cycle-start +net start halui.cycle.pause panel.cycle-pause +net abort halui.abort panel.cycle-abort + +net cancel halui.gui.cancel panel.cancel +net ok halui.gui.ok panel.ok + From 1d96dd0aefecebf37584c7ddd3349a6427304817 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Wed, 27 May 2026 19:04:21 -0700 Subject: [PATCH 55/79] qtvcp -axis tool button: allow for MPG selection --- lib/python/qtvcp/widgets/axis_tool_button.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/python/qtvcp/widgets/axis_tool_button.py b/lib/python/qtvcp/widgets/axis_tool_button.py index 7168a3dc0a7..9080ae29efd 100644 --- a/lib/python/qtvcp/widgets/axis_tool_button.py +++ b/lib/python/qtvcp/widgets/axis_tool_button.py @@ -134,6 +134,8 @@ def homed_on_test(): self.hal_pin_joint = self.HAL_GCOMP_.newpin(str(pname + '-joint'), hal.HAL_BIT, hal.HAL_OUT) self.hal_pin_axis = self.HAL_GCOMP_.newpin(str(pname + '-axis'), hal.HAL_BIT, hal.HAL_OUT) STATUS.connect('general',self.return_value) + if 'MPG' in self._axis.upper(): + self.settingMenu.clear() def _enableGroup(self, state,bstate): for i in(self.zeroButton, self.setButton,self.divideButton, @@ -226,7 +228,7 @@ def _a_from_j(self, axis): return axis, r[jnum] def selectJoint(self): - print(self.objectName(),'select',self._joint,self._axis,self.isChecked()) + print(self.objectName(),f'select: j{self._joint} a{self._axis} ck{self.isChecked()}') if self._block_signal or self._joint == -1 or self._axis == '': return if self.isChecked() == True: if STATUS.is_joint_mode(): @@ -252,7 +254,8 @@ def selectJoint(self): self.hal_pin_axis.set(False) def ChangeState(self, joint = None, axis = None): - print(self.objectName(),'change',joint,axis,self._axis,self.isChecked()) + #print(self.objectName(),f'change: j{joint} a{axis} type{self._axis} ck{self.isChecked()}') + # joint mode if STATUS.is_joint_mode(): if int(joint) != self._joint: @@ -270,18 +273,18 @@ def ChangeState(self, joint = None, axis = None): # axis mode else: if str(axis) != self._axis and self.isChecked(): - print(self.objectName(),'Set false') - if not self.group() == 0: + #print(self.objectName(),'Set false') + if not self.group() in (0,None): self.group().setExclusive(False) self._block_signal = True self.setChecked(False) self._block_signal = False - if not self.group() == 0: + if not self.group() in (0,None): self.group().setExclusive(True) if self._halpin_option and self._axis != '': self.hal_pin_joint.set(False) elif str(axis) == self._axis and not self.isChecked(): - print(self.objectName(),'Set True') + #print(self.objectName(),'Set True') self._block_signal = True self.setChecked(True) self._block_signal = False @@ -318,6 +321,8 @@ def set_axis(self, data): self.goToG53Button.setText(text) text = 'Go To G5x Origin in {}'.format(self._axis) self.goToG5xButton.setText(text) + elif data.upper() in('MPG0','MPG1'): + self._axis = str(data.upper()) else: self._axis = str('') From c8e6d98858b04f0c50092eaa6bf77d30509cf2ff Mon Sep 17 00:00:00 2001 From: Cmorley Date: Wed, 27 May 2026 19:06:23 -0700 Subject: [PATCH 56/79] qtdragon -fix MPG selection from panel sometimes selecting a combination of MPG,None,X would end up with None selected when MPG should have. --- share/qtvcp/screens/qtdragon/qtdragon.ui | 14685 ++++++++-------- .../screens/qtdragon/qtdragon_handler.py | 7 - 2 files changed, 7290 insertions(+), 7402 deletions(-) diff --git a/share/qtvcp/screens/qtdragon/qtdragon.ui b/share/qtvcp/screens/qtdragon/qtdragon.ui index d853a2198f4..e0f69fbfe29 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon.ui +++ b/share/qtvcp/screens/qtdragon/qtdragon.ui @@ -7,7 +7,7 @@ 0 0 - 1566 + 1280 768 @@ -1216,7 +1216,7 @@ RESET QFrame::Raised - 1 + 0 @@ -5786,382 +5786,7 @@ LOG 0 - - - - 600 - 16777215 - - - - true - - - - - 0 - 0 - 192 - 547 - - - - - 600 - 16777215 - - - - - - - - 0 - 0 - - - - - 180 - 0 - - - - - 600 - 16777215 - - - - - 4 - - - QLayout::SetDefaultConstraint - - - 4 - - - 4 - - - 4 - - - 4 - - - - - QFrame::NoFrame - - - QFrame::Raised - - - KEYBOARD MAPPING - - - Qt::AlignCenter - - - - - - - ESC - Program Abort - - - - - - - F1 - ESTOP - - - - - - - F2 - Machine OFF - - - - - - - F11 - Fullscreen - - - - - - - F12 - Style Sheet Editor - - - - - - - Home - HOME All - - - - - - - Pause - Pause program - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - Make complicated 3D files more visible - - - ENABLE ALPHA MODE - - - - - - - - 0 - 0 - - - - Make complicated 3D files more visible - - - INHIBIT MOUSE SELECTION - - - - - - - - 0 - 0 - - - - Enable external offsets for spindle pause - - - USE EXTERNAL OFFSETS - - - - - - - - 0 - 0 - - - - Reload last loaded tool - - - RELOAD LAST TOOL - - - - - - - - 0 - 0 - - - - Reload last loaded program - - - RELOAD LAST PROGRAM - - - - - - - - 0 - 0 - - - - Enable keyboard shortcuts - - - USE KEYBOARD SHORTCUTS - - - - - - - - 0 - 0 - - - - Enable run from line - - - USE RUN FROM LINE - - - - - - - - 0 - 0 - - - - Enable use of onboard virtual keyboard - - - USE VIRTUAL KEYBOARD - - - - - - - - 0 - 0 - - - - Enable tool sensor - - - USE TOOL SENSOR - - - true - - - - - - - - 0 - 0 - - - - Enable Webcam for work offset location - - - USE CAMERA - - - true - - - - - - - - 0 - 0 - - - - OVERRIDE LIMITS - - - - - - - - 0 - 0 - - - - Automatically switch to MDI mode with external MDI requests - - - AUTO MODE SWITCH EXTERNAL MDI - - - true - - - - - - - - 0 - 0 - - - - Automatically switch to MDI mode with MDI buttons - - - AUTO MODE SWITCH MACRO BUTTONS - - - true - - - - - - - - - - - - - - Qt::Vertical - - - - - + 0 @@ -6170,20 +5795,23 @@ LOG - 300 + 180 0 - 16777215 + 260 16777215 - + 4 + + QLayout::SetDefaultConstraint + 4 @@ -6197,5948 +5825,3458 @@ LOG 4 - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 120 - 30 - - - - - 120 - 30 - - - - - - - - - - - - 0 - 0 - - - - - 50 - 30 - - - - - 50 - 30 - - - - X - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 50 - 30 - - - - - 50 - 30 - - - - Y - - - Qt::AlignCenter - - - - + + + QFrame::NoFrame + + + QFrame::Raised + + + KEYBOARD MAPPING + + + Qt::AlignCenter + - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 120 - 30 - - - - - 120 - 30 - - - - HOME LOCATION - - - - - - - - 0 - 0 - - - - - 60 - 30 - - - - - 60 - 30 - - - - 8 - - - Qt::AlignCenter - - - true - - - - - - - - 0 - 0 - - - - - 60 - 30 - - - - - 60 - 30 - - - - 8 - - - Qt::AlignCenter - - - true - - - - + + + ESC - Program Abort + - - - TOUCHOFF PARAMETERS + + + F1 - ESTOP - - Qt::AlignCenter + + + + + + F2 - Machine OFF - - - 4 - - - 4 - - - 5 - - - 4 - - - 4 - - - - - - 0 - 30 - - - - - 16777215 - 30 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 120 - 16777215 - - - - Probe down search velocity - - - SEARCH VELOCITY - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - 8 - - - Qt::AlignCenter - - - false - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - MM/MIN - - - Qt::AlignCenter - - - false - - - 0 - - - - - - - - - - - 0 - 30 - - - - - 16777215 - 30 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 120 - 16777215 - - - - Probe down final velocity - - - PROBE VELOCITY - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - 8 - - - Qt::AlignCenter - - - false - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - MM/MIN - - - Qt::AlignCenter - - - false - - - 0 - - - - - - - - - - - 0 - 30 - - - - - 16777215 - 30 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 120 - 16777215 - - - - Max probing distance - - - MAX PROBE - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - 8 - - - Qt::AlignCenter - - - false - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - MM - - - Qt::AlignCenter - - - false - - - 0 - - - - - - - - - - - 0 - 30 - - - - - 16777215 - 30 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 120 - 16777215 - - - - Distance to retract after G38.2 command - - - RETRACT DISTANCE - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - 8 - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - MM - - - Qt::AlignCenter - - - - - - - - - - - 0 - 30 - - - - - 16777215 - 30 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 120 - 16777215 - - - - Z safe travel height during rapid moves - - - Z SAFE TRAVEL - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - 8 - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - - 60 - 16777215 - - - - MM - - - Qt::AlignCenter - - - - - - - - - - - - - SPINDLE RAISE - - - Qt::AlignCenter - - - - 4 - - - 4 - - - 5 - - - 4 - - - 4 - - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 4 - - - - - - 50 - 30 - - - - - 50 - 30 - - - - + - - - - - - - - 50 - 30 - - - - - 50 - 30 - - - - - - - - - - - - - 0 - 0 - - - - - 60 - 30 - - - - - 60 - 30 - - - - 8 - - - Qt::AlignCenter - - - false - - - - - - - - 0 - 0 - - - - - 60 - 30 - - - - - 60 - 30 - - - - MM - - - Qt::AlignCenter - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - GCODE ZOOM - - - Qt::AlignCenter - - - - 4 - - - 0 - - - 5 - - - 0 - - - 4 - - - - - - 50 - 30 - - - - - 50 - 30 - - - - + - - - - - - - - 50 - 30 - - - - - 50 - 30 - - - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - 1 - - - - - 0 - 0 - - - - - - - :/images/images/silver_dragon.png - - - - - - - - - - Qt::Vertical - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 4 - - - 2 - - - 4 - - - 2 - - - 4 - - - - - - 96 - 46 - - - - - 96 - 50 - - - - ABOUT - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 96 - 46 - - - - - 96 - 50 - - - - TEST BUTTON - - - true - - - PROGRAM_LOADER.load_test_button() - - - - - - - - - - - 96 - 46 - - - - - 96 - 50 - - - - TEST LED - - - true - - - PROGRAM_LOADER.load_test_led() - - - - - - - - - - - 0 - 0 - - - - - 96 - 46 - - - - - 96 - 50 - - - - CALIBRATION - - - false - - - false - - - false - - - false - - - false - - - - 255 - 0 - 0 - - - - 0 - - - - 0 - 0 - 0 - - - - 0.300000000000000 - - - 10 - - - 0 - - - 0 - - - 5.000000000000000 - - - 0.300000000000000 - - - 0.900000000000000 - - - True - - - False - - - print"true command" - - - print"false command" - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - 0 - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 0.300000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - tool.status - - - - - - - - 0 - 0 - - - - - 96 - 46 - - - - - 96 - 50 - - - - STATUS - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - tool.status - - - - - - - - 0 - 0 - - - - - 96 - 46 - - - - - 96 - 50 - - - - HAL SCOPE - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - tool.halscope - - - - - - - - 0 - 0 - - - - - 96 - 46 - - - - - 96 - 50 - - - - HAL METER - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - tool.halmeter - - - - - - - - 0 - 0 - - - - - 96 - 46 - - - - - 96 - 50 - - - - HAL SHOW - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - tool.halshow - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - FACING - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - Bolt Hole Circle - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - NgcGui - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - true - - - - 0 - 0 - - - - - 74 - 0 - - - - - 74 - 16777215 - - - - - 4 - - - 1 - - - 4 - - - 4 - - - 1 - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 0 - - - Qt::LeftToRight - - - Macro0 - - - false - - - false - - - true - - - false - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - false - - - false - - - false - - - true - - - false - - - false - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 0 - - - MACRO0 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Qt::StrongFocus - - - Run Macro 1 - - - Macro1 - - - false - - - false - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - false - - - true - - - false - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 1 - - - MACRO1 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 2 - - - Macro2 - - - false - - - false - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 2 - - - MACRO2 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 3 - - - Macro3 - - - false - - - false - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 3 - - - MACRO3 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 4 - - - Macro4 - - - false - - - false - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 4 - - - MACRO4 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 5 - - - Macro5 - - - false - - - false - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 5 - - - MACRO5 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 6 - - - Macro6 - - - false - - - false - - - 300 - - - 100 - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 6 - - - MACRO6 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 7 - - - Macro7 - - - false - - - false - - - 300 - - - 100 - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 7 - - - MACRO7 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 8 - - - false - - - Macro8 - - - false - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 8 - - - MACRO8 - - - %1.3f in - - - %1.2f mm - - - - - - - true - - - - 0 - 0 - - - - - 72 - 35 - - - - - 72 - 72 - - - - - 70 - 45 - - - - Run Macro 9 - - - false - - - Macro9 - - - false - - - true - - - true - - - - 85 - 255 - 0 - - - - 1 - - - true - - - 4 - - - 5 - - - true - - - false - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - p - - - - - - 9 - - - MACRO9 - - - %1.3f in - - - %1.2f mm - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - - - Qt::Vertical - - - - 0 - 762 - - - - - - - - -
- - - - - - - 0 - 0 - - - - - 268 - 0 - - - - - 300 - 16777215 - - - - QFrame::Box - - - QFrame::Raised - - - 1 - - - - 4 - - - 0 - - - 0 - - - 0 - - - 1 - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 11 - - - - - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 16777215 - 328 - - - - - 1 - - - 1 - - - 0 - - - 2 - - - 10 - - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - - - - 44 - 44 - - - - true - - - -1 - - - A - - - - - - - - 0 - 0 - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - :/buttons/images/y_minus_jog_button.png:/buttons/images/y_minus_jog_button.png - - - - 44 - 44 - - - - true - - - false - - - -1 - - - Y - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - - - - - Qt::Vertical - - - - 5 - 0 - - - - - - - - - 0 - 0 - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - :/buttons/images/z_plus_jog_button.png:/buttons/images/z_plus_jog_button.png - - - - 44 - 44 - - - - true - - - -1 - - - Z - - - - - - - - 0 - 0 - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - :/buttons/images/x_minus_jog_button.png:/buttons/images/x_minus_jog_button.png - - - - 44 - 44 - - - - true - - - false - - - -1 - - - X - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - - - - - - 0 - 0 - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - :/buttons/images/x_plus_jog_button.png:/buttons/images/x_plus_jog_button.png - - - - 44 - 44 - - - - true - - - false - - - -1 - - - X - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - - - - - Qt::Vertical - - - - 5 - 0 - - - - - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - 44 - 44 - - - - false - - - true - - - -1 - - - A - - - - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - :/buttons/images/z_minus_jog_button.png:/buttons/images/z_minus_jog_button.png - - - - 44 - 44 - - - - true - - - -1 - - - Z - - - - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - :/buttons/images/y_plus_jog_button.png:/buttons/images/y_plus_jog_button.png - - - - 44 - 44 - - - - true - - - false - - - -1 - - - Y - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - - - - - Qt::Horizontal - - - - 22 - 2 - - - - - - - - Qt::Horizontal - - - - 22 - 2 - - - - - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - 44 - 44 - - - - true - - - -1 - - - C - - - - - - - - 53 - 53 - - - - - 53 - 53 - - - - - - - - - - - 44 - 44 - - - - false - - - true - - - -1 - - - C - - - - - - - - - - - 0 - 0 - - - - - 74 - 0 - - - - - 80 - 328 - - - - - 4 - - - 0 - - - 2 - - - 0 - - - 6 - - - - - 4 - - - 0 - - - - - - 0 - 0 - - - - - 50 - 20 - - - - - 60 - 20 - - - - UNITS - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 56 - 24 - - - - - 60 - 24 - - - - QFrame::WinPanel - - - QFrame::Sunken - - - 1 - - - false - - - Qt::AlignCenter - - - false - - - false - - - MM - - - IN - - - - - - - - - Qt::Vertical - - - - 20 - 31 - - - - - - - - - 0 - 0 - - - - - 0 - 30 - - - - - 60 - 30 - - - - JOG RATE -MM/MIN - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 56 - 28 - - - - - 60 - 30 - - - - QFrame::WinPanel - - - QFrame::Sunken - - - Qt::AlignCenter - - - %.1f - - - %d - - - true - - - - - - - - 0 - 0 - - - - - 30 - 122 - - - - - 60 - 16777215 - - - - Adjust linear jog rate - - - 3600 - - - 100 - - - 100 - - - 3000 - - - Qt::Vertical - - - slider-jogspeed-linear - - - true - - - - - - - - 0 - 0 - - - - - 50 - 30 - - - - - 60 - 30 - - - - Toggle linear jog speed range - - - FAST - - - true - - - true - - - SLOW - - - FAST - - - slider_jog_linear - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 66 - - - - - - - - - 0 - 0 - - - - - 16777215 - 42 - - - - - 0 - - - QLayout::SetDefaultConstraint - - - 1 - - - 0 - - - 2 - - - 0 - - - - - - 0 - 0 - - - - - 0 - 25 - - - - - 150 - 34 - - - - LINEAR INCREMENT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - 0 - 0 - - - - - 80 - 25 - - - - - 100 - 34 - - - - - 0 - 0 - - - - Qt::ClickFocus - - - Select jog increment - - - 12 - - - 20 - - - 20 - - - true - - - jog-linear-increment - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 42 - - - - - 0 - - - QLayout::SetDefaultConstraint - - - 1 - - - 0 - - - 2 - - - 0 - - - - - - 0 - 0 - - - - - 0 - 25 - - - - - 150 - 34 - - - - ANGULAR INCREMENT - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 0 - - - 2 - - - - - - - - 0 - 0 - - - - - 80 - 25 - - - - - 100 - 34 - - - - - 0 - 0 - - - - Qt::ClickFocus - - - Select jog increment - - - -1 - - - 20 - - - 20 - - - false - - - jog-angular-increment - - - - - - - - - - - 0 - 0 - - - - - 0 - 32 - - - - - 4 - - - 6 - - - 2 - - - 4 - - - 1 - - - - - - 0 - 0 - - - - - 50 - 26 - - - - - 52 - 30 - - - - Toggle angular jog speed range - - - FAST - - - true - - - true - - - SLOW - - - FAST - - - slider_jog_angular - - - - - - - - 0 - 0 - - - - - 0 - 26 - - - - - 16777215 - 30 - - - - Adjust angular jog rate - - - 3600 - - - 100 - - - 100 - - - 3000 - - - Qt::Horizontal - - - slider-jogspeed-angular - - - false - - - true - - - - - - - - 0 - 0 - - - - - 60 - 26 - - - - - 60 - 30 - - - - QFrame::WinPanel - - - QFrame::Sunken - - - Qt::AlignCenter - - - %d - - - false - - - true - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 11 - - - - - - - - - - - - - - - - - - - 2 - - - 2 - - - 1 - - - 2 - - - 1 - - - - - - 8 - 0 - - - - - 0 - 0 - - - - - 1000 - 16777215 - - - - - 2 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 10 - 0 - - - - - 188 - 0 - - - - - 16777215 - 16777215 - - - - QFrame::Box - - - QFrame::Raised - - - - 4 - - - 4 - - - 4 - - - 4 - - - 2 - - - - - 6 - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - CYCLE -START - - - true - - - true - - - - 0 - 255 - 0 - - - - 1 - - - 0.200000000000000 - - - 6 - - - 6 - - - true - - - true - - - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - STOP - - - true - - - INSTANCE.progressBar.setFormat('STOPPED') - - - - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - PAUSE - - - true - - - true - - - false - - - true - - - true - - - - 255 - 255 - 0 - - - - 1 - - - true - - - 0.200000000000000 - - - 6 - - - 6 - - - RESUME - - - PAUSE - - - false - - - true - - - false - - - false - - - false - - - true - - - false - - - false - - - false - - - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - STEP - - - true - - - false - - - 0 - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - OPT -BLOCK - - - true - - - true - - - false - - - true - - - - 0 - 255 - 0 - - - - 1 - - - 0.200000000000000 - - - 10 - - - 6 - - - 6 - - - true - - - true - - - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - OPT -STOP - - - true - - - true - - - false - - - true - - - - 0 - 255 - 0 - - - - 1 - - - 0.200000000000000 - - - 6 - - - 6 - - - true - - - true - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - MIST -OFF - - - true - - - false - - - true - - - false - - - true - - - true - - - - 0 - 255 - 0 - - - - 1 - - - 0.200000000000000 - - - 6 - - - 6 - - - MIST -ON - - - MIST -OFF - - - true - - - true - - - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - FLOOD -OFF - - - true - - - true - - - false - - - true - - - true - - - - 0 - 255 - 0 - - - - 1 - - - 0.200000000000000 - - - 6 - - - 6 - - - FLOOD -ON - - - FLOOD -OFF - - - true - - - true - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - Reload last loaded program - - - RELOAD - - - - - - - - 1 - 0 - - - - - 80 - 39 - - - - - 16777215 - 64 - - - - Spindle pause - - - NO -LIFT - - - true - - - false - - - - - - false - - - false - - - true - - - - 255 - 0 - 0 - - - - 1 - - - 0.200000000000000 - - - 6 - - - 6 - - - SPINDLE -LIFT - - - NO -LIFT - - - false - - - - - - - - - - 0 - 0 - - - - - 90 - 24 - - - - - 16777215 - 26 - - - - - Lato - 75 - true - - - - false - - - Qt::ImhNone - - - 99 - - - 0 - - - Qt::AlignCenter - - - true - - - false - - - - - - - - - - - 7 - 0 - - - - - 158 - 0 - - - - - 284 - 16777215 - - - - QFrame::Box - - - QFrame::Raised - - - - 6 - - - 1 - - - 4 - - - 1 - - - 4 - - - - - - 0 - 0 - - - - - 20 - 0 - - - - - - - :/images/images/atc_spindle_tool.png - - - false - - - Qt::AlignBottom|Qt::AlignHCenter - - - 1 - - - -1 - - - - - - - - 4 - - - 2 - - - 0 - - - 2 - - - 0 - - - - - 6 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 60 - 20 - - - - TOOL - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 60 - 20 - - - - DIA - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 60 - 20 - - - - SCS - - - Qt::AlignCenter - - - - - - - - - 4 - - - 1 - - - 1 - - - 0 - - - - - - 0 - 0 - - - - - 42 - 24 - - - - - 110 - 26 - - - - QFrame::WinPanel - - - QFrame::Sunken - - - 1 - - - Qt::AlignCenter - - - true - - - - - - - - 0 - 0 - - - - - 50 - 24 - - - - - 110 - 26 - - - - QFrame::WinPanel - - - QFrame::Sunken - - - 1 - - - 200.000 - - - Qt::AlignCenter - - - %5.3f - - - %5.3f - - - 0 - - - true - - - - - - - - 0 - 0 - - - - - 42 - 24 - - - - - 110 - 26 - - - - Surface cutting speed - - - - - - QFrame::WinPanel - - - QFrame::Sunken - - - 1 - - - 200 - - - Qt::AlignCenter - - - %d - - - %d - - - false - - - true - - - - - - - - - - 0 - 0 - - - - - 20 - 26 - - - - - 379 - 26 - - - - QFrame::WinPanel - - - QFrame::Sunken - - - No Tool Loaded - - - false - - - Qt::AlignCenter - - - true - - - - - - - - - - - - - - - - - 15 - 0 - - - - - 0 - 220 - - - - - 16777215 - 375 - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - + + + + + + F11 - Fullscreen + + + + + + + F12 - Style Sheet Editor + + + + + + + Home - HOME All + + + + + + + Pause - Pause program + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Make complicated 3D files more visible + + + ENABLE ALPHA MODE + + + + + + + + 0 + 0 + + + + Make complicated 3D files more visible + + + INHIBIT MOUSE SELECTION + + + + + + + + 0 + 0 + + + + Enable external offsets for spindle pause + + + USE EXTERNAL OFFSETS + + + + + + + + 0 + 0 + + + + Reload last loaded tool + + + RELOAD LAST TOOL + + + + + + + + 0 + 0 + + + + Reload last loaded program + + + RELOAD LAST PROGRAM + + + + + + + + 0 + 0 + + + + Enable keyboard shortcuts + + + USE KEYBOARD SHORTCUTS + + + + + + + + 0 + 0 + + + + Enable run from line + + + USE RUN FROM LINE + + + + + + + + 0 + 0 + + + + Enable use of onboard virtual keyboard + + + USE VIRTUAL KEYBOARD + + + + + + + + 0 + 0 + + + + Enable tool sensor + + + USE TOOL SENSOR + + + true + + + + + + + + 0 + 0 + + + + Enable Webcam for work offset location + + + USE CAMERA + + + true + + + + + + + + 0 + 0 + + + + OVERRIDE LIMITS + + + + + + + + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + 300 + 0 + + + + + 16777215 + 16777215 + + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 30 + + + + + 120 + 30 + + + + + + + + + + + + 0 + 0 + + + + + 50 + 30 + + + + + 50 + 30 + + + + X + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 50 + 30 + + + + + 50 + 30 + + + + Y + + + Qt::AlignCenter + + + + + + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 30 + + + + + 120 + 30 + + + + HOME LOCATION + + + + + + + + 0 + 0 + + + + + 60 + 30 + + + + + 60 + 30 + + + + 8 + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 60 + 30 + + + + + 60 + 30 + + + + 8 + + + Qt::AlignCenter + + + true + + + + + + + + + + TOUCHOFF PARAMETERS + + + Qt::AlignCenter + + + + 4 + + + 4 + + + 5 + + + 4 + + + 4 + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Probe down search velocity + + + SEARCH VELOCITY + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + 8 + + + Qt::AlignCenter + + + false + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + MM/MIN + + + Qt::AlignCenter + + + false + + + 0 + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Probe down final velocity + + + PROBE VELOCITY + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + 8 + + + Qt::AlignCenter + + + false + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + MM/MIN + + + Qt::AlignCenter + + + false + + + 0 + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Max probing distance + + + MAX PROBE + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + 8 + + + Qt::AlignCenter + + + false + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + MM + + + Qt::AlignCenter + + + false + + + 0 + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Distance to retract after G38.2 command + + + RETRACT DISTANCE + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + 8 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + MM + + + Qt::AlignCenter + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Z safe travel height during rapid moves + + + Z SAFE TRAVEL + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + 8 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + MM + + + Qt::AlignCenter + + + + + + + + + + + + + SPINDLE RAISE + + + Qt::AlignCenter + + + + 4 + + + 4 + + + 5 + + + 4 + + + 4 + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 4 + + + + + + 50 + 30 + + + + + 50 + 30 + + + + + + + + + + + + + 50 + 30 + + + + + 50 + 30 + + + + - + + + + + + + + 0 + 0 + + + + + 60 + 30 + + + + + 60 + 30 + + + + 8 + + + Qt::AlignCenter + + + false + + + + + + + + 0 + 0 + + + + + 60 + 30 + + + + + 60 + 30 + + + + MM + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + GCODE ZOOM + + + Qt::AlignCenter + + + + 4 + + + 0 + + + 5 + + + 0 + + + 4 + + + + + + 50 + 30 + + + + + 50 + 30 + + + + + + + + + + + + + 50 + 30 + + + + + 50 + 30 + + + + - + + + + + + + + + + + 0 + 0 + + + + + 0 + 1 + + + + + 0 + 0 + + + + + + + :/images/images/silver_dragon.png + + + + + + + + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 4 + + + 2 + + + 4 + + + 2 + + + 4 + + + + + + 96 + 46 + + + + + 96 + 50 + + + + ABOUT + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 96 + 46 + + + + + 96 + 50 + + + + TEST BUTTON + + + true + + + PROGRAM_LOADER.load_test_button() + + + + + + + + + + + 96 + 46 + + + + + 96 + 50 + + + + TEST LED + + + true + + + PROGRAM_LOADER.load_test_led() + + + + + + + + + + + 0 + 0 + + + + + 96 + 46 + + + + + 96 + 50 + + + + CALIBRATION + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print"true command" + + + print"false command" + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + tool.status + + + + + + + + 0 + 0 + + + + + 96 + 46 + + + + + 96 + 50 + + + + STATUS + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + tool.status + + + + + + + + 0 + 0 + + + + + 96 + 46 + + + + + 96 + 50 + + + + HAL SCOPE + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + tool.halscope + + + + + + + + 0 + 0 + + + + + 96 + 46 + + + + + 96 + 50 + + + + HAL METER + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + tool.halmeter + + + + + + + + 0 + 0 + + + + + 96 + 46 + + + + + 96 + 50 + + + + HAL SHOW + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + tool.halshow + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + FACING + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Bolt Hole Circle + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + NgcGui + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + true + + + + 0 + 0 + + + + + 74 + 0 + + + + + 74 + 16777215 + + + + + 4 + + + 1 + + + 4 + + + 4 + + + 1 + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 0 + + + Qt::LeftToRight + + + Macro0 + + + false + + + false + + + true + + + false + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + false + + + false + + + false + + + true + + + false + + + false + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 0 + + + MACRO0 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Qt::StrongFocus + + + Run Macro 1 + + + Macro1 + + + false + + + false + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + false + + + true + + + false + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 1 + + + MACRO1 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 2 + + + Macro2 + + + false + + + false + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 2 + + + MACRO2 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 3 + + + Macro3 + + + false + + + false + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 3 + + + MACRO3 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 4 + + + Macro4 + + + false + + + false + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 4 + + + MACRO4 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 5 + + + Macro5 + + + false + + + false + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 5 + + + MACRO5 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 6 + + + Macro6 + + + false + + + false + + + 300 + + + 100 + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 6 + + + MACRO6 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 7 + + + Macro7 + + + false + + + false + + + 300 + + + 100 + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 7 + + + MACRO7 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 8 + + + false + + + Macro8 + + + false + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 8 + + + MACRO8 + + + %1.3f in + + + %1.2f mm + + + + + + + true + + + + 0 + 0 + + + + + 72 + 35 + + + + + 72 + 72 + + + + + 70 + 45 + + + + Run Macro 9 + + + false + + + Macro9 + + + false + + + true + + + true + + + + 85 + 255 + 0 + + + + 1 + + + true + + + 4 + + + 5 + + + true + + + false + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + p + + + + + + 9 + + + MACRO9 + + + %1.3f in + + + %1.2f mm + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + Qt::Vertical + + + + 0 + 762 + + + + + + + + + + + - + - - 32 + + 0 0 - 600 + 268 0 - 16777215 + 300 16777215 - + + QFrame::Box + + + QFrame::Raised + + + 1 + + - 2 + 4 0 @@ -12150,56 +9288,57 @@ LIFT 0 - 0 + 1 - - - - 61 - 0 - + + + Qt::Vertical - - - 0 - 0 - + + QSizePolicy::Expanding - + - 16777215 - 16777211 + 20 + 11 - - QFrame::Box - - - QFrame::Raised - - - 1 - - + + + + + - 2 + 4 - 4 + 0 - 4 + 0 - 4 + 0 - 4 + 0 - - + + + + 0 + 0 + + + + + 16777215 + 328 + + + 1 @@ -12207,114 +9346,474 @@ LIFT 1 - 1 + 0 - 4 + 2 - 4 + 10 - - + + + + + 53 + 53 + + + + + 53 + 53 + + + + + + + + + + + 44 + 44 + + + + true + + + -1 + + + A + + + + + + + + 0 + 0 + + + + + 53 + 53 + + + + + 53 + 53 + + + + + + + + :/buttons/images/y_minus_jog_button.png:/buttons/images/y_minus_jog_button.png + + + + 44 + 44 + + + + true + + + false + + + -1 + + + Y + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + Qt::Vertical + + + + 5 + 0 + + + + + + - - 1 + + 0 + 0 + + + + + 53 + 53 + + + + + 53 + 53 + + + + + + + + :/buttons/images/z_plus_jog_button.png:/buttons/images/z_plus_jog_button.png + + + + 44 + 44 + + + + true + + + -1 + + + Z + + + + + + + + 0 + 0 + + + + + 53 + 53 + + + + + 53 + 53 + + + + + + + + :/buttons/images/x_minus_jog_button.png:/buttons/images/x_minus_jog_button.png + + + + 44 + 44 + + + + true + + + false + + + -1 + + + X + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + + 0 0 - 58 - 36 + 53 + 53 + + + + + 53 + 53 + + + + + + + + :/buttons/images/x_plus_jog_button.png:/buttons/images/x_plus_jog_button.png + + + + 44 + 44 + + + + true + + + false + + + -1 + + + X + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + Qt::Vertical + + + + 5 + 0 + + + + + + + + + 53 + 53 - 16777215 - 76 + 53 + 53 - - Select work coordinate system - - WCS + - - true + + + 44 + 44 + - + + false + + true - - QToolButton::DelayedPopup + + -1 + + + A - - - - - 1 - 0 - - + + - 58 - 36 + 53 + 53 - 16777215 - 76 + 53 + 53 - - Zero axis A - - ZERO + - - false + + + :/buttons/images/z_minus_jog_button.png:/buttons/images/z_minus_jog_button.png - - false + + + 44 + 44 + - - - 0 - 255 - 0 - + + true - - - 255 - 0 - 0 - + + -1 - - 0.200000000000000 + + Z - - false + + + + + + + 53 + 53 + - + + + 53 + 53 + + + + + + + + :/buttons/images/y_plus_jog_button.png:/buttons/images/y_plus_jog_button.png + + + + 44 + 44 + + + true false - 3 + -1 - A + Y 0.010000000000000 @@ -12351,632 +9850,2304 @@ LIFT - - - - - 1 - 0 - + + + + Qt::Horizontal + + + + 22 + 2 + + + + + + + + Qt::Horizontal + + + + 22 + 2 + + + + + - 58 - 36 + 53 + 53 - 16777215 - 76 + 53 + 53 + + + + + + + + 44 + 44 + + + + true + + + -1 + + + C + + + + + + + + 53 + 53 + + + + + 53 + 53 + + + + + + + + + + + 44 + 44 - + + false + + + true + + + -1 + + + C + + + + + + + + + + + 0 + 0 + + + + + 74 + 0 + + + + + 80 + 328 + + + + + 4 + + + 0 + + + 2 + + + 0 + + + 6 + + + + + 4 + + 0 - - - - 0 - 0 - - - - - 16777215 - 76 - - - - - 0 - - - 0 - - - 0 - - - 0 + + + + + 0 + 0 + - - 0 + + + 50 + 20 + - - - - - 0 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - HOME - - - - 16 - 16 - - - - false - - - false - - - true - - - false - - - true - - - false - - - - 0 - 255 - 0 - - - - 1 - - - 0.200000000000000 - - - 4 - - - 5 - - - UNHOME - - - HOME - - - false - - - true - - - 0 - - - - - - - - - 0 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - - 0 + + + 60 + 20 + - - 0 + + UNITS - - 0 + + Qt::AlignCenter - - 0 + + + + + + + 0 + 0 + - - 0 + + + 56 + 24 + - - - - - 0 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - - 0 - 0 - - - - - 0 - 0 - - - - TOOL - - - - 24 - 24 - - - - QToolButton::InstantPopup - - - X - - - - - - + + + 60 + 24 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + 1 + + + false + + + Qt::AlignCenter + + + false + + + false + + + MM + + + IN + + + + - - - - - 1 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - + + + + Qt::Vertical - + - 0 - 0 + 20 + 31 - - Show distance to go - - - DTG - - - true - - - true - - - false - - - true - - + - - + + - + 0 0 - 58 - 36 + 0 + 30 - 16777215 - 76 + 60 + 30 - - QFrame::WinPanel - - - QFrame::Sunken - - + JOG RATE +MM/MIN - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 0 - - - true - - - false - - - false - - - true - - - false - - - false - - - - - - - - 1 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - MPG -SCROLL - - - true - - - - - - true - - - false - - - - 255 - 0 - 255 - - - - 4 - - - 0.300000000000000 - - - 0 - - - 0 - - - false + Qt::AlignCenter - - selectButtonGroup - - - + + - - 1 + + 0 0 - 58 - 36 + 56 + 28 - 16777215 - 76 + 60 + 30 - - Y - - - true - - - false - - - QToolButton::DelayedPopup - - - axis-select-z - - - true - - - false - - - - 255 - 0 - 255 - - - - 4 + + QFrame::WinPanel - - 0 + + QFrame::Sunken - - 0 + + Qt::AlignCenter - - 1 + + %.1f - - Y + + %d - - CALCULATOR + + true - - selectButtonGroup - - - + + - - 1 + + 0 0 - 58 - 36 + 30 + 122 - 16777215 - 76 + 60 + 16777215 - Zero axis X - - - ZERO + Adjust linear jog rate - - false + + 3600 - - false + + 100 - - - 0 - 255 - 0 - + + 100 - - - 255 - 0 - 0 - + + 3000 - - 0.200000000000000 + + Qt::Vertical - - false + + slider-jogspeed-linear - + true - - false - - - 0 - - - X - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - + + - - 1 + + 0 0 - 58 - 36 + 50 + 30 - 16777215 - 76 + 60 + 30 + + Toggle linear jog speed range + - 4 + FAST true - - false - - - QToolButton::DelayedPopup - - + true - - - 255 - 0 - 255 - - - - 4 - - - 0 - - - 0 - - - 3 + + SLOW - - + + FAST - - CALCULATOR + + slider_jog_linear - - selectButtonGroup - - - + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 66 + + + + + + + + + 0 + 0 + + + + + 16777215 + 42 + + + + + 0 + + + QLayout::SetDefaultConstraint + + + 1 + + + 0 + + + 2 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 150 + 34 + + + + LINEAR INCREMENT + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + + + + + + 0 + 0 + + + + + 80 + 25 + + + + + 100 + 34 + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Select jog increment + + + 12 + + + 20 + + + 20 + + + true + + + jog-linear-increment + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 42 + + + + + 0 + + + QLayout::SetDefaultConstraint + + + 1 + + + 0 + + + 2 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 150 + 34 + + + + ANGULAR INCREMENT + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 0 + + + 2 + + + + + + + + 0 + 0 + + + + + 80 + 25 + + + + + 100 + 34 + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Select jog increment + + + -1 + + + 20 + + + 20 + + + false + + + jog-angular-increment + + + + + + + + + + + 0 + 0 + + + + + 0 + 32 + + + + + 4 + + + 6 + + + 2 + + + 4 + + + 1 + + + + + + 0 + 0 + + + + + 50 + 26 + + + + + 52 + 30 + + + + Toggle angular jog speed range + + + FAST + + + true + + + true + + + SLOW + + + FAST + + + slider_jog_angular + + + + + + + + 0 + 0 + + + + + 0 + 26 + + + + + 16777215 + 30 + + + + Adjust angular jog rate + + + 3600 + + + 100 + + + 100 + + + 3000 + + + Qt::Horizontal + + + slider-jogspeed-angular + + + false + + + true + + + + + + + + 0 + 0 + + + + + 60 + 26 + + + + + 60 + 30 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + Qt::AlignCenter + + + %d + + + false + + + true + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 11 + + + + + + + + + + + + + + + + + + + 2 + + + 2 + + + 1 + + + 2 + + + 1 + + + + + + 8 + 0 + + + + + 0 + 0 + + + + + 1000 + 16777215 + + + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 10 + 0 + + + + + 188 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::Box + + + QFrame::Raised + + + + 4 + + + 4 + + + 4 + + + 4 + + + 2 + + + + + 6 + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + CYCLE +START + + + true + + + true + + + + 0 + 255 + 0 + + + + 1 + + + 0.200000000000000 + + + 6 + + + 6 + + + true + + + true + + + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + STOP + + + true + + + INSTANCE.progressBar.setFormat('STOPPED') + + + + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + PAUSE + + + true + + + true + + + false + + + true + + + true + + + + 255 + 255 + 0 + + + + 1 + + + true + + + 0.200000000000000 + + + 6 + + + 6 + + + RESUME + + + PAUSE + + + false + + + true + + + false + + + false + + + false + + + true + + + false + + + false + + + false + + + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + STEP + + + true + + + false + + + 0 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + OPT +BLOCK + + + true + + + true + + + false + + + true + + + + 0 + 255 + 0 + + + + 1 + + + 0.200000000000000 + + + 10 + + + 6 + + + 6 + + + true + + + true + + + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + OPT +STOP + + + true + + + true + + + false + + + true + + + + 0 + 255 + 0 + + + + 1 + + + 0.200000000000000 + + + 6 + + + 6 + + + true + + + true + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + MIST +OFF + + + true + + + false + + + true + + + false + + + true + + + true + + + + 0 + 255 + 0 + + + + 1 + + + 0.200000000000000 + + + 6 + + + 6 + + + MIST +ON + + + MIST +OFF + + + true + + + true + + + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + FLOOD +OFF + + + true + + + true + + + false + + + true + + + true + + + + 0 + 255 + 0 + + + + 1 + + + 0.200000000000000 + + + 6 + + + 6 + + + FLOOD +ON + + + FLOOD +OFF + + + true + + + true + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + Reload last loaded program + + + RELOAD + + + + + + + + 1 + 0 + + + + + 80 + 39 + + + + + 16777215 + 64 + + + + Spindle pause + + + NO +LIFT + + + true + + + false + + + + + + false + + + false + + + true + + + + 255 + 0 + 0 + + + + 1 + + + 0.200000000000000 + + + 6 + + + 6 + + + SPINDLE +LIFT + + + NO +LIFT + + + false + + + + + + + + + + 0 + 0 + + + + + 90 + 24 + + + + + 16777215 + 26 + + + + + Lato + 75 + true + + + + false + + + Qt::ImhNone + + + 99 + + + 0 + + + Qt::AlignCenter + + + true + + + false + + + + + + + + + + + 7 + 0 + + + + + 158 + 0 + + + + + 284 + 16777215 + + + + QFrame::Box + + + QFrame::Raised + + + + 6 + + + 1 + + + 4 + + + 1 + + + 4 + + + + + + 0 + 0 + + + + + 20 + 0 + + + + + + + :/images/images/atc_spindle_tool.png + + + false + + + Qt::AlignBottom|Qt::AlignHCenter + + + 1 + + + -1 + + + + + + + + 4 + + + 2 + + + 0 + + + 2 + + + 0 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 60 + 20 + + + + TOOL + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 60 + 20 + + + + DIA + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 60 + 20 + + + + SCS + + + Qt::AlignCenter + + + + + + + + + 4 + + + 1 + + + 1 + + + 0 + + + + + + 0 + 0 + + + + + 42 + 24 + + + + + 110 + 26 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + 1 + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 50 + 24 + + + + + 110 + 26 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + 1 + + + 200.000 + + + Qt::AlignCenter + + + %5.3f + + + %5.3f + + + 0 + + + true + + + + + + + + 0 + 0 + + + + + 42 + 24 + + + + + 110 + 26 + + + + Surface cutting speed + + + + + + QFrame::WinPanel + + + QFrame::Sunken + + + 1 + + + 200 + + + Qt::AlignCenter + + + %d + + + %d + + + false + + + true + + + + + + + + + + 0 + 0 + + + + + 20 + 26 + + + + + 379 + 26 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + No Tool Loaded + + + false + + + Qt::AlignCenter + + + true + + + + + + + + + + + + + + + + + 15 + 0 + + + + + 0 + 220 + + + + + 16777215 + 375 + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 32 + 0 + + + + + 600 + 0 + + + + + 16777215 + 16777215 + + + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 61 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777211 + + + + QFrame::Box + + + QFrame::Raised + + + 1 + + + + 2 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + 1 + + + 1 + + + 1 + + + 4 + + + 4 + + + 1 @@ -12996,7 +12167,7 @@ SCROLL - Zero axis Y + Zero axis A ZERO @@ -13034,10 +12205,10 @@ SCROLL false - 1 + 3 - Y + A 0.010000000000000 @@ -13074,11 +12245,11 @@ SCROLL - - + + - - 0 + + 1 0 @@ -13094,98 +12265,36 @@ SCROLL 76 - - QFrame::WinPanel - - - QFrame::Sunken - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - true - - - true - - - false - - - - - - - - 1 - 0 - - - + - 58 - 36 + 0 + 0 - - - 16777215 - 76 - + + Show distance to go - 5 + DTG true - false - - - QToolButton::DelayedPopup - - true - - - 255 - 0 - 255 - - - - 4 - - - 0 - - - 0 - - - 4 - - - + + false - - CALCULATOR + + true - - selectButtonGroup - - - + + - + 0 0 @@ -13202,31 +12311,204 @@ SCROLL 76 - - QFrame::WinPanel - - - QFrame::Sunken - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 3 - - - true - - - true - - - false + + 0 + + + + 0 + 0 + + + + + 16777215 + 76 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + HOME + + + + 16 + 16 + + + + false + + + false + + + true + + + false + + + true + + + false + + + + 0 + 255 + 0 + + + + 1 + + + 0.200000000000000 + + + 4 + + + 5 + + + UNHOME + + + HOME + + + false + + + true + + + 1 + + + 1 + + + + + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + + 0 + 0 + + + + TOOL + + + QToolButton::InstantPopup + + + Y + + + + + - - + + 1 @@ -13246,7 +12528,7 @@ SCROLL - Zero axis Z + Zero axis X ZERO @@ -13284,10 +12566,10 @@ SCROLL false - 2 + 0 - Z + X 0.010000000000000 @@ -13324,7 +12606,7 @@ SCROLL - + @@ -13574,8 +12856,51 @@ SCROLL - - + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 3 + + + true + + + true + + + false + + + + + 1 @@ -13595,49 +12920,140 @@ SCROLL - X + HOME +ALL - + true - - false + + true - - false + + + 0 + 255 + 0 + - - QToolButton::DelayedPopup + + 1 - - axis-select-x + + 0.200000000000000 - + + 4 + + + 5 + + true + + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + Zero axis Z + + + ZERO + + + false + + + false + + + 0 + 255 + 0 + + + 255 0 - 255 + 0 - - 4 + + 0.200000000000000 + + + false + + + true + + + false + + + 2 - X + Z + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in - - CALCULATOR + + %1.2f mm - - selectButtonGroup - - - + + 1 @@ -13657,7 +13073,7 @@ SCROLL - Z + 5 true @@ -13668,25 +13084,9 @@ SCROLL QToolButton::DelayedPopup - - Qt::NoArrow - - - - true - - false - - - - 255 - 0 - 255 - - 4 @@ -13697,10 +13097,10 @@ SCROLL 0 - 2 + 4 - Z + CALCULATOR @@ -13710,11 +13110,11 @@ SCROLL - - + + - - 0 + + 1 0 @@ -13730,31 +13130,87 @@ SCROLL 76 - - QFrame::WinPanel + + Zero axis A - - QFrame::Sunken + + ZERO - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + false - - 4 + + false - - true + + + 0 + 255 + 0 + - + + + 255 + 0 + 0 + + + + 0.200000000000000 + + + false + + true - + + false + + + 5 + + + C + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + false + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + - + 0 @@ -13783,7 +13239,7 @@ SCROLL Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - 2 + 1 true @@ -13796,11 +13252,11 @@ SCROLL - - + + - - 1 + + 0 0 @@ -13816,87 +13272,43 @@ SCROLL 76 - - Zero axis A + + QFrame::WinPanel - - ZERO + + QFrame::Sunken - - false + + - - false + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 0 - 255 - 0 - + + 0 - - - 255 - 0 - 0 - + + true - - 0.200000000000000 + + false - + false - + true - + false - - 5 - - - C - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - + false - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - + + 0 @@ -13916,9 +13328,9 @@ SCROLL - 0 + 1 - + 0 @@ -13931,7 +13343,7 @@ SCROLL 76 - + 0 @@ -13948,7 +13360,7 @@ SCROLL 0 - + 1 @@ -13970,18 +13382,9 @@ SCROLL HOME - - - 16 - 16 - - false - - false - true @@ -14019,23 +13422,20 @@ SCROLL HOME - - false - true - 1 + 4 - 1 + 4 - + 0 @@ -14054,7 +13454,7 @@ SCROLL 76 - + 0 @@ -14071,7 +13471,7 @@ SCROLL 0 - + 0 @@ -14103,16 +13503,90 @@ SCROLL QToolButton::InstantPopup - Y + A + + + + 0 + 0 + + + + + 16777215 + 76 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + - - + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + true + + + true + + + false + + + + + 1 @@ -14131,41 +13605,141 @@ SCROLL 76 + + Select work coordinate system + - HOME -ALL + WCS + + + true + + + true + + + QToolButton::DelayedPopup + + + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + Z + + + true + + + false + + + QToolButton::DelayedPopup + + + Qt::NoArrow + + + true - true + false - 0 - 255 - 0 + 255 + 0 + 255 - 1 - - - 0.200000000000000 + 4 - 4 + 0 - 5 + 0 - + + 2 + + + Z + + + CALCULATOR + + + selectButtonGroup + + + + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + true + + true + + false + - + @@ -14188,7 +13762,7 @@ ALL 0 - + 0 @@ -14201,7 +13775,7 @@ ALL 76 - + 0 @@ -14295,7 +13869,7 @@ ALL - + 0 0 @@ -14309,7 +13883,7 @@ ALL 16777215 - 64 + 76 @@ -14367,13 +13941,164 @@ ALL + + + + 0 + 0 + + + + + 16777215 + 76 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + X + + + true + + + false + + + false + + + QToolButton::DelayedPopup + + + axis-select-x + + + true + + + + 255 + 0 + 255 + + + + 4 + + + X + + + CALCULATOR + + + selectButtonGroup + - - + + - 0 + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + 4 + + + true + + + false + + + QToolButton::DelayedPopup + + + true + + + 4 + + + 0 + + + 0 + + + 3 + + + + + + CALCULATOR + + + selectButtonGroup + + + + + + + + 1 0 @@ -14392,7 +14117,7 @@ ALL 0 - + 0 @@ -14405,7 +14130,7 @@ ALL 76 - + 0 @@ -14422,10 +14147,10 @@ ALL 0 - + - 1 + 0 0 @@ -14444,9 +14169,18 @@ ALL HOME + + + 16 + 16 + + false + + false + true @@ -14484,22 +14218,22 @@ ALL HOME + + false + true - - 4 - - 4 + 0 - + - + 0 0 @@ -14513,10 +14247,10 @@ ALL 16777215 - 64 + 76 - + 0 @@ -14533,9 +14267,9 @@ ALL 0 - + - + 0 0 @@ -14552,6 +14286,12 @@ ALL 76 + + + 0 + 0 + + 0 @@ -14561,11 +14301,17 @@ ALL TOOL + + + 24 + 24 + + QToolButton::InstantPopup - B + X @@ -14573,6 +14319,254 @@ ALL + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + Y + + + true + + + false + + + QToolButton::DelayedPopup + + + axis-select-z + + + true + + + false + + + + 255 + 0 + 255 + + + + 4 + + + 0 + + + 0 + + + 1 + + + Y + + + CALCULATOR + + + selectButtonGroup + + + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + Zero axis Y + + + ZERO + + + false + + + false + + + + 0 + 255 + 0 + + + + + 255 + 0 + 0 + + + + 0.200000000000000 + + + false + + + true + + + false + + + 1 + + + Y + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + MPG +SCROLL + + + true + + + false + + + QToolButton::DelayedPopup + + + true + + + + 255 + 0 + 255 + + + + 4 + + + 0 + + + 0 + + + -2 + + + MPG0 + + + CALCULATOR + + + false + + + false + + + false + + + false + + + selectButtonGroup + + + @@ -18094,7 +18088,7 @@ ALL 2 - 02:37:25 + 06:39:39 PM Qt::AlignCenter @@ -18331,7 +18325,7 @@ ALL cam_dia_changed() - 490 + 404 135 @@ -18347,12 +18341,12 @@ ALL btn_spindle_z_down_clicked() - 931 - 338 + 424 + 85 926 - 0 + -8 @@ -18363,8 +18357,8 @@ ALL btn_gcode_edit_clicked() - 540 - 105 + 454 + 104 515 @@ -18379,8 +18373,8 @@ ALL chk_use_virtual_changed() - 758 - 246 + 474 + 85 565 @@ -18395,8 +18389,8 @@ ALL chk_override_limits_checked() - 758 - 354 + 474 + 85 719 @@ -18416,7 +18410,7 @@ ALL 273 - 767 + 859 @@ -18427,8 +18421,8 @@ ALL chk_alpha_mode_changed() - 758 - -37 + 474 + 85 645 @@ -18475,12 +18469,12 @@ ALL chk_use_camera_changed() - 758 - 318 + 474 + 85 656 - 767 + 859 @@ -18507,7 +18501,7 @@ ALL cam_zoom_changed() - 490 + 404 135 @@ -18523,7 +18517,7 @@ ALL cam_rot_changed() - 490 + 404 135 @@ -18539,8 +18533,8 @@ ALL chk_inhibit_selection_changed() - 758 - 19 + 474 + 85 719 @@ -18571,8 +18565,8 @@ ALL chk_run_from_line_checked() - 758 - 210 + 474 + 85 554 @@ -18587,8 +18581,8 @@ ALL btn_copy_file_clicked() - 540 - 115 + 454 + 114 446 @@ -18619,8 +18613,8 @@ ALL btn_load_file_clicked() - 540 - 105 + 454 + 104 1059 @@ -18651,8 +18645,8 @@ ALL btn_save_status_clicked() - 540 - 105 + 454 + 104 1098 @@ -18667,12 +18661,12 @@ ALL btn_spindle_z_up_clicked() - 868 - 338 + 424 + 85 717 - 0 + -11 @@ -18683,12 +18677,12 @@ ALL chk_use_sensor_changed() - 758 - 282 + 474 + 85 508 - 767 + 859 @@ -18699,12 +18693,12 @@ ALL btn_zoomin_clicked() - 915 - 424 + 424 + 85 631 - 0 + -11 @@ -18715,8 +18709,8 @@ ALL btn_copy_file_clicked() - 540 - 115 + 454 + 114 471 @@ -18731,12 +18725,12 @@ ALL btn_zoomout_clicked() - 1029 - 424 + 424 + 85 1073 - 0 + -19 @@ -18763,12 +18757,12 @@ ALL btn_about_clicked() - 1207 - 105 + 470 + 100 988 - 0 + -20 @@ -18779,8 +18773,8 @@ ALL btn_clear_status_clicked() - 540 - 105 + 454 + 104 1039 @@ -18795,7 +18789,7 @@ ALL slow_button_clicked() - 1553 + 1267 331 @@ -18811,7 +18805,7 @@ ALL slow_button_clicked() - 1354 + 1068 434 @@ -18827,12 +18821,12 @@ ALL percent_loaded_changed() - 557 - 82 + 533 + 102 484 - 0 + -62 @@ -18843,12 +18837,12 @@ ALL slider_rapid_changed() - 1094 - 588 + 816 + 582 861 - 767 + 791 @@ -18859,28 +18853,28 @@ ALL btn_home_all_clicked() - 868 - 490 + 678 + 478 789 - 767 + 784 btn_home_0 - clicked() + clicked(bool) MainWindow btn_home_clicked() - 868 - 529 + 703 + 556 616 - 767 + 795 @@ -18891,12 +18885,12 @@ ALL btn_home_clicked() - 868 - 567 + 655 + 556 621 - 767 + 781 @@ -18907,12 +18901,28 @@ ALL btn_home_clicked() - 868 - 606 + 684 + 596 706 - 767 + 793 + + + + + btn_home_3 + clicked() + MainWindow + btn_home_clicked() + + + 645 + 636 + + + 643 + 791 @@ -18923,12 +18933,12 @@ ALL btn_systemtool_toggled() - 695 - 490 + 517 + 478 494 - 767 + 781 @@ -18960,7 +18970,7 @@ ALL 155 - 767 + 789 @@ -18976,7 +18986,7 @@ ALL 7 - 767 + 800 @@ -18992,7 +19002,7 @@ ALL 64 - 767 + 804 @@ -19008,7 +19018,7 @@ ALL 60 - 767 + 786 @@ -19024,122 +19034,10 @@ ALL 794 - 0 - - - - - chk_auto_mode_ext_macro - toggled(bool) - MainWindow - chk_auto_mode_external_macro_changed() - - - 616 - 367 - - - 699 - -57 - - - - - chk_auto_mode_macro_buttons - toggled(bool) - MainWindow - chk_auto_mode_macro_changed() - - - 634 - 398 - - - 671 -41 - - btn_maxv_ovr_100 - clicked() - MainWindow - btn_maxv_100_clicked() - - - 1127 - 495 - - - 782 - 383 - - - - - btn_maxv_ovr_50 - clicked() - MainWindow - btn_maxv_50_clicked() - - - 911 - 495 - - - 782 - 383 - - - - - slider_maxv_ovr - valueChanged(int) - MainWindow - slider_maxv_changed() - - - 1019 - 495 - - - 782 - 383 - - - - - btn_home_3 - clicked() - MainWindow - btn_home_clicked() - - - 827 - 626 - - - 782 - 383 - - - - - btn_home_4 - clicked() - MainWindow - btn_home_clicked() - - - 827 - 665 - - - 782 - 383 - - - @@ -19222,13 +19120,10 @@ ALL btn_stop_clicked() btn_systemtool_toggled() hideVirtualKeyboard() - chk_auto_mode_macro_changed() - chk_auto_mode_external_macro_changed() - - + + - diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index 781e838e1a9..6f739341c7a 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -1456,12 +1456,8 @@ def btn_systemtool_toggled(self, state): def mpg_selection_changed(self, data): if data =='MPG0': - self.w.btn_mpg_scroll.setChecked(True) self.recolorMPGFocusBorder() elif data == 'None': - self.w.btn_mpg_scroll.group().setExclusive(False) - self.w.btn_mpg_scroll.setChecked(False) - self.w.btn_mpg_scroll.group().setExclusive(True) self.removeMPGFocusBorder() def MPG_select_changed(self, button): @@ -1476,12 +1472,9 @@ def MPG_select_changed(self, button): if button == self.w.btn_mpg_scroll: self.removeMPGFocusBorder() - if not self.w.btn_mpg_scroll.isChecked(): - ACTION.SET_SELECTED_AXIS('None') return if button == self.w.btn_mpg_scroll: if self.w.btn_mpg_scroll.isChecked(): - ACTION.SET_SELECTED_AXIS('MPG0') self.recolorMPGFocusBorder() else: self.removeMPGFocusBorder() From 9fb194aa91fc69141a358869fe5504099159e0f1 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Wed, 27 May 2026 19:08:59 -0700 Subject: [PATCH 57/79] qtdragon sim -fix goto user macro raise up to Z0 in g53 rather then user units --- configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini index e7a674f81b2..2e5e1884e84 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini @@ -95,7 +95,7 @@ EMBED_TAB_LOCATION=tabWidget_utilities [MDI_COMMAND_LIST] # for macro buttons on main oage up to 10 possible -MDI_COMMAND_MACRO0 = G0 Z25;X0 Y0;Z0, Goto\nUser\nZero +MDI_COMMAND_MACRO0 = G53 G0 Z0;G0 X0 Y0;Z0, Goto\nUser\nZero MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero [FILTER] From e052b547b654cddc72cce3b1093c358715e26344 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Wed, 24 Jun 2026 20:49:11 -0700 Subject: [PATCH 58/79] gmoccapy -fix merge error --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index ab27cab9123..34026f8e210 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -1352,7 +1352,7 @@ def request_pause(self,data): def request_macro_call(self, data): # if MDI command change to MDI and run cmd = self.INFO.get_ini_mdi_command(data) - print('MDI command:',data,cmd) + print(f'MDI command:{cmd} data:{data}') if not cmd is None: LOG.debug("INI MDI COMMAND #: {} = {}".format(data, cmd)) self.ACTION.CALL_INI_MDI(data,mode_return = True) @@ -2575,7 +2575,7 @@ def on_offset_col_edit_started(self, widget, filtered_path, new_text, col): (store_path,) = offsetpage.modelfilter.convert_path_to_child_path(path) row = store_path if self.widgets.offsetpage1.btn_edit_offsets.get_active() or \ - if self.touch_button_dic["edit_offsets"].get_active(): + self.touch_button_dic["edit_offsets"].get_active(): value = self.dialogs.show_entry_dialog(data=offsetpage.store[row][col], header=_("Enter value for offset"), label=f"{offsetpage.store[row][0]} {AXISLIST[col]}-" + _("offset:"), From 9c0034aa230bc90a857b029a65a3a18ab38c2a23 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Sat, 27 Jun 2026 20:08:13 -0700 Subject: [PATCH 59/79] qtdragon.ui -fix merge --- share/qtvcp/screens/qtdragon/qtdragon.ui | 3136 +++++++++++----------- 1 file changed, 1626 insertions(+), 1510 deletions(-) diff --git a/share/qtvcp/screens/qtdragon/qtdragon.ui b/share/qtvcp/screens/qtdragon/qtdragon.ui index e0f69fbfe29..4edf09dff06 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon.ui +++ b/share/qtvcp/screens/qtdragon/qtdragon.ui @@ -7,7 +7,7 @@ 0 0 - 1280 + 1566 768 @@ -1216,7 +1216,7 @@ RESET QFrame::Raised - 0 + 1 @@ -3504,7 +3504,7 @@ PLATE QFrame::Raised - 0 + 9 @@ -5786,7 +5786,382 @@ LOG 0 - + + + + 600 + 16777215 + + + + true + + + + + 0 + -351 + 306 + 734 + + + + + 600 + 16777215 + + + + + + + + 0 + 0 + + + + + 180 + 0 + + + + + 600 + 16777215 + + + + + 4 + + + QLayout::SetDefaultConstraint + + + 4 + + + 4 + + + 4 + + + 4 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + KEYBOARD MAPPING + + + Qt::AlignCenter + + + + + + + ESC - Program Abort + + + + + + + F1 - ESTOP + + + + + + + F2 - Machine OFF + + + + + + + F11 - Fullscreen + + + + + + + F12 - Style Sheet Editor + + + + + + + Home - HOME All + + + + + + + Pause - Pause program + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Make complicated 3D files more visible + + + ENABLE ALPHA MODE + + + + + + + + 0 + 0 + + + + Make complicated 3D files more visible + + + INHIBIT MOUSE SELECTION + + + + + + + + 0 + 0 + + + + Enable external offsets for spindle pause + + + USE EXTERNAL OFFSETS + + + + + + + + 0 + 0 + + + + Reload last loaded tool + + + RELOAD LAST TOOL + + + + + + + + 0 + 0 + + + + Reload last loaded program + + + RELOAD LAST PROGRAM + + + + + + + + 0 + 0 + + + + Enable keyboard shortcuts + + + USE KEYBOARD SHORTCUTS + + + + + + + + 0 + 0 + + + + Enable run from line + + + USE RUN FROM LINE + + + + + + + + 0 + 0 + + + + Enable use of onboard virtual keyboard + + + USE VIRTUAL KEYBOARD + + + + + + + + 0 + 0 + + + + Enable tool sensor + + + USE TOOL SENSOR + + + true + + + + + + + + 0 + 0 + + + + Enable Webcam for work offset location + + + USE CAMERA + + + true + + + + + + + + 0 + 0 + + + + OVERRIDE LIMITS + + + + + + + + 0 + 0 + + + + Automatically switch to MDI mode with external MDI requests + + + AUTO MODE SWITCH EXTERNAL MDI + + + true + + + + + + + + 0 + 0 + + + + Automatically switch to MDI mode with MDI buttons + + + AUTO MODE SWITCH MACRO BUTTONS + + + true + + + + + + + + + + + + + + Qt::Vertical + + + + + 0 @@ -5795,23 +6170,20 @@ LOG - 180 + 300 0 - 260 + 16777215 16777215 - + 4 - - QLayout::SetDefaultConstraint - 4 @@ -5825,311 +6197,110 @@ LOG 4 - - - QFrame::NoFrame - - - QFrame::Raised - - - KEYBOARD MAPPING - - - Qt::AlignCenter - - - - - - - ESC - Program Abort - - - - - - - F1 - ESTOP - - - - - - - F2 - Machine OFF - - - - - - - F11 - Fullscreen - - - - - - - F12 - Style Sheet Editor - - - - - - - Home - HOME All - - - - - - - Pause - Pause program - + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 120 + 30 + + + + + 120 + 30 + + + + + + + + + + + + 0 + 0 + + + + + 50 + 30 + + + + + 50 + 30 + + + + X + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 50 + 30 + + + + + 50 + 30 + + + + Y + + + Qt::AlignCenter + + + + - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - Make complicated 3D files more visible - - - ENABLE ALPHA MODE - - - - - - - - 0 - 0 - - - - Make complicated 3D files more visible - - - INHIBIT MOUSE SELECTION - - - - - - - - 0 - 0 - - - - Enable external offsets for spindle pause - - - USE EXTERNAL OFFSETS - - - - - - - - 0 - 0 - - - - Reload last loaded tool - - - RELOAD LAST TOOL - - - - - - - - 0 - 0 - - - - Reload last loaded program - - - RELOAD LAST PROGRAM - - - - - - - - 0 - 0 - - - - Enable keyboard shortcuts - - - USE KEYBOARD SHORTCUTS - - - - - - - - 0 - 0 - - - - Enable run from line - - - USE RUN FROM LINE - - - - - - - - 0 - 0 - - - - Enable use of onboard virtual keyboard - - - USE VIRTUAL KEYBOARD - - - - - - - - 0 - 0 - - - - Enable tool sensor - - - USE TOOL SENSOR - - - true - - - - - - - - 0 - 0 - - - - Enable Webcam for work offset location - - - USE CAMERA - - - true - - - - - - - - 0 - 0 - - - - OVERRIDE LIMITS - - - - - - - - - - Qt::Vertical - - - - - - - - 0 - 0 - - - - - 300 - 0 - - - - - 16777215 - 16777215 - - - - - 4 - - - 4 - - - 4 - - - 4 - - - 4 - - - - + + 4 @@ -6146,9 +6317,9 @@ LOG 0 - + - + 0 0 @@ -6166,12 +6337,12 @@ LOG - + HOME LOCATION - + 0 @@ -6180,26 +6351,29 @@ LOG - 50 + 60 30 - 50 + 60 30 - - X + + 8 Qt::AlignCenter + + true + - + 0 @@ -6208,158 +6382,53 @@ LOG - 50 + 60 30 - 50 + 60 30 - - Y + + 8 Qt::AlignCenter + + true + - - + + + TOUCHOFF PARAMETERS + + + Qt::AlignCenter + + 4 - 0 + 4 - 0 + 5 - 0 + 4 - 0 - - - - - - 0 - 0 - - - - - 120 - 30 - - - - - 120 - 30 - - - - HOME LOCATION - - - - - - - - 0 - 0 - - - - - 60 - 30 - - - - - 60 - 30 - - - - 8 - - - Qt::AlignCenter - - - true - - - - - - - - 0 - 0 - - - - - 60 - 30 - - - - - 60 - 30 - - - - 8 - - - Qt::AlignCenter - - - true - - - - - - - - - - TOUCHOFF PARAMETERS - - - Qt::AlignCenter - - - - 4 - - - 4 - - - 5 - - - 4 - - - 4 + 4 @@ -12047,468 +12116,144 @@ LIFT 0 - - - - - 32 - 0 - - - - - 600 - 0 - - - - - 16777215 - 16777215 - - - - - 2 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 61 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777211 - - - - QFrame::Box - - - QFrame::Raised - - - 1 - - - - 2 - - - 4 - - - 4 - - - 4 - - - 4 - - - - - - 1 - - - 1 - - - 1 - - - 4 - - - 4 - - - - - - 1 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - Zero axis A - - - ZERO - - - false - - - false - - - - 0 - 255 - 0 - - - - - 255 - 0 - 0 - - - - 0.200000000000000 - - - false - - - true - - - false - - - 3 - - - A - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - - 0 - - - %1.3f in - - - %1.2f mm - - - - - - - - 1 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - - 0 - 0 - - - - Show distance to go - - - DTG - - - true - - - true - - - false - - - true - - - - - - - - 0 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - 0 - - - - - 0 - 0 - - - - - 16777215 - 76 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 1 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - HOME - - - - 16 - 16 - - - - false - - - false - - - true - - - false - - - true - - - false - - - - 0 - 255 - 0 - - - - 1 - - - 0.200000000000000 - - - 4 - - - 5 - - - UNHOME - - - HOME - - - false - - - true - - - 1 - - - 1 - - - - - - - - - 0 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - - 0 - 0 - - - - TOOL - - - QToolButton::InstantPopup - - - Y - - - - - + + + + + 32 + 0 + + + + + 600 + 0 + + + + + 16777215 + 16777215 + + + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 61 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777211 + + + + QFrame::Box + + + QFrame::Raised + + + 1 + + + + 2 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + 1 + + + 1 + + + 1 + + + 4 + + + 4 + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + Select work coordinate system + + + WCS + + + true + + + true + + + QToolButton::DelayedPopup + - - + + 1 @@ -12528,7 +12273,7 @@ LIFT - Zero axis X + Zero axis A ZERO @@ -12566,10 +12311,10 @@ LIFT false - 0 + 3 - X + A 0.010000000000000 @@ -12606,11 +12351,11 @@ LIFT - - + + - 0 + 1 0 @@ -12629,7 +12374,7 @@ LIFT 0 - + 0 @@ -12642,7 +12387,7 @@ LIFT 76 - + 0 @@ -12659,10 +12404,10 @@ LIFT 0 - + - 1 + 0 0 @@ -12681,9 +12426,18 @@ LIFT HOME + + + 16 + 16 + + false + + false + true @@ -12721,22 +12475,22 @@ LIFT HOME + + false + true - - 2 - - 2 + 0 - + - + 0 0 @@ -12750,10 +12504,10 @@ LIFT 16777215 - 64 + 76 - + 0 @@ -12770,9 +12524,9 @@ LIFT 0 - + - + 0 0 @@ -12789,6 +12543,12 @@ LIFT 76 + + + 0 + 0 + + 0 @@ -12798,11 +12558,17 @@ LIFT TOOL + + + 24 + 24 + + QToolButton::InstantPopup - Z + X @@ -12810,8 +12576,8 @@ LIFT - - + + 1 @@ -12837,27 +12603,27 @@ LIFT - Show absolute coordinates + Show distance to go - ABS + DTG true - - true - true + false + + true - - + + 0 @@ -12882,25 +12648,37 @@ LIFT QFrame::Sunken + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - 3 + 0 true + + false + + + false + true + + false + false - - + + 1 @@ -12920,41 +12698,58 @@ LIFT - HOME -ALL + Y + + + true + + + false + + + QToolButton::DelayedPopup + + + axis-select-z true - true + false - - 0 - 255 - 0 + + 255 + 0 + 255 - 1 - - - 0.200000000000000 + 4 - 4 + 0 - 5 + 0 - - true + + 1 + + + Y + + CALCULATOR + + + selectButtonGroup + - - + + 1 @@ -12974,7 +12769,7 @@ ALL - Zero axis Z + Zero axis X ZERO @@ -13012,10 +12807,10 @@ ALL false - 2 + 0 - Z + X 0.010000000000000 @@ -13052,8 +12847,8 @@ ALL - - + + 1 @@ -13073,7 +12868,7 @@ ALL - 5 + 4 true @@ -13087,6 +12882,13 @@ ALL true + + + 255 + 0 + 255 + + 4 @@ -13097,7 +12899,7 @@ ALL 0 - 4 + 3 @@ -13110,8 +12912,8 @@ ALL - - + + 1 @@ -13131,7 +12933,7 @@ ALL - Zero axis A + Zero axis Y ZERO @@ -13169,10 +12971,10 @@ ALL false - 5 + 1 - C + Y 0.010000000000000 @@ -13209,7 +13011,7 @@ ALL - + @@ -13252,8 +13054,73 @@ ALL - - + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + 5 + + + true + + + false + + + QToolButton::DelayedPopup + + + true + + + + 255 + 0 + 255 + + + + 4 + + + 0 + + + 0 + + + 4 + + + + + + CALCULATOR + + + selectButtonGroup + + + + + 0 @@ -13278,37 +13145,124 @@ ALL QFrame::Sunken - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - 0 + 3 true - + + true + + false - + + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + Zero axis Z + + + ZERO + + false - + + false + + + + 0 + 255 + 0 + + + + + 255 + 0 + 0 + + + + 0.200000000000000 + + + false + + true - + false - + + 2 + + + Z + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + false + + 100.000000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + - - + + 0 @@ -13328,9 +13282,9 @@ ALL - 1 + 0 - + 0 @@ -13343,7 +13297,7 @@ ALL 76 - + 0 @@ -13360,7 +13314,7 @@ ALL 0 - + 1 @@ -13426,18 +13380,18 @@ ALL true - 4 + 2 - 4 + 2 - + - + 0 0 @@ -13451,10 +13405,10 @@ ALL 16777215 - 76 + 64 - + 0 @@ -13471,7 +13425,7 @@ ALL 0 - + 0 @@ -13503,50 +13457,19 @@ ALL QToolButton::InstantPopup - A + Z - - - - 0 - 0 - - - - - 16777215 - 76 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - + + - - 0 + + 1 0 @@ -13562,31 +13485,34 @@ ALL 76 - - QFrame::WinPanel + + + 0 + 0 + - - QFrame::Sunken + + Show absolute coordinates - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + ABS - - 2 + + true - + true - + true - - false + + true - - + + 1 @@ -13605,24 +13531,49 @@ ALL 76 - - Select work coordinate system - - WCS + X true + + false + - true + false QToolButton::DelayedPopup + + axis-select-x + + + true + + + + 255 + 0 + 255 + + + + 4 + + + X + + + CALCULATOR + + + selectButtonGroup + - + @@ -13654,93 +13605,235 @@ ALL QToolButton::DelayedPopup - - Qt::NoArrow + + Qt::NoArrow + + + + + + true + + + false + + + + 255 + 0 + 255 + + + + 4 + + + 0 + + + 0 + + + 2 + + + Z + + + CALCULATOR + + + selectButtonGroup + + + + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + true + + + true + + + false + + + + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + true + + + true + + + false + + + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + Zero axis A - - + + ZERO - true + false - + false + + 0 + 255 + 0 + + + 255 0 - 255 + 0 - - 4 + + 0.200000000000000 - - 0 + + false - - 0 + + true + + + false - 2 + 5 - Z + C - - CALCULATOR + + 0.010000000000000 - - selectButtonGroup - - - - - - - - 0 - 0 - + + 0.025000000000000 - - - 58 - 36 - + + -1.000000000000000 - - - 16777215 - 76 - + + false - - QFrame::WinPanel + + 100.000000000000000 - - QFrame::Sunken + + 50.000000000000000 - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + P - - 4 + + - - true + + 0 - - true + + %1.3f in - - false + + %1.2f mm - - + + 0 @@ -13762,7 +13855,7 @@ ALL 0 - + 0 @@ -13775,7 +13868,7 @@ ALL 76 - + 0 @@ -13792,7 +13885,7 @@ ALL 0 - + 1 @@ -13814,9 +13907,18 @@ ALL HOME + + + 16 + 16 + + false + + false + true @@ -13854,20 +13956,23 @@ ALL HOME + + false + true - 3 + 1 - 3 + 1 - + 0 @@ -13886,7 +13991,7 @@ ALL 76 - + 0 @@ -13903,7 +14008,7 @@ ALL 0 - + 0 @@ -13935,47 +14040,16 @@ ALL QToolButton::InstantPopup - A + Y - - - - 0 - 0 - - - - - 16777215 - 76 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - + + 1 @@ -13995,110 +14069,44 @@ ALL - X + HOME +ALL - + true - - false - - - false - - - QToolButton::DelayedPopup - - - axis-select-x - - + true - 255 - 0 - 255 + 0 + 255 + 0 - 4 - - - X - - - CALCULATOR - - - selectButtonGroup - - - - - - - - 1 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - 4 - - - true - - - false - - - QToolButton::DelayedPopup - - - true + 1 - - 4 + + 0.200000000000000 - 0 + 4 - 0 - - - 3 - - - + 5 - - CALCULATOR + + true - - selectButtonGroup - - - + + - 1 + 0 0 @@ -14117,7 +14125,7 @@ ALL 0 - + 0 @@ -14130,7 +14138,7 @@ ALL 76 - + 0 @@ -14147,10 +14155,10 @@ ALL 0 - + - 0 + 1 0 @@ -14169,18 +14177,9 @@ ALL HOME - - - 16 - 16 - - false - - false - true @@ -14218,22 +14217,22 @@ ALL HOME - - false - true + + 3 + - 0 + 3 - + - + 0 0 @@ -14247,10 +14246,10 @@ ALL 16777215 - 76 + 64 - + 0 @@ -14267,9 +14266,9 @@ ALL 0 - + - + 0 0 @@ -14286,12 +14285,6 @@ ALL 76 - - - 0 - 0 - - 0 @@ -14301,17 +14294,11 @@ ALL TOOL - - - 24 - 24 - - QToolButton::InstantPopup - X + A @@ -14319,82 +14306,11 @@ ALL - - - - - 1 - 0 - - - - - 58 - 36 - - - - - 16777215 - 76 - - - - Y - - - true - - - false - - - QToolButton::DelayedPopup - - - axis-select-z - - - true - - - false - - - - 255 - 0 - 255 - - - - 4 - - - 0 - - - 0 - - - 1 - - - Y - - - CALCULATOR - - - selectButtonGroup - - - - - + + - 1 + 0 0 @@ -14410,83 +14326,188 @@ ALL 76 - - Zero axis Y - - - ZERO - - - false - - - false - - - - 0 - 255 - 0 - - - - - 255 - 0 - 0 - - - - 0.200000000000000 - - - false - - - true - - - false - - - 1 - - - Y - - - 0.010000000000000 - - - 0.025000000000000 - - - -1.000000000000000 - - - false - - - 100.000000000000000 - - - 50.000000000000000 - - - P - - - - - + 0 - - %1.3f in - - - %1.2f mm - + + + + 0 + 0 + + + + + 16777215 + 76 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 1 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + HOME + + + false + + + true + + + false + + + true + + + false + + + + 0 + 255 + 0 + + + + 1 + + + 0.200000000000000 + + + 4 + + + 5 + + + UNHOME + + + HOME + + + true + + + 4 + + + 4 + + + + + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 64 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 58 + 36 + + + + + 16777215 + 76 + + + + + 0 + 0 + + + + TOOL + + + QToolButton::InstantPopup + + + B + + + + + @@ -14562,9 +14583,6 @@ SCROLL false - - selectButtonGroup - @@ -18088,7 +18106,7 @@ SCROLL 2 - 06:39:39 PM + 08:01:11 PM Qt::AlignCenter @@ -18325,7 +18343,7 @@ SCROLL cam_dia_changed() - 404 + 490 135 @@ -18341,12 +18359,12 @@ SCROLL btn_spindle_z_down_clicked() - 424 - 85 + 931 + 338 926 - -8 + 0 @@ -18357,8 +18375,8 @@ SCROLL btn_gcode_edit_clicked() - 454 - 104 + 540 + 105 515 @@ -18373,8 +18391,8 @@ SCROLL chk_use_virtual_changed() - 474 - 85 + 758 + 246 565 @@ -18389,8 +18407,8 @@ SCROLL chk_override_limits_checked() - 474 - 85 + 758 + 354 719 @@ -18410,7 +18428,7 @@ SCROLL 273 - 859 + 767 @@ -18421,8 +18439,8 @@ SCROLL chk_alpha_mode_changed() - 474 - 85 + 758 + -37 645 @@ -18469,12 +18487,12 @@ SCROLL chk_use_camera_changed() - 474 - 85 + 758 + 318 656 - 859 + 767 @@ -18501,7 +18519,7 @@ SCROLL cam_zoom_changed() - 404 + 490 135 @@ -18517,7 +18535,7 @@ SCROLL cam_rot_changed() - 404 + 490 135 @@ -18533,8 +18551,8 @@ SCROLL chk_inhibit_selection_changed() - 474 - 85 + 758 + 19 719 @@ -18565,8 +18583,8 @@ SCROLL chk_run_from_line_checked() - 474 - 85 + 758 + 210 554 @@ -18581,8 +18599,8 @@ SCROLL btn_copy_file_clicked() - 454 - 114 + 540 + 115 446 @@ -18613,8 +18631,8 @@ SCROLL btn_load_file_clicked() - 454 - 104 + 540 + 105 1059 @@ -18645,8 +18663,8 @@ SCROLL btn_save_status_clicked() - 454 - 104 + 540 + 105 1098 @@ -18661,12 +18679,12 @@ SCROLL btn_spindle_z_up_clicked() - 424 - 85 + 868 + 338 717 - -11 + 0 @@ -18677,12 +18695,12 @@ SCROLL chk_use_sensor_changed() - 474 - 85 + 758 + 282 508 - 859 + 767 @@ -18693,12 +18711,12 @@ SCROLL btn_zoomin_clicked() - 424 - 85 + 915 + 424 631 - -11 + 0 @@ -18709,8 +18727,8 @@ SCROLL btn_copy_file_clicked() - 454 - 114 + 540 + 115 471 @@ -18725,12 +18743,12 @@ SCROLL btn_zoomout_clicked() - 424 - 85 + 1029 + 424 1073 - -19 + 0 @@ -18757,12 +18775,12 @@ SCROLL btn_about_clicked() - 470 - 100 + 1207 + 105 988 - -20 + 0 @@ -18773,8 +18791,8 @@ SCROLL btn_clear_status_clicked() - 454 - 104 + 540 + 105 1039 @@ -18789,7 +18807,7 @@ SCROLL slow_button_clicked() - 1267 + 1553 331 @@ -18805,7 +18823,7 @@ SCROLL slow_button_clicked() - 1068 + 1354 434 @@ -18821,12 +18839,12 @@ SCROLL percent_loaded_changed() - 533 - 102 + 557 + 82 484 - -62 + 0 @@ -18837,12 +18855,12 @@ SCROLL slider_rapid_changed() - 816 - 582 + 1094 + 588 861 - 791 + 767 @@ -18853,28 +18871,28 @@ SCROLL btn_home_all_clicked() - 678 - 478 + 868 + 490 789 - 784 + 767 btn_home_0 - clicked(bool) + clicked() MainWindow btn_home_clicked() - 703 - 556 + 868 + 529 616 - 795 + 767 @@ -18885,12 +18903,12 @@ SCROLL btn_home_clicked() - 655 - 556 + 868 + 567 621 - 781 + 767 @@ -18901,28 +18919,12 @@ SCROLL btn_home_clicked() - 684 - 596 + 868 + 606 706 - 793 - - - - - btn_home_3 - clicked() - MainWindow - btn_home_clicked() - - - 645 - 636 - - - 643 - 791 + 767 @@ -18933,12 +18935,12 @@ SCROLL btn_systemtool_toggled() - 517 - 478 + 695 + 490 494 - 781 + 767 @@ -18970,7 +18972,7 @@ SCROLL 155 - 789 + 767 @@ -18986,7 +18988,7 @@ SCROLL 7 - 800 + 767 @@ -19002,7 +19004,7 @@ SCROLL 64 - 804 + 767 @@ -19018,7 +19020,7 @@ SCROLL 60 - 786 + 767 @@ -19034,10 +19036,122 @@ SCROLL 794 + 0 + + + + + chk_auto_mode_ext_macro + toggled(bool) + MainWindow + chk_auto_mode_external_macro_changed() + + + 616 + 367 + + + 699 + -57 + + + + + chk_auto_mode_macro_buttons + toggled(bool) + MainWindow + chk_auto_mode_macro_changed() + + + 634 + 398 + + + 671 -41 + + btn_maxv_ovr_100 + clicked() + MainWindow + btn_maxv_100_clicked() + + + 1127 + 495 + + + 782 + 383 + + + + + btn_maxv_ovr_50 + clicked() + MainWindow + btn_maxv_50_clicked() + + + 911 + 495 + + + 782 + 383 + + + + + slider_maxv_ovr + valueChanged(int) + MainWindow + slider_maxv_changed() + + + 1019 + 495 + + + 782 + 383 + + + + + btn_home_3 + clicked() + MainWindow + btn_home_clicked() + + + 827 + 626 + + + 782 + 383 + + + + + btn_home_4 + clicked() + MainWindow + btn_home_clicked() + + + 827 + 665 + + + 782 + 383 + + + @@ -19120,10 +19234,12 @@ SCROLL btn_stop_clicked() btn_systemtool_toggled() hideVirtualKeyboard() + chk_auto_mode_macro_changed() + chk_auto_mode_external_macro_changed() - - + + From 305b219ee47e98c4dcbfff32d3883c66b1612040 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 2 Jul 2026 19:42:10 -0700 Subject: [PATCH 60/79] bridge -look for macro commands too MDI and macro commands are similar enough to combine --- lib/python/bridgeui/bridge.py | 45 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index 1d0edfaeddd..c9d8d4aac4b 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -63,14 +63,6 @@ def __init__(self, readAddress = "tcp://127.0.0.1:5690", self.init_read() self.init_write() - def update(self, *arg): - print(self, arg) - raw=arg[0]; row=arg[1];column=arg[2];state=arg[3] - LOG.debug('raw {}, row {}, col {}, state {}'.format(raw,row,column,state)) - print ('raw',raw,'row:',row,'column:',column,'state:',state) - self.writeMsg('set_selected_axis','Y') - self.activeJoint.set(10) - def init(self): self.jogRate = 0 self.jogRateAngular = 0 @@ -143,7 +135,7 @@ def action(self, msg, data): # send msg to hal_glib def writeMsg(self, msg, data): - print('Write Msg called') + #print('Write Msg called') if ZMQ: topic = self.writeTopic message = json.dumps({'FUNCTION':msg,'ARGS':data}) @@ -170,27 +162,43 @@ def ok(self): def cancel(self): self.writeMsg('request_cancel', True) + # if the number is bigger then MDI command list + # then look for MACRO commands def getMdiName(self, num): if num >len(self.INFO.MDI_COMMAND_DICT)-1: + offset = len(self.INFO.MDI_COMMAND_DICT) + return self.getMacroName(num-offset) + else: + temp = list(self.INFO.MDI_COMMAND_DICT.keys())[num] + LOG.debug('MDI:{} {}'.format(num,temp)) + return temp + + def getMacroName(self, num): + if num >len(self.INFO.MACRO_COMMAND_DICT)-1: return 'None' - temp = list(self.INFO.MDI_COMMAND_DICT.keys())[num] - LOG.debug('{} {}'.format(num,temp)) + temp = list(self.INFO.MACRO_COMMAND_DICT.keys())[num] + LOG.debug('MACRO:{} {}'.format(num,temp)) return temp - def getMacroNames(self): - for i in self.INFO.INI_MACROS: - name = i.split()[0] - LOG.debug('{} {}'.format(name,i)) - def runIndexedMacro(self, num): + # check for any MDI commands first: name = self.getMdiName(num) LOG.debug('Macro name:{} ,index: {}'.format(name, num)) if name != 'None': self.writeMsg('request_macro_call', name) + # else look for any MACRO commands: + else: + offset = len(self.INFO.MDI_COMMAND_DICT) + name = self.getMacroName(num-offset) + LOG.debug('Macro name:{} ,index: {}'.format(name, num)) + if name != 'None': + self.writeMsg('request_macro_call', name) + + # cound of MDI and MACRO commands def getMdiCount(self): - print(len(self.INFO.MDI_COMMAND_DICT)) - return len(self.INFO.MDI_COMMAND_DICT) + #print('->',len(self.INFO.MDI_COMMAND_DICT),len(self.INFO.MACRO_COMMAND_DICT)) + return len(self.INFO.MDI_COMMAND_DICT) + len(self.INFO.MACRO_COMMAND_DICT) def getJogRate(self): return self.jogRate @@ -202,6 +210,7 @@ def getJogRateAngular(self): def setJogRateAngular(self, value): self.writeMsg('set_jograte_angular', value) + # XYZABCUVW, None, or MPG0 def getSelectedAxis(self): name = self.currentSelectedAxis if name == 'None': From 89cd1efb513594325da5d0795cea65c6b31e11cf Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 2 Jul 2026 19:49:35 -0700 Subject: [PATCH 61/79] qtdragon -external run of macros, use cycle start for MDI running --- .../screens/qtdragon/qtdragon_handler.py | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index 6f739341c7a..2b90d757d14 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -917,20 +917,24 @@ def lastRunLine(self, line): # called from hal_glib to run macros from external event def request_macro_call(self, data): + #print(f'macro call data: {data}') if not self.w.chk_auto_mode_ext_macro.isChecked() and not STATUS.is_mdi_mode(): self.add_status(_translate("HandlerClass",'Machine must be in MDI mode to run macros'), WARNING) return - - if 'ini-macro-cmd' in data: + cmd = INFO.get_ini_mdi_command(data) + #print(f'MDI command:{cmd} data:{data}') + if INFO.get_ini_mdi_command(data) is None: data = data.replace('ini-macro-cmd-','') try: temp = INFO.MACRO_COMMAND_DICT.get(data).get('cmd') + #print(temp) self.run_macro(data=temp) return - except: - self.add_status(_translate(f"HandlerClass",'External requested INI macro data not recognized:{data}'), CRITICAL) + except Exception as e: + print(e) + self.add_status(_translate("HandlerClass",f'External requested INI macro data not recognized:{data}'), CRITICAL) - elif 'ini-mdi-cmd' in data: + elif INFO.get_ini_macro_command(data) is None: for b in range(0,10): button = self.w['macrobutton{}'.format(b)] # prefer named INI MDI commands @@ -953,9 +957,9 @@ def request_macro_call(self, data): self.add_status(_translate("HandlerClass",'Error running macro: {} {}\n{}'.format(key, text, e))) break else: - self.add_status(_translate(f"HandlerClass",'External requested INI mdi {data} does not match button name/number'), CRITICAL) + self.add_status(_translate("HandlerClass",f'External requested INI mdi {data} does not match button name/number'), CRITICAL) else: - self.add_status(_translate(f"HandlerClass",'External requested INI macro data not recognized:{data}'), CRITICAL) + self.add_status(_translate("HandlerClass",f'External requested INI macro data not recognized:{data}'), CRITICAL) ####################### # CALLBACKS FROM FORM # @@ -990,10 +994,20 @@ def cmb_gcode_history_clicked(self): # program frame def btn_start_clicked(self, obj): + if not STATUS.is_all_homed(): self.add_status(_translate("HandlerClass","Machine must be is homed"), CRITICAL) return - if not os.path.exists(self.last_loaded_program): + if STATUS.is_auto_paused(): + self.command.auto(linuxcnc.AUTO_RESUME) + return + if STATUS.is_mdi_mode(): + self.w.mdiline.submit() + return + if STATUS.is_man_mode(): + self.add_status(_translate("HandlerClass","Can't start cycles or submit MDI commands in manual Mode"),WARNING) + return + if not os.path.exists(self.last_loaded_program): self.add_status(_translate("HandlerClass","No program to execute"), WARNING) return if not STATUS.is_auto_mode(): From 592bb75538f07d116d3f6d4ce1cb721ea1b4f851 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 2 Jul 2026 19:51:13 -0700 Subject: [PATCH 62/79] hal_bridge -add a warning if the write address is already used --- src/hal/user_comps/hal_bridge.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hal/user_comps/hal_bridge.py b/src/hal/user_comps/hal_bridge.py index 1833ab7e7af..39977946508 100644 --- a/src/hal/user_comps/hal_bridge.py +++ b/src/hal/user_comps/hal_bridge.py @@ -118,7 +118,10 @@ def init_hal(self): def init_write(self): context = zmq.Context() self.writeSocket = context.socket(zmq.PUB) - self.writeSocket.bind(self.writeAddress) + try: + self.writeSocket.bind(self.writeAddress) + except zmq.error.ZMQError: + LOG.critical(f'Write address already in use? {self.writeAddress}') def init_read(self): # ZeroMQ Context From 74a99693fb6b6069388074ce7e98f4efea18a8f3 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 2 Jul 2026 19:52:43 -0700 Subject: [PATCH 63/79] qtdragon sim -add a macro command to run from the panel --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 2 +- .../sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal index c630fcf6d87..43f84036885 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.hal +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -24,7 +24,7 @@ net jog-m halui.axis.selected.minus panel.jog-neg net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 -#net m2 halui.gui.mdi-command-0 panel.mdi-2 +net m2 halui.gui.mdi-command-MACRO6 panel.mdi-2 net man panel.manual-mode halui.mode.manual net mdi panel.mdi-mode halui.mode.mdi diff --git a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini index 2e5e1884e84..5efd17e4785 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini +++ b/configs/sim/qtdragon/qtdragon_xyz/qtdragon_halui_test.ini @@ -94,10 +94,17 @@ EMBED_TAB_COMMAND=qtvcp vismach_mill_xyz EMBED_TAB_LOCATION=tabWidget_utilities [MDI_COMMAND_LIST] -# for macro buttons on main oage up to 10 possible +# for macro buttons on main page up to 10 possible MDI_COMMAND_MACRO0 = G53 G0 Z0;G0 X0 Y0;Z0, Goto\nUser\nZero MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero +[MACROS] +MACRO_COMMAND_MACRO6 = go_to_position x-pos y-pos z-pos, Go To \nPosition +MACRO_COMMAND_MACRO2 = lost, LOST +MACRO_COMMAND_MACRO3 = increment x-incr y-incr, INCR +MACRO_COMMAND_MACRO4 = macro_4 +MACRO_COMMAND_MACRO5 = macro_5 + [FILTER] # Controls what programs are shown inqtdragon file manager PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap) @@ -125,7 +132,7 @@ PARAMETER_FILE = qtdragon.var RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.0127 G80 G90 G94 G97 M5 M9 # subroutine/remap path list -SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs +SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs:./macros # on abort, this ngc file is called. required for basic/versa probe ON_ABORT_COMMAND=O call From cce5d206ef1230e74bd8bfdfe4b244cb3d754a09 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Wed, 8 Jul 2026 23:03:57 -0700 Subject: [PATCH 64/79] hal_glib -add function to process one ZMQ message In some cases, we need to directly process one message. eg when using 'wait to don't block' dialog option --- lib/python/common/hal_glib.py | 50 +++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/lib/python/common/hal_glib.py b/lib/python/common/hal_glib.py index caa00c6ba75..ec7e19aec02 100644 --- a/lib/python/common/hal_glib.py +++ b/lib/python/common/hal_glib.py @@ -404,30 +404,40 @@ def init_read_socket(self): GObject.IO_IN|GObject.IO_ERR|GObject.IO_HUP, self.onReadMsg, self.readSocket) - # convert message to a function name and data - # then call that function + # called directly to process any current message + def readNextMsg(self): + event = self.readSocket.poll(timeout=0) + if event & zmq.POLLIN: + self.convertMsg() + + # called when GObject notices a change def onReadMsg(self, queue, condition, sock): while self.readSocket.getsockopt(zmq.EVENTS) & zmq.POLLIN: - # get raw message - topic, data = self.readSocket.recv_multipart() - # convert from json object to python object - y = json.loads(data) - function = y.get('FUNCTION') - data = y.get('ARGS') - LOG.debug('REQUESTED:{}'.format(y)) - if data == '': - try: - self[function]() - except Exception as e: - LOG.debug('not a valid request\n {}'.format(e)) - else: - try: - self[function](data) - except Exception as e: - LOG.debug('not a valid request\n {}'.format(e)) - #self. action(y.get('MESSAGE'),y.get('ARGS')) + self.convertMsg() return True + # convert message to a function name and data + # then call that function + def convertMsg(self): + # get raw message + topic, data = self.readSocket.recv_multipart() + # convert from json object to python object + y = json.loads(data) + function = y.get('FUNCTION') + data = y.get('ARGS') + LOG.debug('REQUESTED:{}'.format(y)) + if data == '': + try: + self[function]() + except Exception as e: + LOG.debug('not a valid request\n {}'.format(e)) + else: + try: + self[function](data) + except Exception as e: + LOG.debug('not a valid request\n {}'.format(e)) + #self. action(y.get('MESSAGE'),y.get('ARGS')) + def merge(self): self.old['command-state'] = self.stat.state self.old['state'] = self.stat.task_state From d912332a4e4a59399e22135734185e5162a47876 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Wed, 8 Jul 2026 23:06:07 -0700 Subject: [PATCH 65/79] qtvcp -dialog_widget: check ZMQ messages directly When waiting for a dialog answer (with wait but don't block option) --- lib/python/qtvcp/widgets/dialog_widget.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/python/qtvcp/widgets/dialog_widget.py b/lib/python/qtvcp/widgets/dialog_widget.py index 25a7e3f5452..a0fa1028c1b 100644 --- a/lib/python/qtvcp/widgets/dialog_widget.py +++ b/lib/python/qtvcp/widgets/dialog_widget.py @@ -1871,6 +1871,10 @@ def showdialog(self, preload=None, overlay=True, cycle=False, wait=False): if wait: self._flag = True while self._flag: + # read any ZMQ messages + # then update widgets + # till we get a dialog answer + STATUS.readNextMsg() QApplication.processEvents() return (self.display.text(), self._result) else: From fc7e738cdeb58f6109337b918aa179ed2e23eeaf Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 9 Jul 2026 13:05:22 -0700 Subject: [PATCH 66/79] gmoccapy -update sample control panel --- configs/sim/gmoccapy/panel-4axis.hal | 4 +- configs/sim/gmoccapy/panel.hal | 2 +- configs/sim/gmoccapy/panel.ui | 1139 ++++++++++++++++++++------ 3 files changed, 913 insertions(+), 232 deletions(-) diff --git a/configs/sim/gmoccapy/panel-4axis.hal b/configs/sim/gmoccapy/panel-4axis.hal index d1dde2dcefb..5dd73b509ff 100644 --- a/configs/sim/gmoccapy/panel-4axis.hal +++ b/configs/sim/gmoccapy/panel-4axis.hal @@ -1,5 +1,5 @@ -net rate halui.axis.jog-speed panel.jog-rate-f -net angular-rate halui.axis.jog-speed-angular panel.jog-rate-angular-f +net rate halui.axis.jog-speed panel.jog-rate +net angular-rate halui.axis.jog-speed-angular panel.jog-rate-angular net sx halui.axis.x.select panel.axis-x net sy halui.axis.y.select panel.axis-y diff --git a/configs/sim/gmoccapy/panel.hal b/configs/sim/gmoccapy/panel.hal index e93020bc83f..8429fce4cb4 100644 --- a/configs/sim/gmoccapy/panel.hal +++ b/configs/sim/gmoccapy/panel.hal @@ -1,4 +1,4 @@ -net rate halui.axis.jog-speed panel.jog-rate-f +net rate halui.axis.jog-speed panel.jog-rate net sx halui.axis.x.select panel.axis-x net sy halui.axis.y.select panel.axis-y diff --git a/configs/sim/gmoccapy/panel.ui b/configs/sim/gmoccapy/panel.ui index 73215dec2cd..86f4a0f4e99 100644 --- a/configs/sim/gmoccapy/panel.ui +++ b/configs/sim/gmoccapy/panel.ui @@ -6,237 +6,218 @@ 0 0 - 389 - 600 + 571 + 756 MainWindow - - + + - - - Axis Selection - - - - 0 - - - 3 - - - 0 - - - 0 - - - 4 - - - - - Z - - - true - - - true - - - axis-z - - - - - - - X - - - true - - - true - - - axis-x - - - - - - - None - - - true - - - true - - - axis-none - - - - - - - Y - - - true - - - true - - - axis-y - - - - - - - C - - - true - - - true - - - axis-c - - - - - - - B - - - true - - - true - - - axis-b - - - - - - - A - - - true - - - true - - - axis-a - - - - - - - - - - Axis Jog - - - - 0 - - - 3 - - - 0 - - - 0 - - - - - + - - - jog-pos - - - - - - - - - - - jog-neg - - - - - + + + + + Axis Jog + + + + + + + + + + jog-pos + + + + + + + - + + + jog-neg + + + + + + + + + + linear rate /angular rate + + + + + + Qt::Horizontal + + + jog-rate + + + true + + + + + + + Qt::Horizontal + + + jog-rate-angular + + + false + + + true + + + + + + + - - - jog rate - - - - - - 300 - - - Qt::Horizontal - - - jog-rate - - - - - - - - - - jAngular jog rate - - - - - - 1800 - - - Qt::Horizontal - - - jog-rate-angular - - - - - + + + + + MPG + + + + + + .001 + + + true + + + true + + + true + + + mpg-scale-small + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.001000000000000 + + + buttonGroup_mpgscale + + + + + + + .01 + + + true + + + true + + + mpg-scale-med + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.010000000000000 + + + buttonGroup_mpgscale + + + + + + + .1 + + + true + + + true + + + mpg-scale-large + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.100000000000000 + + + buttonGroup_mpgscale + + + + + + + + + + + 0 + 74 + + + + false + + + true + + + false + + + mpg-wheel + + + + @@ -289,10 +270,10 @@ Manual - true + false - false + true manual-mode @@ -314,10 +295,10 @@ MDI - true + false - false + true mdi-mode @@ -431,6 +412,688 @@ + + + + Axis Selection + + + + 0 + + + 3 + + + 0 + + + 0 + + + 4 + + + + + None + + + true + + + true + + + axis-none + + + + + + + A + + + true + + + true + + + axis-a + + + + + + + Y + + + true + + + true + + + axis-y + + + + + + + X + + + true + + + true + + + axis-x + + + + + + + Z + + + true + + + true + + + axis-z + + + + + + + B + + + true + + + true + + + axis-b + + + + + + + C + + + true + + + true + + + axis-c + + + + + + + GUI + + + true + + + true + + + select-gui0 + + + + + + + + + + + + ESTOP + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print("true command") + + + print("false command") + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + true + + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + ON + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print("true command") + + + print("false command") + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + true + + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + HOME + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print("true command") + + + print("false command") + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + true + + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + @@ -438,25 +1101,43 @@ 0 0 - 389 - 22 + 571 + 31 + + IndicatedPushButton + QPushButton +
qtvcp.widgets.simple_widgets
+
PushButton QPushButton
qtvcp.widgets.simple_widgets
- Slider - QSlider + Dial + QDial
qtvcp.widgets.simple_widgets
+ + ActionButton + IndicatedPushButton +
qtvcp.widgets.action_button
+
+ + StatusSlider + QSlider +
qtvcp.widgets.status_slider
+
+ + + From ed6b21e0dfde6532af69178f7c49feb5fbe4d09f Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 9 Jul 2026 13:06:20 -0700 Subject: [PATCH 67/79] qtdragon -update sim control panel --- configs/sim/qtdragon/qtdragon_xyz/panel.ui | 811 ++++++++++++++++++--- 1 file changed, 715 insertions(+), 96 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index 50da9ae96f1..86f4a0f4e99 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -6,106 +6,17 @@ 0 0 - 495 - 587 + 571 + 756 MainWindow - - + + - - - - Axis Selection - - - - - - GUI - - - true - - - true - - - select-gui0 - - - - - - - None - - - true - - - true - - - axis-none - - - - - - - X - - - true - - - true - - - axis-x - - - - - - - Y - - - true - - - true - - - axis-y - - - - - - - Z - - - true - - - true - - - axis-z - - - - - - @@ -140,7 +51,7 @@ - jog rate + linear rate /angular rate @@ -156,6 +67,22 @@ + + + + Qt::Horizontal + + + jog-rate-angular + + + false + + + true + + +
@@ -485,6 +412,688 @@
+ + + + Axis Selection + + + + 0 + + + 3 + + + 0 + + + 0 + + + 4 + + + + + None + + + true + + + true + + + axis-none + + + + + + + A + + + true + + + true + + + axis-a + + + + + + + Y + + + true + + + true + + + axis-y + + + + + + + X + + + true + + + true + + + axis-x + + + + + + + Z + + + true + + + true + + + axis-z + + + + + + + B + + + true + + + true + + + axis-b + + + + + + + C + + + true + + + true + + + axis-c + + + + + + + GUI + + + true + + + true + + + select-gui0 + + + + + + + + + + + + ESTOP + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print("true command") + + + print("false command") + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + true + + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + ON + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print("true command") + + + print("false command") + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + true + + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + HOME + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print("true command") + + + print("false command") + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + true + + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + +
@@ -492,14 +1101,19 @@ 0 0 - 495 - 22 + 571 + 31 + + IndicatedPushButton + QPushButton +
qtvcp.widgets.simple_widgets
+
PushButton QPushButton @@ -510,6 +1124,11 @@ QDial
qtvcp.widgets.simple_widgets
+ + ActionButton + IndicatedPushButton +
qtvcp.widgets.action_button
+
StatusSlider QSlider From 49ad24a8768ab79b5c4382628f46e83470ccae0d Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 9 Jul 2026 14:11:26 -0700 Subject: [PATCH 68/79] halui -add reload display and shutdown pins --- lib/python/bridgeui/bridge.py | 8 ++++- src/emc/usr_intf/halui.cc | 55 ++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index c9d8d4aac4b..777f88e625f 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -134,7 +134,7 @@ def action(self, msg, data): print ('axis state', self.axesSelected,self.currentSelectedAxis) # send msg to hal_glib - def writeMsg(self, msg, data): + def writeMsg(self, msg, data=''): #print('Write Msg called') if ZMQ: topic = self.writeTopic @@ -162,6 +162,12 @@ def ok(self): def cancel(self): self.writeMsg('request_cancel', True) + def reloadDisplay(self): + self.writeMsg('request_reload_display', True) + + def shutdownController(self): + self.writeMsg('request_shutdown') + # if the number is bigger then MDI command list # then look for MACRO commands def getMdiName(self, num): diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index c9daf4ae1a0..4d29f27771e 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -216,6 +216,8 @@ static int axis_mask = 0; \ FIELD(hal_bit_t,gui_ok) /* pin for acknowledging dialog ok */ \ FIELD(hal_bit_t,gui_cancel) /* pin for acknowledging dialog cancel */ \ + FIELD(hal_bit_t,gui_reload) /* pin for acknowledging dialog ok */ \ + FIELD(hal_bit_t,gui_shutdown) /* pin for acknowledging dialog cancel */ \ \ FIELD(hal_float_t,units_per_mm) \ @@ -561,7 +563,7 @@ static void py_call_cycleStart() { // check socket messages for jogspeed pFuncWrite = PyObject_GetAttrString(pInstance, "cycleStart"); - if (pFuncRead && PyCallable_Check(pFuncWrite)) { + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { pValue = PyObject_CallNoArgs(pFuncWrite); if (pValue == NULL){ fprintf(stderr, "Halui Bridge: cycleStart function failed: returned NULL\n"); @@ -576,7 +578,7 @@ static void py_call_cyclePause() { // check socket messages for jogspeed pFuncWrite = PyObject_GetAttrString(pInstance, "cyclePause"); - if (pFuncRead && PyCallable_Check(pFuncWrite)) { + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { pValue = PyObject_CallNoArgs(pFuncWrite); if (pValue == NULL){ fprintf(stderr, "Halui Bridge: cyclePause function failed: returned NULL\n"); @@ -591,7 +593,7 @@ static void py_call_ok() { // check socket messages for gui ok message pFuncWrite = PyObject_GetAttrString(pInstance, "ok"); - if (pFuncRead && PyCallable_Check(pFuncWrite)) { + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { pValue = PyObject_CallNoArgs(pFuncWrite); if (pValue == NULL){ fprintf(stderr, "Halui Bridge: ok function failed: returned NULL\n"); @@ -605,7 +607,7 @@ static void py_call_cancel() { // check socket messages for gui cancel message pFuncWrite = PyObject_GetAttrString(pInstance, "cancel"); - if (pFuncRead && PyCallable_Check(pFuncWrite)) { + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { pValue = PyObject_CallNoArgs(pFuncWrite); if (pValue == NULL){ fprintf(stderr, "Halui Bridge: cancel function failed: returned NULL\n"); @@ -615,6 +617,34 @@ static void py_call_cancel() { Py_DECREF(pFuncWrite); return ; } +static void py_call_reload_display() { + + // check socket messages for gui reload display message + pFuncWrite = PyObject_GetAttrString(pInstance, "reloadDisplay"); + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallNoArgs(pFuncWrite); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: reload display function failed: returned NULL\n"); + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncWrite); + return ; +} +static void py_call_shutdown_controller() { + + // check socket messages for gui shutdown message + pFuncWrite = PyObject_GetAttrString(pInstance, "shutdownController"); + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallNoArgs(pFuncWrite); + if (pValue == NULL){ + fprintf(stderr, "Halui Bridge: shutdownController function failed: returned NULL\n"); + } + Py_DECREF(pValue); + } + Py_DECREF(pFuncWrite); + return ; +} static int py_call_get_mdi_count() { int value = 0; // check socket messages for jogspeed @@ -1085,6 +1115,12 @@ int halui_hal_init(void) retval = halui_export_pin_IN_bit(&(halui_data->gui_cancel), "halui.gui.cancel"); if (retval < 0) return retval; + retval = halui_export_pin_IN_bit(&(halui_data->gui_reload), "halui.gui.reload-display"); + if (retval < 0) return retval; + + retval = halui_export_pin_IN_bit(&(halui_data->gui_shutdown), "halui.gui.shutdown"); + if (retval < 0) return retval; + hal_ready(comp_id); return 0; } @@ -2612,6 +2648,17 @@ static void check_hal_changes() fprintf(stderr,"GUI CANCEL command called\n"); py_call_cancel(); } + + if (check_bit_changed(new_halui_data.gui_reload, old_halui_data.gui_reload) != 0) { + fprintf(stderr,"GUI RELOAD DISPLAY command called\n"); + py_call_reload_display(); + } + + if (check_bit_changed(new_halui_data.gui_shutdown, old_halui_data.gui_shutdown) != 0) { + fprintf(stderr,"GUI SHUTDOWN command called\n"); + py_call_shutdown_controller(); + } + } // this function looks at the received NML status message From 54b4112f267ced03c1e5b2e11dd1a4aed6b6cc81 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 9 Jul 2026 14:12:15 -0700 Subject: [PATCH 69/79] gladevcp -hal_gremlin: clear the plot if reloading the screen --- lib/python/gladevcp/hal_gremlin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/python/gladevcp/hal_gremlin.py b/lib/python/gladevcp/hal_gremlin.py index c0cfd5675ea..d7badb66747 100644 --- a/lib/python/gladevcp/hal_gremlin.py +++ b/lib/python/gladevcp/hal_gremlin.py @@ -139,6 +139,7 @@ def __init__(self, *a, **kw): def reloadfile(self,w): try: self.fileloaded(None,self._reload_filename) + self.clear_live_plotter() except: pass self.gstat.emit('graphics-gcode-properties',self.gcode_properties) From 456f6e74856a58f48d3b410c6b20b40e56f51db4 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 9 Jul 2026 14:13:15 -0700 Subject: [PATCH 70/79] gmoccapy -honour shutdown request --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 34026f8e210..b67234d36d5 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -438,6 +438,7 @@ def __init__(self, argv): self.GSTAT.connect('ok-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.ACCEPT)) self.GSTAT.connect('cancel-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.CANCEL)) self.GSTAT.connect('cancel-request', lambda w, state: self._del_notification()) + self.GSTAT.connect('shutdown-request', lambda w: self.on_btn_exit_clicked(w)) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) From 1451f7abe1a7f92d89e6e13758168b7a6e900d3e Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 9 Jul 2026 19:58:05 -0700 Subject: [PATCH 71/79] halui -add softkey pins and messages --- lib/python/bridgeui/bridge.py | 8 ++++++-- lib/python/common/hal_glib.py | 5 +++++ src/emc/usr_intf/halui.cc | 37 ++++++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/lib/python/bridgeui/bridge.py b/lib/python/bridgeui/bridge.py index 777f88e625f..e04ccb7837d 100644 --- a/lib/python/bridgeui/bridge.py +++ b/lib/python/bridgeui/bridge.py @@ -168,8 +168,12 @@ def reloadDisplay(self): def shutdownController(self): self.writeMsg('request_shutdown') - # if the number is bigger then MDI command list - # then look for MACRO commands + def softkey(self, index): + print(f'Softkey index {index}') + self.writeMsg('request_softkey', index) + + # if the number is bigger then MDI command list + # then look for MACRO commands def getMdiName(self, num): if num >len(self.INFO.MDI_COMMAND_DICT)-1: offset = len(self.INFO.MDI_COMMAND_DICT) diff --git a/lib/python/common/hal_glib.py b/lib/python/common/hal_glib.py index ec7e19aec02..7da10816f76 100644 --- a/lib/python/common/hal_glib.py +++ b/lib/python/common/hal_glib.py @@ -248,6 +248,7 @@ class _GStat(GObject.GObject): 'cycle-start-request': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_BOOLEAN,)), 'cycle-pause-request': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_BOOLEAN,)), 'macro-call-request': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)), + 'softkey-pressed': (GObject.SignalFlags.RUN_FIRST , GObject.TYPE_NONE, (GObject.TYPE_INT,)), } STATES = { linuxcnc.STATE_ESTOP: 'state-estop' @@ -421,6 +422,7 @@ def onReadMsg(self, queue, condition, sock): def convertMsg(self): # get raw message topic, data = self.readSocket.recv_multipart() + LOG.debug(f'RAW REQUESTED:{topic},{data}') # convert from json object to python object y = json.loads(data) function = y.get('FUNCTION') @@ -1497,6 +1499,9 @@ def request_ok(self, data): def request_cancel(self, data): self.emit('cancel-request', data) + def request_softkey(self, index): + self.emit('softkey-pressed', index) + ############################################# def shutdown(self): diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 4d29f27771e..07f77d7f477 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -54,6 +54,7 @@ static int axis_mask = 0; #define JOGTELEOP 0 #define MDI_MAX 64 +#define SOFTKEY_MAX 20 #pragma GCC diagnostic push #if defined(__GNUC__) && (__GNUC__ > 4) @@ -213,6 +214,7 @@ static int axis_mask = 0; \ ARRAY(hal_bit_t,mdi_commands,MDI_MAX) \ ARRAY(hal_bit_t,gui_mdi_commands,MDI_MAX) \ + ARRAY(hal_bit_t,gui_soft_keys,SOFTKEY_MAX) \ \ FIELD(hal_bit_t,gui_ok) /* pin for acknowledging dialog ok */ \ FIELD(hal_bit_t,gui_cancel) /* pin for acknowledging dialog cancel */ \ @@ -269,6 +271,8 @@ static char *gui_mdi_commands[MDI_MAX]; static int num_gui_mdi_commands = 0; static int have_home_all = 0; +static int num_gui_soft_keys = SOFTKEY_MAX; + static int comp_id, done; /* component ID, main while loop */ static int num_axes = 0; //number of axes, taken from the INI [TRAJ] section @@ -1109,6 +1113,11 @@ int halui_hal_init(void) if (retval < 0) return retval; } + for (int n=0; ngui_soft_keys[n]), comp_id, "halui.gui.softkey-%d", n); + if (retval < 0) return retval; + } + retval = halui_export_pin_IN_bit(&(halui_data->gui_ok), "halui.gui.ok"); if (retval < 0) return retval; @@ -1970,6 +1979,24 @@ static void py_call_request_MDI( int index) Py_DECREF(pFuncWrite); } +static void py_call_request_softkey( int index) +{ + pFuncWrite = PyObject_GetAttrString(pInstance, "softkey"); + + if (pFuncWrite && PyCallable_Check(pFuncWrite)) { + pValue = PyObject_CallFunction(pFuncWrite, "i", index); + if (pValue == NULL){ + fprintf(stderr, "halui bridge: softkey function failed: returned NULL\n"); + if (PyErr_Occurred()) PyErr_Print(); + } + Py_DECREF(pValue); + + }else{ + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "halui Bridge: Failed python function softkey"); + } + Py_DECREF(pFuncWrite); +} static int py_call_get_axis_type( int index) { int value = 0; // check socket messages for selected axis @@ -2631,7 +2658,7 @@ static void check_hal_changes() sendMdiCommand(n); } - // request GUI ti run MDI commands + // request GUI to run MDI commands for(int n = 0; n < num_gui_mdi_commands; n++) { if (check_bit_changed(new_halui_data.gui_mdi_commands[n], old_halui_data.gui_mdi_commands[n]) != 0){ fprintf(stderr,"GUI MDI command called index: %i\n", n); @@ -2639,6 +2666,14 @@ static void check_hal_changes() } } + // request GUI soft keys + for(int n = 0; n < num_gui_soft_keys; n++) { + if (check_bit_changed(new_halui_data.gui_soft_keys[n], old_halui_data.gui_soft_keys[n]) != 0){ + fprintf(stderr,"GUI SOFTKEY called index: %i\n", n); + py_call_request_softkey(n); + } + } + if (check_bit_changed(new_halui_data.gui_ok, old_halui_data.gui_ok) != 0) { fprintf(stderr,"GUI OK command called\n"); py_call_ok(); From 82b4412acc879c2dca40900e6e307b90ea87f181 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Thu, 9 Jul 2026 21:29:04 -0700 Subject: [PATCH 72/79] qtdragon -add basic support for softkeys for Tab selection --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 14 ++ configs/sim/qtdragon/qtdragon_xyz/panel.ui | 186 +++++++++++++++++- .../screens/qtdragon/qtdragon_handler.py | 10 + 3 files changed, 208 insertions(+), 2 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal index 43f84036885..00862a2023c 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.hal +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -37,3 +37,17 @@ net abort halui.abort panel.cycle-abort net cancel halui.gui.cancel panel.cancel net ok halui.gui.ok panel.ok +net softkey0 halui.gui.softkey-0 panel.softkey-0 +net softkey1 halui.gui.softkey-1 panel.softkey-1 +net softkey2 halui.gui.softkey-2 panel.softkey-2 +net softkey3 halui.gui.softkey-3 panel.softkey-3 +net softkey4 halui.gui.softkey-4 panel.softkey-4 +net softkey5 halui.gui.softkey-5 panel.softkey-5 +net softkey6 halui.gui.softkey-6 panel.softkey-6 +net softkey7 halui.gui.softkey-7 panel.softkey-7 +net softkey8 halui.gui.softkey-8 panel.softkey-8 +net softkey9 halui.gui.softkey-9 panel.softkey-9 +net softkey10 halui.gui.softkey-10 panel.softkey-10 + +net exit halui.gui.shutdown panel.exit +net reload halui.gui.reload-display panel.reload diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index 86f4a0f4e99..a3831f062f5 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -6,7 +6,7 @@ 0 0 - 571 + 583 756 @@ -1092,6 +1092,188 @@
+ + + + MainTab + + + softkey-0 + + + PushButton::BIT + + + + + + + FileTab + + + softkey-1 + + + PushButton::BIT + + + + + + + Status + + + softkey-2 + + + PushButton::BIT + + + + + + + Tools + + + softkey-3 + + + PushButton::BIT + + + + + + + Offsets + + + softkey-4 + + + PushButton::BIT + + + + + + + Settings + + + softkey-5 + + + PushButton::BIT + + + + + + + Setup + + + softkey-6 + + + PushButton::BIT + + + + + + + Utils + + + softkey-7 + + + PushButton::BIT + + + + + + + Probe + + + softkey-8 + + + PushButton::BIT + + + + + + + Gcodes + + + softkey-9 + + + PushButton::BIT + + + + + + + Cam + + + softkey-10 + + + PushButton::BIT + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Reload + + + reload + + + PushButton::BIT + + + + + + + exit + + + exit + + + PushButton::BIT + + +
@@ -1101,7 +1283,7 @@ 0 0 - 571 + 583 31 diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index 2b90d757d14..f499cf24046 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -158,6 +158,7 @@ def __init__(self, halcomp, widgets, paths): STATUS.connect('ok-request', lambda w, state: self.dialog_ext_control(w,1,1)) STATUS.connect('cancel-request', lambda w, state: self.dialog_ext_control(w,1,0)) STATUS.connect('axis-selection-changed', lambda w,data: self.mpg_selection_changed(data)) + STATUS.connect('softkey-pressed', lambda w,data: self.softkey_pressed(data)) self.swoopPath = os.path.join(paths.IMAGEDIR,'lcnc_swoop.png') self.swoopURL = QtCore.QUrl.fromLocalFile(self.swoopPath) @@ -961,6 +962,15 @@ def request_macro_call(self, data): else: self.add_status(_translate("HandlerClass",f'External requested INI macro data not recognized:{data}'), CRITICAL) + # external request for a softkey press from HALUI/halbridge + def softkey_pressed(self, index): + tmp=['main','file','offsets','settings', + 'status','tool','utils','user', + 'gcodes','probe','setup'] + btn = self.w[f'btn_{tmp[index]}'] + print(f'index{index}, btn, {btn}') + btn.click() + ####################### # CALLBACKS FROM FORM # ####################### From 5b467fbfebc6f55ce6bd0a0d96d7ea489621a9a7 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Fri, 10 Jul 2026 10:20:22 -0700 Subject: [PATCH 73/79] gladevcp gtk_action -get shutdown to work reliably gnome-sessions-quit wil not pop up consistantly withoout the gtk dialog --- lib/python/gladevcp/gtk_action.py | 36 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/python/gladevcp/gtk_action.py b/lib/python/gladevcp/gtk_action.py index ae56852891a..834b62ac665 100644 --- a/lib/python/gladevcp/gtk_action.py +++ b/lib/python/gladevcp/gtk_action.py @@ -616,21 +616,29 @@ def ADJUST_GRAPHICS_PAN(self, x, y): def ADJUST_GRAPHICS_ROTATE(self, x, y): STATUS.emit('graphics-view-changed', 'rotate-view', {'X': x, 'Y': y}) + #TODO without the gtk dialog, gnome-sessions + # does not start reliably def SHUT_SYSTEM_DOWN_PROMPT(self): - import subprocess - try: - try: - subprocess.call('gnome-session-quit --power-off', shell=True) - except: - try: - subprocess.call('xfce4-session-logout', shell=True) - except: - try: - subprocess.call('systemctl poweroff', shell=True) - except: - raise - except Exception as e: - LOG.warning("Couldn't shut system down: {}".format(e)) + import shutil + import time + + dialog = gtk.MessageDialog(parent=None, + message_type=gtk.MessageType.QUESTION, + buttons=gtk.ButtonsType.YES_NO, + text='Shutdown System?') + dialog.set_keep_above(True) + dialog.format_secondary_text('Unsaved data will be lost') + response = dialog.run() + dialog.destroy() + if response == gtk.ResponseType.YES: + + if shutil.which('gnome-session-quit'): + subprocess.run(["gnome-session-quit", "--power-off"]) + elif shutil.which('xfce4-session-logout'): + subprocess.call('xfce4-session-logout', shell=True) + else: + # force a shutdown - no prompt + subprocess.call('systemctl poweroff', shell=True) def SHUT_SYSTEM_DOWN_NOW(self): import subprocess From f73294bda162422ac8e4fdf10704650c5b612168 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Fri, 10 Jul 2026 10:21:38 -0700 Subject: [PATCH 74/79] gmoccapy -respond to softkeys and make exit do shutdown --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index b67234d36d5..6829053fc21 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -438,7 +438,8 @@ def __init__(self, argv): self.GSTAT.connect('ok-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.ACCEPT)) self.GSTAT.connect('cancel-request', lambda w, state: self.dialogs.dialog_ext_control(Gtk.ResponseType.CANCEL)) self.GSTAT.connect('cancel-request', lambda w, state: self._del_notification()) - self.GSTAT.connect('shutdown-request', lambda w: self.on_btn_exit_clicked(w)) + self.GSTAT.connect('shutdown-request', lambda w: self.system_shutdown(w)) + self.GSTAT.connect('softkey-pressed', lambda w,data: self.softkey_pressed(data)) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) @@ -2934,6 +2935,9 @@ def on_rbt_auto_pressed(self, widget, data=None): def on_btn_exit_clicked(self, widget, data=None): self.widgets.window1.destroy() + def system_shutdown(self, widget): + self.ACTION.SHUT_SYSTEM_DOWN_PROMPT() + # button handlers End # ========================================================= @@ -6400,6 +6404,20 @@ def _blockdelete(self, pin): self.command.set_optional_stop(pin.get()) # ========================================================= + # external request for a softkey press from HALUI/halbridge + def softkey_pressed(self, index): + if index > 9: + location = "bottom" + number = index -10 + elif index < 7: + location = "right" + number = index + else: + LOG.debug(f"Could not translate softkey {index} to button number") + LOG.debug(f"softkey index: {index}, location: {location}, number: {number}") + button = self._get_child_button(location, number) + self.process_button(button) + # The actions of the buttons def _button_pin_changed(self, pin): # we check if the button is pressed or released, @@ -6423,6 +6441,9 @@ def _button_pin_changed(self, pin): return button = self._get_child_button(location, number) + self.process_button(button) + + def process_button(self, button): if not button: LOG.debug("no button here") return From 9ea4d2943ee312def924f8546ff982296acf1c49 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Fri, 10 Jul 2026 12:17:23 -0700 Subject: [PATCH 75/79] gmoccapy -update simulated control panels MPG jog --- configs/sim/gmoccapy/panel-4axis.hal | 38 + configs/sim/gmoccapy/panel.hal | 34 + configs/sim/gmoccapy/panel.ui | 1752 +++++++++++++++----------- 3 files changed, 1080 insertions(+), 744 deletions(-) diff --git a/configs/sim/gmoccapy/panel-4axis.hal b/configs/sim/gmoccapy/panel-4axis.hal index 5dd73b509ff..7b12e1ef3a1 100644 --- a/configs/sim/gmoccapy/panel-4axis.hal +++ b/configs/sim/gmoccapy/panel-4axis.hal @@ -6,9 +6,26 @@ net sy halui.axis.y.select panel.axis-y net sz halui.axis.z.select panel.axis-z net sc halui.axis.c.select panel.axis-c +net sx axis.x.jog-enable +net sy axis.y.jog-enable +net sz axis.z.jog-enable +net sc axis.c.jog-enable +net sgui halui.mpg-select.0 panel.select-gui0 + net jog-p halui.axis.selected.plus panel.jog-pos net jog-m halui.axis.selected.minus panel.jog-neg +net mpg-scale axis.x.jog-scale panel.mpg-scale +net mpg-scale axis.y.jog-scale +net mpg-scale axis.z.jog-scale +net mpg-scale axis.c.jog-scale + +net mpg-count panel.mpg-wheel-s +net mpg-count axis.x.jog-counts +net mpg-count axis.y.jog-counts +net mpg-count axis.z.jog-counts +net mpg-count axis.c.jog-counts + net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 net m2 halui.gui.mdi-command-MACRO2 panel.mdi-2 @@ -24,3 +41,24 @@ net abort halui.abort panel.cycle-abort net cancel halui.gui.cancel panel.cancel net ok halui.gui.ok panel.ok + +net softkey0 halui.gui.softkey-0 panel.softkey-v0 +net softkey1 halui.gui.softkey-1 panel.softkey-v1 +net softkey2 halui.gui.softkey-2 panel.softkey-v2 +net softkey3 halui.gui.softkey-3 panel.softkey-v3 +net softkey4 halui.gui.softkey-4 panel.softkey-v4 +net softkey5 halui.gui.softkey-5 panel.softkey-v5 +net softkey6 halui.gui.softkey-6 panel.softkey-v6 +net softkeyh0 halui.gui.softkey-10 panel.softkey-h0 +net softkeyh1 halui.gui.softkey-11 panel.softkey-h1 +net softkeyh2 halui.gui.softkey-12 panel.softkey-h2 +net softkeyh3 halui.gui.softkey-13 panel.softkey-h3 +net softkeyh4 halui.gui.softkey-14 panel.softkey-h4 +net softkeyh5 halui.gui.softkey-15 panel.softkey-h5 +net softkeyh6 halui.gui.softkey-16 panel.softkey-h6 +net softkeyh7 halui.gui.softkey-17 panel.softkey-h7 +net softkeyh8 halui.gui.softkey-18 panel.softkey-h8 +net softkeyh9 halui.gui.softkey-19 panel.softkey-h9 + +net exit halui.gui.shutdown panel.exit +net reload halui.gui.reload-display panel.reload diff --git a/configs/sim/gmoccapy/panel.hal b/configs/sim/gmoccapy/panel.hal index 8429fce4cb4..dd7799248c2 100644 --- a/configs/sim/gmoccapy/panel.hal +++ b/configs/sim/gmoccapy/panel.hal @@ -4,9 +4,23 @@ net sx halui.axis.x.select panel.axis-x net sy halui.axis.y.select panel.axis-y net sz halui.axis.z.select panel.axis-z +net sx axis.x.jog-enable +net sy axis.y.jog-enable +net sz axis.z.jog-enable +net sgui halui.mpg-select.0 panel.select-gui0 + net jog-p halui.axis.selected.plus panel.jog-pos net jog-m halui.axis.selected.minus panel.jog-neg +net mpg-scale axis.x.jog-scale panel.mpg-scale +net mpg-scale axis.y.jog-scale +net mpg-scale axis.z.jog-scale + +net mpg-count panel.mpg-wheel-s +net mpg-count axis.x.jog-counts +net mpg-count axis.y.jog-counts +net mpg-count axis.z.jog-counts + net m0 halui.gui.mdi-command-MACRO0 panel.mdi-0 net m1 halui.gui.mdi-command-MACRO1 panel.mdi-1 net m2 halui.gui.mdi-command-MACRO2 panel.mdi-2 @@ -22,3 +36,23 @@ net abort halui.abort panel.cycle-abort net cancel halui.gui.cancel panel.cancel net ok halui.gui.ok panel.ok +net softkey0 halui.gui.softkey-0 panel.softkey-v0 +net softkey1 halui.gui.softkey-1 panel.softkey-v1 +net softkey2 halui.gui.softkey-2 panel.softkey-v2 +net softkey3 halui.gui.softkey-3 panel.softkey-v3 +net softkey4 halui.gui.softkey-4 panel.softkey-v4 +net softkey5 halui.gui.softkey-5 panel.softkey-v5 +net softkey6 halui.gui.softkey-6 panel.softkey-v6 +net softkeyh0 halui.gui.softkey-10 panel.softkey-h0 +net softkeyh1 halui.gui.softkey-11 panel.softkey-h1 +net softkeyh2 halui.gui.softkey-12 panel.softkey-h2 +net softkeyh3 halui.gui.softkey-13 panel.softkey-h3 +net softkeyh4 halui.gui.softkey-14 panel.softkey-h4 +net softkeyh5 halui.gui.softkey-15 panel.softkey-h5 +net softkeyh6 halui.gui.softkey-16 panel.softkey-h6 +net softkeyh7 halui.gui.softkey-17 panel.softkey-h7 +net softkeyh8 halui.gui.softkey-18 panel.softkey-h8 +net softkeyh9 halui.gui.softkey-19 panel.softkey-h9 + +net exit halui.gui.shutdown panel.exit +net reload halui.gui.reload-display panel.reload diff --git a/configs/sim/gmoccapy/panel.ui b/configs/sim/gmoccapy/panel.ui index 86f4a0f4e99..cf614f0bb7f 100644 --- a/configs/sim/gmoccapy/panel.ui +++ b/configs/sim/gmoccapy/panel.ui @@ -6,7 +6,7 @@ 0 0 - 571 + 874 756 @@ -15,561 +15,186 @@ - - - - - - - - Axis Jog - - - - - - + - - - jog-pos - - - - - - - - - - - jog-neg - - - - - - - - - - linear rate /angular rate - - - - - - Qt::Horizontal - - - jog-rate - - - true - - - - - - - Qt::Horizontal - - - jog-rate-angular - - - false - - - true - - - - - - - - - - - - - - MPG - - - - - - .001 - - - true - - - true - - - true - - - mpg-scale-small - - - true - - - PushButton::FLOAT - - - mpg-scale - - - 0.001000000000000 - - - buttonGroup_mpgscale - - - - - - - .01 - - - true - - - true - - - mpg-scale-med - - - true - - - PushButton::FLOAT - - - mpg-scale - - - 0.010000000000000 - - - buttonGroup_mpgscale - - - - - - - .1 - - - true - - - true - - - mpg-scale-large - - - true - - - PushButton::FLOAT - - - mpg-scale - - - 0.100000000000000 - - - buttonGroup_mpgscale - - - - - - - - - - - 0 - 74 - - - - false - - - true - - - false - - - mpg-wheel - - - - - - - - - MDI Comands - - - - - - 0 - - - mdi-0 - - - - - - - 1 - - - mdi-1 - - - - - - - 2 - - - mdi-2 - - - - - - - - - - Mode Comands - - - - - - Manual - - - false - - - true - - - manual-mode - - - true - - - true - - - true - - - - - - - MDI - - - false - - - true - - - mdi-mode - - - true - - - true - - - true - - - - - - - Auto - - - false - - - true - - - auto-mode - - - true - - - true - - - true - - - - - - - - - - program control - - - - - - start - - - cycle-start - - - - - - - pause - - - cycle-pause - - - - - - - Abort - - - cycle-abort - - - - - - - - - - dialog control - - - - - - ok - - - ok - - - - - - - cancel - - - cancel - - - - - - - - - - - - Axis Selection - - - - 0 - - - 3 - - - 0 - - - 0 - - - 4 - - - - - None - - - true - - - true - - - axis-none - - - - - - - A - - - true - - - true - - - axis-a - - - - - - - Y - - - true - - - true - - - axis-y - - - - - - - X - - - true - - - true - - - axis-x - - - - - - - Z - - - true - - - true - - - axis-z - - - - - - - B - - - true - - - true - - - axis-b - - - - - - - C - - - true - - - true - - - axis-c - - - - - - - GUI - - - true - - - true - - - select-gui0 - - - - - + + - + + + ESTOP + + + false + + + false + + + false + + + false + + + false + + + + 255 + 0 + 0 + + + + 0 + + + + 0 + 0 + 0 + + + + 0.300000000000000 + + + 10 + + + 0 + + + 0 + + + 5.000000000000000 + + + 0.300000000000000 + + + 0.900000000000000 + + + True + + + False + + + print("true command") + + + print("false command") + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + 0 + + + true + + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + - ESTOP + ON false @@ -693,7 +318,7 @@ 0 - + true @@ -738,9 +363,9 @@ - + - ON + HOME false @@ -864,249 +489,888 @@ 0 - + true - - false + + false + + + -1 + + + 0.010000000000000 + + + 0.025000000000000 + + + -1.000000000000000 + + + false + + + 0.300000000000000 + + + 50.000000000000000 + + + P + + + + + + 0 + + + %1.3f in + + + %1.2f mm + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + softKey +V0 + + + softkey-v0 + + + PushButton::BIT + + + + + + + SoftKey +V1 + + + softkey-v1 + + + PushButton::BIT + + + + + + + SoftKey +V2 + + + softkey-v2 + + + PushButton::BIT + + + + + + + SoftKey +V3 + + + softkey-v3 + + + PushButton::BIT + + + + + + + SoftKey +V4 + + + softkey-v4 + + + PushButton::BIT + + + + + + + SoftKey +V5 + + + softkey-v5 + + + PushButton::BIT + + + + + + + SoftKey +V6 + + + softkey-v6 + + + PushButton::BIT + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Reload - - -1 + + reload - - 0.010000000000000 + + PushButton::BIT - - 0.025000000000000 + + + + + + SYSTEM +Exit - - -1.000000000000000 + + exit - - false + + PushButton::BIT - - 0.300000000000000 + + + + + + + + + + + + Axis Jog + + + + + + + + + + jog-pos + + + + + + + - + + + jog-neg + + + + + + + + + + linear rate / angular rate + + + + + + Qt::Horizontal + + + jog-rate + + + true + + + + + + + Qt::Horizontal + + + jog-rate-angular + + + false + + + true + + + + + + + + + + + + + + MPG + + + + + + .001 + + + true + + + true + + + true + + + mpg-scale-small + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.001000000000000 + + + buttonGroup_mpgscale + + + + + + + .01 + + + true + + + true + + + mpg-scale-med + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.010000000000000 + + + buttonGroup_mpgscale + + + + + + + .1 + + + true + + + true + + + mpg-scale-large + + + true + + + PushButton::FLOAT + + + mpg-scale + + + 0.100000000000000 + + + buttonGroup_mpgscale + + + + + + + + + + + 0 + 74 + + + + false + + + true + + + false + + + mpg-wheel + + + + + + + + + MDI Comands - - 50.000000000000000 + + + + + 0 + + + mdi-0 + + + + + + + 1 + + + mdi-1 + + + + + + + 2 + + + mdi-2 + + + + + + + + + + Mode Comands - - P + + + + + Manual + + + false + + + true + + + manual-mode + + + true + + + true + + + true + + + + + + + MDI + + + false + + + true + + + mdi-mode + + + true + + + true + + + true + + + + + + + Auto + + + false + + + true + + + auto-mode + + + true + + + true + + + true + + + + + + + + + + program control - - + + + + + start + + + cycle-start + + + + + + + pause + + + cycle-pause + + + + + + + Abort + + + cycle-abort + + + + + + + + + + dialog control - - 0 + + + + + ok + + + ok + + + + + + + cancel + + + cancel + + + + + + + + + + + + Axis Selection + + + + 0 + + + 3 + + + 0 + + + 0 + + + 4 + + + + + None + + + true + + + true + + + axis-none + + + + + + + A + + + true + + + true + + + axis-a + + + + + + + Y + + + true + + + true + + + axis-y + + + + + + + X + + + true + + + true + + + axis-x + + + + + + + Z + + + true + + + true + + + axis-z + + + + + + + B + + + true + + + true + + + axis-b + + + + + + + C + + + true + + + true + + + axis-c + + + + + + + GUI + + + true + + + true + + + select-gui0 + + + + + + + + + + + + H0 - - %1.3f in + + softkey-h0 - - %1.2f mm + + PushButton::BIT - + - HOME - - - false - - - false - - - false - - - false - - - false - - - - 255 - 0 - 0 - - - - 0 - - - - 0 - 0 - 0 - - - - 0.300000000000000 - - - 10 - - - 0 - - - 0 - - - 5.000000000000000 - - - 0.300000000000000 - - - 0.900000000000000 - - - True - - - False - - - print("true command") - - - print("false command") - - - false - - - false - - - false - - - false - - - false - - - false - - - false + H1 - - false - - - false - - - false + + softkey-h1 - - false - - - false + + PushButton::BIT - - false + + + + + + H2 - - false + + softkey-h2 - - false + + PushButton::BIT - - false + + + + + + H3 - - false + + softkey-h3 - - false + + PushButton::BIT - - 0 + + + + + + H4 - - true + + softkey-h4 - - false + + PushButton::BIT - - -1 + + + + + + H5 - - 0.010000000000000 + + softkey-h5 - - 0.025000000000000 + + PushButton::BIT - - -1.000000000000000 + + + + + + H6 - - false + + softkey-h6 - - 0.300000000000000 + + PushButton::BIT - - 50.000000000000000 + + + + + + H7 - - P + + softkey-h7 - - + + PushButton::BIT - - 0 + + + + + + H8 - - %1.3f in + + softkey-h8 - - %1.2f mm + + PushButton::BIT - - - Qt::Vertical + + + H9 - - - 20 - 40 - + + softkey-h9 - + + PushButton::BIT + +
- - - - 0 - 0 - 571 - 31 - - - - From 9e9761c034c9f23ab57a19374581a63a10282d09 Mon Sep 17 00:00:00 2001 From: Cmorley Date: Fri, 10 Jul 2026 12:18:52 -0700 Subject: [PATCH 76/79] qtdragon -fix order of softkeys for tab control --- configs/sim/qtdragon/qtdragon_xyz/panel.hal | 1 + configs/sim/qtdragon/qtdragon_xyz/panel.ui | 44 ++++++++++--------- .../screens/qtdragon/qtdragon_handler.py | 12 ++--- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.hal b/configs/sim/qtdragon/qtdragon_xyz/panel.hal index 00862a2023c..22f87b4cea2 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.hal +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.hal @@ -48,6 +48,7 @@ net softkey7 halui.gui.softkey-7 panel.softkey-7 net softkey8 halui.gui.softkey-8 panel.softkey-8 net softkey9 halui.gui.softkey-9 panel.softkey-9 net softkey10 halui.gui.softkey-10 panel.softkey-10 +net softkey11 halui.gui.softkey-11 panel.softkey-11 net exit halui.gui.shutdown panel.exit net reload halui.gui.reload-display panel.reload diff --git a/configs/sim/qtdragon/qtdragon_xyz/panel.ui b/configs/sim/qtdragon/qtdragon_xyz/panel.ui index a3831f062f5..ecef3135492 100644 --- a/configs/sim/qtdragon/qtdragon_xyz/panel.ui +++ b/configs/sim/qtdragon/qtdragon_xyz/panel.ui @@ -7,7 +7,7 @@ 0 0 583 - 756 + 694 @@ -51,7 +51,7 @@ - linear rate /angular rate + linear rate / angular rate @@ -1121,7 +1121,7 @@ - Status + Offsets softkey-2 @@ -1147,7 +1147,7 @@ - Offsets + Status softkey-4 @@ -1160,7 +1160,7 @@ - Settings + Probe softkey-5 @@ -1173,7 +1173,7 @@ - Setup + Gcodes softkey-6 @@ -1186,7 +1186,7 @@ - Utils + Setup softkey-7 @@ -1199,7 +1199,7 @@ - Probe + Settings softkey-8 @@ -1212,7 +1212,7 @@ - Gcodes + Utils softkey-9 @@ -1225,7 +1225,7 @@ - Cam + User softkey-10 @@ -1235,6 +1235,19 @@ + + + + Cam + + + softkey-11 + + + PushButton::BIT + + + @@ -1278,17 +1291,6 @@ - - - - 0 - 0 - 583 - 31 - - - - diff --git a/share/qtvcp/screens/qtdragon/qtdragon_handler.py b/share/qtvcp/screens/qtdragon/qtdragon_handler.py index f499cf24046..f0efe8888eb 100644 --- a/share/qtvcp/screens/qtdragon/qtdragon_handler.py +++ b/share/qtvcp/screens/qtdragon/qtdragon_handler.py @@ -964,12 +964,14 @@ def request_macro_call(self, data): # external request for a softkey press from HALUI/halbridge def softkey_pressed(self, index): - tmp=['main','file','offsets','settings', - 'status','tool','utils','user', - 'gcodes','probe','setup'] + tmp=['main','file','offsets','tool','status', + 'probe','gcodes','setup','settings', + 'utils','user','camera'] + btn = self.w[f'btn_{tmp[index]}'] - print(f'index{index}, btn, {btn}') - btn.click() + #print(f'index{index}, btn, {btn}') + if btn.isVisible(): + btn.click() ####################### # CALLBACKS FROM FORM # From 006481cd624eb6483db02d05c2c1efde30fe668f Mon Sep 17 00:00:00 2001 From: Cmorley Date: Fri, 10 Jul 2026 13:23:52 -0700 Subject: [PATCH 77/79] gmoccapy -add MPG input to zoom and scroll scroll the gcode if in auto and not running otherwise zoom the gcode display. Only if the MPG is enabled from HALUI --- src/emc/usr_intf/gmoccapy/gmoccapy.py | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/emc/usr_intf/gmoccapy/gmoccapy.py b/src/emc/usr_intf/gmoccapy/gmoccapy.py index 6829053fc21..58ba3707705 100644 --- a/src/emc/usr_intf/gmoccapy/gmoccapy.py +++ b/src/emc/usr_intf/gmoccapy/gmoccapy.py @@ -228,6 +228,8 @@ def __init__(self, argv): self.so_counts = 0 # need to calculate difference in counts to change the spindle override slider self.jv_counts = 0 # need to calculate difference in counts to change the jog_vel slider self.ro_counts = 0 # need to calculate difference in counts to change the rapid override slider + self._last_count = 0 # need to calculate MPG count difference + self.mpg_enabled = False self.spindle_override = 1 # holds the feed override value and is needed to be able to react to halui pin self.feed_override = 1 # holds the spindle override value and is needed to be able to react to halui pin @@ -440,6 +442,7 @@ def __init__(self, argv): self.GSTAT.connect('cancel-request', lambda w, state: self._del_notification()) self.GSTAT.connect('shutdown-request', lambda w: self.system_shutdown(w)) self.GSTAT.connect('softkey-pressed', lambda w,data: self.softkey_pressed(data)) + self.GSTAT.connect('axis-selection-changed', lambda w,data: self.mpg_selection_changed(data)) # get if run from line should be used self.run_from_line = self.prefs.getpref("run_from_line", "no_run", str) @@ -6403,6 +6406,31 @@ def _blockdelete(self, pin): LOG.debug("Received a signal from pin {0} with state = {1}".format(pin.name, pin.get())) self.command.set_optional_stop(pin.get()) + # from gmoccapy's MPG input pin + def _external_mpg(self, pin): + count = pin.get() + diff = count - self._last_count + if self.mpg_enabled: + if diff <0: + if self.GSTAT.is_auto_mode() and not self.GSTAT.is_auto_running(): + self.widgets.gcode_view.line_up() + else: + self.widgets.gremlin.zoom_out() + else: + if self.GSTAT.is_auto_mode() and not self.GSTAT.is_auto_running(): + self.widgets.gcode_view.line_down() + self.widgets.gcode_view.line_down() + else: + self.widgets.gremlin.zoom_in() + self._last_count = count + + # enabled externally by halui/hal_bridge + def mpg_selection_changed(self, data): + if data =='MPG0': + self.mpg_enabled = True + else: + self.mpg_enabled = False + # ========================================================= # external request for a softkey press from HALUI/halbridge def softkey_pressed(self, index): @@ -6637,6 +6665,8 @@ def _make_hal_pins(self): pin = self.halcomp.newpin("blockdelete", hal.HAL_BIT, hal.HAL_IN) hal_glib.GPin(pin).connect("value_changed", self._blockdelete) + pin = self.halcomp.newpin('mpg-in',hal.HAL_S32, hal.HAL_IN) + hal_glib.GPin(pin).connect("value_changed", self._external_mpg) ############################## # required class boiler code # From b505d4cda80a438ce6e309858046d2125061f7cb Mon Sep 17 00:00:00 2001 From: Cmorley Date: Fri, 10 Jul 2026 13:26:37 -0700 Subject: [PATCH 78/79] gmoccapy -sim: connect GUI MPG signals --- configs/sim/gmoccapy/panel-4axis.hal | 1 + configs/sim/gmoccapy/panel.hal | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/sim/gmoccapy/panel-4axis.hal b/configs/sim/gmoccapy/panel-4axis.hal index 7b12e1ef3a1..95e7d4fdf6c 100644 --- a/configs/sim/gmoccapy/panel-4axis.hal +++ b/configs/sim/gmoccapy/panel-4axis.hal @@ -21,6 +21,7 @@ net mpg-scale axis.z.jog-scale net mpg-scale axis.c.jog-scale net mpg-count panel.mpg-wheel-s +net mpg-count gmoccapy.mpg-in net mpg-count axis.x.jog-counts net mpg-count axis.y.jog-counts net mpg-count axis.z.jog-counts diff --git a/configs/sim/gmoccapy/panel.hal b/configs/sim/gmoccapy/panel.hal index dd7799248c2..3be61d9baf4 100644 --- a/configs/sim/gmoccapy/panel.hal +++ b/configs/sim/gmoccapy/panel.hal @@ -17,6 +17,7 @@ net mpg-scale axis.y.jog-scale net mpg-scale axis.z.jog-scale net mpg-count panel.mpg-wheel-s +net mpg-count gmoccapy.mpg-in net mpg-count axis.x.jog-counts net mpg-count axis.y.jog-counts net mpg-count axis.z.jog-counts From 6b0dd79e122932869cc81334922a0be57b92211e Mon Sep 17 00:00:00 2001 From: Cmorley Date: Fri, 10 Jul 2026 16:02:39 -0700 Subject: [PATCH 79/79] halui - remove redundent check for J<0 --- src/emc/usr_intf/halui.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/emc/usr_intf/halui.cc b/src/emc/usr_intf/halui.cc index 07f77d7f477..70cdd2b0746 100644 --- a/src/emc/usr_intf/halui.cc +++ b/src/emc/usr_intf/halui.cc @@ -1470,8 +1470,6 @@ static void sendJogStop(int ja, int jjogmode) static void sendJogCont(int ja, double speed, int jjogmode) { - // no selected axis/joint - if (ja < 0) { return; } EMC_JOG_CONT emc_jog_cont_msg;