597 lines
25 KiB
Python
597 lines
25 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# Qtvcp widget
|
|
# Copyright (c) 2017 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.
|
|
###############################################################################
|
|
|
|
import sys
|
|
import os
|
|
import locale
|
|
|
|
from qtpy.QtCore import Qt, QAbstractTableModel, Property, Slot
|
|
from qtpy.QtGui import QColor
|
|
from qtpy.QtWidgets import QTableView, QAbstractItemView, QApplication
|
|
|
|
from qtvcp.widgets.widget_baseclass import _HalWidgetBase
|
|
from qtvcp.core import Status, Action, Info
|
|
from qtvcp import logger
|
|
|
|
#BASE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
|
|
#LOCALEDIR = os.path.join(BASE, "share", "locale")
|
|
#locale.setlocale(locale.LC_ALL, '')
|
|
|
|
# Instantiate the libraries with global reference
|
|
# STATUS gives us status messages from linuxcnc
|
|
# INI holds ini details
|
|
# ACTION gives commands to linuxcnc
|
|
# LOG is for running code logging
|
|
STATUS = Status()
|
|
ACTION = Action()
|
|
INFO = Info()
|
|
LOG = logger.getLogger(__name__)
|
|
|
|
# Force the log level for this module
|
|
# LOG.setLevel(logger.DEBUG) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL
|
|
|
|
|
|
class OriginOffsetView(QTableView, _HalWidgetBase):
|
|
def __init__(self, parent=None):
|
|
super(OriginOffsetView, self).__init__(parent)
|
|
self.setAlternatingRowColors(True)
|
|
|
|
self.filename = INFO.PARAMETER_FILE
|
|
self.axisletters = ["x", "y", "z", "a", "b", "c", "u", "v", "w"]
|
|
self.current_system = None
|
|
self._system_int = 1
|
|
self.current_tool = 0
|
|
self.metric_display = False
|
|
self.metric_text_template = '%10.3f'
|
|
self.imperial_text_template = '%9.4f'
|
|
self.setEnabled(False)
|
|
self.dialog_code = 'CALCULATOR'
|
|
self.text_dialog_code = 'KEYBOARD'
|
|
self.table = self.createTable()
|
|
|
|
def _hal_init(self):
|
|
self.delay = 0
|
|
STATUS.connect('all-homed', lambda w: self.setEnabled(True))
|
|
STATUS.connect('not-all-homed', lambda w, axis: self.setEnabled(False))
|
|
STATUS.connect('interp-idle', lambda w: self.setEnabled(STATUS.machine_is_on()
|
|
and (STATUS.is_all_homed()
|
|
or INFO.NO_HOME_REQUIRED)))
|
|
STATUS.connect('interp-run', lambda w: self.setEnabled(False))
|
|
STATUS.connect('periodic', self.periodic_check)
|
|
STATUS.connect('metric-mode-changed', lambda w, data: self.metricMode(data))
|
|
STATUS.connect('tool-in-spindle-changed', lambda w, data: self.currentTool(data))
|
|
STATUS.connect('user-system-changed', self._convert_system)
|
|
STATUS.connect('general',self.return_value)
|
|
|
|
conversion = {0:"X", 1:"Y", 2:"Z", 3:"A", 4:"B", 5:"C", 6:"U", 7:"V", 8:"W"}
|
|
for num, let in conversion.items():
|
|
if let in (INFO.AVAILABLE_AXES):
|
|
continue
|
|
self.hideColumn(num)
|
|
|
|
# If there is a preference file object use it to load the hi/low toggle points
|
|
if self.PREFS_:
|
|
self.tabledata[4][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G54', 'User System 1', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[5][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G55', 'User System 2', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[6][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G56', 'User System 3', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[7][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G57', 'User System 4', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[8][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G58', 'User System 5', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[9][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G59', 'User System 6', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[10][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G59.1', 'User System 7', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[11][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G59.2', 'User System 8', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tabledata[12][10] = self.PREFS_.getpref(self.HAL_NAME_+'-G59.3', 'User System 9', str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.tablemodel.layoutChanged.emit()
|
|
|
|
# when qtvcp closes this gets called
|
|
def _hal_cleanup(self):
|
|
if self.PREFS_:
|
|
LOG.debug('Saving {} data to file.'.format(self.HAL_NAME_))
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G54', self.tabledata[4][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G55', self.tabledata[5][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G56', self.tabledata[6][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G57', self.tabledata[7][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G58', self.tabledata[8][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G59', self.tabledata[9][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G59.1', self.tabledata[10][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G59.2', self.tabledata[11][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
self.PREFS_.putpref(self.HAL_NAME_+'-G59.3', self.tabledata[12][10], str, 'ORIGINOFFSET_SYSTEM_NAMES')
|
|
|
|
def _convert_system(self, w, data):
|
|
convert = ("None", "G54", "G55", "G56", "G57", "G58", "G59", "G59.1", "G59.2", "G59.3")
|
|
self.current_system = convert[int(data)]
|
|
self._system_int = int(data)
|
|
|
|
def currentTool(self, data):
|
|
self.current_tool = data
|
|
def metricMode(self, state):
|
|
self.metric_display = state
|
|
|
|
def createTable(self):
|
|
# create blank taple array
|
|
self.tabledata = [[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Absolute Position'],
|
|
[None, None, 2, None, None, None, None, None, None, None, 'Rotational Offsets'],
|
|
[0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'G92 Offsets'],
|
|
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Current Tool'],
|
|
[0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 'System 1'],
|
|
[0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 'System 2'],
|
|
[0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 'System 3'],
|
|
[0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'System 4'],
|
|
[0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 'System 5'],
|
|
[0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 'System 6'],
|
|
[0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 'System 7'],
|
|
[0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 'System 8'],
|
|
[0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 'System 9']]
|
|
|
|
# create the view
|
|
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
|
|
|
# set the table model
|
|
header = ['X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'Rot', 'Name']
|
|
vheader = ['ABS', 'Rot', 'G92', 'Tool', 'G54', 'G55', 'G56', 'G57', 'G58', 'G59', 'G59.1', 'G59.2', 'G59.3']
|
|
self.tablemodel = MyTableModel(self.tabledata, header, vheader, self)
|
|
self.setModel(self.tablemodel)
|
|
self.clicked.connect(self.showSelection)
|
|
#self.dataChanged.connect(self.selection_changed)
|
|
|
|
# set the minimum size
|
|
self.setMinimumSize(100, 100)
|
|
|
|
# set horizontal header properties
|
|
hh = self.horizontalHeader()
|
|
hh.setStretchLastSection(True)
|
|
hh.setMinimumSectionSize(75)
|
|
|
|
# set column width to fit contents
|
|
self.resizeColumnsToContents()
|
|
|
|
# set row height
|
|
self.resizeRowsToContents()
|
|
|
|
# enable sorting
|
|
self.setSortingEnabled(False)
|
|
|
|
def showSelection(self, item):
|
|
cellContent = item.data()
|
|
#text = cellContent.toPyObject() # test
|
|
text = cellContent
|
|
LOG.debug('Text: {}, Row: {}, Column: {}'.format(text, item.row(), item.column()))
|
|
sf = "You clicked on {}".format(text)
|
|
# display in title bar for convenience
|
|
self.setWindowTitle(sf)
|
|
# row 0 is not editable (absolute position)
|
|
# row 1 has limited entries (rotational)
|
|
# column 10 is the descriptive text column
|
|
if item.column() == 10:
|
|
self.callTextDialog(text,item)
|
|
elif item.row() == 1:
|
|
if item.column() == 2:
|
|
self.callDialog(text,item)
|
|
elif item.row() in (2,3) and item.column() == 9:
|
|
pass
|
|
elif item.row() > 1:
|
|
self.callDialog(text,item)
|
|
|
|
# alphanumerical
|
|
def callTextDialog(self, text,item):
|
|
text = self.tablemodel.arraydata[item.row()][10]
|
|
system = self.tablemodel.Vheaderdata[item.row()]
|
|
mess = {'NAME':self.text_dialog_code,'ID':'%s__' % self.objectName(),
|
|
'PRELOAD':text, 'TITLE':'{} System Description Entry'.format(system),
|
|
'ITEM':item}
|
|
LOG.debug('message sent:{}'.format (mess))
|
|
STATUS.emit('dialog-request', mess)
|
|
|
|
def callDialog(self, text,item,next=False):
|
|
axis = self.tablemodel.headerdata[item.column()]
|
|
system = self.tablemodel.Vheaderdata[item.row()]
|
|
mess = {'NAME':self.dialog_code,'ID':'%s__' % self.objectName(),
|
|
'PRELOAD':locale.delocalize(text), 'TITLE':'{} Offset of {},{}'.format(system, axis,text),
|
|
'ITEM':item,
|
|
'NEXT':next,
|
|
'WIDGETCYCLE': True}
|
|
STATUS.emit('dialog-request', mess)
|
|
LOG.debug('message sent:{}'.format (mess))
|
|
|
|
# process the STATUS return message
|
|
def return_value(self, w, message):
|
|
num = message['RETURN']
|
|
code = bool(message.get('ID') == '%s__'% self.objectName())
|
|
name = bool(message.get('NAME') == self.dialog_code)
|
|
name2 = bool(message.get('NAME') == self.text_dialog_code)
|
|
item = message.get('ITEM')
|
|
next = message.get('NEXT', False)
|
|
back = message.get('BACK', False)
|
|
|
|
if code:
|
|
LOG.debug('message returned:{}'.format (message))
|
|
if code and (name or name2) and num is not None:
|
|
self.tablemodel.setData(item, num, None)
|
|
self.tablemodel.layoutChanged.emit()
|
|
if code and name:
|
|
# request for next input widget from nextlist
|
|
if next:
|
|
self.right()
|
|
|
|
newobj = self.currentIndex()
|
|
# if we selected the text column, move back
|
|
if newobj.column() == 10:
|
|
self.left()
|
|
newobj = self.currentIndex()
|
|
cellContent = newobj.data()
|
|
text = cellContent
|
|
|
|
# update the screen
|
|
QApplication.processEvents()
|
|
|
|
# update the dialog
|
|
self.callDialog(text,newobj,True)
|
|
elif back:
|
|
self.left()
|
|
|
|
newobj = self.currentIndex()
|
|
cellContent = newobj.data()
|
|
text = cellContent
|
|
|
|
# update the screen
|
|
QApplication.processEvents()
|
|
|
|
# update the dialog
|
|
self.callDialog(text,newobj,True)
|
|
|
|
# This function uses the color name (string); setProperty
|
|
# expects a QColor object
|
|
def highlight(self, color):
|
|
self.setProperty('styleColorHighlight', QColor(color))
|
|
|
|
#############################################################
|
|
|
|
# Reload the offsets into display
|
|
def reload_offsets(self):
|
|
|
|
# read the var file so we get all of the user offsets.
|
|
temp = self.read_file()
|
|
|
|
# overwrite with motion's version of the current system offset
|
|
# this should be more up to date
|
|
STATUS.stat.poll()
|
|
temp[STATUS.stat.g5x_index-1] = list(STATUS.stat.g5x_offset)
|
|
# inject the current rotation into the list
|
|
temp[STATUS.stat.g5x_index-1].append(STATUS.stat.rotation_xy)
|
|
|
|
g54, g55, g56, g57, g58, g59, g59_1, g59_2, g59_3 = temp
|
|
if g54 is None: return
|
|
|
|
# fake if linuxcnc is not running
|
|
if STATUS.is_status_valid() == False:
|
|
self.current_system = "G54"
|
|
self._system_int = 1
|
|
|
|
# Get the offsets arrays and convert the units if the display
|
|
# is not in machine native units
|
|
|
|
ap = STATUS.stat.actual_position
|
|
tool = STATUS.stat.tool_offset
|
|
g92 = STATUS.stat.g92_offset
|
|
rot = STATUS.stat.rotation_xy
|
|
|
|
if self.metric_display != INFO.MACHINE_IS_METRIC:
|
|
ap = INFO.convert_units_10(ap)
|
|
tool = INFO.convert_units_10(tool)
|
|
g92 = INFO.convert_units_10(g92)
|
|
g54 = INFO.convert_units_10(g54)
|
|
g55 = INFO.convert_units_10(g55)
|
|
g56 = INFO.convert_units_10(g56)
|
|
g57 = INFO.convert_units_10(g57)
|
|
g58 = INFO.convert_units_10(g58)
|
|
g59 = INFO.convert_units_10(g59)
|
|
g59_1 = INFO.convert_units_10(g59_1)
|
|
g59_2 = INFO.convert_units_10(g59_2)
|
|
g59_3 = INFO.convert_units_10(g59_3)
|
|
|
|
# set the text style based on unit type
|
|
if self.metric_display:
|
|
tmpl = self.metric_text_template
|
|
else:
|
|
tmpl = self.imperial_text_template
|
|
|
|
degree_tmpl = "%{}.2f".format(len(locale.format_string(tmpl, 0)))
|
|
|
|
# fill each row of the liststore from the offsets arrays
|
|
for row, i in enumerate([ap, rot, g92, tool, g54, g55, g56, g57, g58, g59, g59_1, g59_2, g59_3]):
|
|
for column in range(0, 10):
|
|
|
|
# current rotational
|
|
if row == 1:
|
|
if column == 2:
|
|
self.tabledata[row][column] = locale.format_string(degree_tmpl, rot)
|
|
else:
|
|
self.tabledata[row][column] = " "
|
|
|
|
# rotational column not available in row 0,2,3
|
|
elif row in (0,2,3) and column == 9:
|
|
self.tabledata[row][column] = " "
|
|
|
|
elif column == 9:
|
|
self.tabledata[row][column] = locale.format_string(degree_tmpl, i[column])
|
|
else:
|
|
self.tabledata[row][column] = locale.format_string(tmpl, i[column])
|
|
|
|
self.tablemodel.layoutChanged.emit()
|
|
|
|
# We read the var file directly
|
|
# and pull out the info we need
|
|
# if anything goes wrong we set all the info to 0
|
|
def read_file(self):
|
|
try:
|
|
g54 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g55 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g56 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g57 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g58 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g59 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g59_1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g59_2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
g59_3 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
if self.filename is None:
|
|
return g54, g55, g56, g57, g58, g59, g59_1, g59_2, g59_3
|
|
if not os.path.exists(self.filename):
|
|
LOG.error('File does not exist: yellow<{}>'.format(self.filename))
|
|
return g54, g55, g56, g57, g58, g59, g59_1, g59_2, g59_3
|
|
logfile = open(self.filename, "r").readlines()
|
|
for line in logfile:
|
|
temp = line.split()
|
|
param = int(temp[0])
|
|
data = float(temp[1])
|
|
|
|
if 5230 >= param >= 5221:
|
|
g54[param - 5221] = data
|
|
elif 5250 >= param >= 5241:
|
|
g55[param - 5241] = data
|
|
elif 5270 >= param >= 5261:
|
|
g56[param - 5261] = data
|
|
elif 5290 >= param >= 5281:
|
|
g57[param - 5281] = data
|
|
elif 5310 >= param >= 5301:
|
|
g58[param - 5301] = data
|
|
elif 5330 >= param >= 5321:
|
|
g59[param - 5321] = data
|
|
elif 5350 >= param >= 5341:
|
|
g59_1[param - 5341] = data
|
|
elif 5370 >= param >= 5361:
|
|
g59_2[param - 5361] = data
|
|
elif 5390 >= param >= 5381:
|
|
g59_3[param - 5381] = data
|
|
return [g54, g55, g56, g57, g58, g59, g59_1, g59_2, g59_3]
|
|
except:
|
|
return [None, None, None, None, None, None, None, None, None]
|
|
|
|
def dataChanged(self, new, old, x):
|
|
row = new.row()
|
|
col = new.column()
|
|
data = self.tabledata[row][col]
|
|
|
|
if row == 0: return
|
|
|
|
# Hack to not edit any rotational offset but Z axis
|
|
if row == 1 and not col == 2: return
|
|
|
|
if row in(2,3) and col == 9: return
|
|
|
|
# don't evaluate text column
|
|
if col == 10 :return
|
|
|
|
# make sure we switch to correct units for machine and rotational, row 2, does not get converted
|
|
try:
|
|
qualified = float(data)
|
|
#qualified = float(locale.atof(data))
|
|
except Exception as e:
|
|
LOG.exception(e)
|
|
# now update linuxcnc to the change
|
|
try:
|
|
if STATUS.is_status_valid():
|
|
ACTION.RECORD_CURRENT_MODE()
|
|
if row == 0: # current Origin
|
|
ACTION.CALL_MDI("G10 L2 P0 %s %10.4f" % (self.axisletters[col], qualified))
|
|
elif row == 1: # current rotational
|
|
if col == 2: # Z axis only
|
|
ACTION.CALL_MDI("G10 L2 P0 R %10.4f" % (qualified))
|
|
elif row == 2: # G92 offset
|
|
ACTION.CALL_MDI("G92 %s %10.4f" % (self.axisletters[col], qualified))
|
|
elif row == 3: # Tool
|
|
if not self.current_tool == 0:
|
|
ACTION.CALL_MDI("G10 L1 P%d %s %10.4f" % (self.current_tool, self.axisletters[col], qualified))
|
|
ACTION.CALL_MDI('g43')
|
|
elif col == 9: # rotational
|
|
ACTION.CALL_MDI("G10 L2 P%d R %10.4f" % (row-3, qualified))
|
|
else:
|
|
ACTION.CALL_MDI("G10 L2 P%d %s %10.4f" % (row-3, self.axisletters[col], qualified))
|
|
|
|
ACTION.UPDATE_VAR_FILE()
|
|
ACTION.RESTORE_RECORDED_MODE()
|
|
STATUS.emit('reload-display')
|
|
self.reload_offsets()
|
|
except Exception as e:
|
|
LOG.exception("offsetpage widget error: MDI call error", exc_info=e)
|
|
self.reload_offsets()
|
|
|
|
# only update every 10th time periodic calls
|
|
def periodic_check(self, w):
|
|
if self.delay < 9:
|
|
self.delay += 1
|
|
return
|
|
else:
|
|
self.delay = 0
|
|
if self.filename:
|
|
self.reload_offsets()
|
|
return True
|
|
|
|
# moves the selection up
|
|
@Slot()
|
|
def up(self):
|
|
self.setCurrentIndex(self.moveCursor(QAbstractItemView.CursorAction.MoveUp,Qt.NoModifier))
|
|
|
|
# moves the selection down
|
|
@Slot()
|
|
def down(self):
|
|
self.setCurrentIndex(self.moveCursor(QAbstractItemView.CursorAction.MoveDown,Qt.NoModifier))
|
|
|
|
def left(self):
|
|
self.setCurrentIndex(self.moveCursor(QAbstractItemView.CursorAction.MoveLeft,Qt.NoModifier))
|
|
|
|
def right(self):
|
|
self.setCurrentIndex(self.moveCursor(QAbstractItemView.CursorAction.MoveRight,Qt.NoModifier))
|
|
|
|
#########################################################################
|
|
# 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
|
|
#
|
|
########################################################################
|
|
|
|
def set_dialog_code(self, data):
|
|
self.dialog_code = data
|
|
def get_dialog_code(self):
|
|
return self.dialog_code
|
|
def reset_dialog_code(self):
|
|
self.dialog_code = 'CALCULATOR'
|
|
dialog_code_string = Property(str, get_dialog_code, set_dialog_code, reset_dialog_code)
|
|
|
|
def set_keyboard_code(self, data):
|
|
self.text_dialog_code = data
|
|
def get_keyboard_code(self):
|
|
return self.text_dialog_code
|
|
def reset_keyboard_code(self):
|
|
self.text_dialog_code = 'KEYBOARD'
|
|
text_dialog_code_string = Property(str, get_keyboard_code, set_keyboard_code, reset_keyboard_code)
|
|
|
|
def setmetrictemplate(self, data):
|
|
self.metric_text_template = data
|
|
def getmetrictemplate(self):
|
|
return self.metric_text_template
|
|
def resetmetrictemplate(self):
|
|
self.metric_text_template = '%10.3f'
|
|
metric_template = Property(str, getmetrictemplate, setmetrictemplate, resetmetrictemplate)
|
|
|
|
def setimperialtexttemplate(self, data):
|
|
self.imperial_text_template = data
|
|
def getimperialtexttemplate(self):
|
|
return self.imperial_text_template
|
|
def resetimperialtexttemplate(self):
|
|
self.imperial_text_template = '%9.4f'
|
|
imperial_template = Property(str, getimperialtexttemplate, setimperialtexttemplate, resetimperialtexttemplate)
|
|
|
|
def getColorHighlight(self):
|
|
return QColor(self.tablemodel._highlightcolor)
|
|
def setColorHighlight(self, value):
|
|
self.tablemodel._highlightcolor = value.name()
|
|
#self.tablemodel.layoutChanged.emit()
|
|
styleColorHighlight = Property(QColor, getColorHighlight, setColorHighlight)
|
|
|
|
#########################################
|
|
# custom model
|
|
#########################################
|
|
class MyTableModel(QAbstractTableModel):
|
|
def __init__(self, datain, headerdata, vheaderdata, parent=None):
|
|
"""
|
|
Args:
|
|
datain: a list of lists\n
|
|
headerdata: a list of strings
|
|
"""
|
|
super(MyTableModel, self).__init__(parent)
|
|
self.arraydata = datain
|
|
self.headerdata = headerdata
|
|
self.Vheaderdata = vheaderdata
|
|
self._highlightcolor = '#00ffff'
|
|
|
|
def rowCount(self, parent):
|
|
return len(self.arraydata)
|
|
|
|
def columnCount(self, parent):
|
|
if len(self.arraydata) > 0:
|
|
return len(self.arraydata[0])
|
|
return 0
|
|
|
|
def data(self, index, role):
|
|
if role == Qt.EditRole:
|
|
return self.arraydata[index.row()][index.column()]
|
|
if role == Qt.DisplayRole:
|
|
return self.arraydata[index.row()][index.column()]
|
|
elif role == Qt.BackgroundRole:
|
|
value = self.arraydata[index.row()][index.column()]
|
|
if (isinstance(value, int) or isinstance(value, float) or
|
|
isinstance(value, str)):
|
|
if int(index.row()) == self.parent()._system_int + 3:
|
|
return QColor(self._highlightcolor)
|
|
else:
|
|
return None
|
|
return None
|
|
|
|
|
|
def flags(self, index):
|
|
if not index.isValid():
|
|
return None
|
|
# print(">>> flags() index.column() = ", index.column())
|
|
if index.column() == 10 and index.row() in(0, 1, 2, 3):
|
|
return Qt.ItemIsEnabled
|
|
elif index.row() == 0:
|
|
return Qt.ItemIsEnabled
|
|
elif index.row() == 1 and not index.column() == 2:
|
|
return Qt.NoItemFlags
|
|
elif index.row() in(2, 3) and index.column() == 9:
|
|
return Qt.NoItemFlags
|
|
else:
|
|
return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
|
|
def setData(self, index, value, role):
|
|
if not index.isValid():
|
|
return False
|
|
LOG.debug(self.arraydata[index.row()][index.column()])
|
|
LOG.debug(">>> setData() role = {}".format(role))
|
|
LOG.debug(">>> setData() index.column() = {}".format(index.column()))
|
|
if index.row() == 0: return False
|
|
try:
|
|
if index.column() == 10:
|
|
v = str(value)
|
|
else:
|
|
v = float(value)
|
|
except:
|
|
return False
|
|
LOG.debug(">>> setData() value = {}".format(value))
|
|
LOG.debug(">>> setData() qualified value = {}".format(v))
|
|
# self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index)
|
|
LOG.debug(">>> setData() index.row = {}".format(index.row()))
|
|
LOG.debug(">>> setData() index.column = {}".format(index.column()))
|
|
self.arraydata[index.row()][index.column()] = v
|
|
self.dataChanged.emit(index, index)
|
|
return True
|
|
|
|
def headerData(self, col, orientation, role):
|
|
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
|
return self.headerdata[col]
|
|
if orientation != Qt.Horizontal and role == Qt.DisplayRole:
|
|
return self.Vheaderdata[col]
|
|
return None
|
|
|
|
if __name__ == "__main__":
|
|
from qtpy.QtWidgets import QApplication
|
|
app = QApplication([])
|
|
w = OriginOffsetView()
|
|
w.PREFS_ = None
|
|
w._hal_init()
|
|
w.setProperty('styleColorHighlight',QColor('purple'))
|
|
w.show()
|
|
sys.exit(app.exec())
|