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