diff --git a/setupVars_out.py b/.out/setupVars_out.py similarity index 100% rename from setupVars_out.py rename to .out/setupVars_out.py diff --git a/VariableSelector.py b/VariableSelector.py index 6010e53..4504cda 100644 --- a/VariableSelector.py +++ b/VariableSelector.py @@ -30,10 +30,9 @@ class VariableSelectorDialog(QDialog): self.tree = QTreeWidget() self.tree.setHeaderLabels(["Имя переменной", "Тип"]) self.tree.setSelectionMode(QTreeWidget.ExtendedSelection) - self.tree.setRootIsDecorated(False) # без иконки "вложенность" + self.tree.setRootIsDecorated(True) self.tree.setUniformRowHeights(True) - # --- Автоматическая ширина колонок self.tree.setStyleSheet(""" QTreeWidget::item:selected { background-color: #87CEFA; @@ -47,11 +46,15 @@ class VariableSelectorDialog(QDialog): self.btn_add = QPushButton("Добавить выбранные") self.btn_add.clicked.connect(self.on_add_clicked) + self.btn_delete = QPushButton("Удалить выбранные") + self.btn_delete.clicked.connect(self.on_delete_clicked) + layout = QVBoxLayout() layout.addWidget(QLabel("Поиск:")) layout.addWidget(self.search_input) layout.addWidget(self.tree) layout.addWidget(self.btn_add) + layout.addWidget(self.btn_delete) # Кнопка удаления self.setLayout(layout) self.populate_tree() @@ -68,14 +71,18 @@ class VariableSelectorDialog(QDialog): item = QTreeWidgetItem([name, type_str]) item.setData(0, Qt.UserRole, name) + # Делаем bitfield-поля неактивными + if "(bitfield:" in type_str: + item.setDisabled(True) + self.set_tool(item, "Битовые поля недоступны для выбора") + for i, attr in enumerate(['file', 'extern', 'static']): item.setData(0, Qt.UserRole + 1 + i, var.get(attr)) if show_var: item.setForeground(0, Qt.gray) item.setForeground(1, Qt.gray) - item.setToolTip(0, "Уже добавлена") - item.setToolTip(1, "Уже добавлена") + self.set_tool(item, "Уже добавлена") if parent is None: self.tree.addTopLevelItem(item) @@ -95,32 +102,61 @@ class VariableSelectorDialog(QDialog): self.add_tree_item_recursively(None, var) header = self.tree.header() - header.setSectionResizeMode(0, QHeaderView.Stretch) - header.setSectionResizeMode(1, QHeaderView.ResizeToContents) + header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять + self.tree.setColumnWidth(0, 400) + self.tree.resizeColumnToContents(1) + """ header.setSectionResizeMode(0, QHeaderView.Stretch) + header.setSectionResizeMode(1, QHeaderView.ResizeToContents) """ def filter_tree(self): text = self.search_input.text().strip().lower() + path_parts = text.split('.') if text else [] - def match_recursive(item): - matched = False + def hide_all(item): + item.setHidden(True) for i in range(item.childCount()): - child = item.child(i) - if match_recursive(child): + hide_all(item.child(i)) + + def path_matches_search(name, search_parts): + name_parts = name.lower().split('.') + if len(name_parts) < len(search_parts): + return False + for sp, np in zip(search_parts, name_parts): + if not np.startswith(sp): + return False + return True + + def show_matching_path(item, level=0): + name = item.text(0).lower() + # Проверяем соответствие до длины path_parts + if not path_parts: + matched = True + else: + matched = False + # Проверяем совпадение по пути + if path_matches_search(name, path_parts[:level+1]): matched = True - # Проверяем текущий элемент - name = item.text(0).lower() - typ = item.text(1).lower() - if text in name or text in typ: - matched = True - item.setHidden(not matched) - # Открываем только те элементы, у которых есть совпадение в потомках или в себе - item.setExpanded(matched) - return matched + + # Раскрываем, если это не последний уровень поиска + if matched and level < len(path_parts) - 1: + item.setExpanded(True) + else: + item.setExpanded(False) + + matched_any_child = False + for i in range(item.childCount()): + child = item.child(i) + if show_matching_path(child, level + 1): + matched_any_child = True + + return matched or matched_any_child for i in range(self.tree.topLevelItemCount()): - match_recursive(self.tree.topLevelItem(i)) + item = self.tree.topLevelItem(i) + hide_all(item) + show_matching_path(item, 0) def on_add_clicked(self): @@ -165,4 +201,21 @@ class VariableSelectorDialog(QDialog): self.all_vars.append(new_var) self.var_map[name] = new_var # Чтобы в будущем не добавлялось повторно - self.accept() \ No newline at end of file + self.accept() + + def on_delete_clicked(self): + # Деактивируем (удаляем из видимых) выбранные переменные + for item in self.tree.selectedItems(): + name = item.text(0) + if not name: + continue + if name in self.var_map: + var = self.var_map[name] + var['show_var'] = 'false' + var['enable'] = 'false' + self.accept() + + + def set_tool(self, item, text): + item.setToolTip(0, text) + item.setToolTip(1, text) \ No newline at end of file diff --git a/__pycache__/VariableSelector.cpython-313.pyc b/__pycache__/VariableSelector.cpython-313.pyc index a7a0ce9..7aceb77 100644 Binary files a/__pycache__/VariableSelector.cpython-313.pyc and b/__pycache__/VariableSelector.cpython-313.pyc differ diff --git a/__pycache__/generateVars.cpython-313.pyc b/__pycache__/generateVars.cpython-313.pyc index 071dffd..fe5d6a7 100644 Binary files a/__pycache__/generateVars.cpython-313.pyc and b/__pycache__/generateVars.cpython-313.pyc differ diff --git a/__pycache__/parseMakefile.cpython-313.pyc b/__pycache__/parseMakefile.cpython-313.pyc index 5ecea53..cae460a 100644 Binary files a/__pycache__/parseMakefile.cpython-313.pyc and b/__pycache__/parseMakefile.cpython-313.pyc differ diff --git a/__pycache__/scanVars.cpython-313.pyc b/__pycache__/scanVars.cpython-313.pyc index 2131601..a7c01fb 100644 Binary files a/__pycache__/scanVars.cpython-313.pyc and b/__pycache__/scanVars.cpython-313.pyc differ diff --git a/__pycache__/setupVars.cpython-313.pyc b/__pycache__/setupVars.cpython-313.pyc index 7ea3a5f..ba8b570 100644 Binary files a/__pycache__/setupVars.cpython-313.pyc and b/__pycache__/setupVars.cpython-313.pyc differ diff --git a/debug_vars.c b/debug_vars.c index d39a4c0..2f82485 100644 --- a/debug_vars.c +++ b/debug_vars.c @@ -1,8 +1,8 @@ -// ���� ���� ������������ ������������� +// #include "debug_tools.h" -// ������� ��� ������� � ���������� +// #include "xp_project.h" #include "RS_Functions_modbus.h" #include "vector.h" @@ -44,7 +44,7 @@ #include "rmp_cntl_my1.h" -// �������� ��� ������� � ���������� +// extern int ADC0finishAddr; extern int ADC0startAddr; extern int ADC1finishAddr; @@ -313,9 +313,9 @@ extern _iq zadan_Id_min; extern int zero_ADC[20]; -// ����������� ������� � ����������� �� ���������� ��� ������� +// int DebugVar_Qnt = 1; #pragma DATA_SECTION(dbg_vars,".dbgvar_info") DebugVar_t dbg_vars[] = {\ -{(char *)&project.cds_tk.plane_address , pt_uint16 , t_iq_none , "project.cds_tk.plane_address" }, \ +{(char *)&ADC1finishAddr , pt_int16 , iq_none , "ADC1finishAddr" }, \ }; diff --git a/setupVars.py b/setupVars.py index 9f52d92..ae20700 100644 --- a/setupVars.py +++ b/setupVars.py @@ -89,7 +89,7 @@ def parse_structs(filename): structs = {} typedef_map = {} - + def parse_struct_element(elem): fields = {} @@ -99,19 +99,22 @@ def parse_structs(filename): # Проверка на вложенную структуру nested_struct_elem = field.find("struct") + if nested_struct_elem is not None: # Рекурсивно парсим вложенную структуру и вставляем её как подсловарь nested_fields = parse_struct_element(nested_struct_elem) - fields[fname] = nested_fields + + # Оборачиваем в dict с ключом 'type' для хранения типа из XML + fields[fname] = { + 'type': ftype, # здесь тип, например "BENDER_ERROR" + **nested_fields # развёрнутые поля вложенной структуры + } else: # Обычное поле fields[fname] = ftype return fields - - - structs_elem = root.find("structs") if structs_elem is not None: for struct in structs_elem.findall("struct"): @@ -156,16 +159,11 @@ def safe_parse_xml(xml_path): except Exception as e: print(f"Неожиданная ошибка при чтении XML файла '{xml_path}': {e}") return None, None - def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, depth=0): - """ - Рекурсивно разворачивает структуру. - type_str может быть строкой (имя типа) или словарём (вложенная структура). - """ if depth > 10: return [] - # Если тип уже является вложенной структурой + # Если type_str — словарь структуры if isinstance(type_str, dict): fields = type_str else: @@ -175,21 +173,42 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de return [] children = [] - for field_name, field_type in fields.items(): - full_name = f"{prefix}.{field_name}" - child = { - 'name': full_name, - 'type': field_type, - 'pt_type': '', - 'file': var_attrs.get('file'), - 'extern': var_attrs.get('extern'), - 'static': var_attrs.get('static'), - } + for field_name, field_value in fields.items(): + # Пропускаем поле 'type', оно служит для хранения имени типа + if field_name == 'type': + continue - # Рекурсивно разворачиваем, если field_type — вложенная структура - subchildren = expand_struct_recursively(full_name, field_type, structs, typedefs, var_attrs, depth + 1) - if subchildren: - child['children'] = subchildren + full_name = f"{prefix}.{field_name}" + + if isinstance(field_value, dict): + # Если вложенная структура — берем её имя типа из поля 'type' или пустую строку + type_name = field_value.get('type', '') + child = { + 'name': full_name, + 'type': type_name, + 'pt_type': '', + 'file': var_attrs.get('file'), + 'extern': var_attrs.get('extern'), + 'static': var_attrs.get('static'), + } + # Рекурсивно раскрываем вложенные поля + subchildren = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1) + if subchildren: + child['children'] = subchildren + else: + # Простое поле — строка типа + # Пропускаем указатели на функции + if isinstance(field_value, str) and "(" in field_value and "*" in field_value and ")" in field_value: + continue + + child = { + 'name': full_name, + 'type': field_value, + 'pt_type': '', + 'file': var_attrs.get('file'), + 'extern': var_attrs.get('extern'), + 'static': var_attrs.get('static'), + } children.append(child) @@ -219,6 +238,11 @@ def expand_vars(vars_list, structs, typedefs): new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var) expanded.append(new_var) + elif pt_type == 'pt_union' and isinstance(fields, dict): + new_var = var.copy() + new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var) + expanded.append(new_var) + else: expanded.append(var) diff --git a/setupVars_GUI.py b/setupVars_GUI.py index 2c4b7a7..c935df3 100644 --- a/setupVars_GUI.py +++ b/setupVars_GUI.py @@ -118,6 +118,7 @@ class VarEditor(QWidget): proj_layout = QHBoxLayout() proj_layout.addWidget(QLabel("Project Path:")) self.proj_path_edit = QLineEdit() + self.proj_path_edit.returnPressed.connect(self.read_xml_file) self.proj_path_edit.textChanged.connect(self.__on_proj_path_changed) proj_layout.addWidget(self.proj_path_edit) btn_proj_browse = QPushButton("...") @@ -129,6 +130,7 @@ class VarEditor(QWidget): makefile_layout = QHBoxLayout() makefile_layout.addWidget(QLabel("Makefile Path (relative path):")) self.makefile_edit = QLineEdit() + self.makefile_edit.returnPressed.connect(self.read_xml_file) self.makefile_edit.textChanged.connect(self.__on_makefile_path_changed) makefile_layout.addWidget(self.makefile_edit) btn_makefile_browse = QPushButton("...") @@ -375,7 +377,6 @@ class VarEditor(QWidget): ) self.xml_output_edit.setText(file_path) self.xml_path = file_path - self.read_xml_file() def keyPressEvent(self, event: QKeyEvent): if event.key() == Qt.Key_Delete: @@ -405,9 +406,11 @@ class VarEditor(QWidget): def __on_xml_path_changed(self): self.xml_path = self.get_xml_path() + self.read_xml_file() def __on_proj_path_changed(self): self.proj_path = self.get_proj_path() + self.read_xml_file() def __on_makefile_path_changed(self): self.makefile_path = self.get_makefile_path() @@ -415,6 +418,7 @@ class VarEditor(QWidget): path = make_relative_path(self.makefile_path, self.proj_path) self.makefile_edit.setText(path) self.makefile_path = path + self.read_xml_file() def __after_scanvars_finished(self): diff --git a/vars.xml b/vars.xml index 2b7f467..40c6a99 100644 --- a/vars.xml +++ b/vars.xml @@ -1,5 +1,5 @@ - + false @@ -27,7 +27,7 @@ false - true + false ADC1finishAddr pt_int16 iq_none @@ -3602,8 +3602,8 @@ false - true - true + false + false project.cds_tk.plane_address pt_uint16 t_iq_none