#!/usr/bin/env python3 # # QTVcp Widget # Copyright (c) 2018 Chris Morley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. ############################################################################### from qtpy.QtWidgets import (QToolButton, QMenu, QAction, QComboBox, QWidgetAction) from qtpy.QtCore import Property from qtpy.QtGui import QIcon from qtvcp.widgets.widget_baseclass import _HalWidgetBase from qtvcp.widgets.indicatorMixIn import IndicatedMixIn from qtvcp.core import Status, Action, Info from qtvcp import logger # Instiniate the libraries with global reference # STATUS gives us status messages from linuxcnc # AUX_PRGM holds helper program loader # INI holds ini details # ACTION gives commands to linuxcnc # LOG is for running code logging STATUS = Status() INFO = Info() ACTION = Action() LOG = logger.getLogger(__name__) # Force the log level for this module #LOG.setLevel(logger.DEBUG) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL class ActionToolButton(QToolButton, IndicatedMixIn): def __init__(self, parent=None): super(ActionToolButton, self).__init__(parent) self._gridSize = 0 self._userView = True self._optionMenu = False def buildMenu(self): if self._userView: settingMenu = QMenu(self) self.settingMenu = settingMenu self.recordButton = QAction(QIcon('exit24.png'), 'Record View', settingMenu) self.recordButton.triggered.connect(self.recordView) settingMenu.addAction(self.recordButton) self.setMenu(settingMenu) self.clicked.connect(self.setView) elif self._optionMenu: settingMenu = QMenu(self) self.settingMenu = settingMenu self.showGridAct = QAction( 'Show Grid', settingMenu, checkable=True) self.showGridAct.setChecked(True) self.showGridAct.triggered.connect(self.showGrid) settingMenu.addAction(self.showGridAct) self.comboBox = QComboBox(self) for i in (INFO.GRID_INCREMENTS): self.comboBox.addItem(i) self.comboBox.currentTextChanged.connect(self.setGridSize) wid = QWidgetAction(self) wid.setDefaultWidget(self.comboBox) settingMenu.addAction(wid) self.showDimsAct = QAction( 'Show Dimensions', settingMenu, checkable=True) self.showDimsAct.setChecked(True) self.showDimsAct.triggered.connect(self.showDims) settingMenu.addAction(self.showDimsAct) self.showDROAct = QAction( 'Show DRO', settingMenu, checkable=True) self.showDROAct.setChecked(False) self.showDROAct.triggered.connect(self.showDRO) settingMenu.addAction(self.showDROAct) self.showDTGAct = QAction( 'Show DTG', settingMenu, checkable=True) self.showDTGAct.setChecked(False) self.showDTGAct.triggered.connect(self.showDTG) settingMenu.addAction(self.showDTGAct) self.showLargeAct = QAction( 'Large Font', settingMenu, checkable=True) self.showLargeAct.setChecked(False) self.showLargeAct.triggered.connect(self.showLarge) settingMenu.addAction(self.showLargeAct) self.setMenu(settingMenu) # Override setText function so we can toggle displayed text def setText(self, text): if not self._state_text: super(ActionToolButton,self).setText(text) return if self.isCheckable(): if self.isChecked(): super(ActionToolButton,self).setText(self._true_string) else: super(ActionToolButton,self).setText(self._false_string) elif self._indicator_state: super(ActionToolButton,self).setText(self._true_string) else: super(ActionToolButton,self).setText(self._false_string) def _hal_init(self): def homed_on_test(): return (STATUS.machine_is_on() and (STATUS.is_all_homed() or INFO.NO_HOME_REQUIRED)) super(ActionToolButton, self)._hal_init() self.buildMenu() def recordView(self): ACTION.SET_GRAPHICS_VIEW('record-view') def setView(self): ACTION.SET_GRAPHICS_VIEW('set-recorded-view') def showDims(self, data): if data: ACTION.SET_GRAPHICS_VIEW('dimensions-on') else: ACTION.SET_GRAPHICS_VIEW('dimensions-off') def showGrid(self, data): if data: ACTION.SET_GRAPHICS_GRID_SIZE(self._gridSize) else: ACTION.SET_GRAPHICS_VIEW('grid-off') def setGridSize(self, data): size = self.parse_increment(data) self._gridSize = size if self.showGridAct.isChecked(): ACTION.SET_GRAPHICS_GRID_SIZE(size) def showDRO(self, data): if data: ACTION.SET_GRAPHICS_VIEW('overlay-dro-on') else: ACTION.SET_GRAPHICS_VIEW('overlay-dro-off') def showDTG(self, data): if data: ACTION.SET_GRAPHICS_VIEW('dtg-on') else: ACTION.SET_GRAPHICS_VIEW('dtg-off') def showLarge(self, data): if data: ACTION.SET_GRAPHICS_VIEW('set-large-dro') else: ACTION.SET_GRAPHICS_VIEW('set-small-dro') ################################################### # helper functions ################################################### # We convert INI parced increments to machine units def parse_increment(self, gridincr): if gridincr.endswith("mm"): scale = self.conversion(1) elif gridincr.endswith("cm"): scale = self.conversion(10) elif gridincr.endswith("um"): scale = self.conversion(.001) elif gridincr.endswith("in") or gridincr.endswith("inch"): scale = self.conversion(1., metric = False) elif gridincr.endswith("mil"): scale = self.conversion(.001, metric = False) else: scale = 1 incr = gridincr.rstrip(" inchmuil") try: if "/" in incr: p, q = incr.split("/") incr = float(p) / float(q) else: incr = float(incr) except: return None LOG.verbose("parsed: text: {} Increment: {} scaled: {}".format(gridincr, incr, (incr * scale))) return incr * scale # This does the conversion # calling function must tell us if the data is metric or not. def conversion(self, data, metric = True): if STATUS.is_metric_mode(): if metric: return INFO.convert_metric_to_machine(data) else: return INFO.convert_imperial_to_machine(data) else: if metric: return INFO.convert_metric_to_machine(data) else: return INFO.convert_imperial_to_machine(data) ######################################################################### # This is how designer can interact with our widget properties. # designer will show the Property properties in the editor # it will use the get set and reset calls to do those actions # ######################################################################## # user view def setViewAction(self, state): self._userView = state def getViewAction(self): return self._userView userViewAction = Property(bool, getViewAction, setViewAction) # option menu def setOptionMenu(self, state): self._optionMenu = state def getOptionMenu(self): return self._optionMenu OptionMenuAction = Property(bool, getOptionMenu, setOptionMenu) # for testing without editor: def main(): import sys from qtpy.QtWidgets import QApplication app = QApplication(sys.argv) widget = ActionToolButton() widget.show() sys.exit(app.exec()) if __name__ == "__main__": main()