работа с таблицей перенесена в отдельный файл
сделано автозаполнение при поиске переменых сделано правильное формирование структур, через . или -> пофиксены мелкие фиксы
This commit is contained in:
		
							parent
							
								
									0b50c31aa8
								
							
						
					
					
						commit
						4962276760
					
				
							
								
								
									
										
											BIN
										
									
								
								DebugVarEdit.exe
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								DebugVarEdit.exe
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							@ -1,9 +1,10 @@
 | 
			
		||||
import re
 | 
			
		||||
from PySide6.QtWidgets import (
 | 
			
		||||
    QDialog, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QPushButton,
 | 
			
		||||
    QLineEdit, QLabel, QHeaderView
 | 
			
		||||
    QLineEdit, QLabel, QHeaderView, QCompleter, QCheckBox, QHBoxLayout
 | 
			
		||||
)
 | 
			
		||||
from PySide6.QtCore import Qt
 | 
			
		||||
from PySide6.QtGui import QKeySequence, QKeyEvent
 | 
			
		||||
from PySide6.QtCore import Qt, QStringListModel, QSettings
 | 
			
		||||
from setupVars import *
 | 
			
		||||
from scanVars import *
 | 
			
		||||
 | 
			
		||||
@ -25,9 +26,21 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
 | 
			
		||||
        self.xml_path = xml_path  # сохраняем путь к xml
 | 
			
		||||
 | 
			
		||||
        # --- Добавляем чекбокс для автодополнения ---
 | 
			
		||||
        self.autocomplete_checkbox = QCheckBox("Включить автодополнение")
 | 
			
		||||
        self.autocomplete_checkbox.setChecked(True)
 | 
			
		||||
 | 
			
		||||
        # Инициализируем QSettings с именем организации и приложения
 | 
			
		||||
        self.settings = QSettings("SET", "DebugVarEdit_VarsSelector")
 | 
			
		||||
        # Восстанавливаем сохранённое состояние чекбокса, если есть
 | 
			
		||||
        checked = self.settings.value("autocomplete_enabled", True, type=bool)
 | 
			
		||||
        self.autocomplete_checkbox.setChecked(checked)
 | 
			
		||||
        # При изменении состояния чекбокса сохраняем его
 | 
			
		||||
        self.autocomplete_checkbox.stateChanged.connect(self.save_checkbox_state)
 | 
			
		||||
 | 
			
		||||
        self.search_input = QLineEdit()
 | 
			
		||||
        self.search_input.setPlaceholderText("Поиск по имени переменной...")
 | 
			
		||||
        self.search_input.textChanged.connect(self.filter_tree)
 | 
			
		||||
        self.search_input.textChanged.connect(self.on_search_text_changed)
 | 
			
		||||
 | 
			
		||||
        self.tree = QTreeWidget()
 | 
			
		||||
        self.tree.setHeaderLabels(["Имя переменной", "Тип"])
 | 
			
		||||
