мерж + чистка build и перенос всякого в сурсы

+ добавлено подсвечивание предупреждений и ошибок в таблице выбранных переменных
This commit is contained in:
2025-07-10 18:05:11 +03:00
parent a95a1535a9
commit 07e42c774a
63 changed files with 235 additions and 33318 deletions

View File

@@ -10,10 +10,11 @@ from enum import IntEnum
import threading
from scanVars import run_scan
from generateVars import run_generate
from setupVars import *
from VariableSelector import *
import setupVars
from VariableSelector import VariableSelectorDialog
from VariableTable import VariableTableWidget, rows
from scanVarGUI import *
from scanVarGUI import ProcessOutputWindowDummy
import scanVars
from PySide2.QtWidgets import (
QApplication, QWidget, QTableWidget, QTableWidgetItem,
@@ -21,7 +22,7 @@ from PySide2.QtWidgets import (
QCompleter, QAbstractItemView, QLabel, QMessageBox, QFileDialog, QTextEdit,
QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy, QHeaderView
)
from PySide2.QtGui import QTextCursor, QKeyEvent
from PySide2.QtGui import QTextCursor, QKeyEvent, QIcon
from PySide2.QtCore import Qt, QProcess, QObject, Signal, QSettings
@@ -45,6 +46,12 @@ class VarEditor(QWidget):
def initUI(self):
self.setWindowTitle("Variable Editor")
base_path = scanVars.get_base_path()
icon_path = os.path.join(base_path, "icon.ico")
self.setWindowIcon(QIcon(icon_path))
if os.path.exists(icon_path):
self.setWindowIcon(QIcon(icon_path))
# --- Поля ввода пути проекта и XML ---
# XML Output
@@ -138,18 +145,18 @@ class VarEditor(QWidget):
def get_makefile_path(self):
proj_path = self.get_proj_path()
makefile_path = make_absolute_path(self.makefile_edit.text().strip(), proj_path)
makefile_path = setupVars.make_absolute_path(self.makefile_edit.text().strip(), proj_path)
return makefile_path
def get_struct_path(self):
proj_path = self.get_proj_path()
xml_path = self.get_xml_path()
root, tree = safe_parse_xml(xml_path)
root, tree = scanVars.safe_parse_xml(xml_path)
if root is None:
return
# --- structs_path из атрибута ---
structs_path = root.attrib.get('structs_path', '').strip()
structs_path_full = make_absolute_path(structs_path, proj_path)
structs_path_full = setupVars.make_absolute_path(structs_path, proj_path)
if structs_path_full and os.path.isfile(structs_path_full):
structs_path = structs_path_full
else:
@@ -248,7 +255,7 @@ class VarEditor(QWidget):
return
try:
root, tree = safe_parse_xml(self.xml_path)
root, tree = scanVars.safe_parse_xml(self.xml_path)
if root is None:
return
@@ -278,7 +285,7 @@ class VarEditor(QWidget):
if not self.makefile_path:
# --- makefile_path из атрибута ---
makefile_path = root.attrib.get('makefile_path', '').strip()
makefile_path_full = make_absolute_path(makefile_path, self.proj_path)
makefile_path_full = setupVars.make_absolute_path(makefile_path, self.proj_path)
if makefile_path_full and os.path.isfile(makefile_path_full):
self.makefile_edit.setText(makefile_path)
else:
@@ -286,14 +293,14 @@ class VarEditor(QWidget):
# --- structs_path из атрибута ---
structs_path = root.attrib.get('structs_path', '').strip()
structs_path_full = make_absolute_path(structs_path, self.proj_path)
structs_path_full = setupVars.make_absolute_path(structs_path, self.proj_path)
if structs_path_full and os.path.isfile(structs_path_full):
self.structs_path = structs_path_full
self.structs, self.typedef_map = parse_structs(structs_path_full)
self.structs, self.typedef_map = setupVars.setupVars.parse_structs(structs_path_full)
else:
self.structs_path = None
self.vars_list = parse_vars(self.xml_path, self.typedef_map)
self.vars_list = setupVars.parse_vars(self.xml_path, self.typedef_map)
self.table.populate(self.vars_list, self.structs, self.write_to_xml)
except Exception as e:
QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
@@ -309,7 +316,7 @@ class VarEditor(QWidget):
self.proj_path = dir_path
if self.makefile_path and self.proj_path:
path = make_relative_path(self.makefile_path, self.proj_path)
path = setupVars.make_relative_path(self.makefile_path, self.proj_path)
self.makefile_edit.setText(path)
self.makefile_path = path
@@ -333,7 +340,7 @@ class VarEditor(QWidget):
self, "Выберите Makefile", filter="Makefile (makefile);;All Files (*)"
)
if file_path and self.proj_path:
path = make_relative_path(file_path, self.proj_path)
path = setupVars.make_relative_path(file_path, self.proj_path)
else:
path = file_path
self.makefile_edit.setText(path)
@@ -348,18 +355,18 @@ class VarEditor(QWidget):
self.output_path = ''
def __on_xml_path_changed(self):
def __on_xml_path_changed(self, _):
self.xml_path = self.get_xml_path()
self.update()
def __on_proj_path_changed(self):
def __on_proj_path_changed(self, _):
self.proj_path = self.get_proj_path()
self.update()
def __on_makefile_path_changed(self):
def __on_makefile_path_changed(self, _):
self.makefile_path = self.get_makefile_path()
if self.makefile_path and self.proj_path:
path = make_relative_path(self.makefile_path, self.proj_path)
path = setupVars.make_relative_path(self.makefile_path, self.proj_path)
self.makefile_edit.setText(path)
self.update()
@@ -409,7 +416,7 @@ class VarEditor(QWidget):
self.update()
def write_to_xml(self):
def write_to_xml(self, dummy=None):
self.update_all_paths()
if not self.xml_path or not os.path.isfile(self.xml_path):
@@ -423,7 +430,7 @@ class VarEditor(QWidget):
return
try:
root, tree = safe_parse_xml(self.xml_path)
root, tree = scanVars.safe_parse_xml(self.xml_path)
if root is None:
return
@@ -431,11 +438,11 @@ class VarEditor(QWidget):
root.set("proj_path", self.proj_path.replace("\\", "/"))
if self.makefile_path and os.path.isfile(self.makefile_path):
rel_makefile = make_relative_path(self.makefile_path, self.proj_path)
rel_makefile = setupVars.make_relative_path(self.makefile_path, self.proj_path)
root.set("makefile_path", rel_makefile)
if self.structs_path and os.path.isfile(self.structs_path):
rel_struct = make_relative_path(self.structs_path, self.proj_path)
rel_struct = setupVars.make_relative_path(self.structs_path, self.proj_path)
root.set("structs_path", rel_struct)
vars_elem = root.find('variables')
@@ -506,9 +513,10 @@ class VarEditor(QWidget):
set_sub_elem_text(var_elem, 'static', static_val)
# Преобразуем дерево в строку
indent_xml(root)
self.table.check()
scanVars.indent_xml(root)
ET.ElementTree(root).write(self.xml_path, encoding="utf-8", xml_declaration=True)
except Exception as e:
print(f"Ошибка при сохранении XML: {e}")

