Ejemplo n.º 1
0
    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'))
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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()
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
#   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.
Ejemplo n.º 9
0
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()
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
          # 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
Ejemplo n.º 12
0
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'))
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
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),
}
Ejemplo n.º 16
0
"""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)
Ejemplo n.º 17
0
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()
Ejemplo n.º 18
0
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)
Ejemplo n.º 19
0
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()
Ejemplo n.º 20
0
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
Ejemplo n.º 21
0
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)
Ejemplo n.º 22
0
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