def __init__(self, parent=None): super(MkFileListView, self).__init__(parent) self.info = Info() self.nc_file_editor = self.info.getEditor() self.nc_file_dir = self.info.getProgramPrefix() self.nc_file_exts = self.info.getProgramExtentions() # file system model self.model = MkFileSystemModel() # self.model.setReadOnly(True) self.model.setFilter(QDir.AllDirs | QDir.AllEntries | QDir.NoDot) self.setModel(self.model) # selection model self.selection_model = self.selectionModel() # self.selection_model.selectionChanged.connect(self.onSelectionChanged) # icon provider self.icon_provider = MkFileIconProvider() self.model.setIconProvider(self.icon_provider) # appearance self.setAlternatingRowColors(True) # signals self.clicked.connect(self.openLocation) self.activated.connect(self.openSelectedItem) self.model.rootPathChanged.connect(self.updateRootPath) self.setRootPath(os.path.expanduser('~/linuxcnc/nc_files'))
def __init__(self): super(LinuxCncDataSource, self).__init__(None) self._info = Info() self._status = getPlugin('status') self._tooltable = getPlugin('tooltable') self._offsettable = getPlugin('offsettable') self._inifile = linuxcnc.ini(os.getenv("INI_FILE_NAME")) self._is_lathe = bool(self._inifile.find("DISPLAY", "LATHE")) self._status.file.notify(self.__handleProgramLoaded) self._status.position.notify(self.__handlePositionChanged) self._status.motion_type.notify(self.__handleMotionTypeChanged) self._status.g5x_offset.notify(self.__handleG5xOffsetChange) self._status.g92_offset.notify(self.__handleG92OffsetChange) self._status.g5x_index.notify(self.__handleG5xIndexChange) self._status.rotation_xy.notify(self.__handleRotationChangeXY) self._offsettable.offset_table_changed.connect( self.__handleOffsetTableChanged) self._offsettable.active_offset_changed.connect( self.__handleActiveOffsetChanged) self._status.tool_offset.notify(self.__handleToolOffsetChanged) self._status.tool_table.notify(self.__handleToolTableChanged)
def __init__(self, parent=None): super(OffsetsDialog, self).__init__(parent=parent) self.info = Info() self.log = Log axis_list = self.info.getAxisList() self.axis_combo = QComboBox() for axis in axis_list: self.axis_combo.addItem(axis.upper(), axis) coords_msg = QLabel("Coordinate relative to workpiece:") system_msg = QLabel("Coordinate System:") self.coords_input = QDoubleSpinBox() self.coords_input.setRange(-999999, 999999) self.system_combo = QComboBox() coord_systems = { "P0": "P0 Current", "P1": "P1 G54", "P2": "P2 G55", "P3": "P3 G56", "P4": "P4 G57", "P5": "P5 G58", "P6": "P6 G59", "P7": "P7 G59.1", "P8": "P8 G59.1", "P9": "P9 G59.3" } for key, value in OrderedDict( sorted(coord_systems.items(), key=lambda t: t[0])).items(): self.system_combo.addItem(value, key) close_button = QPushButton("Close") set_button = QPushButton("Set") main_layout = QVBoxLayout() button_layout = QHBoxLayout() button_layout.addWidget(close_button) button_layout.addWidget(set_button) main_layout.addWidget(self.axis_combo, alignment=Qt.AlignTop) main_layout.addWidget(coords_msg, alignment=Qt.AlignLeft | Qt.AlignTop) main_layout.addWidget(self.coords_input, alignment=Qt.AlignTop) main_layout.addWidget(system_msg, alignment=Qt.AlignLeft | Qt.AlignTop) main_layout.addWidget(self.system_combo, alignment=Qt.AlignBottom) main_layout.addLayout(button_layout) self.setLayout(main_layout) self.setWindowTitle("Regular Offsets") set_button.clicked.connect(self.set_method) close_button.clicked.connect(self.close_method) self.setWindowFlags(Qt.Popup)
def __init__(self, parent=None): super(RemovableDeviceComboBox, self).__init__(parent) self._first_show = True self.setSizeAdjustPolicy(QComboBox.AdjustToContents) self._file_locations = getPlugin('file_locations') self._file_locations.removable_devices.notify(self.onRemovableDevicesChanged) self._file_locations.new_device.notify(self.onNewDeviceAdded) self.info = Info() self._program_prefix = self.info.getProgramPrefix() self.currentTextChanged.connect(self.onCurrentTextChanged) # initialize device list self.onRemovableDevicesChanged(self._file_locations.removable_devices.value)
def __init__(self, parent=None): super(FileSystemTable, self).__init__(parent) self._table_type = TableType.Local self._hidden_columns = '' self._name_columns_width = 0 self._fixed_name_column = False # This prevents doing unneeded initialization # when QtDesginer loads the plugin. if parent is None: return self.parent = parent self.path_data = dict() self.selected_row = None self.clipboard = QApplication.clipboard() self.model = QtpyVCPQFileSystemModel() self.model.setReadOnly(True) self.model.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot | QDir.AllEntries) self.setModel(self.model) self.verticalHeader().hide() self.horizontalHeader().setStretchLastSection(True) self.setAlternatingRowColors(True) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.selection_model = self.selectionModel() self.selection_model.selectionChanged.connect(self.onSelectionChanged) # open selected item on double click or enter pressed self.activated.connect(self.openSelectedItem) self.info = Info() self.nc_file_editor = self.info.getEditor() self.nc_file_dir = self.info.getProgramPrefix() self.nc_file_exts = self.info.getProgramExtentions() self.setRootPath(self.nc_file_dir) self.model.rootPathChanged.connect(self.onRootPathChanged)
def __init__(self, parent=None): super(RemovableDeviceComboBox, self).__init__(parent) self.info = Info() self._program_prefix = self.info.getProgramPrefix() self.usb_present = False self.usbPresent.emit(self.usb_present) self.context = Context() self.monitor = Monitor.from_netlink(self.context) self.monitor.filter_by(subsystem='block') self.observer = MonitorObserver(self.monitor) self.observer.deviceEvent.connect(self.usb_handler) self.monitor.start() self.refreshDeviceList()
def __init__(self, parent=None): super(ProbeSim, self).__init__(parent=parent) self.info = Info() self.log = Log self.close_button = QPushButton("Touch") self.pulse_checkbox = QCheckBox("Pulse") main_layout = QVBoxLayout() main_layout.addWidget(self.close_button) main_layout.addWidget(self.pulse_checkbox) self.setLayout(main_layout) self.setWindowTitle("Simulate touch probe") self.close_button.pressed.connect(self.touch_on) self.close_button.released.connect(self.touch_off) self.timer = QTimer() self.timer.timeout.connect(self.pulse_off) self.timer.setSingleShot(True)
# GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with This program. If not, see <http://www.gnu.org/licenses/>. import os # For file path manipulation import linuxcnc # For commanding linuxcnc from qtpyvcp.plugins.notifications import Notifications from qtpy import uic, QtWidgets from qtpyvcp.utilities.info import Info PARENT_DIR = os.path.dirname(os.path.realpath(__file__)) INFO = Info() # Change this path to match [RS274NGC] SUBROUTINE_PATH given in the INI SUBROUTINE_PATH = INFO.getSubroutinePath() CMD = linuxcnc.command() STAT = linuxcnc.stat() class SubCaller(QtWidgets.QWidget): def __init__(self, parent=None): super(SubCaller, self).__init__(parent) # This prevents doing unneeded initialization # when QtDesginer loads the plugin.
class RemovableDeviceComboBox(QComboBox): """ComboBox for choosing from a list of removable devices.""" usbPresent = Signal(bool) def __init__(self, parent=None): super(RemovableDeviceComboBox, self).__init__(parent) self.info = Info() self._program_prefix = self.info.getProgramPrefix() self.usb_present = False self.usbPresent.emit(self.usb_present) self.context = Context() self.monitor = Monitor.from_netlink(self.context) self.monitor.filter_by(subsystem='block') self.observer = MonitorObserver(self.monitor) self.observer.deviceEvent.connect(self.usb_handler) self.monitor.start() self.refreshDeviceList() def usb_handler(self, device): if device.action == "add": if device.device_type == 'partition': partitions = [ device.device_node for device in self.context.list_devices( subsystem='block', DEVTYPE='partition', parent=device) ] for p in partitions: os.system("udisksctl mount --block-device {}".format(p)) # self.addItem(device.get('ID_FS_LABEL'), device.get('')) # self.setCurrentIndex(0) self.refreshDeviceList() @Slot() def refreshDeviceList(self): self.usb_present = False self.clear() self.addItem(self._program_prefix, self._program_prefix) removable = [ device for device in self.context.list_devices(subsystem='block', DEVTYPE='disk') if device.attributes.asstring('removable') == '1' ] part_index = 0 for device in removable: partitions = [ device.device_node for device in self.context.list_devices( subsystem='block', DEVTYPE='partition', parent=device) ] # print("All removable partitions: {}".format(", ".join(partitions))) # # print("Mounted removable partitions:") for p in psutil.disk_partitions(): if p.device in partitions: # print("Mounted partition: {}: {}".format(p.device, p.mountpoint)) self.addItem(p.mountpoint, p.device) self.usb_present = True part_index += 1 self.setCurrentIndex(part_index) self.usbPresent.emit(self.usb_present) @Slot() def ejectDevice(self): if not self.usb_present: # print("USB NOT PRESENT") return index = self.currentIndex() if index == 0: # print("CANT UMOUNT HOME") return device = self.itemData(index) self.setCurrentIndex(0) os.system("udisksctl unmount --block-device {}".format(device)) os.system("udisksctl power-off --block-device {}".format(device)) self.refreshDeviceList()
class FileSystemTable(QTableView, TableType): if IN_DESIGNER: from PyQt5.QtCore import Q_ENUMS Q_ENUMS(TableType) gcodeFileSelected = Signal(bool) filePreviewText = Signal(str) fileNamePreviewText = Signal(str) transferFileRequest = Signal(str) rootChanged = Signal(str) def __init__(self, parent=None): super(FileSystemTable, self).__init__(parent) self._table_type = TableType.Local self._hidden_columns = '' # This prevents doing unneeded initialization # when QtDesginer loads the plugin. if parent is None: return self.parent = parent self.path_data = dict() self.doubleClicked.connect(self.openSelectedItem) self.selected_row = None self.clipboard = QApplication.clipboard() self.model = QFileSystemModel() self.model.setReadOnly(True) self.model.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot | QDir.AllEntries) self.setModel(self.model) self.verticalHeader().hide() self.horizontalHeader().setStretchLastSection(True) self.setAlternatingRowColors(True) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.selection_model = self.selectionModel() self.selection_model.selectionChanged.connect(self.onSelectionChanged) self.info = Info() self.editor = self.info.getEditor() self._nc_file_dir = self.info.getProgramPrefix() self.nc_file_exts = self.info.getProgramExtentions() self.setRootPath(self._nc_file_dir) def showEvent(self, event=None): self.rootChanged.emit(self._nc_file_dir) def onSelectionChanged(self, selected, deselected): if len(selected) == 0: return index = selected.indexes()[0] path = self.model.filePath(index) if os.path.isfile(path): self.gcodeFileSelected.emit(True) with open(path, 'r') as fh: content = fh.read() self.filePreviewText.emit(content) self.fileNamePreviewText.emit(path) else: self.gcodeFileSelected.emit(False) self.filePreviewText.emit('') self.fileNamePreviewText.emit('') @Slot() def openSelectedItem(self, index=None): """If ngc file, opens in LinuxCNC, if dir displays dir.""" if index is None: selection = self.getSelection() if selection is None: return index = selection[0] path = self.model.filePath(self.rootIndex()) name = self.model.filePath(index) absolute_path = os.path.join(path, name) file_info = QFileInfo(absolute_path) if file_info.isDir(): self.model.setRootPath(absolute_path) self.setRootIndex(self.model.index(absolute_path)) self.rootChanged.emit(absolute_path) elif file_info.isFile(): # if file_info.completeSuffix() not in self.nc_file_exts: # LOG.warn("Unsuported NC program type with extention .%s", # file_info.completeSuffix()) loadProgram(absolute_path) @Slot() def editSelectedFile(self): """Open the selected file in editor.""" selection = self.getSelection() if selection is not None: path = self.model.filePath(selection[0]) subprocess.Popen([self.editor, path]) return False @Slot() def loadSelectedFile(self): """Loads the selected file into LinuxCNC.""" selection = self.getSelection() if selection is not None: path = self.model.filePath(selection[0]) loadProgram(path) return True return False @Slot() def selectPrevious(self): """Select the previous item in the view.""" selection = self.getSelection() if selection is None: # select last item in view self.selectRow(self.model.rowCount(self.rootIndex()) - 1) else: self.selectRow(selection[0].row() - 1) return True @Slot() def selectNext(self): """Select the next item in the view.""" selection = self.getSelection() if selection is None: # select first item in view self.selectRow(0) else: self.selectRow(selection[-1].row() + 1) return True @Slot() def rename(self): """renames the selected file or folder""" index = self.selectionModel().currentIndex() path = self.model.filePath(index) if path: file_info = QFileInfo(path) if file_info.isFile(): filename = self.rename_dialog("file") if filename: q_file = QFile(path) file_info.absolutePath() new_path = os.path.join(file_info.absolutePath(), str(filename)) q_file.rename(new_path) elif file_info.isDir(): filename = self.rename_dialog("directory") if filename: directory = QDir(path) file_info.absolutePath() new_path = os.path.join(file_info.absolutePath(), str(filename)) directory.rename(path, new_path) @Slot() def newFile(self): """Create a new empty file""" path = self.model.filePath(self.rootIndex()) new_file_path = os.path.join(path, "New File.ngc") count = 1 while os.path.exists(new_file_path): new_file_path = os.path.join(path, "New File {}.ngc".format(count)) count += 1 new_file = QFile(new_file_path) new_file.open(QIODevice.ReadWrite) @Slot() def newFolder(self): path = self.model.filePath(self.rootIndex()) new_name = 'New Folder' count = 1 while os.path.exists(os.path.join(path, new_name)): new_name = "New Folder {}".format(count) count += 1 directory = QDir(path) directory.mkpath(new_name) directory.setPath(new_name) @Slot() @deprecated(replaced_by='newFolder', reason='for consistency with newFile method name') def createDirectory(self): self.newFolder() @Slot() def deleteItem(self): """Delete the selected item (either a file or folder).""" # ToDo: use Move2Trash, instead of deleting the file index = self.selectionModel().currentIndex() path = self.model.filePath(index) if path: file_info = QFileInfo(path) if file_info.isFile(): if not self.ask_dialog( "Do you wan't to delete the selected file?"): return q_file = QFile(path) q_file.remove() elif file_info.isDir(): if not self.ask_dialog( "Do you wan't to delete the selected directory?"): return directory = QDir(path) directory.removeRecursively() @Slot() @deprecated(replaced_by='deleteItem', reason='because of unclear method name') def deleteFile(self): self.deleteItem() @Slot(str) def setRootPath(self, root_path): """Sets the currently displayed path.""" self.rootChanged.emit(root_path) self.model.setRootPath(root_path) self.setRootIndex(self.model.index(root_path)) return True @Slot() def viewParentDirectory(self): """View the parent directory of the current view.""" path = self.model.filePath(self.rootIndex()) file_info = QFileInfo(path) directory = file_info.dir() new_path = directory.absolutePath() currentRoot = self.rootIndex() self.model.setRootPath(new_path) self.setRootIndex(currentRoot.parent()) self.rootChanged.emit(new_path) @Slot() @deprecated(replaced_by='viewParentDirectory') def goUP(self): self.viewParentDirecotry() @Slot() def viewHomeDirectory(self): self.setRootPath(os.path.expanduser('~/')) @Slot() def viewNCFilesDirectory(self): # ToDo: Make preset user definable path = os.path.expanduser('~/linuxcnc/nc_files') self.setRootPath(path) @Slot() def viewPresetDirectory(self): # ToDo: Make preset user definable preset = os.path.expanduser('~/linuxcnc/nc_files') self.setRootPath(preset) @Slot() def doFileTransfer(self): index = self.selectionModel().currentIndex() path = self.model.filePath(index) self.transferFileRequest.emit(path) @Slot(str) def transferFile(self, src_path): dest_path = self.model.filePath(self.rootIndex()) src_file = QFile() src_file.setFileName(src_path) src_file_info = QFileInfo(src_path) dst_path = os.path.join(dest_path, src_file_info.fileName()) src_file.copy(dst_path) @Slot() def getSelection(self): """Returns list of selected indexes, or None.""" selection = self.selection_model.selectedIndexes() if len(selection) == 0: return None return selection @Slot() def getCurrentDirectory(self): return self.model.rootPath() @Property(TableType) def tableType(self): return self._table_type @tableType.setter def tableType(self, table_type): self._table_type = table_type if table_type == TableType.Local: self.setRootPath(self._nc_file_dir) else: self.setRootPath('/media/') @Property(str) def hiddenColumns(self): """String of comma separated column numbers to hide.""" return self._hidden_columns @hiddenColumns.setter def hiddenColumns(self, columns): try: col_list = [int(c) for c in columns.split(',') if c != ''] except: return False self._hidden_columns = columns header = self.horizontalHeader() for col in range(4): if col in col_list: header.hideSection(col) else: header.showSection(col) def ask_dialog(self, message): box = QMessageBox.question(self.parent, 'Are you sure?', message, QMessageBox.Yes, QMessageBox.No) if box == QMessageBox.Yes: return True else: return False def rename_dialog(self, data_type): text, ok_pressed = QInputDialog.getText( self.parent, "Rename", "New {} name:".format(data_type), QLineEdit.Normal, "") if ok_pressed and text != '': return text else: return False
# format used for imperial units imperial_format: "%8.4f" ToDO: Add joint positions. """ import math from qtpyvcp.utilities.info import Info from qtpyvcp.utilities.logger import getLogger from qtpyvcp.plugins import DataPlugin, DataChannel, getPlugin STATUS = getPlugin('status') STAT = STATUS.stat INFO = Info() # Set up logging LOG = getLogger(__name__) MACHINE_COORDS = INFO.getCoordinates() MACHINE_UNITS = 2 if INFO.getIsMachineMetric() else 1 # Set the conversions used for changing the DRO units # Only convert linear axes (XYZUVW), use factor of unity for ABC if MACHINE_UNITS == 2: # List of factors for converting from mm to inches CONVERSION_FACTORS = [1.0 / 25.4] * 3 + [1] * 3 + [1.0 / 25.4] * 3 else: # List of factors for converting from inches to mm CONVERSION_FACTORS = [25.4] * 3 + [1] * 3 + [25.4] * 3
class RemovableDeviceComboBox(QComboBox): """ComboBox for choosing from a list of removable devices.""" usbPresent = Signal(bool) currentPathChanged = Signal(str) currentDeviceEjectable = Signal(bool) def __init__(self, parent=None): super(RemovableDeviceComboBox, self).__init__(parent) self._first_show = True self.setSizeAdjustPolicy(QComboBox.AdjustToContents) self._file_locations = getPlugin('file_locations') self._file_locations.removable_devices.notify(self.onRemovableDevicesChanged) self._file_locations.new_device.notify(self.onNewDeviceAdded) self.info = Info() self._program_prefix = self.info.getProgramPrefix() self.currentTextChanged.connect(self.onCurrentTextChanged) # initialize device list self.onRemovableDevicesChanged(self._file_locations.removable_devices.value) def showEvent(self, event=None): if self._first_show: self._first_show = False self.setCurrentText(self._file_locations.default_location) data = self.currentData() or {} self.currentDeviceEjectable.emit(data.get('removable', False)) super(RemovableDeviceComboBox, self).showEvent(event) def onCurrentTextChanged(self, text): data = self.currentData() if data: self.currentPathChanged.emit(data.get('path', '/')) self.currentDeviceEjectable.emit(data.get('removable', False)) def onRemovableDevicesChanged(self, devices): self.blockSignals(True) self.clear() for label, path in list(self._file_locations.local_locations.items()): self.addItem(label, {'path': os.path.expanduser(path)}) self.insertSeparator(100) if devices: for devices_node, device_data in list(devices.items()): self.addItem(device_data.get('label', 'Unknown'), device_data) self.blockSignals(False) def onNewDeviceAdded(self, device): if device: self.setCurrentText(device.get('label')) else: self.setCurrentText(self._file_locations.default_location) @Slot() def ejectDevice(self): data = self.currentData() if data: self._file_locations.ejectDevice(data.get('device'))
from qtpy import uic from qtpy.QtCore import Slot, Signal from qtpy.QtWidgets import QWidget, QWidgetItem from qtpyvcp.actions.program_actions import load as loadProgram from qtpyvcp.utilities.info import Info from probe_param_input import ProbeParamInputWidget from enum import IntEnum from qtpy.QtWidgets import qApp # from statemachine import StateMachine, State from qtpyvcp.utilities import logger LOG = logger.getLogger(__name__) INFO = Info() SUBROUTINE_SEARCH_DIRS = INFO.getSubroutineSearchDirs() PROGRAM_PREFIX = INFO.getProgramPrefix() UI_FILE = os.path.join(os.path.dirname(__file__), "probe_wizard_widget.ui") MAX_NUMBER_OF_PARAMS = 30 PROBE_MODE_PARAM_NAME = "setting_probe_mode" # input: #<input_param_name> = #1 (=0.125 comment) # result: [("input_param_name", "1", "0.125", "comment")] # if a group is not present it will be an empty string PARSE_SETTING_ARGS = re.compile( r' *# *<(setting_[a-z0-9_-]+)> *= *#([0-9]+) *(?:\(= *([0-9.+-]+[0-9.]*?|) *(.*)\))?', re.I) PARSE_INPUT_ARGS = re.compile( r' *# *<(input_[a-z0-9_-]+)> *= *#([0-9]+) *(?:\(= *([0-9.+-]+[0-9.]*?|) *(.*)\))?', re.I)
import os import re from qtpy.QtWidgets import qApp from qtpy.QtCore import Property from qtpyvcp.utilities.info import Info INFO = Info() from qtpyvcp.widgets import VCPButton from qtpyvcp.actions.machine_actions import issue_mdi from qtpyvcp.utilities import logger LOG = logger.getLogger(__name__) # input: #<param_name> = #1 (=0.125 comment) # result: [("param_name", "1", "0.125", "comment")] # if a group is not present it will be an empty string PARSE_POSITIONAL_ARGS = re.compile( r' *# *<([a-z0-9_-]+)> *= *#([0-9]+) *(?:\(= *([0-9.+-]+[0-9.]*?|) *(.*)\))?', re.I) SUBROUTINE_SEARCH_DIRS = INFO.getSubroutineSearchDirs() class SubCallButton(VCPButton): """Button for calling ngc subroutines. Args: parent (QWidget, optional) : The parent widget of the button, or None. filename (str, optional) : The filename of the NGCGUI style subroutine the button should call, including any extension. The subroutine must
from qtpy.QtCore import Property, Signal, Slot, QTimer from qtpy.QtGui import QColor import vtk from vtk.util.colors import tomato, yellow, mint from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor from qtpyvcp.plugins import getPlugin from qtpyvcp.widgets import VCPWidget from qtpyvcp.utilities import logger from qtpyvcp.utilities.info import Info from base_canon import StatCanon from base_backplot import BaseBackPlot INFO = Info() LOG = logger.getLogger(__name__) STATUS = getPlugin('status') TOOLTABLE = getPlugin('tooltable') IN_DESIGNER = os.getenv('DESIGNER', False) INIFILE = linuxcnc.ini(os.getenv("INI_FILE_NAME")) MACHINE_UNITS = 2 if INFO.getIsMachineMetric() else 1 COLOR_MAP = { 'traverse': (188, 252, 201, 75), 'arcfeed': (255, 255, 255, 128), 'feed': (255, 255, 255, 128), 'dwell': (100, 100, 100, 255), 'user': (100, 100, 100, 255), }
"""MDI Entry """ from qtpy.QtCore import Qt, QStringListModel, Slot from qtpy.QtGui import QValidator from qtpy.QtWidgets import QLineEdit, QCompleter from qtpyvcp.plugins import getPlugin from qtpyvcp.utilities.info import Info from qtpyvcp.actions.machine_actions import issue_mdi from qtpyvcp.widgets.base_widgets.base_widget import CMDWidget STATUS = getPlugin('status') INFO = Info() MDI_HISTORY_FILE = INFO.getMDIHistoryFile() class Validator(QValidator): def validate(self, string, pos): # eventually could do some actual validating here return QValidator.Acceptable, string.upper(), pos class MDIEntry(QLineEdit, CMDWidget): def __init__(self, parent=None): super(MDIEntry, self).__init__(parent) self.model = QStringListModel() completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setModel(self.model)
class LinuxCncDataSource(QObject): programLoaded = Signal(str) positionChanged = Signal(tuple) motionTypeChanged = Signal(int) g5xOffsetChanged = Signal(tuple) g92OffsetChanged = Signal(tuple) g5xIndexChanged = Signal(int) offsetTableChanged = Signal(dict) activeOffsetChanged = Signal(int) toolTableChanged = Signal(tuple) toolOffsetChanged = Signal(tuple) def __init__(self): super(LinuxCncDataSource, self).__init__(None) self._info = Info() self._status = getPlugin('status') self._tooltable = getPlugin('tooltable') self._offsettable = getPlugin('offsettable') self._inifile = linuxcnc.ini(os.getenv("INI_FILE_NAME")) self._is_lathe = bool(self._inifile.find("DISPLAY", "LATHE")) self._status.file.notify(self.__handleProgramLoaded) self._status.position.notify(self.__handlePositionChanged) self._status.motion_type.notify(self.__handleMotionTypeChanged) self._status.g5x_offset.notify(self.__handleG5xOffsetChange) self._status.g92_offset.notify(self.__handleG92OffsetChange) self._status.g5x_index.notify(self.__handleG5xIndexChange) self._status.rotation_xy.notify(self.__handleRotationChangeXY) self._offsettable.offset_table_changed.connect( self.__handleOffsetTableChanged) self._offsettable.active_offset_changed.connect( self.__handleActiveOffsetChanged) self._status.tool_offset.notify(self.__handleToolOffsetChanged) self._status.tool_table.notify(self.__handleToolTableChanged) def __handleProgramLoaded(self, fname): #LOG.debug("__handleProgramLoaded: {}".format(fname)) self.programLoaded.emit(fname) def __handlePositionChanged(self, position): #LOG.debug("__handlePositionChanged: {}".format(type(position))) self.positionChanged.emit(position) def __handleMotionTypeChanged(self, motion_type): #LOG.debug("__handleMotionTypeChanged: {}".format(motion_type)) self.motionTypeChanged.emit(motion_type) def __handleG5xOffsetChange(self, offset): # the received parameter, its missing the rotation of the current wcs emitted_offset = list(offset) active_wcs = self.getWcsOffsets()[self.getActiveWcsIndex()] LOG.debug("--------initial offset emitted: {} {}".format( type(offset), offset)) LOG.debug("--------active wcs: {} {}".format(type(active_wcs), active_wcs)) emitted_offset.append(self.__getRotationOfActiveWcs()) LOG.debug("--------correct_offset: {}".format(emitted_offset)) result = tuple(emitted_offset) LOG.debug("--------result: {} {}".format(type(result), result)) self.g5xOffsetChanged.emit(result) def __handleG92OffsetChange(self, offset): #LOG.debug("__handleG92OffsetChange: {}".format(type(offset))) self.g92OffsetChanged.emit(offset) def __handleG5xIndexChange(self, value): LOG.debug("__handleG5xIndexChange: {}".format(value - 1)) self.g5xIndexChanged.emit(value - 1) def __handleRotationChangeXY(self, value): LOG.debug("__handleRotationChangeXY: {}".format(value)) active_wcs = self.getWcsOffsets()[self.getActiveWcsIndex()] LOG.debug("--------active wcs: {} {}".format(type(active_wcs), active_wcs)) active_wcs[9] = value LOG.debug("--------active new wcs: {} {}".format( type(active_wcs), active_wcs)) self.g5xOffsetChanged.emit(tuple(active_wcs)) def __handleOffsetTableChanged(self, offset_table): #LOG.debug("__handleOffsetTableChanged: {}".format(type(offset_table))) self.offsetTableChanged.emit(offset_table) #self.g5xOffsetChanged.emit(self.getActiveWcsOffsets()) def __handleActiveOffsetChanged(self, active_offset_index): # the first one is g53 - machine coordinates, we're not interested in that one current_wcs_index = active_offset_index - 1 LOG.debug( "__handleActiveOffsetChanged index: {}".format(current_wcs_index)) self.activeOffsetChanged.emit(current_wcs_index) def __handleToolOffsetChanged(self, tool_offset): #LOG.debug("__handleToolOffsetChanged: {}".format(type(tool_offset))) self.toolOffsetChanged.emit(tool_offset) def __handleToolTableChanged(self, tool_table): #LOG.debug("__handleToolTableChanged: {}".format(type(tool_table))) self.toolTableChanged.emit(tool_table) def getAxis(self): return self._status.stat.axis def getAxisMask(self): return self._status.stat.axis_mask def getToolTable(self): return self._status.stat.tool_table def getToolOffset(self): return self._status.tool_offset def isMachineMetric(self): return self._info.getIsMachineMetric() def getProgramUnits(self): return str(self._status.program_units) def isMachineLathe(self): return self._is_lathe def isModeMdi(self): return str(self._status.task_mode) == "MDI" def isModeAuto(self): return str(self._status.task_mode) == "Auto" def getActiveWcsIndex(self): # in the stat, the first one the list is G53 (Machine Coordinates) # therefore to get the correct index of the G54 we need to do a -1 return self._status.stat.g5x_index - 1 def getActiveWcsOffsets(self): # g5x_offset does not contain the rotation information xx = self._status.stat.g5x_offset LOG.debug("self._status.stat.g5x_offset: {}".format(type(xx))) xy = list(xx) xy.append(self.__getRotationOfActiveWcs()) return tuple(xy) def __getRotationOfActiveWcs(self): if not IN_DESIGNER: try: current_wcs = self.getWcsOffsets()[self.getActiveWcsIndex()] LOG.debug("-----current_wcs index: {}".format(current_wcs)) return current_wcs[9] except KeyError: LOG.warn('-----KeyError: Likely means no program loaded.') return 0 else: return 0 def getG92_offset(self): return self._status.stat.g92_offset def getWcsOffsets(self): # returns a dictionary with the coordinate systems from 0 to 8 (g54 up to g59.3) return self._offsettable.getOffsetTable()
import linuxcnc # Set up logging from qtpyvcp.utilities import logger LOG = logger.getLogger(__name__) from qtpyvcp.utilities.info import Info from qtpyvcp.plugins import getPlugin STATUS = getPlugin('status') STAT = STATUS.stat INFO = Info() SPINDLES = list(range(INFO.spindles())) DEFAULT_SPEED = INFO.defaultSpindleSpeed() CMD = linuxcnc.command() from qtpyvcp.actions.base_actions import setTaskMode def _spindle_exists(spindle): if spindle in SPINDLES: return True return False def _spindle_ok(speed=None, spindle=0, widget=None): if spindle not in SPINDLES: ok = False msg = "No spindle No. {}".format(spindle)
class OffsetsDialog(QDialog): def __init__(self, parent=None): super(OffsetsDialog, self).__init__(parent=parent) self.info = Info() self.log = Log axis_list = self.info.getAxisList() self.axis_combo = QComboBox() for axis in axis_list: self.axis_combo.addItem(axis.upper(), axis) coords_msg = QLabel("Coordinate relative to workpiece:") system_msg = QLabel("Coordinate System:") self.coords_input = QDoubleSpinBox() self.coords_input.setDecimals(4) self.coords_input.setRange(-999999, 999999) self.system_combo = QComboBox() coord_systems = { "P0": "P0 Current", "P1": "P1 G54", "P2": "P2 G55", "P3": "P3 G56", "P4": "P4 G57", "P5": "P5 G58", "P6": "P6 G59", "P7": "P7 G59.1", "P8": "P8 G59.1", "P9": "P9 G59.3" } for key, value in OrderedDict( sorted(coord_systems.items(), key=lambda t: t[0])).items(): self.system_combo.addItem(value, key) close_button = QPushButton("Close") set_button = QPushButton("Set") main_layout = QVBoxLayout() button_layout = QHBoxLayout() button_layout.addWidget(close_button) button_layout.addWidget(set_button) main_layout.addWidget(self.axis_combo, alignment=Qt.AlignTop) main_layout.addWidget(coords_msg, alignment=Qt.AlignLeft | Qt.AlignTop) main_layout.addWidget(self.coords_input, alignment=Qt.AlignTop) main_layout.addWidget(system_msg, alignment=Qt.AlignLeft | Qt.AlignTop) main_layout.addWidget(self.system_combo, alignment=Qt.AlignBottom) main_layout.addLayout(button_layout) self.setLayout(main_layout) self.setWindowTitle("Regular Offsets") set_button.clicked.connect(self.set_method) close_button.clicked.connect(self.close_method) self.setWindowFlags(Qt.Popup) def set_method(self): system = self.system_combo.currentData() axis = self.axis_combo.currentData() coords = self.coords_input.value() offset_mdi = "G10 L20 {} {}{:f}".format(system, axis, coords) if issue_mdi.ok(): issue_mdi(offset_mdi) else: self.log.debug("Error issuing MDI: {}".format(issue_mdi.ok.msg)) def close_method(self): self.hide()
from qtpy.QtWidgets import QComboBox from qtpyvcp.utilities.settings import setting # Set up logging from qtpyvcp.utilities import logger LOG = logger.getLogger(__name__) from qtpyvcp.actions.base_actions import setTaskMode from qtpyvcp.plugins import getPlugin STATUS = getPlugin('status') STAT = STATUS.stat from qtpyvcp.utilities.info import Info INFO = Info() CMD = linuxcnc.command() # ------------------------------------------------------------------------- # E-STOP action # ------------------------------------------------------------------------- class estop: """E-Stop action group""" @staticmethod def activate(): """Set E-Stop active""" LOG.debug("Setting state red<ESTOP>") CMD.state(linuxcnc.STATE_ESTOP) @staticmethod
from qtpy.QtGui import QKeySequence from qtpy.QtCore import Qt, Slot, QTimer from qtpy.QtWidgets import QMainWindow, QApplication, QAction, QMessageBox, \ QMenu, QMenuBar, QLineEdit, QShortcut, QActionGroup import qtpyvcp from qtpyvcp import actions from qtpyvcp.utilities import logger from qtpyvcp.utilities.info import Info from qtpyvcp.plugins import getPlugin from qtpyvcp.utilities.settings import getSetting from qtpyvcp.widgets.dialogs import showDialog as _showDialog from qtpyvcp.app.launcher import _initialize_object_from_dict LOG = logger.getLogger(__name__) INFO = Info() class VCPMainWindow(QMainWindow): def __init__(self, parent=None, opts=None, ui_file=None, stylesheet=None, maximize=False, fullscreen=False, position=None, size=None, confirm_exit=True, title=None, menu='default'): super(VCPMainWindow, self).__init__(parent) if opts is None: opts = qtpyvcp.OPTIONS self.setWindowTitle(title)
class MkFileListView(QListView): rootChanged = Signal(str) def __init__(self, parent=None): super(MkFileListView, self).__init__(parent) self.info = Info() self.nc_file_editor = self.info.getEditor() self.nc_file_dir = self.info.getProgramPrefix() self.nc_file_exts = self.info.getProgramExtentions() # file system model self.model = MkFileSystemModel() # self.model.setReadOnly(True) self.model.setFilter(QDir.AllDirs | QDir.AllEntries | QDir.NoDot) self.setModel(self.model) # selection model self.selection_model = self.selectionModel() # self.selection_model.selectionChanged.connect(self.onSelectionChanged) # icon provider self.icon_provider = MkFileIconProvider() self.model.setIconProvider(self.icon_provider) # appearance self.setAlternatingRowColors(True) # signals self.clicked.connect(self.openLocation) self.activated.connect(self.openSelectedItem) self.model.rootPathChanged.connect(self.updateRootPath) self.setRootPath(os.path.expanduser('~/linuxcnc/nc_files')) def updateRootPath(self, root_path): self.setRootIndex(self.model.index(root_path)) @Slot(str) def setRootPath(self, root_path): """Sets the currently displayed path.""" # self.rootChanged.emit(root_path) self.model.setRootPath(root_path) self.setRootIndex(self.model.index(root_path)) return True @Slot(QModelIndex) def openLocation(self, index): path = self.model.filePath(self.rootIndex()) name = self.model.filePath(index) absolute_path = os.path.join(path, name) file_info = QFileInfo(absolute_path) if file_info.isDir(): self.model.setRootPath(absolute_path) self.setRootIndex(self.model.index(absolute_path)) self.rootChanged.emit(absolute_path) @Slot() def openSelectedItem(self, index=None): """If ngc file, opens in LinuxCNC, if dir displays dir.""" if index is None: selection = self.getSelection() if selection is None: return index = selection[0] path = self.model.filePath(self.rootIndex()) name = self.model.filePath(index) absolute_path = os.path.join(path, name) file_info = QFileInfo(absolute_path) if file_info.isDir(): self.model.setRootPath(absolute_path) self.setRootIndex(self.model.index(absolute_path)) self.rootChanged.emit(absolute_path) elif file_info.isFile(): if file_info.completeSuffix() not in self.nc_file_exts: LOG.warn("Unsuported NC program type with extention .%s", file_info.completeSuffix()) hideActiveDialog() loadProgram(absolute_path) @Slot() def getSelection(self): """Returns list of selected indexes, or None.""" selection = self.selection_model.selectedIndexes() if len(selection) == 0: return None return selection def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: super(MkFileListView, self).dragEnterEvent(event) def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.MoveAction) event.accept() else: super(MkFileListView, self).dragMoveEvent(event) def dropEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.MoveAction) event.accept() links = [] for url in event.mimeData().urls(): links.append(str(url.toLocalFile())) self.copyFiles(links) # self.emit(QtCore.SIGNAL("dropped"), links) else: event.setDropAction(Qt.MoveAction) super(MkFileListView, self).dropEvent(event) def copyFiles(self, files): dst = self.model.filePath(self.rootIndex()) for file in files: print "Copy: {} > {}".format(file, dst) self.copyRecursively(file, dst) def copyRecursively(self, src, tgt): src_info = QFileInfo(src) if src_info.isDir(): tgt_dir = QDir(tgt) if not tgt_dir.mkdir(src_info.fileName()): return False src_dir = QDir(src) fnames = src_dir.entryList(QDir.Files | QDir.Dirs | QDir.NoDotAndDotDot | QDir.Hidden | QDir.System) for fname in fnames: new_src = os.path.join(src, fname) new_tgt = os.path.join(tgt, src_info.fileName()) if not self.copyRecursively(new_src, new_tgt): return False elif src_info.isFile(): fname = src_info.fileName() if not QFile.copy(src, os.path.join(tgt, fname)): return False return True