@ -51,17 +64,33 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
        self.btn_delete = QPushButton("Удалить выбранные")
 | 
			
		||||
        self.btn_delete.clicked.connect(self.on_delete_clicked)
 | 
			
		||||
 | 
			
		||||
        self.completer = QCompleter()
 | 
			
		||||
        self.completer.setCompletionMode(QCompleter.PopupCompletion)  # важно!
 | 
			
		||||
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
 | 
			
		||||
        self.completer.setFilterMode(Qt.MatchContains)
 | 
			
		||||
        self.completer.setWidget(self.search_input)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        self.search_input.installEventFilter(self)
 | 
			
		||||
        
 | 
			
		||||
        # Создаем горизонтальный layout для "Поиск:" и чекбокса справа
 | 
			
		||||
        search_layout = QHBoxLayout()
 | 
			
		||||
        label_search = QLabel("Поиск:")
 | 
			
		||||
        search_layout.addWidget(label_search, alignment=Qt.AlignLeft)
 | 
			
		||||
        search_layout.addStretch()  # чтобы чекбокс прижался вправо
 | 
			
		||||
        search_layout.addWidget(self.autocomplete_checkbox, alignment=Qt.AlignRight)
 | 
			
		||||
        self.completer.activated[str].connect(self.insert_completion)
 | 
			
		||||
 | 
			
		||||
        layout = QVBoxLayout()
 | 
			
		||||
        layout.addWidget(QLabel("Поиск:"))
 | 
			
		||||
        layout.addLayout(search_layout)         # заменили label и чекбокс
 | 
			
		||||
        layout.addWidget(self.search_input)
 | 
			
		||||
        layout.addWidget(self.tree)
 | 
			
		||||
        layout.addWidget(self.btn_add)
 | 
			
		||||
        layout.addWidget(self.btn_delete)  # Кнопка удаления
 | 
			
		||||
        layout.addWidget(self.btn_delete)
 | 
			
		||||
        self.setLayout(layout)
 | 
			
		||||
 | 
			
		||||
        self.populate_tree()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def add_tree_item_recursively(self, parent, var):
 | 
			
		||||
        """
 | 
			
		||||
        Рекурсивно добавляет переменную и её дочерние поля в дерево.
 | 
			
		||||
@ -113,7 +142,7 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
 | 
			
		||||
    def filter_tree(self):
 | 
			
		||||
        text = self.search_input.text().strip().lower()
 | 
			
		||||
        path_parts = text.split('.') if text else []
 | 
			
		||||
        path_parts = self.split_path(text) if text else []
 | 
			
		||||
 | 
			
		||||
        def hide_all(item):
 | 
			
		||||
            item.setHidden(True)
 | 
			
		||||
@ -121,7 +150,7 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
                hide_all(item.child(i))
 | 
			
		||||
 | 
			
		||||
        def path_matches_search(name, search_parts):
 | 
			
		||||
            name_parts = name.lower().split('.')
 | 
			
		||||
            name_parts = self.split_path(name.lower())
 | 
			
		||||
            if len(name_parts) < len(search_parts):
 | 
			
		||||
                return False
 | 
			
		||||
            for sp, np in zip(search_parts, name_parts):
 | 
			
		||||
@ -156,11 +185,189 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
 | 
			
		||||
            return matched or matched_any_child
 | 
			
		||||
 | 
			
		||||
        for i in range(self.tree.topLevelItemCount()):
 | 
			
		||||
            item = self.tree.topLevelItem(i)
 | 
			
		||||
            hide_all(item)
 | 
			
		||||
            show_matching_path(item, 0)
 | 
			
		||||
        # Если в поиске нет точки — особая логика для первого уровня
 | 
			
		||||
        if '.' not in text and '->' not in text and text != '':
 | 
			
		||||
            for i in range(self.tree.topLevelItemCount()):
 | 
			
		||||
                item = self.tree.topLevelItem(i)
 | 
			
		||||
                name = item.text(0).lower()
 | 
			
		||||
                if text in name:
 | 
			
		||||
                    item.setHidden(False)
 | 
			
		||||
                    item.setExpanded(False)  # НЕ раскрываем потомков
 | 
			
		||||
                else:
 | 
			
		||||
                    hide_all(item)
 | 
			
		||||
                    item.setHidden(True)
 | 
			
		||||
        else:
 | 
			
		||||
            # Обычная логика с поиском по пути
 | 
			
		||||
            for i in range(self.tree.topLevelItemCount()):
 | 
			
		||||
                item = self.tree.topLevelItem(i)
 | 
			
		||||
                hide_all(item)
 | 
			
		||||
                show_matching_path(item, 0)
 | 
			
		||||
    
 | 
			
		||||
    def update_completions(self, text = None):
 | 
			
		||||
        if text is None:
 | 
			
		||||
            text = self.search_input.text().strip()
 | 
			
		||||
        else:
 | 
			
		||||
            text = text.strip()
 | 
			
		||||
        parts = self.split_path(text)
 | 
			
		||||
        path_parts = parts[:-1]
 | 
			
		||||
        prefix = parts[-1].lower() if not text.endswith(('.', '>')) else ''
 | 
			
		||||
 | 
			
		||||
        # Если путь есть (например: project.adc или project.adc.), ищем внутри него
 | 
			
		||||
        search_deep = len(path_parts) > 0
 | 
			
		||||
 | 
			
		||||
        def find_path_items(path_parts):
 | 
			
		||||
            items = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
 | 
			
		||||
 | 
			
		||||
            for part in path_parts:
 | 
			
		||||
                part_lower = part.lower()
 | 
			
		||||
                matched = []
 | 
			
		||||
 | 
			
		||||
                for item in items:
 | 
			
		||||
                    # Берём последний фрагмент имени item, разделённого точками
 | 
			
		||||
                    item_name_part = self.split_path(item.text(0))[-1].lower()
 | 
			
		||||
                    
 | 
			
		||||
                    if item_name_part == part_lower:
 | 
			
		||||
                        matched.append(item)
 | 
			
		||||
 | 
			
		||||
                if not matched:
 | 
			
		||||
                    return []
 | 
			
		||||
                items = []
 | 
			
		||||
                # Собираем детей для следующего уровня поиска
 | 
			
		||||
                for node in matched:
 | 
			
		||||
                    for i in range(node.childCount()):
 | 
			
		||||
                        items.append(node.child(i))
 | 
			
		||||
 | 
			
		||||
            return matched
 | 
			
		||||
 | 
			
		||||
        if not search_deep:
 | 
			
		||||
            # Без точки — ищем только в топ-уровне, фильтруя по prefix
 | 
			
		||||
            items = []
 | 
			
		||||
            for i in range(self.tree.topLevelItemCount()):
 | 
			
		||||
                item = self.tree.topLevelItem(i)
 | 
			
		||||
                name_part = self.split_path(item.text(0))[-1].lower()
 | 
			
		||||
                if name_part.startswith(prefix):
 | 
			
		||||
                    items.append(item)
 | 
			
		||||
            completions = [item.text(0) for item in items]
 | 
			
		||||
        else:
 | 
			
		||||
            # С точкой — углубляемся по пути и показываем имена детей
 | 
			
		||||
            if len(path_parts) == 0:
 | 
			
		||||
                items = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
 | 
			
		||||
            else:
 | 
			
		||||
                items = find_path_items(path_parts)
 | 
			
		||||
 | 
			
		||||
            completions = []
 | 
			
		||||
            for item in items:
 | 
			
		||||
                for i in range(item.childCount()):
 | 
			
		||||
                    child = item.child(i)
 | 
			
		||||
                    name_part = self.split_path(child.text(0))[-1].lower()
 | 
			
		||||
                    if prefix == '' or name_part.startswith(prefix):
 | 
			
		||||
                        completions.append(child.text(0))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        self.completer.setModel(QStringListModel(completions))
 | 
			
		||||
        return completions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def eventFilter(self, obj, event):
 | 
			
		||||
        if obj == self.search_input and isinstance(event, QKeyEvent):
 | 
			
		||||
            if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier:
 | 
			
		||||
                completions = self.update_completions()
 | 
			
		||||
                self.completer.complete()
 | 
			
		||||
                text = self.search_input.text().strip()
 | 
			
		||||
 | 
			
		||||
                if len(completions) == 1 and completions[0].lower() == text.lower():
 | 
			
		||||
                    # Найдем узел с таким именем
 | 
			
		||||
                    def find_exact_item(name):
 | 
			
		||||
                        stack = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
 | 
			
		||||
                        while stack:
 | 
			
		||||
                            node = stack.pop()
 | 
			
		||||
                            if node.text(0).lower() == name.lower():
 | 
			
		||||
                                return node
 | 
			
		||||
                            for i in range(node.childCount()):
 | 
			
		||||
                                stack.append(node.child(i))
 | 
			
		||||
                        return None
 | 
			
		||||
 | 
			
		||||
                    node = find_exact_item(completions[0])
 | 
			
		||||
                    if node and node.childCount() > 0:
 | 
			
		||||
                        # Используем первую подсказку, чтобы определить нужный разделитель                        
 | 
			
		||||
                        completions = self.update_completions(text + '.')
 | 
			
		||||
                        suggestion = completions[0]
 | 
			
		||||
 | 
			
		||||
                        # Ищем, какой символ идёт после текущего текста
 | 
			
		||||
                        separator = '.'
 | 
			
		||||
                        if suggestion.startswith(text):
 | 
			
		||||
                            rest = suggestion[len(text):]
 | 
			
		||||
                            if rest.startswith('->'):
 | 
			
		||||
                                separator = '->'
 | 
			
		||||
                            elif rest.startswith('.'):
 | 
			
		||||
                                separator = '.'
 | 
			
		||||
 | 
			
		||||
                        self.search_input.setText(text + separator)
 | 
			
		||||
                        completions = self.update_completions()
 | 
			
		||||
                        self.completer.setModel(QStringListModel(completions))
 | 
			
		||||
                        self.completer.complete()
 | 
			
		||||
                        return True
 | 
			
		||||
 | 
			
		||||
                # Иначе просто показываем подсказки
 | 
			
		||||
                self.completer.setModel(QStringListModel(completions))
 | 
			
		||||
                if completions:
 | 
			
		||||
                    self.completer.complete()
 | 
			
		||||
                return True
 | 
			
		||||
 | 
			
		||||
        return super().eventFilter(obj, event)
 | 
			
		||||
    
 | 
			
		||||
    # Функция для поиска узла с полным именем
 | 
			
		||||
    def find_node_by_fullname(self, name):
 | 
			
		||||
        stack = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
 | 
			
		||||
        while stack:
 | 
			
		||||
            node = stack.pop()
 | 
			
		||||
            if node.text(0).lower() == name.lower():
 | 
			
		||||
                return node
 | 
			
		||||
            for i in range(node.childCount()):
 | 
			
		||||
                stack.append(node.child(i))
 | 
			
		||||
        return None
 | 
			
		||||
    def insert_completion(self, text):
 | 
			
		||||
 | 
			
		||||
        node = self.find_node_by_fullname(text)
 | 
			
		||||
        if node and node.childCount() > 0 and not (text.endswith('.') or text.endswith('->')):
 | 
			
		||||
            # Определяем разделитель по имени первого ребёнка
 | 
			
		||||
            child_name = node.child(0).text(0)
 | 
			
		||||
            if child_name.startswith(text + '->'):
 | 
			
		||||
                text += '->'
 | 
			
		||||
            else:
 | 
			
		||||
                text += '.'
 | 
			
		||||
 | 
			
		||||
            self.search_input.setText(text)
 | 
			
		||||
            self.search_input.setCursorPosition(len(text))
 | 
			
		||||
            self.update_completions()
 | 
			
		||||
            self.completer.complete()
 | 
			
		||||
        else:
 | 
			
		||||
            self.search_input.setText(text)
 | 
			
		||||
            self.search_input.setCursorPosition(len(text))
 | 
			
		||||
 | 
			
		||||
    def on_search_text_changed(self, text):
 | 
			
		||||
        if self.autocomplete_checkbox.isChecked():
 | 
			
		||||
            completions = self.update_completions(text)
 | 
			
		||||
            node = self.find_node_by_fullname(text)
 | 
			
		||||
 | 
			
		||||
            should_show = False
 | 
			
		||||
 | 
			
		||||
            if completions:
 | 
			
		||||
                if len(completions) > 1:
 | 
			
		||||
                    should_show = True
 | 
			
		||||
                elif len(completions) == 1:
 | 
			
		||||
                    single_node = self.find_node_by_fullname(completions[0])
 | 
			
		||||
                    if single_node and single_node.childCount() > 0:
 | 
			
		||||
                        should_show = True
 | 
			
		||||
            elif node and node.childCount() > 0 and not (text.endswith('.') or text.endswith('->')):
 | 
			
		||||
                should_show = True
 | 
			
		||||
 | 
			
		||||
            if should_show:
 | 
			
		||||
                self.completer.setModel(QStringListModel(completions))
 | 
			
		||||
                self.completer.complete()
 | 
			
		||||
        self.filter_tree()
 | 
			
		||||
    
 | 
			
		||||
    def on_add_clicked(self):
 | 
			
		||||
        self.selected_names = []
 | 
			
		||||
@ -206,16 +413,55 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
 | 
			
		||||
        self.accept()
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    def on_delete_clicked(self):
 | 
			
		||||
        # Деактивируем (удаляем из видимых) выбранные переменные
 | 
			
		||||
        for item in self.tree.selectedItems():
 | 
			
		||||
            name = item.text(0)
 | 
			
		||||
            if not name:
 | 
			
		||||
                continue
 | 
			
		||||
        selected_names = self._get_selected_var_names()
 | 
			
		||||
        if not selected_names:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # Обновляем var_map и all_vars
 | 
			
		||||
        for name in selected_names:
 | 
			
		||||
            if name in self.var_map:
 | 
			
		||||
                var = self.var_map[name]
 | 
			
		||||
                var['show_var'] = 'false'
 | 
			
		||||
                var['enable'] = 'false'
 | 
			
		||||
                self.var_map[name]['show_var'] = 'false'
 | 
			
		||||
                self.var_map[name]['enable'] = 'false'
 | 
			
		||||
 | 
			
		||||
            for v in self.all_vars:
 | 
			
		||||
                if v['name'] == name:
 | 
			
		||||
                    v['show_var'] = 'false'
 | 
			
		||||
                    v['enable'] = 'false'
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
        # Проверка пути к XML
 | 
			
		||||
        if not hasattr(self, 'xml_path') or not self.xml_path:
 | 
			
		||||
            from PySide6.QtWidgets import QMessageBox
 | 
			
		||||
            QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно обновить переменные.")
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        import xml.etree.ElementTree as ET
 | 
			
		||||
        tree = ET.parse(self.xml_path)
 | 
			
		||||
        root = tree.getroot()
 | 
			
		||||
        if root is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        vars_section = root.find('variables')
 | 
			
		||||
        if vars_section is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        for var_elem in vars_section.findall('var'):
 | 
			
		||||
            name = var_elem.attrib.get('name')
 | 
			
		||||
            if name in selected_names:
 | 
			
		||||
                def set_text(tag, value):
 | 
			
		||||
                    el = var_elem.find(tag)
 | 
			
		||||
                    if el is None:
 | 
			
		||||
                        el = ET.SubElement(var_elem, tag)
 | 
			
		||||
                    el.text = value
 | 
			
		||||
                set_text('show_var', 'false')
 | 
			
		||||
                set_text('enable', 'false')
 | 
			
		||||
 | 
			
		||||
        ET.indent(tree, space="  ", level=0)
 | 
			
		||||
        tree.write(self.xml_path, encoding='utf-8', xml_declaration=True)
 | 
			
		||||
 | 
			
		||||
        self.populate_tree()
 | 
			
		||||
        self.accept()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -231,16 +477,11 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
            super().keyPressEvent(event)
 | 
			
		||||
 | 
			
		||||
    def delete_selected_vars(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'
 | 
			
		||||
        selected_names = self._get_selected_var_names()
 | 
			
		||||
        if not selected_names:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # Проверка пути к XML
 | 
			
		||||
        if not hasattr(self, 'xml_path') or not self.xml_path:
 | 
			
		||||
            from PySide6.QtWidgets import QMessageBox
 | 
			
		||||
            QMessageBox.warning(self, "Ошибка", "Путь к XML не задан, невозможно удалить переменные.")
 | 
			
		||||
@ -249,31 +490,39 @@ class VariableSelectorDialog(QDialog):
 | 
			
		||||
        import xml.etree.ElementTree as ET
 | 
			
		||||
        tree = ET.parse(self.xml_path)
 | 
			
		||||
        root = tree.getroot()
 | 
			
		||||
 | 
			
		||||
        if root is None:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        vars_section = root.find('variables')
 | 
			
		||||
        if vars_section is None:
 | 
			
		||||
            return  # Нет секции variables — ничего удалять
 | 
			
		||||
 | 
			
		||||
        selected_names = [item.text(0) for item in self.tree.selectedItems() if item.text(0)]
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        removed_any = False
 | 
			
		||||
        for var_elem in vars_section.findall('var'):
 | 
			
		||||
        for var_elem in list(vars_section.findall('var')):
 | 
			
		||||
            name = var_elem.attrib.get('name')
 | 
			
		||||
            if name in selected_names:
 | 
			
		||||
                vars_section.remove(var_elem)
 | 
			
		||||
                removed_any = True
 | 
			
		||||
                if name in self.var_map:
 | 
			
		||||
                    del self.var_map[name]
 | 
			
		||||
                # Удаляем элементы из списка на месте
 | 
			
		||||
                self.all_vars[:] = [v for v in self.all_vars if v['name'] != name]
 | 
			
		||||
                self.var_map.pop(name, None)
 | 
			
		||||
 | 
			
		||||
        # Удаляем из all_vars (глобально)
 | 
			
		||||
        self.all_vars[:] = [v for v in self.all_vars if v['name'] not in selected_names]
 | 
			
		||||
 | 
			
		||||
        if removed_any:
 | 
			
		||||
            ET.indent(tree, space="  ", level=0)
 | 
			
		||||
            tree.write(self.xml_path, encoding='utf-8', xml_declaration=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        self.populate_tree()
 | 
			
		||||
        self.filter_tree()
 | 
			
		||||
 | 
			
		||||
    def _get_selected_var_names(self):
 | 
			
		||||
        return [item.text(0) for item in self.tree.selectedItems() if item.text(0)]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def save_checkbox_state(self):
 | 
			
		||||
        self.settings.setValue("autocomplete_enabled", self.autocomplete_checkbox.isChecked())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def split_path(self, path):
 | 
			
		||||
        # Разбиваем по точке или по -> (учитываем, что -> длиной 2 символа)
 | 
			
		||||
        return re.split(r'\.|->', path)
 | 
			
		||||
							
								
								
									
										184
									
								
								Src/VariableTable.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								Src/VariableTable.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,184 @@
 | 
			
		||||
from PySide6.QtWidgets import (
 | 
			
		||||
    QTableWidget, QTableWidgetItem, QCheckBox, QComboBox, QLineEdit, QCompleter,
 | 
			
		||||
    QAbstractItemView, QHeaderView
 | 
			
		||||
)
 | 
			
		||||
from PySide6.QtCore import Qt
 | 
			
		||||
from enum import IntEnum
 | 
			
		||||
from generateVars import type_map
 | 
			
		||||
 | 
			
		||||
class rows(IntEnum):
 | 
			
		||||
    No = 0
 | 
			
		||||
    include = 1
 | 
			
		||||
    name = 2
 | 
			
		||||
    type = 3
 | 
			
		||||
    pt_type = 4
 | 
			
		||||
    iq_type = 5
 | 
			
		||||
    ret_type = 6
 | 
			
		||||
    short_name = 7
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VariableTableWidget(QTableWidget):
 | 
			
		||||
    def __init__(self, parent=None):
 | 
			
		||||
        super().__init__(0, 8, parent)
 | 
			
		||||
        # Таблица переменных
 | 
			
		||||
        self.setHorizontalHeaderLabels([
 | 
			
		||||
            '№',             # новый столбец
 | 
			
		||||
            'En',
 | 
			
		||||
            'Name',
 | 
			
		||||
            'Origin Type',
 | 
			
		||||
            'Pointer Type',
 | 
			
		||||
            'IQ Type',
 | 
			
		||||
            'Return Type',
 | 
			
		||||
            'Short Name'
 | 
			
		||||
        ])
 | 
			
		||||
        self.setEditTriggers(QAbstractItemView.AllEditTriggers)
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        self.type_options = list(dict.fromkeys(type_map.values()))
 | 
			
		||||
        self.display_type_options = [t.replace('pt_', '') for t in self.type_options]
 | 
			
		||||
        self.iq_types = ['iq_none', 'iq'] + [f'iq{i}' for i in range(1, 31)]
 | 
			
		||||
 | 
			
		||||
        header = self.horizontalHeader()
 | 
			
		||||
        # Для остальных колонок — растяжение (Stretch), чтобы они заняли всю оставшуюся ширину
 | 
			
		||||
 | 
			
		||||
        for col in range(self.columnCount()):
 | 
			
		||||
            if col == self.columnCount() - 1:
 | 
			
		||||
                header.setSectionResizeMode(col, QHeaderView.Stretch)
 | 
			
		||||
            else:
 | 
			
		||||
                header.setSectionResizeMode(col, QHeaderView.Interactive)
 | 
			
		||||
 | 
			
		||||
        parent_widget = self.parentWidget()
 | 
			
		||||
        # Сделаем колонки с номерами фиксированной ширины
 | 
			
		||||
        self.setColumnWidth(rows.No, 30)
 | 
			
		||||
        self.setColumnWidth(rows.include, 30)
 | 
			
		||||
        self.setColumnWidth(rows.pt_type, 85)
 | 
			
		||||
        self.setColumnWidth(rows.iq_type, 85)
 | 
			
		||||
        self.setColumnWidth(rows.ret_type, 85)
 | 
			
		||||
 | 
			
		||||
        self.setColumnWidth(rows.name, 300)
 | 
			
		||||
        self.setColumnWidth(rows.type, 100)
 | 
			
		||||
        self._resizing = False
 | 
			
		||||
        self.horizontalHeader().sectionResized.connect(self.on_section_resized)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def populate(self, vars_list, structs, on_change_callback):
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
        for row, var in enumerate(filtered_vars):
 | 
			
		||||
            # №
 | 
			
		||||
            no_item = QTableWidgetItem(str(row))
 | 
			
		||||
            no_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
 | 
			
		||||
            self.setItem(row, rows.No, no_item)
 | 
			
		||||
 | 
			
		||||
            # Enable
 | 
			
		||||
            cb = QCheckBox()
 | 
			
		||||
            cb.setChecked(var.get('enable', 'false') == 'true')
 | 
			
		||||
            cb.stateChanged.connect(on_change_callback)
 | 
			
		||||
            self.setCellWidget(row, rows.include, cb)
 | 
			
		||||
 | 
			
		||||
            # Name
 | 
			
		||||
            name_edit = QLineEdit(var['name'])
 | 
			
		||||
            if var['type'] in structs:
 | 
			
		||||
                completer = QCompleter(structs[var['type']].keys())
 | 
			
		||||
                completer.setCaseSensitivity(Qt.CaseInsensitive)
 | 
			
		||||
                name_edit.setCompleter(completer)
 | 
			
		||||
            name_edit.textChanged.connect(on_change_callback)
 | 
			
		||||
            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)
 | 
			
		||||
 | 
			
		||||
            # pt_type
 | 
			
		||||
            pt_combo = QComboBox()
 | 
			
		||||
            pt_combo.addItems(self.display_type_options)
 | 
			
		||||
            value = var['pt_type'].replace('pt_', '')
 | 
			
		||||
            if value not in self.display_type_options:
 | 
			
		||||
                pt_combo.addItem(value)
 | 
			
		||||
            pt_combo.setCurrentText(value)
 | 
			
		||||
            pt_combo.currentTextChanged.connect(on_change_callback)
 | 
			
		||||
            self.setCellWidget(row, rows.pt_type, pt_combo)
 | 
			
		||||
 | 
			
		||||
            # iq_type
 | 
			
		||||
            iq_combo = QComboBox()
 | 
			
		||||
            iq_combo.addItems(self.iq_types)
 | 
			
		||||
            value = var['iq_type'].replace('t_', '')
 | 
			
		||||
            if value not in self.iq_types:
 | 
			
		||||
                iq_combo.addItem(value)
 | 
			
		||||
            iq_combo.setCurrentText(value)
 | 
			
		||||
            iq_combo.currentTextChanged.connect(on_change_callback)
 | 
			
		||||
            self.setCellWidget(row, rows.iq_type, iq_combo)
 | 
			
		||||
 | 
			
		||||
            # return_type
 | 
			
		||||
            ret_combo = QComboBox()
 | 
			
		||||
            ret_combo.addItems(self.iq_types)
 | 
			
		||||
            ret_combo.setCurrentText(var.get('return_type', ''))
 | 
			
		||||
            ret_combo.currentTextChanged.connect(on_change_callback)
 | 
			
		||||
            self.setCellWidget(row, rows.ret_type, ret_combo)
 | 
			
		||||
 | 
			
		||||
            # short_name
 | 
			
		||||
            short_name_edit = QLineEdit(var.get('shortname', var['name']))
 | 
			
		||||
            short_name_edit.textChanged.connect(on_change_callback)
 | 
			
		||||
            self.setCellWidget(row, rows.short_name, short_name_edit)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def read_data(self):
 | 
			
		||||
        result = []
 | 
			
		||||
        for row in range(self.rowCount()):
 | 
			
		||||
            cb = self.cellWidget(row, rows.include)
 | 
			
		||||
            name = self.cellWidget(row, rows.name).text()
 | 
			
		||||
            pt = self.cellWidget(row, rows.pt_type).currentText()
 | 
			
		||||
            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()
 | 
			
		||||
 | 
			
		||||
            result.append({
 | 
			
		||||
                'show_var': True,
 | 
			
		||||
                'enable': cb.isChecked(),
 | 
			
		||||
                'name': name,
 | 
			
		||||
                'pt_type': f'pt_{pt}',
 | 
			
		||||
                'iq_type': iq,
 | 
			
		||||
                'return_type': ret,
 | 
			
		||||
                'shortname': shortname,
 | 
			
		||||
                'type': origin_type,
 | 
			
		||||
            })
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
    def on_section_resized(self, logicalIndex, oldSize, newSize):
 | 
			
		||||
        if self._resizing:
 | 
			
		||||
            return  # предотвращаем рекурсию
 | 
			
		||||
 | 
			
		||||
        min_width = 50
 | 
			
		||||
        delta = newSize - oldSize
 | 
			
		||||
        right_index = logicalIndex + 1
 | 
			
		||||
 | 
			
		||||
        if right_index >= self.columnCount():
 | 
			
		||||
            # Если правая колока - нет соседа, ограничиваем минимальную ширину
 | 
			
		||||
            if newSize < min_width:
 | 
			
		||||
                self._resizing = True
 | 
			
		||||
                self.setColumnWidth(logicalIndex, min_width)
 | 
			
		||||
                self._resizing = False
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self._resizing = True
 | 
			
		||||
        try:
 | 
			
		||||
            right_width = self.columnWidth(right_index)
 | 
			
		||||
            new_right_width = right_width - delta
 | 
			
		||||
 | 
			
		||||
            # Если соседняя колонка станет уже минимальной - подкорректируем левую
 | 
			
		||||
            if new_right_width < min_width:
 | 
			
		||||
                new_right_width = min_width
 | 
			
		||||
                newSize = oldSize + (right_width - min_width)
 | 
			
		||||
                self.setColumnWidth(logicalIndex, newSize)
 | 
			
		||||
 | 
			
		||||
            self.setColumnWidth(right_index, new_right_width)
 | 
			
		||||
        finally:
 | 
			
		||||
            self._resizing = False
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Src/__pycache__/VariableSelector.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Src/__pycache__/VariableSelector.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Src/__pycache__/VariableTable.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Src/__pycache__/VariableTable.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Src/__pycache__/generateVars.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Src/__pycache__/generateVars.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Src/__pycache__/parseMakefile.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Src/__pycache__/parseMakefile.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Src/__pycache__/scanVars.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Src/__pycache__/scanVars.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Src/__pycache__/setupVars.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Src/__pycache__/setupVars.cpython-313.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -330,12 +330,13 @@ def generate_vars_file(proj_path, xml_path, output_dir):
 | 
			
		||||
 | 
			
		||||
        # Дополнительные поля, например комментарий
 | 
			
		||||
        comment = info.get("comment", "")
 | 
			
		||||
        short_name = info.get("shortname", f'"{vname}"')
 | 
			
		||||
 | 
			
		||||
        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} , {formated_name:<42}}}, \\{comment_str}'
 | 
			
		||||
            line = f'{{(char *)&{vname:<41} , {pt_type:<21} , {iq_type:<21} , {short_name:<42}}}, \\{comment_str}'
 | 
			
		||||
            new_debug_vars[vname] = line
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
 | 
			
		||||
@ -7,11 +7,14 @@ def strip_single_line_comments(code):
 | 
			
		||||
    return re.sub(r'//.*?$', '', code, flags=re.MULTILINE)
 | 
			
		||||
 | 
			
		||||
def read_file_try_encodings(filepath):
 | 
			
		||||
    if not os.path.isfile(filepath):
 | 
			
		||||
        # Файл не существует — просто вернуть пустую строку или None
 | 
			
		||||
        return "", None
 | 
			
		||||
    for enc in ['utf-8', 'cp1251']:
 | 
			
		||||
        try:
 | 
			
		||||
            with open(filepath, 'r', encoding=enc) as f:
 | 
			
		||||
                content = f.read()
 | 
			
		||||
                content = strip_single_line_comments(content)  # <=== ВАЖНО
 | 
			
		||||
                content = strip_single_line_comments(content)
 | 
			
		||||
            return content, enc
 | 
			
		||||
        except UnicodeDecodeError:
 | 
			
		||||
            continue
 | 
			
		||||
@ -38,6 +41,8 @@ def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
 | 
			
		||||
        processed_files.add(norm_path)
 | 
			
		||||
 | 
			
		||||
        content, _ = read_file_try_encodings(cfile)
 | 
			
		||||
        if content is None:
 | 
			
		||||
            continue
 | 
			
		||||
        includes = include_pattern.findall(content)
 | 
			
		||||
        for inc in includes:
 | 
			
		||||
            # Ищем полный путь к include-файлу в include_dirs
 | 
			
		||||
@ -61,9 +66,9 @@ def find_all_includes_recursive(c_files, include_dirs, processed_files=None):
 | 
			
		||||
    return include_files
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_makefile(makefile_path):
 | 
			
		||||
def parse_makefile(makefile_path, proj_path):
 | 
			
		||||
    makefile_dir = os.path.dirname(makefile_path)
 | 
			
		||||
    project_root = os.path.dirname(makefile_dir)  # поднялись из Debug
 | 
			
		||||
    project_root = proj_path
 | 
			
		||||
 | 
			
		||||
    with open(makefile_path, 'r', encoding='utf-8') as f:
 | 
			
		||||
        lines = f.readlines()
 | 
			
		||||
@ -115,6 +120,8 @@ def parse_makefile(makefile_path):
 | 
			
		||||
            continue
 | 
			
		||||
        if "v120" in obj_path:
 | 
			
		||||
            continue
 | 
			
		||||
        if "v100" in obj_path:
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        if obj_path.startswith("Debug\\") or obj_path.startswith("Debug/"):
 | 
			
		||||
            rel_path = obj_path.replace("Debug\\", "Src\\").replace("Debug/", "Src/")
 | 
			
		||||
@ -129,6 +136,10 @@ def parse_makefile(makefile_path):
 | 
			
		||||
        else:
 | 
			
		||||
            c_path = abs_path
 | 
			
		||||
 | 
			
		||||
        # Проверяем существование файла, если нет — пропускаем
 | 
			
		||||
        if not os.path.isfile(c_path):
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        # Сохраняем только .c файлы
 | 
			
		||||
        if c_path.lower().endswith(".c"):
 | 
			
		||||
            c_files.append(c_path)
 | 
			
		||||
 | 
			
		||||
@ -812,7 +812,7 @@ Usage example:
 | 
			
		||||
        print(f"Error: Makefile path '{makefile_path}' does not exist.")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
    c_files, h_files, include_dirs = parse_makefile(makefile_path)
 | 
			
		||||
    c_files, h_files, include_dirs = parse_makefile(makefile_path, proj_path)
 | 
			
		||||
 | 
			
		||||
    vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs)
 | 
			
		||||
    typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs)
 | 
			
		||||
@ -855,7 +855,7 @@ def run_scan(proj_path, makefile_path, output_xml, verbose=2):
 | 
			
		||||
    if not os.path.isfile(makefile_path):
 | 
			
		||||
        raise FileNotFoundError(f"Makefile path '{makefile_path}' does not exist.")
 | 
			
		||||
 | 
			
		||||
    c_files, h_files, include_dirs = parse_makefile(makefile_path)
 | 
			
		||||
    c_files, h_files, include_dirs = parse_makefile(makefile_path, proj_path)
 | 
			
		||||
 | 
			
		||||
    vars, includes, externs = analyze_variables_across_files(c_files, h_files, include_dirs)
 | 
			
		||||
    typedefs, structs = analyze_typedefs_and_structs_across_files(c_files, include_dirs)
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,21 @@ def parse_vars(filename, typedef_map=None):
 | 
			
		||||
            iq_type = var.findtext('iq_type')
 | 
			
		||||
            if not iq_type:
 | 
			
		||||
                iq_type = get_iq_define(var_type)
 | 
			
		||||
                # Записываем iq_type в XML
 | 
			
		||||
                iq_type_elem = var.find('iq_type')
 | 
			
		||||
                if iq_type_elem is None:
 | 
			
		||||
                    iq_type_elem = ET.SubElement(var, 'iq_type')
 | 
			
		||||
                iq_type_elem.text = iq_type
 | 
			
		||||
 | 
			
		||||
            # Вычисляем pt_type и iq_type
 | 
			
		||||
            pt_type = var.findtext('pt_type')
 | 
			
		||||
            if not pt_type:
 | 
			
		||||
                pt_type = map_type_to_pt(var_type, name, typedef_map)
 | 
			
		||||
                # Записываем pt_type в XML
 | 
			
		||||
                pt_type_elem = var.find('pt_type')
 | 
			
		||||
                if pt_type_elem is None:
 | 
			
		||||
                    pt_type_elem = ET.SubElement(var, 'pt_type')
 | 
			
		||||
                pt_type_elem.text = pt_type
 | 
			
		||||
 | 
			
		||||
            vars_list.append({
 | 
			
		||||
                'name': name,
 | 
			
		||||
@ -78,6 +93,10 @@ def parse_vars(filename, typedef_map=None):
 | 
			
		||||
                'static': var.findtext('static', 'false') == 'true',
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
    ET.indent(tree, space="  ", level=0)
 | 
			
		||||
    # Сохраняем изменения в XML-файл
 | 
			
		||||
    tree.write(filename, encoding='utf-8', xml_declaration=True)
 | 
			
		||||
 | 
			
		||||
    return vars_list
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -159,6 +178,9 @@ 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):
 | 
			
		||||
    if depth > 10:
 | 
			
		||||
        return []
 | 
			
		||||
@ -178,7 +200,15 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
 | 
			
		||||
        if field_name == 'type':
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        full_name = f"{prefix}.{field_name}"
 | 
			
		||||
        # Определяем разделитель между prefix и полем
 | 
			
		||||
        if prefix.endswith('*'):
 | 
			
		||||
            separator = '->'
 | 
			
		||||
            # Для красоты можно убрать пробелы у указателя
 | 
			
		||||
            # например, если prefix="ptr*" -> "ptr->field"
 | 
			
		||||
            full_name = f"{prefix[:-1]}{separator}{field_name}"
 | 
			
		||||
        else:
 | 
			
		||||
            separator = '.'
 | 
			
		||||
            full_name = f"{prefix}{separator}{field_name}"
 | 
			
		||||
 | 
			
		||||
        if isinstance(field_value, dict):
 | 
			
		||||
            # Если вложенная структура — берем её имя типа из поля 'type' или пустую строку
 | 
			
		||||
@ -187,10 +217,14 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
 | 
			
		||||
                'name': full_name,
 | 
			
		||||
                'type': type_name,
 | 
			
		||||
                'pt_type': '',
 | 
			
		||||
                'iq_type': '',
 | 
			
		||||
                'return_type': '',
 | 
			
		||||
                'file': var_attrs.get('file'),
 | 
			
		||||
                'extern': var_attrs.get('extern'),
 | 
			
		||||
                'static': var_attrs.get('static'),
 | 
			
		||||
            }
 | 
			
		||||
            if '*' in type_name and not full_name.endswith('*'):
 | 
			
		||||
                full_name += '*'
 | 
			
		||||
            # Рекурсивно раскрываем вложенные поля
 | 
			
		||||
            subchildren = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1)
 | 
			
		||||
            if subchildren:
 | 
			
		||||
@ -205,6 +239,8 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
 | 
			
		||||
                'name': full_name,
 | 
			
		||||
                'type': field_value,
 | 
			
		||||
                'pt_type': '',
 | 
			
		||||
                'iq_type': '',
 | 
			
		||||
                'return_type': '',
 | 
			
		||||
                'file': var_attrs.get('file'),
 | 
			
		||||
                'extern': var_attrs.get('extern'),
 | 
			
		||||
                'static': var_attrs.get('static'),
 | 
			
		||||
@ -215,6 +251,7 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
 | 
			
		||||
    return children
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def expand_vars(vars_list, structs, typedefs):
 | 
			
		||||
    """
 | 
			
		||||
    Раскрывает структуры и массивы структур в деревья.
 | 
			
		||||