View File

@@ -5,8 +5,8 @@ from PySide2.QtWidgets import (
)
from PySide2.QtGui import QKeySequence, QKeyEvent
from PySide2.QtCore import Qt, QStringListModel, QSettings
from setupVars import *
from scanVars import *
import setupVars
import scanVars
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
@@ -15,6 +15,7 @@ class VariableSelectorDialog(QDialog):
def __init__(self, all_vars, structs, typedefs, xml_path=None, parent=None):
super().__init__(parent)
self.setWindowTitle("Выбор переменных")
self.setAttribute(Qt.WA_DeleteOnClose)
self.resize(600, 500)
self.selected_names = []
@@ -88,6 +89,8 @@ class VariableSelectorDialog(QDialog):
layout.addWidget(self.btn_add)
layout.addWidget(self.btn_delete)
self.setLayout(layout)
self.expanded_vars = setupVars.expand_vars(self.all_vars, self.structs, self.typedefs)
self.populate_tree()
@@ -128,9 +131,7 @@ class VariableSelectorDialog(QDialog):
def populate_tree(self):
self.tree.clear()
expanded_vars = expand_vars(self.all_vars, self.structs, self.typedefs)
for var in expanded_vars:
for var in self.expanded_vars:
self.add_tree_item_recursively(None, var)
header = self.tree.header()
@@ -370,8 +371,10 @@ class VariableSelectorDialog(QDialog):
self.filter_tree()
def on_add_clicked(self):
print("on_add_clicked triggered")
self.selected_names = []
self.tree.setFocus()
for item in self.tree.selectedItems():
name = item.text(0) # имя переменной (в колонке 1)
type_str = item.text(1) # тип переменной (в колонке 2)
@@ -411,12 +414,15 @@ class VariableSelectorDialog(QDialog):
self.all_vars.append(new_var)
self.var_map[name] = new_var # Чтобы в будущем не добавлялось повторно
self.accept()
print("accept")
self.done(QDialog.Accepted)
def on_delete_clicked(self):
print("on_delete_clicked triggered")
selected_names = self._get_selected_var_names()
if not selected_names:
print("nothing selected")
return
# Обновляем var_map и all_vars
@@ -458,11 +464,12 @@ class VariableSelectorDialog(QDialog):
set_text('show_var', 'false')
set_text('enable', 'false')
indent_xml(root)
scanVars.indent_xml(root)
ET.ElementTree(root).write(self.xml_path, encoding="utf-8", xml_declaration=True)
self.populate_tree()
self.accept()
print("accept")
self.done(QDialog.Accepted)
def set_tool(self, item, text):
@@ -509,13 +516,14 @@ class VariableSelectorDialog(QDialog):
self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names]
if removed_any:
indent_xml(root)
scanVars.indent_xml(root)
ET.ElementTree(root).write(self.xml_path, encoding="utf-8", xml_declaration=True)
self.populate_tree()
self.filter_tree()
def _get_selected_var_names(self):
self.tree.setFocus()
return [item.text(0) for item in self.tree.selectedItems() if item.text(0)]

