Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/src/gui/images/qtvcp_operator_value.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions docs/src/gui/qtvcp-widgets.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,53 @@ It is a comma separated list of keyword and data:
*`SAVE:yes`*::
Shows a save button.

[[sub:qtvcp:widgets:operatorvalueline]]
=== `OperatorValueLine` - Operator Value Line Entry Widget

The operator enters values into this widget, which will be applied to a template and then optionally issued to the MDI either immediately or applied at a later time. The widget supports the optional popup calculator or keyboard for touchscreen-friendly entry.

image::images/qtvcp_operator_value.png["QtVCP OperatorValueLine",scale="25%"]


==== Formatting MDI Command
The widget supports a formatting option which is passed to Python's string `format()` to produce the final output for the MDI command. The special token `{value}` can be inserted anywhere in this format string where the value should appear. The formatting property is called `mdi_command_format_option`, e.g.:

* `M3 S{value}` to start the spindle at the speed entered by the operator.
* `M6 T{value} G43 H{value}` to issue a tool change and tool length offset change from the tool number entered

==== Automatic vs Deferred MDI Issue
The widget may be configured to automatically issue the MDI command upon submit when `issue_mdi_on_submit_option` is set to `True`. If `False` issuing the command may be done at a later time via a signal or function call from another widget.

In cases where `issue_mdi_on_submit_option` is `False`, calling the `issue_mdi()` function will issue the command. Slots attached to widgets such as PushButtons can trigger the MDI command when pressed, e.g.:

----
def setSpindleSpeed(self, event):
self.w.lineSpindleSpeed.issue_mdi()
ACTION.SET_MANUAL_MODE()

def setToolNumber(self, event):
self.w.lineToolNumber.issue_mdi()
ACTION.SET_MANUAL_MODE()
----

==== Pending State Styling Example

The widget tracks whether a value entered is pending and has not yet been issued via the property `isPendingValue`. This may be used to style the widget via the stylesheet. This can be used to alert the operator that they entered a value but another action must be taken to apply it.

The following style sheet excerpt will highlight the entry widget with a cyan background when values are pending and have not been applied.

----
#lineSpindleSpeed[isPendingValue=true],
#lineToolNumber[isPendingValue=true] {
background: cyan;
}

#lineSpindleSpeed[isPendingValue=false],
#lineToolNumber[isPendingValue=false] {
background: none;
}
----

[[sub:qtvcp:widgets:mdiline]]
=== `MDILine` - MDI Commands Line Entry Widget

Expand Down Expand Up @@ -2658,6 +2705,13 @@ When using ``STATUS``'s `request-dialog` function, the default launch name is *`

It is based on PyQt's _QDialog_.

==== INI file options for CALCULATOR

In the `DISPLAY` section of the INI file the following options may be set:

* `CALCULATOR_CONST_VALUES` - a comma-delimited list of common values you might enter, that will appear on a dedicated row of buttons at the bottom of the calculator. e.g. setting to `0.100,-0.100` would provide two buttons for +0.100 and -0.100 which are commonly used when edge-finding on inch mills. Up to six (6) values may be entered, beyond that the list will be truncated. Values must be valid floating point or integer.
* `CALCULATOR_ON_SHOW` - optionally set to `CLEAR_ALL` to issue a "Clear All" each time the calculator is shown. This will clear any previously entered values from the last time the calculator was used and open with the display value set to `0`

[[sub:qtvcp:widgets:runfromlinedialog]]
=== `RunFromLine` - Run-From-Line Dialog Widget

Expand Down
45 changes: 45 additions & 0 deletions lib/python/qtvcp/plugins/widgets_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from PyQt5.QtDesigner import QPyDesignerCustomWidgetPlugin
from qtvcp.widgets.dro_widget import DROLabel
from qtvcp.widgets.mdi_line import MDILine
from qtvcp.widgets.operator_value_line import OperatorValueLine
from qtvcp.widgets.mdi_history import MDIHistory
from qtvcp.widgets.mdi_touchy import MDITouchy
from qtvcp.widgets.gcode_editor import GcodeEditor, GcodeDisplay
Expand Down Expand Up @@ -107,6 +108,50 @@ def includeFile(self):
return "qtvcp.widgets.mdi_line"


####################################
# Operator Value edit line
####################################
class OperatorValueLinePlugin(QPyDesignerCustomWidgetPlugin):
def __init__(self, parent=None):
super(OperatorValueLinePlugin, self).__init__(parent)
self.initialized = False

def initialize(self, formEditor):
if self.initialized:
return
self.initialized = True

def isInitialized(self):
return self.initialized

def createWidget(self, parent):
return OperatorValueLine(parent)

def name(self):
return "OperatorValueLine"

def group(self):
return "Linuxcnc - Controller"

def icon(self):
return QtGui.QIcon(QtGui.QPixmap(ICON.get_path('operatorvalueline')))

def toolTip(self):
return "Operator value edit line Widget"

def whatsThis(self):
return ""

def isContainer(self):
return True

def domXml(self):
return '<widget class="OperatorValueLine" name="operatorvalueline" />\n'

def includeFile(self):
return "qtvcp.widgets.operator_value_line"