@ -228,6 +265,11 @@ def expand_vars(vars_list, structs, typedefs):
 | 
			
		||||
 | 
			
		||||
        fields = structs.get(base_type)
 | 
			
		||||
 | 
			
		||||
        if pt_type.startswith('pt_ptr_') 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)
 | 
			
		||||
 | 
			
		||||
        if pt_type.startswith('pt_arr_') and isinstance(fields, dict):
 | 
			
		||||
            new_var = var.copy()
 | 
			
		||||
            new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var)
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ from scanVars import run_scan
 | 
			
		||||
from generateVars import run_generate
 | 
			
		||||
from setupVars import *
 | 
			
		||||
from VariableSelector import * 
 | 
			
		||||
from VariableTable import VariableTableWidget, rows
 | 
			
		||||
 | 
			
		||||
from PySide6.QtWidgets import (
 | 
			
		||||
    QApplication, QWidget, QTableWidget, QTableWidgetItem,
 | 
			
		||||
@ -20,19 +21,9 @@ from PySide6.QtWidgets import (
 | 
			
		||||
    QDialog, QTreeWidget, QTreeWidgetItem, QSizePolicy
 | 
			
		||||
)
 | 
			
		||||
from PySide6.QtGui import QTextCursor, QKeyEvent
 | 
			
		||||
from PySide6.QtCore import Qt, QProcess, QObject, Signal, QTimer
 | 
			
		||||
from PySide6.QtCore import Qt, QProcess, QObject, Signal, QSettings
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class rows(IntEnum):
 | 
			
		||||
    No = 0
 | 
			
		||||
    include = 1
 | 
			
		||||
    name = 2
 | 
			
		||||
    type = 3
 | 
			
		||||
    pt_type = 4
 | 
			
		||||
    iq_type = 5
 | 
			
		||||
    ret_type = 6
 | 
			
		||||
    short_name = 7
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EmittingStream(QObject):
 | 
			
		||||
    text_written = Signal(str)
 | 
			
		||||
@ -54,11 +45,12 @@ class EmittingStream(QObject):
 | 
			
		||||
            self._buffer = ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProcessOutputWindowDummy(QWidget):
 | 
			
		||||
class ProcessOutputWindowDummy(QDialog):
 | 
			
		||||
    def __init__(self, on_done_callback):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
        self.setWindowTitle("Поиск переменных...")
 | 
			
		||||
        self.resize(600, 400)
 | 
			
		||||
        self.setModal(True)  # сделаем окно модальным
 | 
			
		||||
 | 
			
		||||
        self.layout = QVBoxLayout(self)
 | 
			
		||||
        self.output_edit = QTextEdit()
 | 
			
		||||
@ -75,7 +67,7 @@ class ProcessOutputWindowDummy(QWidget):
 | 
			
		||||
    def __handle_done(self):
 | 
			
		||||
        if self._on_done_callback:
 | 
			
		||||
            self._on_done_callback()
 | 
			
		||||
        self.close()
 | 
			
		||||
        self.accept()  # закрыть диалог
 | 
			
		||||
 | 
			
		||||
    def append_text(self, text):
 | 
			
		||||
        cursor = self.output_edit.textCursor()
 | 
			
		||||
@ -161,20 +153,6 @@ class VarEditor(QWidget):
 | 
			
		||||
        self.btn_update_vars = QPushButton("Обновить данные о переменных")
 | 
			
		||||
        self.btn_update_vars.clicked.connect(self.update_vars_data)
 | 
			
		||||
 | 
			
		||||
        # Таблица переменных
 | 
			
		||||
        self.table = QTableWidget(len(self.vars_list), 8)
 | 
			
		||||
        self.table.setHorizontalHeaderLabels([
 | 
			
		||||
            '№',             # новый столбец
 | 
			
		||||
            'En',
 | 
			
		||||
            'Name',
 | 
			
		||||
            'Origin Type',
 | 
			
		||||
            'Pointer Type',
 | 
			
		||||
            'IQ Type',
 | 
			
		||||
            'Return Type',
 | 
			
		||||
            'Short Name'
 | 
			
		||||
        ])
 | 
			
		||||
        self.table.setEditTriggers(QAbstractItemView.AllEditTriggers)
 | 
			
		||||
 | 
			
		||||
        # Кнопка сохранения
 | 
			
		||||
        btn_save = QPushButton("Build")
 | 
			
		||||
        btn_save.clicked.connect(self.save_build)
 | 
			
		||||
@ -183,7 +161,8 @@ class VarEditor(QWidget):
 | 
			
		||||
        self.btn_add_vars = QPushButton("Add Variables")
 | 
			
		||||
        self.btn_add_vars.clicked.connect(self.__open_variable_selector)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        # Таблица
 | 
			
		||||
        self.table = VariableTableWidget()
 | 
			
		||||
        # Основной layout
 | 
			
		||||
        layout = QVBoxLayout()
 | 
			
		||||
        layout.addLayout(xml_layout)
 | 
			
		||||
@ -195,68 +174,9 @@ class VarEditor(QWidget):
 | 
			
		||||
        layout.addLayout(source_output_layout)
 | 
			
		||||
        layout.addWidget(btn_save)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        header = self.table.horizontalHeader()
 | 
			
		||||
        # Для остальных колонок — растяжение (Stretch), чтобы они заняли всю оставшуюся ширину
 | 
			
		||||
 | 
			
		||||
        for col in range(self.table.columnCount()):
 | 
			
		||||
            if col == self.table.columnCount() - 1:
 | 
			
		||||
                header.setSectionResizeMode(col, QHeaderView.Stretch)
 | 
			
		||||
            else:
 | 
			
		||||
                header.setSectionResizeMode(col, QHeaderView.Interactive)
 | 
			
		||||
 | 
			
		||||
        parent_widget = self.table.parentWidget()
 | 
			
		||||
        if parent_widget:
 | 
			
		||||
            w = parent_widget.width()
 | 
			
		||||
            h = parent_widget.height()
 | 
			
		||||
        viewport_width = self.table.viewport().width()
 | 
			
		||||
        # Сделаем колонки с номерами фиксированной ширины
 | 
			
		||||
        self.table.setColumnWidth(rows.No, 30)
 | 
			
		||||
        self.table.setColumnWidth(rows.include, 30)
 | 
			
		||||
        self.table.setColumnWidth(rows.pt_type, 85)
 | 
			
		||||
        self.table.setColumnWidth(rows.iq_type, 85)
 | 
			
		||||
        self.table.setColumnWidth(rows.ret_type, 85)
 | 
			
		||||
 | 
			
		||||
        self.table.setColumnWidth(rows.name, 300)
 | 
			
		||||
        self.table.setColumnWidth(rows.type, 100)
 | 
			
		||||
        
 | 
			
		||||
        self.table.horizontalHeader().sectionResized.connect(self.on_section_resized)
 | 
			
		||||
 | 
			
		||||
        self.setLayout(layout)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def on_section_resized(self, logicalIndex, oldSize, newSize):
 | 
			
		||||
        if self._resizing:
 | 
			
		||||
            return  # предотвращаем рекурсию
 | 
			
		||||
 | 
			
		||||
        min_width = 50
 | 
			
		||||
        delta = newSize - oldSize
 | 
			
		||||
        right_index = logicalIndex + 1
 | 
			
		||||
 | 
			
		||||
        if right_index >= self.table.columnCount():
 | 
			
		||||
            # Если правая колока - нет соседа, ограничиваем минимальную ширину
 | 
			
		||||
            if newSize < min_width:
 | 
			
		||||
                self._resizing = True
 | 
			
		||||
                self.table.setColumnWidth(logicalIndex, min_width)
 | 
			
		||||
                self._resizing = False
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self._resizing = True
 | 
			
		||||
        try:
 | 
			
		||||
            right_width = self.table.columnWidth(right_index)
 | 
			
		||||
            new_right_width = right_width - delta
 | 
			
		||||
 | 
			
		||||
            # Если соседняя колонка станет уже минимальной - подкорректируем левую
 | 
			
		||||
            if new_right_width < min_width:
 | 
			
		||||
                new_right_width = min_width
 | 
			
		||||
                newSize = oldSize + (right_width - min_width)
 | 
			
		||||
                self.table.setColumnWidth(logicalIndex, newSize)
 | 
			
		||||
 | 
			
		||||
            self.table.setColumnWidth(right_index, new_right_width)
 | 
			
		||||
        finally:
 | 
			
		||||
            self._resizing = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    def get_xml_path(self):
 | 
			
		||||
        xml_path = self.xml_output_edit.text().strip()
 | 
			
		||||
@ -416,18 +336,17 @@ class VarEditor(QWidget):
 | 
			
		||||
                    else:
 | 
			
		||||
                        self.makefile_path = None
 | 
			
		||||
 | 
			
		||||
                if not self.structs_path:
 | 
			
		||||
                    # --- structs_path из атрибута ---
 | 
			
		||||
                    structs_path = root.attrib.get('structs_path', '').strip()
 | 
			
		||||
                    structs_path_full = 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)
 | 
			
		||||
                    else:
 | 
			
		||||
                        self.structs_path = None
 | 
			
		||||
                # --- structs_path из атрибута ---
 | 
			
		||||
                structs_path = root.attrib.get('structs_path', '').strip()
 | 
			
		||||
                structs_path_full = 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)
 | 
			
		||||
                else:
 | 
			
		||||
                    self.structs_path = None
 | 
			
		||||
                
 | 
			
		||||
                self.vars_list = parse_vars(self.xml_path, self.typedef_map)
 | 
			
		||||
                self.update_table()
 | 
			
		||||
                self.table.populate(self.vars_list, self.structs, self.write_to_xml)
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                QMessageBox.warning(self, "Ошибка", f"Ошибка при чтении XML:\n{e}")
 | 
			
		||||
 | 
			
		||||