View File

@@ -1,7 +1,8 @@
from PySide2.QtWidgets import (
QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
QAbstractItemView, QHeaderView
QAbstractItemView, QHeaderView, QLabel
)
from PySide2.QtGui import QColor, QBrush, QPalette
from PySide2.QtCore import Qt
from enum import IntEnum
from generateVars import type_map
@@ -32,7 +33,7 @@ class VariableTableWidget(QTableWidget):
'Short Name'
])
self.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.var_list = []
self.type_options = list(dict.fromkeys(type_map.values()))
self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
@@ -62,12 +63,14 @@ class VariableTableWidget(QTableWidget):
def populate(self, vars_list, structs, on_change_callback):
self.var_list = vars_list
self.type_options = list(dict.fromkeys(type_map.values()))
self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
iq_types = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
filtered_vars = [v for v in vars_list if v.get('show_var', 'false') == 'true']
self.setRowCount(len(filtered_vars))
self.verticalHeader().setVisible(False)
style_with_padding = "padding-left: 5px; padding-right: 5px; font-size: 14pt;" # регулируй отступы по горизонтали
for row, var in enumerate(filtered_vars):
# №
@@ -79,6 +82,7 @@ class VariableTableWidget(QTableWidget):
cb = QCheckBox()
cb.setChecked(var.get('enable', 'false') == 'true')
cb.stateChanged.connect(on_change_callback)
cb.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.include, cb)
# Name
@@ -88,12 +92,16 @@ class VariableTableWidget(QTableWidget):
completer.setCaseSensitivity(Qt.CaseInsensitive)
name_edit.setCompleter(completer)
name_edit.textChanged.connect(on_change_callback)
name_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.name, name_edit)
# Origin Type (readonly)
origin_item = QTableWidgetItem(var.get('type', ''))
origin_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(row, rows.type, origin_item)
origin_edit = QLineEdit(var.get('type', ''))
origin_edit.setReadOnly(True) # делает поле не редактируемым
origin_edit.setEnabled(True) # включен, чтобы можно было копировать и получать текст
origin_edit.setFocusPolicy(Qt.NoFocus) # не фокусируется при клике
origin_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.type, origin_edit)
# pt_type
pt_combo = QComboBox()
@@ -103,6 +111,7 @@ class VariableTableWidget(QTableWidget):
pt_combo.addItem(value)
pt_combo.setCurrentText(value)
pt_combo.currentTextChanged.connect(on_change_callback)
pt_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.pt_type, pt_combo)
# iq_type
@@ -113,6 +122,7 @@ class VariableTableWidget(QTableWidget):
iq_combo.addItem(value)
iq_combo.setCurrentText(value)
iq_combo.currentTextChanged.connect(on_change_callback)
iq_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.iq_type, iq_combo)
# return_type
@@ -120,13 +130,48 @@ class VariableTableWidget(QTableWidget):
ret_combo.addItems(self.iq_types)
ret_combo.setCurrentText(var.get('return_type', ''))
ret_combo.currentTextChanged.connect(on_change_callback)
ret_combo.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.ret_type, ret_combo)
# short_name
short_name_edit = QLineEdit(var.get('shortname', var['name']))
short_name_val = var.get('shortname', var['name'])
short_name_edit = QLineEdit(short_name_val)
short_name_edit.textChanged.connect(on_change_callback)
short_name_edit.setStyleSheet(style_with_padding)
self.setCellWidget(row, rows.short_name, short_name_edit)
self.check()
def check(self):
warning_color = (QColor("#FFFACD")) # Жёлтый для длинных shortname
error_color = (QColor("#FFB6C1")) # Светло-красный для отсутствующих переменных
tooltip_shortname = "Short Name длиннее 10 символов — будет обрезано при генерации"
tooltip_missing = f'Имя переменной не найдено среди переменных. Добавьте её через кнопку "Добавить переменные"'
for row in range(self.rowCount()):
# Получаем имя переменной (столбец `name`)
name_widget = self.cellWidget(row, rows.name)
name = name_widget.text() if name_widget else ""
# Получаем shortname
short_name_edit = self.cellWidget(row, rows.short_name)
shortname = short_name_edit.text() if short_name_edit else ""
# Флаги ошибок
long_shortname = len(shortname) > 10
found = any(v.get('name') == name for v in self.var_list)
# Выбираем цвет и подсказку
color = None
tooltip = ""
if not found:
color = error_color
tooltip = tooltip_missing
elif long_shortname:
color = warning_color
tooltip = tooltip_shortname
self.highlight_row(row, color, tooltip)
def read_data(self):
@@ -138,7 +183,7 @@ class VariableTableWidget(QTableWidget):
iq = self.cellWidget(row, rows.iq_type).currentText()
ret = self.cellWidget(row, rows.ret_type).currentText()
shortname = self.cellWidget(row, rows.short_name).text()
origin_type = self.item(row, rows.type).text()
origin_type = self.cellWidget(row, rows.type).text()
result.append({
'show_var': True,
@@ -182,3 +227,34 @@ class VariableTableWidget(QTableWidget):
self.setColumnWidth(right_index, new_right_width)
finally:
self._resizing = False
def highlight_row(self, row: int, color: QColor = None, tooltip: str = ""):
"""
Подсвечивает строку таблицы цветом `color`, не меняя шрифт.
Работает с QLineEdit, QComboBox, QCheckBox (включая обёртки).
Если `color=None`, сбрасывает подсветку.
"""
css_reset = "background-color: none; font: inherit;"
css_color = f"background-color: {color.name()};" if color else css_reset
for col in range(self.columnCount()):
item = self.item(row, col)
widget = self.cellWidget(row, col)
# Подсветка обычной item-ячейки (например, тип переменной)
if item is not None:
if color:
item.setBackground(QBrush(color))
item.setToolTip(tooltip)
else:
item.setBackground(QBrush(Qt.NoBrush))
item.setToolTip("")
# Подсветка виджетов — здесь главная доработка
elif widget is not None:
# Надёжная подсветка: через styleSheet
widget.setStyleSheet(css_color)
widget.setToolTip(tooltip if color else "")

View File

@@ -334,12 +334,14 @@ def generate_vars_file(proj_path, xml_path, output_dir):
# Дополнительные поля, например комментарий
comment = info.get("comment", "")
short_name = info.get("shortname", f'"{vname}"')
short_trimmed = short_name[:10] # ограничиваем длину до 10
short_str = f'"{short_trimmed}"' # оборачиваем в кавычки
if pt_type not in ('pt_struct', 'pt_union'):
formated_name = f'"{vname}"'
# Добавим комментарий после записи, если он есть
comment_str = f' // {comment}' if comment else ''
line = f'{{(char *)&{vname:<41} , {pt_type:<21} , {iq_type:<21} , {short_name:<42}}}, \\{comment_str}'
line = f'{{(char *)&{vname:<41} , {pt_type:<21} , {iq_type:<21} , {short_str:<20}}}, \\{comment_str}'
new_debug_vars[vname] = line
else:

BIN
Src/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
Src/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -1,17 +1,7 @@
import sys
import re
import subprocess
import xml.etree.ElementTree as ET
from generateVars import type_map
from enum import IntEnum
import threading
from scanVars import run_scan
from generateVars import run_generate
from setupVars import *
from VariableSelector import *
from VariableTable import VariableTableWidget, rows
from scanVarGUI import *
from PySide2.QtWidgets import (
QApplication, QWidget, QTableWidget, QTableWidgetItem,

View File

@@ -4,8 +4,8 @@ import re
import xml.etree.ElementTree as ET
from generateVars import map_type_to_pt, get_iq_define, type_map
from enum import IntEnum
from scanVars import *
from generateVars import *
import scanVars
import setupVars
def make_absolute_path(path, base_path):
@@ -93,7 +93,7 @@ def parse_vars(filename, typedef_map=None):
'static': var.findtext('static', 'false') == 'true',
})
indent_xml(root)
scanVars.indent_xml(root)
ET.ElementTree(root).write(filename, encoding="utf-8", xml_declaration=True)
return vars_list
@@ -188,7 +188,7 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
if isinstance(type_str, dict):
fields = type_str
else:
base_type = strip_ptr_and_array(type_str)
base_type = scanVars.strip_ptr_and_array(type_str)
fields = structs.get(base_type)
if not isinstance(fields, dict):
return []
@@ -260,7 +260,7 @@ def expand_vars(vars_list, structs, typedefs):
for var in vars_list:
pt_type = var.get('pt_type', '')
raw_type = var.get('type', '')
base_type = strip_ptr_and_array(raw_type)
base_type = scanVars.strip_ptr_and_array(raw_type)
fields = structs.get(base_type)