Import LinuxCNC source tree
This commit is contained in:
285
lib/python/qtvcp/widgets/entry_widget.py
Normal file
285
lib/python/qtvcp/widgets/entry_widget.py
Normal file
@@ -0,0 +1,285 @@
|
||||
#!/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.
|
||||
#
|
||||
# base code Found on Code Cookbook
|
||||
#
|
||||
# This widget pops up an onscreen keyboard for entries
|
||||
# Used in the Macro and MDI line widget
|
||||
|
||||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
#from decimal import Decimal
|
||||
|
||||
# applicationle widgets
|
||||
SIP_WIDGETS = [QtWidgets.QLineEdit]
|
||||
|
||||
|
||||
class MyFlatPushButton(QtWidgets.QPushButton):
|
||||
def __init__(self, caption, min_size=(50, 50)):
|
||||
self.MIN_SIZE = min_size
|
||||
super(MyFlatPushButton, self).__init__(caption)
|
||||
self.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||
|
||||
def sizeHint(self):
|
||||
return QtCore.QSize(self.MIN_SIZE[0], self.MIN_SIZE[1])
|
||||
|
||||
class SoftInputWidget(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None, keyboard_type='default'):
|
||||
super(SoftInputWidget, self).__init__(parent)
|
||||
self.setWindowModality(QtCore.Qt.ApplicationModal)
|
||||
self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint |
|
||||
QtCore.Qt.WindowStaysOnTopHint)
|
||||
self.INPUT_WIDGET = None
|
||||
self.PARENT_OBJECT = parent
|
||||
self.signalMapper = QtCore.QSignalMapper(self)
|
||||
|
||||
self.NO_ORD_KEY_LIST = list()
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Left)
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Up)
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Right)
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Down)
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Backspace)
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Enter)
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Tab)
|
||||
self.NO_ORD_KEY_LIST.append(QtCore.Qt.Key_Escape)
|
||||
|
||||
self.do_layout(keyboard_type)
|
||||
|
||||
mapped = getattr(self.signalMapper, 'mappedInt', None) or self.signalMapper.mapped[int]
|
||||
mapped.connect(self.buttonClicked)
|
||||
|
||||
def do_layout(self, keyboard_type='default'):
|
||||
"""
|
||||
@param keyboard_type:
|
||||
@return:
|
||||
"""
|
||||
gl = QtWidgets.QVBoxLayout()
|
||||
self.setFont(self.PARENT_OBJECT.font())
|
||||
number_widget_list = []
|
||||
sym_list = list(range(0, 10))
|
||||
for sym in sym_list:
|
||||
button = MyFlatPushButton(str(sym))
|
||||
button.KEY_CHAR = ord(str(sym))
|
||||
number_widget_list.append(button)
|
||||
|
||||
# alphabets
|
||||
alpha_widget_list = []
|
||||
sym_list = ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P',
|
||||
'new_row',
|
||||
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L',
|
||||
'new_row',
|
||||
'Z', 'X', 'C', 'V', 'B', 'N', 'M']
|
||||
for sym in sym_list:
|
||||
if sym == 'new_row':
|
||||
alpha_widget_list.append('new_row')
|
||||
else:
|
||||
button = MyFlatPushButton(sym)
|
||||
button.KEY_CHAR = ord(sym)
|
||||
alpha_widget_list.append(button)
|
||||
|
||||
button = MyFlatPushButton('.')
|
||||
button.KEY_CHAR = ord('.')
|
||||
alpha_widget_list.append(button)
|
||||
button = MyFlatPushButton('-')
|
||||
button.KEY_CHAR = ord('-')
|
||||
alpha_widget_list.append(button)
|
||||
|
||||
control_widget_list = []
|
||||
|
||||
button = MyFlatPushButton('LINE\nUP')
|
||||
button.setToolTip('Cursor Up')
|
||||
button.KEY_CHAR = QtCore.Qt.Key_Up
|
||||
control_widget_list.append(button)
|
||||
|
||||
button = MyFlatPushButton('LINE\nDOWN')
|
||||
button.setToolTip('Cursor Down')
|
||||
button.KEY_CHAR = QtCore.Qt.Key_Down
|
||||
control_widget_list.append(button)
|
||||
|
||||
# space
|
||||
button = MyFlatPushButton('SPACE', min_size=(160, 50))
|
||||
button.KEY_CHAR = QtCore.Qt.Key_Space
|
||||
control_widget_list.append(button)
|
||||
|
||||
# back space
|
||||
button = MyFlatPushButton('BACK')
|
||||
button.setToolTip('Backspace')
|
||||
button.KEY_CHAR = QtCore.Qt.Key_Backspace
|
||||
control_widget_list.append(button)
|
||||
|
||||
# close
|
||||
button = MyFlatPushButton('CLOSE')
|
||||
button.setToolTip('Close Keyboard')
|
||||
button.KEY_CHAR = QtCore.Qt.Key_Escape
|
||||
control_widget_list.append(button)
|
||||
|
||||
# enter
|
||||
button = MyFlatPushButton('ENTER', min_size=(105, 50))
|
||||
button.setToolTip('Enter Command')
|
||||
button.KEY_CHAR = QtCore.Qt.Key_Enter
|
||||
control_widget_list.append(button)
|
||||
|
||||
MAX_COL = 10
|
||||
col = 0
|
||||
tlist = list()
|
||||
if keyboard_type == 'numeric':
|
||||
widget_list = number_widget_list
|
||||
elif keyboard_type == 'alpha':
|
||||
widget_list = alpha_widget_list
|
||||
else:
|
||||
widget_list = list()
|
||||
widget_list.extend(number_widget_list)
|
||||
widget_list.append('new_row')
|
||||
widget_list.extend(alpha_widget_list)
|
||||
|
||||
widget_list.append('new_row')
|
||||
widget_list.extend(control_widget_list)
|
||||
|
||||
for widget in widget_list:
|
||||
if widget == 'new_row':
|
||||
col = MAX_COL
|
||||
else:
|
||||
tlist.append(widget)
|
||||
widget.clicked.connect(self.signalMapper.map)
|
||||
self.signalMapper.setMapping(widget, widget.KEY_CHAR)
|
||||
|
||||
if col == MAX_COL:
|
||||
col = 0
|
||||
v = QtWidgets.QHBoxLayout()
|
||||
v.addStretch()
|
||||
v.setSpacing(5)
|
||||
list(map(v.addWidget, tlist))
|
||||
v.addStretch()
|
||||
gl.addLayout(v)
|
||||
tlist = []
|
||||
else:
|
||||
col += 1
|
||||
|
||||
v = QtWidgets.QHBoxLayout()
|
||||
v.setSpacing(5)
|
||||
v.addStretch()
|
||||
list(map(v.addWidget, tlist))
|
||||
v.addStretch()
|
||||
gl.addLayout(v)
|
||||
gl.setContentsMargins(4, 4, 4, 4)
|
||||
gl.setSpacing(4)
|
||||
gl.setSizeConstraint(gl.SetFixedSize)
|
||||
|
||||
self.setLayout(gl)
|
||||
|
||||
def reject(self):
|
||||
self.buttonClicked(QtCore.Qt.Key_Escape)
|
||||
|
||||
def buttonClicked(self, char_ord):
|
||||
w = self.INPUT_WIDGET
|
||||
if char_ord in self.NO_ORD_KEY_LIST:
|
||||
keyPress = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, char_ord, QtCore.Qt.NoModifier, '')
|
||||
else:
|
||||
keyPress = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, char_ord, QtCore.Qt.NoModifier, chr(char_ord))
|
||||
# hide on enter or esc button click
|
||||
if char_ord == QtCore.Qt.Key_Escape:
|
||||
self.hide()
|
||||
else:
|
||||
# send keypress event to widget
|
||||
QtWidgets.QApplication.sendEvent(w, keyPress)
|
||||
if char_ord == QtCore.Qt.Key_Enter:
|
||||
self.hide()
|
||||
|
||||
# line edit returnPressed event is triggering twice for press and release both
|
||||
# that is why do not send release event for special key
|
||||
if char_ord not in self.NO_ORD_KEY_LIST:
|
||||
keyRelease = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, char_ord, QtCore.Qt.NoModifier, '')
|
||||
QtWidgets.QApplication.sendEvent(w, keyRelease)
|
||||
|
||||
def show_input_panel(self, widget):
|
||||
self.INPUT_WIDGET = widget
|
||||
self.show()
|
||||
self.update_panel_position()
|
||||
self.setFocus()
|
||||
self.raise_()
|
||||
|
||||
def update_panel_position(self):
|
||||
widget = self.INPUT_WIDGET
|
||||
if not widget: return
|
||||
|
||||
widget_rect = widget.rect()
|
||||
widget_bottom = widget.mapToGlobal(QtCore.QPoint(widget.frameGeometry().x(),
|
||||
widget.frameGeometry().y())).y()
|
||||
screen_height = QtWidgets.QApplication.primaryScreen().availableGeometry().height()
|
||||
input_panel_height = self.geometry().height() + 5
|
||||
|
||||
if (screen_height - widget_bottom) > input_panel_height:
|
||||
# display input panel at bottom of widget
|
||||
panelPos = QtCore.QPoint(widget_rect.left(), widget_rect.bottom() + 2)
|
||||
else:
|
||||
# display input panel at top of widget
|
||||
panelPos = QtCore.QPoint(widget_rect.left(), widget_rect.top() - input_panel_height)
|
||||
|
||||
panelPos = widget.mapToGlobal(panelPos)
|
||||
self.move(panelPos)
|
||||
|
||||
|
||||
# a widget that calls our keyboard dialog
|
||||
class TouchInterface(QtWidgets.QWidget):
|
||||
def __init__(self, parent):
|
||||
super(TouchInterface, self).__init__(parent)
|
||||
self._PARENT_WIDGET = parent
|
||||
self._input_panel_alpha = SoftInputWidget(parent, 'alpha')
|
||||
self._input_panel_numeric = SoftInputWidget(parent, 'numeric')
|
||||
self._input_panel_full = SoftInputWidget(parent, 'default')
|
||||
self.keyboard_enable = True
|
||||
self.keyboard_type = 'numeric'
|
||||
|
||||
def childEvent(self, event):
|
||||
if event.type() == QtCore.QEvent.ChildAdded:
|
||||
if isinstance(event.child(), *SIP_WIDGETS):
|
||||
event.child().installEventFilter(self)
|
||||
|
||||
def eventFilter(self, widget, event):
|
||||
try:
|
||||
if self._PARENT_WIDGET.focusWidget() == widget and event.type() == QtCore.QEvent.MouseButtonPress:
|
||||
if self.keyboard_enable is False:
|
||||
return False
|
||||
self.callDialog(widget, self.keyboard_type.lower())
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
# can be class patched to call other entries - like qtvcp dialogs
|
||||
def callDialog(self, widget, ktype):
|
||||
if ktype == 'alpha':
|
||||
self._input_panel_alpha.show_input_panel(widget)
|
||||
elif ktype == 'numeric':
|
||||
self._input_panel_numeric.show_input_panel(widget)
|
||||
else:
|
||||
self._input_panel_full.show_input_panel(widget)
|
||||
|
||||
## testing ##
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from qtpy.QtWidgets import QWidget
|
||||
app = QtWidgets.QApplication([])
|
||||
w = QWidget()
|
||||
w.setGeometry(100, 100, 200, 100)
|
||||
w.setWindowTitle('Entry Widget')
|
||||
line = QtWidgets.QLineEdit()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(line)
|
||||
test = TouchInterface(line)
|
||||
# test.callDialog(line, 'numeric')
|
||||
# test.callDialog(line, 'alpha')
|
||||
test.callDialog(line, 'default')
|
||||
w.setLayout(layout)
|
||||
w.show()
|
||||
sys.exit(app.exec())
|
||||
Reference in New Issue
Block a user