@ -528,7 +447,7 @@ class VarEditor(QWidget):
 | 
			
		||||
                        v['show_var'] = 'false'
 | 
			
		||||
                        break
 | 
			
		||||
 | 
			
		||||
        self.update_table()
 | 
			
		||||
        self.table.populate(self.vars_list, self.structs, self.write_to_xml)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __open_variable_selector(self):
 | 
			
		||||
@ -542,102 +461,6 @@ class VarEditor(QWidget):
 | 
			
		||||
            self.update()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def update_table(self):
 | 
			
		||||
        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 self.vars_list if v.get('show_var', 'false') == 'true']
 | 
			
		||||
        self.table.setRowCount(len(filtered_vars))
 | 
			
		||||
        self.table.verticalHeader().setVisible(False)
 | 
			
		||||
 | 
			
		||||
        for row, var in enumerate(filtered_vars):
 | 
			
		||||
            # Добавляем номер строки в колонку No (0)
 | 
			
		||||
            no_item = QTableWidgetItem(str(row))
 | 
			
		||||
            no_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)  # readonly
 | 
			
		||||
            self.table.setItem(row, rows.No, no_item)
 | 
			
		||||
 | 
			
		||||
            cb = QCheckBox()
 | 
			
		||||
            enable_str = var.get('enable', 'false')
 | 
			
		||||
            cb.setChecked(enable_str.lower() == 'true')
 | 
			
		||||
            self.table.setCellWidget(row, rows.include, cb)
 | 
			
		||||
 | 
			
		||||
            name_edit = QLineEdit(var['name'])
 | 
			
		||||
            if var['type'] in self.structs:
 | 
			
		||||
                completer = QCompleter(self.structs[var['type']].keys())
 | 
			
		||||
                completer.setCaseSensitivity(Qt.CaseInsensitive)
 | 
			
		||||
                name_edit.setCompleter(completer)
 | 
			
		||||
            self.table.setCellWidget(row, rows.name, name_edit)
 | 
			
		||||
 | 
			
		||||
            # Type (origin)
 | 
			
		||||
            origin_type = var.get('type', '').strip()
 | 
			
		||||
            origin_item = QTableWidgetItem(origin_type)
 | 
			
		||||
            origin_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)  # read-only
 | 
			
		||||
            self.table.setItem(row, rows.type, origin_item)
 | 
			
		||||
 | 
			
		||||
            pt_type_combo = QComboBox()
 | 
			
		||||
            pt_type_combo.addItems(self.display_type_options)
 | 
			
		||||
            internal_type = var['pt_type'].replace('pt_', '')
 | 
			
		||||
            if internal_type in self.display_type_options:
 | 
			
		||||
                pt_type_combo.setCurrentText(internal_type)
 | 
			
		||||
            else:
 | 
			
		||||
                pt_type_combo.addItem(internal_type)
 | 
			
		||||
                pt_type_combo.setCurrentText(internal_type)
 | 
			
		||||
            self.table.setCellWidget(row, rows.pt_type, pt_type_combo)
 | 
			
		||||
 | 
			
		||||
            iq_combo = QComboBox()
 | 
			
		||||
            iq_combo.addItems(iq_types)
 | 
			
		||||
            iq_type = var['iq_type'].replace('t_', '')
 | 
			
		||||
            if iq_type in iq_types:
 | 
			
		||||
                iq_combo.setCurrentText(iq_type)
 | 
			
		||||
            else:
 | 
			
		||||
                iq_combo.addItem(iq_type)
 | 
			
		||||
                iq_combo.setCurrentText(iq_type)
 | 
			
		||||
            self.table.setCellWidget(row, rows.iq_type, iq_combo)
 | 
			
		||||
 | 
			
		||||
            ret_combo = QComboBox()
 | 
			
		||||
            ret_combo.addItems(iq_types)
 | 
			
		||||
            self.table.setCellWidget(row, rows.ret_type, ret_combo)
 | 
			
		||||
 | 
			
		||||
            short_name_edit = QLineEdit(var['name'])
 | 
			
		||||
            self.table.setCellWidget(row, rows.short_name, short_name_edit)
 | 
			
		||||
 | 
			
		||||
            cb.stateChanged.connect(self.write_to_xml)
 | 
			
		||||
            name_edit.textChanged.connect(self.write_to_xml)
 | 
			
		||||
            pt_type_combo.currentTextChanged.connect(self.write_to_xml)
 | 
			
		||||
            iq_combo.currentTextChanged.connect(self.write_to_xml)
 | 
			
		||||
            ret_combo.currentTextChanged.connect(self.write_to_xml)
 | 
			
		||||
            short_name_edit.textChanged.connect(self.write_to_xml)
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        self.write_to_xml()
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    def read_table(self):
 | 
			
		||||
        vars_data = []
 | 
			
		||||
        for row in range(self.table.rowCount()):
 | 
			
		||||
            cb = self.table.cellWidget(row, rows.include)
 | 
			
		||||
            name_edit = self.table.cellWidget(row, rows.name)
 | 
			
		||||
            pt_type_combo = self.table.cellWidget(row, rows.pt_type)
 | 
			
		||||
            iq_combo = self.table.cellWidget(row, rows.iq_type)
 | 
			
		||||
            ret_combo = self.table.cellWidget(row, rows.ret_type)
 | 
			
		||||
            short_name_edit = self.table.cellWidget(row, rows.short_name)
 | 
			
		||||
            origin_item = self.table.item(row, rows.type)
 | 
			
		||||
 | 
			
		||||
            vars_data.append({
 | 
			
		||||
                'show_var': True,
 | 
			
		||||
                'enable': cb.isChecked() if cb else False,
 | 
			
		||||
                'name': name_edit.text() if name_edit else '',
 | 
			
		||||
                'pt_type': 'pt_' + pt_type_combo.currentText() if pt_type_combo else '',
 | 
			
		||||
                'iq_type': iq_combo.currentText() if iq_combo else '',
 | 
			
		||||
                'return_type': ret_combo.currentText() if ret_combo else '',
 | 
			
		||||
                'shortname': short_name_edit.text() if short_name_edit else '',
 | 
			
		||||
                'type': origin_item.text() if origin_item else '',
 | 
			
		||||
            })
 | 
			
		||||
        return vars_data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def write_to_xml(self):
 | 
			
		||||
        self.update_all_paths()
 | 
			
		||||
 | 
			
		||||
