PYMOL-3590 Shortcut menu Create/Confirm fixes

- Fixed previous assignment being called
- Create/confirm are now QDialog
- Create/confirm no longer dockable
- Improved key recognition in create
- Replacing _weakrefproxy with _
This commit is contained in:
Thomas Stewart
2021-04-19 12:58:38 -04:00
committed by Jarrett Johnson
parent fb5fae24b3
commit a30c11bc5a
5 changed files with 139 additions and 68 deletions

View File

@@ -2,16 +2,31 @@
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>412</width>
<height>89</height>
<height>90</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>412</width>
<height>90</height>
</size>
</property>
<property name="windowTitle">
<string>Dialog</string>
<string>Confirm Changing Existing Binding</string>
</property>
<widget class="QLabel" name="label">
<property name="geometry">

View File

@@ -10,6 +10,12 @@
<height>104</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Create Shortcut</string>
</property>

View File

@@ -11,6 +11,7 @@ from pymol.keyboard import get_default_keys
Qt = QtCore.Qt
QSI = QtGui.QStandardItem # For brevity
def get_shortcut_key_map():
shortcut_key_map = {}
for key, value in vars(Qt).items():
@@ -18,6 +19,7 @@ def get_shortcut_key_map():
shortcut_key_map[value] = key.partition('_')[2]
return shortcut_key_map
_SHORTCUT_KEY_MAP = get_shortcut_key_map()
_SHORTCUT_MODIFIER_MAP = {
@@ -25,13 +27,26 @@ _SHORTCUT_MODIFIER_MAP = {
Qt.AltModifier: _SHORTCUT_KEY_MAP[Qt.Key_Alt],
Qt.ShiftModifier: _SHORTCUT_KEY_MAP[Qt.Key_Shift],
Qt.MetaModifier: _SHORTCUT_KEY_MAP[Qt.Key_Meta],
}
}
_REPLACE_KEYS = {
'PageUp': 'pgup',
'PageDown': 'pgdn',
'Home': 'home',
'Insert': 'insert',
'Up': 'up',
'Down': 'down',
'Left': 'left',
'Right': 'right',
'End':'end'
}
class PyMOLShortcutMenu(QtWidgets.QWidget):
'''
Keyboard shortcut dialog for PyMOL. This displays all assigned shortcuts
and allows them to be changed or new shortcuts to be created.
'''
def __init__(self, parent, saved_shortcuts, cmd):
QtWidgets.QWidget.__init__(self, parent, Qt.Window)
self.resize(700, 700)
@@ -40,13 +55,13 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
self.build_panel_elements(parent)
def build_panel_elements(self,parent):
def build_panel_elements(self, parent):
'''
Responsible for creating all panel elements in order and adding them to the layout.
'''
self.create_new_form = parent.load_form("create_shortcut","floating")
self.help_form = parent.load_form("help_shortcut","floating")
self.confirm_change = parent.load_form("change_confirm","floating")
self.create_new_form = parent.load_form("create_shortcut", None)
self.help_form = parent.load_form("help_shortcut", None)
self.confirm_change = parent.load_form("change_confirm", None)
self.model = QtGui.QStandardItemModel(self)
self.proxy_model = QtCoreModels.QSortFilterProxyModel(self)
@@ -69,13 +84,14 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
self.filter_le.textChanged.connect(self.proxy_model.setFilterRegExp)
self.refresh_button = QtWidgets.QPushButton(self)
self.refresh_button.resize(26,26)
top_layout.addWidget(self.refresh_button,0,1)
self.refresh_button.resize(26, 26)
top_layout.addWidget(self.refresh_button, 0, 1)
# themed icons only available by default on X11
if self.refresh_button.icon().isNull():
self.refresh_button.setIcon(QtGui.QIcon(
os.path.expandvars('$PYMOL_DATA/pmg_qt/icons/refresh.svg')))
self.refresh_button.setToolTip("Refresh the table to reflect any external changes")
os.path.expandvars('$PYMOL_DATA/pmg_qt/icons/refresh.svg')))
self.refresh_button.setToolTip(
"Refresh the table to reflect any external changes")
self.refresh_button.clicked.connect(self.refresh_populate)
# Table
@@ -91,37 +107,51 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
# Buttons
self.create_new_button = QtWidgets.QPushButton(self)
button_layout.addWidget(self.create_new_button,0,0)
button_layout.addWidget(self.create_new_button, 0, 0)
self.create_new_button.setText("Create New")
self.create_new_button.setToolTip("Add a key binding that does not currently appear on the table")
self.create_new_button.clicked.connect(self.create_new_shortcut_menu)
self.create_new_button.setToolTip(
"Add a key binding that does not currently appear on the table")
self.create_new_button.clicked.connect(
lambda: self.create_new_form._dialog.show())
self.delete_selected_button = QtWidgets.QPushButton(self)
button_layout.addWidget(self.delete_selected_button,0,1)
button_layout.addWidget(self.delete_selected_button, 0, 1)
self.delete_selected_button.setText("Delete Selected")
self.delete_selected_button.setToolTip("Unbind selected key bindings and remove any that have been created")
self.delete_selected_button.setToolTip(
"Unbind selected key bindings and remove any that have been created")
self.delete_selected_button.clicked.connect(self.delete_selected)
self.delete_selected_button.setEnabled(False)
self.reset_selected_button = QtWidgets.QPushButton(self)
button_layout.addWidget(self.reset_selected_button,0,2)
button_layout.addWidget(self.reset_selected_button, 0, 2)
self.reset_selected_button.setText("Reset Selected")
self.reset_selected_button.setToolTip("Restore selected key bindings to their default values")
self.reset_selected_button.setToolTip(
"Restore selected key bindings to their default values")
self.reset_selected_button.clicked.connect(self.reset_selected)
self.reset_selected_button.setEnabled(False)
self.reset_all_button = QtWidgets.QPushButton(self)
button_layout.addWidget(self.reset_all_button,0,3)
button_layout.addWidget(self.reset_all_button, 0, 3)
self.reset_all_button.setText("Reset All")
self.reset_all_button.setToolTip("Restore all key bindings to their default values and remove any that have been created")
self.reset_all_button.setToolTip(
"Restore all key bindings to their default values and remove any that have been created")
self.reset_all_button.clicked.connect(self.reset_all_default)
self.save_button = QtWidgets.QPushButton(self)
button_layout.addWidget(self.save_button,0,4)
button_layout.addWidget(self.save_button, 0, 4)
self.save_button.setText("Save")
self.save_button.setToolTip("Save the current key bindings to be loaded automatically when opening PyMOL")
self.save_button.setToolTip(
"Save the current key bindings to be loaded automatically when opening PyMOL")
self.save_button.clicked.connect(self.shortcut_manager.save_shortcuts)
# Ensuring that confirmed key and binding remain in scope
self.confirm_new_key = ''
self.confirm_new_binding = ''
# Connect create new and confirm menus
self.create_new_shortcut_menu_connect()
self.confirm_menu_connect()
self.model.itemChanged.connect(self.itemChanged)
def populateData(self):
@@ -129,7 +159,8 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
Fill the model with data from shortcut_dict.
'''
self.model.clear()
self.model.setHorizontalHeaderLabels(['Key','Command (click to edit)','Description'])
self.model.setHorizontalHeaderLabels(
['Key', 'Command (click to edit)', 'Description'])
for key, shortcut_list in self.shortcut_manager.cmd.shortcut_dict.items():
key_item = QSI(key)
@@ -195,15 +226,15 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
delete_keys = []
for ind, table_index in enumerate(list_indexes):
table_colm_key = self.table.model().index(table_index.row(),0)
table_colm_command = self.table.model().index(table_index.row(),1)
table_colm_descipt = self.table.model().index(table_index.row(),2)
table_colm_key = self.table.model().index(table_index.row(), 0)
table_colm_command = self.table.model().index(table_index.row(), 1)
table_colm_descipt = self.table.model().index(table_index.row(), 2)
delete_key = table_colm_key.data()
self.cmd.set_key(delete_key,'')
self.cmd.set_key(delete_key, '')
if delete_key in self.shortcut_manager.default_bindings:
self.table.model().setData(table_colm_command,'Deleted')
self.table.model().setData(table_colm_descipt,'Deleted')
self.table.model().setData(table_colm_command, 'Deleted')
self.table.model().setData(table_colm_descipt, 'Deleted')
self.shortcut_manager.cmd.shortcut_dict[delete_key][ShortcutIndex.USER_DEF] = 'Deleted'
else:
self.model.removeRow(table_index.row())
@@ -221,32 +252,35 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
list_indexes = selection_model.selectedIndexes()
for ind, table_index in enumerate(list_indexes):
table_colm_key = self.table.model().index(table_index.row(),0)
table_colm_command = self.table.model().index(table_index.row(),1)
table_colm_descipt = self.table.model().index(table_index.row(),2)
table_colm_key = self.table.model().index(table_index.row(), 0)
table_colm_command = self.table.model().index(table_index.row(), 1)
table_colm_descipt = self.table.model().index(table_index.row(), 2)
reset_key = table_colm_key.data()
if reset_key not in self.shortcut_manager.default_bindings:
print("This key does not have a default value.")
else:
reset_binding = self.shortcut_manager.default_bindings[reset_key]
reset_command = self.shortcut_manager.cmd.shortcut_dict[reset_key][ShortcutIndex.COMMAND]
reset_description = self.shortcut_manager.cmd.shortcut_dict[reset_key][ShortcutIndex.DESCRIPT]
reset_command = self.shortcut_manager.cmd.shortcut_dict[
reset_key][ShortcutIndex.COMMAND]
reset_description = self.shortcut_manager.cmd.shortcut_dict[
reset_key][ShortcutIndex.DESCRIPT]
self.table.model().setData(table_colm_command, reset_command)
self.table.model().setData(table_colm_descipt, reset_description)
self.shortcut_manager.cmd.shortcut_dict[reset_key][ShortcutIndex.USER_DEF] = ''
self.cmd.set_key(reset_key,reset_binding)
self.cmd.set_key(reset_key, reset_binding)
def create_new_shortcut_menu(self):
self.create_new_form._dialog.show()
self.create_new_form.keyEdit.returnPressed.connect(self.create_new_shortcut)
self.create_new_form.commandEdit.returnPressed.connect(self.create_new_shortcut)
self.create_new_form.createButton.clicked.connect(self.create_new_shortcut)
self.create_new_form.helpButton.clicked.connect(self.help_menu_shortcut)
def create_new_shortcut_menu_connect(self):
self.create_new_form.createButton.clicked.connect(
self.create_new_shortcut_caller)
self.create_new_form.helpButton.clicked.connect(
self.help_menu_shortcut)
self.create_new_form.keyEdit.installEventFilter(self)
self.create_new_form.helpButton.setDefault(False)
self.create_new_form.helpButton.setAutoDefault(False)
def eventFilter(self, source, event):
'''
@@ -288,23 +322,40 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
'''
split_string = raw_string.split()
process_list = []
prefix_key = split_string[0]
if len(split_string) >= 2:
if (split_string[0] == 'Control' or split_string[0] == 'Meta') and split_string[1]:
if split_string[1] == 'Shift' and len(split_string) > 2:
prefix_key = split_string[0]
suffix_key = split_string[1]
if (prefix_key == 'Control' or prefix_key == 'Meta') and split_string[1]:
if suffix_key == 'Shift' and len(split_string) > 2:
process_list.append('CTSH')
process_list.append(split_string[2])
suffix_key = split_string[2]
else:
process_list.append('CTRL')
process_list.append(split_string[1])
elif split_string[0] == 'Alt':
elif prefix_key == 'Alt':
process_list.append('ALT')
process_list.append(split_string[1])
elif prefix_key == 'Shift':
process_list.append('SHFT')
if suffix_key in _REPLACE_KEYS:
suffix_key = _REPLACE_KEYS[suffix_key]
process_list.append(suffix_key)
elif prefix_key in _REPLACE_KEYS:
process_list.append(_REPLACE_KEYS[prefix_key])
return('-'.join(process_list))
def help_menu_shortcut(self):
self.help_form._dialog.show()
def create_new_shortcut(self):
def confirm_menu_connect(self):
self.confirm_change.confirmButton.clicked.connect(
lambda: self.shortcut_manager.create_new_shortcut(self.confirm_new_key, self.confirm_new_binding))
self.confirm_change.confirmButton.clicked.connect(lambda: self.populateData())
self.confirm_change.confirmButton.clicked.connect(
lambda: self.confirm_change._dialog.hide())
self.confirm_change.cancelButton.clicked.connect(
lambda: self.confirm_change._dialog.hide())
def create_new_shortcut_caller(self):
'''
Creates a new shortcut after checking existing and reserved keys.
'''
@@ -316,28 +367,24 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
elif new_key in self.shortcut_manager.cmd.shortcut_dict:
hide_confirm_menu = self.confirm_change.doNotShowCheckBox.isChecked()
if not hide_confirm_menu:
self.confirm_new_key = new_key
self.confirm_new_binding = new_binding
self.confirm_change._dialog.show()
self.confirm_change.confirmButton.clicked.connect(
lambda: self.shortcut_manager.create_new_shortcut(new_key, new_binding))
self.confirm_change.confirmButton.clicked.connect(
lambda: self.confirm_change._dialog.hide())
self.confirm_change.cancelButton.clicked.connect(
lambda: self.confirm_change._dialog.hide())
else:
self.shortcut_manager.create_new_shortcut(new_key, new_binding)
self.populateData()
else:
self.shortcut_manager.create_new_shortcut(new_key, new_binding)
self.populateData()
self.table.scrollToBottom()
self.populateData()
def formatTable(self):
'''
Set up the table to look appropriately
'''
hh = self.table.horizontalHeader()
hh.setStretchLastSection(True)
hh.setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
self.table.verticalHeader().setVisible(False)
self.table.setFocus()
self.table.hide()
@@ -353,14 +400,17 @@ class PyMOLShortcutMenu(QtWidgets.QWidget):
"""
try:
if item.column() == 1 and item.text() != "Deleted":
changed_key = self.model.index(item.row(),0).data()
changed_index = self.table.model().index(item.row(),0)
changed_key = self.model.index(item.row(), 0).data()
changed_index = self.table.model().index(item.row(), 0)
self.cmd.set_key(changed_key, item.text())
self.shortcut_manager.cmd.shortcut_dict[changed_key][2] = item.text()
self.table.model().setData(self.table.model().index(item.row(),2),'user defined')
filter_active = bool(self.filter_le.text())
if not filter_active:
self.table.model().setData(self.table.model().index(item.row(), 2), 'user defined')
else:
pass
except Exception as e:
print(e)
print("Failed to change key binding")

View File

@@ -8,8 +8,8 @@
# truncated for this purpose.
#============================================================================#
shortcut_dict_ref = {
'left': ('cmd._weakrefproxy.backward()',"previous movie frame",''),
'right': ('cmd._weakrefproxy.forward()',"next movie frame",''),
'left': ('_ backward',"previous movie frame",''),
'right': ('_ forward',"next movie frame",''),
'pgup': ('scene action=previous',"previous scene",''),
'pgdn': ('scene action=next',"last scene",''),
'home': ('zoom animate=-1',"zoom all",''),
@@ -24,8 +24,8 @@ shortcut_dict_ref = {
'SHFT-insert': ('rock','',''),
'CTRL-left': ('backward','',''),
'CTRL-right': ('forward','',''),
'CTRL-pgup': ("cmd._weakrefproxy.scene('', 'insert_before')",'insert scene before current',''),
'CTRL-pgdn': ("cmd._weakrefproxy.scene('', 'insert_after')",'insert scene after current',''),
'CTRL-pgup': ("_ scene new, insert_before",'insert scene before current',''),
'CTRL-pgdn': ("_ scene new, insert_after",'insert scene after current',''),
'CTRL-home': ('zoom animate=-1','zoom all',''),
'CTRL-end': ('scene new, store','store new scene',''),
'CTRL-insert': ('scene auto, store','store auto scene',''),
@@ -82,8 +82,8 @@ shortcut_dict_ref = {
'ALT-Z': ("editor.attach_amino_acid('pk1', 'nme')",'attach nme',''),
'CTSH-left': ('backward','',''),
'CTSH-right': ('forward','',''),
'CTSH-pgup': ("cmd._weakrefproxy.scene('', 'insert_before')",'insert scene before current',''),
'CTSH-pgdn': ("cmd._weakrefproxy.scene('', 'insert_after')",'insert scene after current',''),
'CTSH-pgup': ("scene new, insert_before",'insert scene before current',''),
'CTSH-pgdn': ("scene new, insert_after",'insert scene after current',''),
'CTSH-home': ('zoom animate=-1','zoom all',''),
'CTSH-end': ('mtoggle','',''),
'CTSH-insert': ('rock','',''),

View File

@@ -18,7 +18,7 @@ class ShortcutManager():
self.cmd.shortcut_dict = {key: list(value) for key,value in shortcut_dict_ref.items()}
# Tuple of keys that are reserved for the system
self.reserved_keys = ('CTRL-S','CTRL-E','CTRL-O','CTRL-M')
self.reserved_keys = ('CTRL-S','CTRL-E','CTRL-O','CTRL-M','up','down')
def check_saved_dict(self):
'''