####################################
# MDI History widget
####################################
Expand Down
24 changes: 20 additions & 4 deletions lib/python/qtvcp/widgets/action_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def __init__(self, parent=None):
self.exit = False
self.template_label = False
self.lathe_mirror_x = False

self.home_no_unhome = False
self.toggle_float = False
self._toggle_state = 0
self.joint = -1
Expand Down Expand Up @@ -473,15 +473,19 @@ def action(self, state=None):
if state:
ACTION.SET_MACHINE_HOMING(self.joint)
else:
ACTION.SET_MACHINE_UNHOMED(self.joint)
if not self.home_no_unhome:
ACTION.SET_MACHINE_UNHOMED(self.joint)
else:
if self.joint == -1:
if STATUS.is_all_homed():
ACTION.SET_MACHINE_UNHOMED(-1)
if not self.home_no_unhome:
ACTION.SET_MACHINE_UNHOMED(-1)
else:
ACTION.SET_MACHINE_HOMING(-1)
elif STATUS.is_joint_homed(self.joint):
ACTION.SET_MACHINE_UNHOMED(self.joint)
if not self.home_no_unhome:
ACTION.SET_MACHINE_UNHOMED(self.joint)
pass
else:
ACTION.SET_MACHINE_HOMING(self.joint)
elif self.unhome:
Expand Down Expand Up @@ -1422,6 +1426,14 @@ def get_lathe_mirror_x(self):
def reset_lathe_mirror_x(self):
self.lathe_mirror_x = False

def set_home_no_unhome(self, data):
self.home_no_unhome = data
def get_home_no_unhome(self):
return self.home_no_unhome
def reset_home_no_unhome(self):
self.home_no_unhome = False


# NON BOOL VARIABLES------------------
def set_incr_imperial(self, data):
self.jog_incr_imperial = data
Expand Down Expand Up @@ -1567,6 +1579,9 @@ def reset_ini_mdi_key(self):
machine_log_dialog_action = QtCore.pyqtProperty(bool, get_machine_log_dialog, set_machine_log_dialog, reset_machine_log_dialog)
lathe_mirror_x_action = QtCore.pyqtProperty(bool, get_lathe_mirror_x, set_lathe_mirror_x, reset_lathe_mirror_x)


home_no_unhome_option = QtCore.pyqtProperty(bool, get_home_no_unhome, set_home_no_unhome, reset_home_no_unhome)

def set_template_label(self, data):
self.template_label = data
def get_template_label(self):
Expand All @@ -1575,6 +1590,7 @@ def reset_template_label(self):
self.template_label = False
template_label_option = QtCore.pyqtProperty(bool, get_template_label, set_template_label, reset_template_label)


# NON BOOL
joint_number = QtCore.pyqtProperty(int, get_joint, set_joint, reset_joint)
axis_letter = QtCore.pyqtProperty(str, get_axis, set_axis, reset_axis)
Expand Down
29 changes: 29 additions & 0 deletions lib/python/qtvcp/widgets/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ def __init__(self, parent=None):
mainLayout.addWidget(self.to_inch_btn, 6, 1)
mainLayout.addWidget(self.tpi_btn, 6, 2)

self.constButtons = []
constValues = INFO.get_error_safe_setting('DISPLAY', 'CALCULATOR_CONST_VALUES', None)
if constValues is not None:
constValues = ''.join(constValues.split())
for value in constValues.split(',')[:6]:
constButton = QPushButton(value)
constButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
constButton.clicked.connect(self.constClicked)
mainLayout.addWidget(constButton, 7, len(self.constButtons))
self.constButtons.append(constButton)

self.backButton = QPushButton('Back')
self.backButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
self.backButton.clicked.connect(self.backAction)
Expand Down Expand Up @@ -146,6 +157,13 @@ def __init__(self, parent=None):
STATUS.connect('all-homed', lambda w: self.axisButton.setEnabled(True))
STATUS.connect('not-all-homed', lambda w, data: self.axisButton.setEnabled(False))

self.behaviorOnShow = INFO.get_error_safe_setting('DISPLAY', 'CALCULATOR_ON_SHOW', None)

def showEvent(self, event):
if self.behaviorOnShow is not None:
if self.behaviorOnShow.upper() == 'CLEAR_ALL':
self.clearAll()

def digitClicked(self):
clickedButton = self.sender()
digitValue = int(clickedButton.text())
Expand Down Expand Up @@ -327,6 +345,17 @@ def convertClicked(self):
self.display.setText(str(result))
self.waitingForOperand = True

def constClicked(self):
clickedButton = self.sender()
constValue = float(clickedButton.text())

if self.waitingForOperand:
self.display.clear()
self.waitingForOperand = False

self.display.setText(str(constValue))


def clear(self):
if self.waitingForOperand:
return
Expand Down
1 change: 1 addition & 0 deletions lib/python/qtvcp/widgets/indicatorMixIn.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ def getFlashRate(self):
@pyqtSlot(int)
def setFlashRate(self, value):
self._flashRate = value
self._timer.setInterval(self._flashRate)
self.update()

def set_indicator_size(self, data):
Expand Down
Loading