@ -682,7 +505,7 @@ class VarEditor(QWidget):
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
            # Читаем переменные из таблицы (активные/изменённые)
 | 
			
		||||
            table_vars = {v['name']: v for v in self.read_table()}
 | 
			
		||||
            table_vars = {v['name']: v for v in self.table.read_data()}
 | 
			
		||||
            # Все переменные (в том числе новые, которых нет в таблице)
 | 
			
		||||
            all_vars_by_name = {v['name']: v for v in self.vars_list}
 | 
			
		||||
 | 
			
		||||
@ -707,8 +530,11 @@ class VarEditor(QWidget):
 | 
			
		||||
                        el = ET.SubElement(parent, tag)
 | 
			
		||||
                    el.text = str(text)
 | 
			
		||||
 | 
			
		||||
                set_sub_elem_text(var_elem, 'show_var', v.get('show_var', 'false'))
 | 
			
		||||
                set_sub_elem_text(var_elem, 'enable', v.get('enable', 'false'))
 | 
			
		||||
                show_var_val = str(v.get('show_var', 'false')).lower()
 | 
			
		||||
                enable_val = str(v_table['enable'] if v_table and 'enable' in v_table else v.get('enable', 'false')).lower()
 | 
			
		||||
 | 
			
		||||
                set_sub_elem_text(var_elem, 'show_var', show_var_val)
 | 
			
		||||
                set_sub_elem_text(var_elem, 'enable', enable_val)
 | 
			
		||||
 | 
			
		||||
                # Тут подтягиваем из таблицы, если есть, иначе из v
 | 
			
		||||
                shortname_val = v_table['shortname'] if v_table and 'shortname' in v_table else v.get('shortname', '')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										82
									
								
								vars.xml
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								vars.xml
									
									
									
									
									
								
							@ -1,5 +1,5 @@
 | 
			
		||||
