From 4c81c0d7e29f51191053d32ce71733afbda87a97 Mon Sep 17 00:00:00 2001 From: dertwist <45437750+dertwist@users.noreply.github.com> Date: Sat, 5 Oct 2024 00:22:29 +0200 Subject: [PATCH] set keybinding presets function --- Hammer5Tools.pyproject.user | 2 +- hotkey_editor/main.py | 94 +++++++++++++++++++++---------- hotkey_editor/main.ui | 64 +++++++++++++++++++-- hotkey_editor/ui_main.py | 76 +++++++++++++++++++------ main.py | 2 + minor_features/addon_functions.py | 5 +- minor_features/steamfixnologon.py | 14 +---- 7 files changed, 189 insertions(+), 68 deletions(-) diff --git a/Hammer5Tools.pyproject.user b/Hammer5Tools.pyproject.user index 6a9f5152..fcd03a43 100644 --- a/Hammer5Tools.pyproject.user +++ b/Hammer5Tools.pyproject.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/hotkey_editor/main.py b/hotkey_editor/main.py index a6a1ff31..5e6de60a 100644 --- a/hotkey_editor/main.py +++ b/hotkey_editor/main.py @@ -1,14 +1,18 @@ import json import re +import shutil + from hotkey_editor.ui_main import Ui_MainWindow -from PySide6.QtWidgets import QApplication, QMainWindow, QTreeWidget, QTreeWidgetItem, QSplitter, QLineEdit, QKeySequenceEdit, QPushButton +from PySide6.QtWidgets import QApplication, QMainWindow, QTreeWidget, QTreeWidgetItem, QSplitter, QLineEdit, QKeySequenceEdit, QPushButton, QMessageBox from PySide6.QtCore import Qt from PySide6.QtGui import QKeyEvent from hotkey_editor.dialog import KeyDialog from hotkey_editor.objects import * -from preferences import debug, get_addon_name +from preferences import debug, get_addon_name, get_cs2_path +from minor_features.addon_functions import launch_addon, kill_addon from explorer.main import Explorer import os +import datetime app_dir = os.getcwd() import keyvalues3 as kv3 @@ -74,19 +78,22 @@ def __init__(self, parent=None): self.data = {} self.opened_file = '' self.editor = '' + self.explorer_instance = None self.FilterInputInstanceButton = KeyButton() self.FilterInputInstanceButton.setMinimumSize(256, 0) self.FilterInputInstanceButton.setMaximumHeight(26) self.ui.horizontalLayout_4.addWidget(self.FilterInputInstanceButton) - self.ui.editor_combobox.currentTextChanged.connect(self.populate_presets) + self.ui.editor_combobox.currentTextChanged.connect(self.editor_switch) self.get_path() - self.populate_presets() + self.editor_switch() - self.ui.presets_list.itemClicked.connect(lambda item: self.select_preset(item.text())) + self.ui.open_button.clicked.connect(self.open_preset) self.ui.new_button.clicked.connect(self.new_preset) self.ui.save_button.clicked.connect(self.save_preset) + self.ui.set_current_button.clicked.connect(lambda :self.set_current(True)) + self.ui.save_restart_button.clicked.connect(self.set_save_restart) self.ui.command_filter_line.textChanged.connect(lambda text: self.filter_command(text, self.ui.keybindings_tree.invisibleRootItem())) self.FilterInputInstanceButton.clicked.connect(self.do_filter_input) @@ -95,7 +102,29 @@ def __init__(self, parent=None): def do_filter_input(self): key = self.FilterInputInstanceButton.key self.filter_input(key, self.ui.keybindings_tree.invisibleRootItem()) - + def set_current(self, explorer_path=True): + path_keybindings = os.path.join(get_cs2_path(), 'game', 'core', 'tools', 'keybindings') + if explorer_path: + index = self.explorer_instance.tree.selectionModel().selectedIndexes()[0] + source = self.explorer_instance.model.filePath(index) + else: + source = self.opened_file + + dest = os.path.join(path_keybindings, f'{self.editor}_key_bindings.txt') + debug(f'Source:{source}, dest: {dest}') + shutil.copy2(source, dest) + reply = QMessageBox.question(self, 'Confirmation', 'Would you like to restart the editor? Keybindings will be applied upon restart.', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + + # Check the user's response and restart if they choose 'Yes' + if reply == QMessageBox.Yes: + self.restart() + def set_save_restart(self): + self.save_preset() + self.set_current(False) + self.restart() + def restart(self): + kill_addon() + launch_addon() def get_path(self): editor = self.ui.editor_combobox.currentText() # convert generic name to source format @@ -103,7 +132,7 @@ def get_path(self): self.editor = editor.replace(' ', '_') self.hotkeys_path = os.path.join(app_dir, 'hotkeys', editor) - def populate_presets(self): + def editor_switch(self): try: self.ui.explorer_layout.itemAt(0).widget().deleteLater() except: @@ -112,12 +141,9 @@ def populate_presets(self): pass else: os.makedirs(self.hotkeys_path) - for file in os.listdir(self.hotkeys_path): - item = os.path.splitext(file)[0] - self.ui.presets_list.addItem(item) - explorer_instance = Explorer(editor_name='HotkeyEditor', tree_directory=self.hotkeys_path, parent=self.ui.frame, addon=get_addon_name()) - self.ui.explorer_layout.insertWidget(0, explorer_instance.frame) + self.explorer_instance = Explorer(editor_name='HotkeyEditor', tree_directory=self.hotkeys_path, parent=self.ui.frame, addon=get_addon_name()) + self.ui.explorer_layout.insertWidget(0, self.explorer_instance.frame) def populate_editor(self): root_item = self.ui.keybindings_tree.invisibleRootItem() unique_contexts = set() # Define the set outside the loop @@ -166,17 +192,18 @@ def populate_editor(self): # self.ui.keybindings_tree.expandAll() - def select_preset(self, item): + def open_preset(self): self.ui.keybindings_tree.clear() - self.selected_preset = os.path.join(self.hotkeys_path, f'{item}.txt') debug(self.selected_preset) - self.open_preset(self.selected_preset) - self.populate_editor() - def open_preset(self, file): - self.data.update(kv3.read(file).value) - self.opened_file = file + index = self.explorer_instance.tree.selectionModel().selectedIndexes()[0] + filename = self.explorer_instance.model.filePath(index) + self.data.update(kv3.read(filename).value) + self.opened_file = filename + + self.populate_editor() + print(f'Opened: {self.opened_file}') def save_preset(self): @@ -187,22 +214,27 @@ def save_preset(self): output.update({'m_Bindings': self.serializing()}) # There is a huge problem with python interpretation, avoid \\ in string. GizmoDebugHook have \\ as input. # So in output it would be only one \ test - name = 'test' - path = os.path.join(self.hotkeys_path, f'{name}.txt') - kv3.write(output, path) + kv3.write(output, self.opened_file) + print('Preset saved') def serializing(self): output = [] root = self.ui.keybindings_tree.invisibleRootItem() for context_index in range(root.childCount()): for command_index in range(root.child(context_index).childCount()): input_widget = (self.ui.keybindings_tree.itemWidget(root.child(context_index).child(command_index), 1)).key - if input_widget != 'None': + if input_widget is not None: output.append({'m_Context': root.child(context_index).text(0), 'm_Command': root.child(context_index).child(command_index).text(0), 'm_Input': input_widget}) return output def new_preset(self): - name = 'new_preset' - path = os.path.join(self.hotkeys_path, f'{name}.txt') - kv3.write(hammer_default, path) + name = f'{self.editor}_new_keybindings_{datetime.datetime.now().strftime("%m_%d_%Y")}' + path = os.path.join(self.hotkeys_path, f'{name}.keybindings') + output = {'editor_info': [ + {'Info': 'Hammer5Tools Hotkey Editor by Twist', 'GitHub': 'https://github.com/dertwist/Hammer5Tools', + 'Steam': 'https://steamcommunity.com/id/der_twist', 'Twitter': 'https://twitter.com/der_twist'}]} + if self.editor == 'hammer': + output.update(hammer_macros) + output.update(hammer_default) + kv3.write(output, path) def filter_input(self, filter_text, parent_item): debug(('filter text', filter_text)) @@ -256,11 +288,13 @@ def filter_widget(self, item, filter_text, is_root=False): item_text = '' else: item_text = str(item_widget.key).lower() - if item_text == 'none': - item_text = '' - debug(('t', item_text, filter_text)) - item_visible = filter_text in item_text + if filter_text == 'none': + item_visible = True + else: + item_visible = filter_text in item_text + + debug(('t', item_text, filter_text)) # Always show the root, regardless of filter if is_root: item.setHidden(False) diff --git a/hotkey_editor/main.ui b/hotkey_editor/main.ui index 28cc020a..213609b2 100644 --- a/hotkey_editor/main.ui +++ b/hotkey_editor/main.ui @@ -240,9 +240,6 @@ QComboBox QAbstractItemView::item:selected { - - - @@ -355,6 +352,61 @@ QComboBox QAbstractItemView::item:selected { + + + + <html><head/><body><p>Ctrl + N</p></body></html> + + + + /* QPushButton default and hover styles */ + QPushButton { + + font: 580 9pt "Segoe UI"; + + + border: 2px solid black; + border-radius: 2px; + border-color: rgba(80, 80, 80, 255); + height:22px; + padding-top: 2px; + padding-bottom:2px; + padding-left: 4px; + padding-right: 4px; + color: #E3E3E3; + background-color: #1C1C1C; + } + QPushButton:hover { + background-color: #414956; + color: white; + } + QPushButton:pressed { + background-color: red; + background-color: #1C1C1C; + margin: 1 px; + margin-left: 2px; + margin-right: 2px; + + } + + + Open preset + + + + :/icons/file_open_16dp_9D9D9D_FILL0_wght400_GRAD0_opsz20.svg:/icons/file_open_16dp_9D9D9D_FILL0_wght400_GRAD0_opsz20.svg + + + + 20 + 20 + + + + Ctrl+N + + + @@ -427,7 +479,7 @@ QComboBox QAbstractItemView::item:selected { - 128 + 196 0 @@ -488,7 +540,7 @@ QComboBox QAbstractItemView::item:selected { - 256 + 196 0 @@ -528,7 +580,7 @@ QComboBox QAbstractItemView::item:selected { } - Set and restart the editor + Set and restart diff --git a/hotkey_editor/ui_main.py b/hotkey_editor/ui_main.py index 62923d61..4990b14f 100644 --- a/hotkey_editor/ui_main.py +++ b/hotkey_editor/ui_main.py @@ -17,10 +17,9 @@ QPainter, QPalette, QPixmap, QRadialGradient, QTransform) from PySide6.QtWidgets import (QApplication, QComboBox, QFrame, QHBoxLayout, - QHeaderView, QLabel, QLineEdit, QListWidget, - QListWidgetItem, QMainWindow, QPushButton, QSizePolicy, - QSpacerItem, QSplitter, QTreeWidget, QTreeWidgetItem, - QVBoxLayout, QWidget) + QHeaderView, QLabel, QLineEdit, QMainWindow, + QPushButton, QSizePolicy, QSpacerItem, QSplitter, + QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget) import rc_resources class Ui_MainWindow(object): @@ -233,11 +232,6 @@ def setupUi(self, MainWindow): self.verticalLayout_4.addLayout(self.explorer_layout) - self.presets_list = QListWidget(self.layoutWidget) - self.presets_list.setObjectName(u"presets_list") - - self.verticalLayout_4.addWidget(self.presets_list) - self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") self.set_current_button = QPushButton(self.layoutWidget) @@ -318,6 +312,45 @@ def setupUi(self, MainWindow): self.horizontalLayout_3.addWidget(self.new_button) + self.open_button = QPushButton(self.layoutWidget) + self.open_button.setObjectName(u"open_button") + self.open_button.setStyleSheet(u"\n" +" /* QPushButton default and hover styles */\n" +" QPushButton {\n" +"\n" +" font: 580 9pt \"Segoe UI\";\n" +" \n" +"\n" +" border: 2px solid black;\n" +" border-radius: 2px;\n" +" border-color: rgba(80, 80, 80, 255);\n" +" height:22px;\n" +" padding-top: 2px;\n" +" padding-bottom:2px;\n" +" padding-left: 4px;\n" +" padding-right: 4px;\n" +" color: #E3E3E3;\n" +" background-color: #1C1C1C;\n" +" }\n" +" QPushButton:hover {\n" +" background-color: #414956;\n" +" color: white;\n" +" }\n" +" QPushButton:pressed {\n" +" background-color: red;\n" +" background-color: #1C1C1C;\n" +" margin: 1 px;\n" +" margin-left: 2px;\n" +" margin-right: 2px;\n" +"\n" +" }") + icon2 = QIcon() + icon2.addFile(u":/icons/file_open_16dp_9D9D9D_FILL0_wght400_GRAD0_opsz20.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.open_button.setIcon(icon2) + self.open_button.setIconSize(QSize(20, 20)) + + self.horizontalLayout_3.addWidget(self.open_button) + self.verticalLayout_4.addLayout(self.horizontalLayout_3) @@ -362,7 +395,7 @@ def setupUi(self, MainWindow): self.save_button = QPushButton(self.layoutWidget1) self.save_button.setObjectName(u"save_button") - self.save_button.setMinimumSize(QSize(128, 0)) + self.save_button.setMinimumSize(QSize(196, 0)) self.save_button.setStyleSheet(u"\n" " /* QPushButton default and hover styles */\n" " QPushButton {\n" @@ -393,16 +426,16 @@ def setupUi(self, MainWindow): " margin-right: 2px;\n" "\n" " }") - icon2 = QIcon() - icon2.addFile(u":/icons/save_16dp_9D9D9D_FILL0_wght400_GRAD0_opsz20.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off) - self.save_button.setIcon(icon2) + icon3 = QIcon() + icon3.addFile(u":/icons/save_16dp_9D9D9D_FILL0_wght400_GRAD0_opsz20.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.save_button.setIcon(icon3) self.save_button.setIconSize(QSize(20, 20)) self.horizontalLayout_6.addWidget(self.save_button) self.save_restart_button = QPushButton(self.layoutWidget1) self.save_restart_button.setObjectName(u"save_restart_button") - self.save_restart_button.setMinimumSize(QSize(256, 0)) + self.save_restart_button.setMinimumSize(QSize(196, 0)) self.save_restart_button.setStyleSheet(u"\n" " /* QPushButton default and hover styles */\n" " QPushButton {\n" @@ -433,9 +466,9 @@ def setupUi(self, MainWindow): " margin-right: 2px;\n" "\n" " }") - icon3 = QIcon() - icon3.addFile(u":/icons/all_match_24dp_9D9D9D_FILL0_wght400_GRAD0_opsz24.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off) - self.save_restart_button.setIcon(icon3) + icon4 = QIcon() + icon4.addFile(u":/icons/all_match_24dp_9D9D9D_FILL0_wght400_GRAD0_opsz24.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.save_restart_button.setIcon(icon4) self.save_restart_button.setIconSize(QSize(20, 20)) self.save_restart_button.setCheckable(True) @@ -479,6 +512,13 @@ def retranslateUi(self, MainWindow): self.new_button.setText(QCoreApplication.translate("MainWindow", u"New preset", None)) #if QT_CONFIG(shortcut) self.new_button.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+N", None)) +#endif // QT_CONFIG(shortcut) +#if QT_CONFIG(tooltip) + self.open_button.setToolTip(QCoreApplication.translate("MainWindow", u"

Ctrl + N

", None)) +#endif // QT_CONFIG(tooltip) + self.open_button.setText(QCoreApplication.translate("MainWindow", u"Open preset", None)) +#if QT_CONFIG(shortcut) + self.open_button.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+N", None)) #endif // QT_CONFIG(shortcut) self.label.setText(QCoreApplication.translate("MainWindow", u"Keybindings editor", None)) ___qtreewidgetitem = self.keybindings_tree.headerItem() @@ -494,7 +534,7 @@ def retranslateUi(self, MainWindow): #if QT_CONFIG(tooltip) self.save_restart_button.setToolTip(QCoreApplication.translate("MainWindow", u"