<?xml version="1.0" ?>
 | 
			
		||||
<analysis proj_path="E:\.WORK\TMS\TMS_new_bus" makefile_path="E:\.WORK\TMS\TMS_new_bus\Debug\makefile" structs_path="E:\.WORK\TMS\TMS_new_bus\Src\DebugTools\structs.xml">
 | 
			
		||||
<?xml version='1.0' encoding='utf-8'?>
 | 
			
		||||
<analysis proj_path="F:/Work/Projects/TMS/TMS_new_bus" makefile_path="Debug/makefile" structs_path="Src/DebugTools/structs.xml">
 | 
			
		||||
  <variables>
 | 
			
		||||
    <var name="ADC0finishAddr">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -14,7 +14,7 @@
 | 
			
		||||
      <static>false</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="ADC0startAddr">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
      <show_var>true</show_var>
 | 
			
		||||
      <enable>true</enable>
 | 
			
		||||
      <shortname>ADC0startAddr</shortname>
 | 
			
		||||
      <pt_type>pt_int16</pt_type>
 | 
			
		||||
@ -407,7 +407,7 @@
 | 
			
		||||
      <type>char[8][16]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="IN0finishAddr">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -863,7 +863,7 @@
 | 
			
		||||
      <type>int[12]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="biTemperatureWarnings">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -875,7 +875,7 @@
 | 
			
		||||
      <type>int[12]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="block_size_counter_fast">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -959,7 +959,7 @@
 | 
			
		||||
      <type>int[12]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="bvTemperatureWarnings">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -971,7 +971,7 @@
 | 
			
		||||
      <type>int[12]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="byte">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1151,7 +1151,7 @@
 | 
			
		||||
      <type>char[4]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="cmd_finish1">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1163,7 +1163,7 @@
 | 
			
		||||
      <type>char</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="cmd_finish2">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1175,7 +1175,7 @@
 | 
			
		||||
      <type>char</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="cmd_start">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1187,7 +1187,7 @@
 | 
			
		||||
      <type>char[5]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="cmd_txt">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1199,7 +1199,7 @@
 | 
			
		||||
      <type>char[4][8]</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="compress_size">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1283,7 +1283,7 @@
 | 
			
		||||
      <type>unsigned int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myXilinx/x_serial_bus.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="crc_16_tab">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1319,7 +1319,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/message_modbus.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="cur_position_buf_modbus16_can">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1343,7 +1343,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/message_modbus.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="cycle">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1367,7 +1367,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="data_to_umu1_8">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1379,7 +1379,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="data_to_umu2_7f">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1391,7 +1391,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="data_to_umu2_8">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1403,7 +1403,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/init_protect_levels.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="delta_capnum">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -1451,7 +1451,7 @@
 | 
			
		||||
      <type>DQ_TO_ALPHABETA</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/v_pwm24.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="enable_can">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2039,7 +2039,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="koef_Base_stop_run">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2279,7 +2279,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="length">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2375,7 +2375,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/PWMTMSHandle.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mPWM_b">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2387,7 +2387,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/PWMTMSHandle.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="m_PWM">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2531,7 +2531,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mzz_limit_1000">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2543,7 +2543,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mzz_limit_1100">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2555,7 +2555,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mzz_limit_1200">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2567,7 +2567,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mzz_limit_1400">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2579,7 +2579,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mzz_limit_1500">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2591,7 +2591,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mzz_limit_2000">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2603,7 +2603,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="mzz_limit_500">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -2615,7 +2615,7 @@
 | 
			
		||||
      <type>int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/modbus_read_table.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="new_cycle_fifo">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -3311,7 +3311,7 @@
 | 
			
		||||
      <type>unsigned int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/main22220.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="timePauseCAN_Messages">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -3323,7 +3323,7 @@
 | 
			
		||||
      <type>unsigned int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/main/main22220.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>true</static>
 | 
			
		||||
      <static>True</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="time_alg">
 | 
			
		||||
      <show_var>false</show_var>
 | 
			
		||||
@ -3577,18 +3577,6 @@
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>false</static>
 | 
			
		||||
    </var>
 | 
			
		||||
    <var name="Bender.KOhms">
 | 
			
		||||
      <show_var>true</show_var>
 | 
			
		||||
      <enable>true</enable>
 | 
			
		||||
      <shortname>Bender.KOhms</shortname>
 | 
			
		||||
      <pt_type>pt_uint16</pt_type>
 | 
			
		||||
      <iq_type>iq_none</iq_type>
 | 
			
		||||
      <return_type>iq_none</return_type>
 | 
			
		||||
      <type>unsigned int</type>
 | 
			
		||||
      <file>Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/DebugTools/Src/myLibs/bender.c</file>
 | 
			
		||||
      <extern>false</extern>
 | 
			
		||||
      <static>false</static>
 | 
			
		||||
    </var>
 | 
			
		||||
  </variables>
 | 
			
		||||
  <includes>
 | 
			
		||||
    <file>Src/main/vector.h</file>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user