Ctrl+ Shif+S

", None)) #endif // QT_CONFIG(tooltip) - self.save_restart_button.setText(QCoreApplication.translate("MainWindow", u"Set and restart the editor", None)) + self.save_restart_button.setText(QCoreApplication.translate("MainWindow", u"Set and restart", None)) #if QT_CONFIG(shortcut) self.save_restart_button.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+Shift+S", None)) #endif // QT_CONFIG(shortcut) diff --git a/main.py b/main.py index a838fb52..583d6b5a 100644 --- a/main.py +++ b/main.py @@ -36,6 +36,7 @@ batchcreator_version = '1.2.2' soundevent_editor_version = '0.5.1' smartprop_editor_version = '0.7.4' +hotkey_editor_version = '1.0.0' import sys @@ -88,6 +89,7 @@ def __init__(self, parent=None): except Exception as e: print(f"Error checking updates: {e}") print(f'SmartProp Editor version: {smartprop_editor_version}') + print(f'Hotkey Editor version: {hotkey_editor_version}') self._restore_user_prefs() if get_config_bool('APP', 'first_launch'): diff --git a/minor_features/addon_functions.py b/minor_features/addon_functions.py index 03659dcd..44987297 100644 --- a/minor_features/addon_functions.py +++ b/minor_features/addon_functions.py @@ -41,4 +41,7 @@ def launch_addon(): psutil.Popen((cs2_launch_commands + " -nocustomermachine"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) set_config_bool('LAUNCH', 'ncm_mode_setup', True) else: - psutil.Popen(cs2_launch_commands, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) \ No newline at end of file + psutil.Popen(cs2_launch_commands, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + +def kill_addon(): + subprocess.run(["taskkill", "/f", "/im", "cs2.exe"]) \ No newline at end of file diff --git a/minor_features/steamfixnologon.py b/minor_features/steamfixnologon.py index b8b1bfb0..317b5299 100644 --- a/minor_features/steamfixnologon.py +++ b/minor_features/steamfixnologon.py @@ -1,6 +1,7 @@ import time, psutil, subprocess from PySide6.QtCore import QThread, Signal from preferences import get_steam_path, get_cs2_path, get_addon_name, get_config_bool +from minor_features.addon_functions import launch_addon steam_path = get_steam_path() counter_strikke_2_path = get_cs2_path() @@ -9,17 +10,6 @@ class SteamNoLogoFixThreadClass(QThread): any_signal = Signal(int) - def launch_addon(self): - addon_name = get_addon_name() - cs2_path = get_cs2_path() - cs2_launch_commands = '"' + cs2_path + '"' + r"\game\bin\win64\cs2.exe" + " -addon " + addon_name + ' -tool hammer' + ' -asset maps/' + addon_name + '.vmap' + " -tools -steam -retail -gpuraytracing -noinsecru +install_dlc_workshoptools_cvar 1" - if get_config_bool('LAUNCH', 'ncm_mode'): - if get_config_bool('LAUNCH', 'ncm_mode_setup'): - psutil.Popen((cs2_launch_commands + " -nocustomermachine"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - else: - psutil.Popen((cs2_launch_commands + " -nocustomermachine"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - else: - psutil.Popen(cs2_launch_commands, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) def is_steam_running(self): for process in psutil.process_iter(['pid', 'name']): @@ -48,7 +38,7 @@ def run(self): launch_addon_after_nosteamlogon_fix = get_config_bool('OTHER', 'launch_addon_after_nosteamlogon_fix') print(launch_addon_after_nosteamlogon_fix) if launch_addon_after_nosteamlogon_fix: - self.launch_addon() + launch_addon() except: pass def stop(self):