class ForceActuatorBumpTestPageWidget(QWidget): """ Enable user to select actuator for bump test. Show graphs depicting actual demand and measured forces. Shows button to run a bump test and stop any running bump test. Parameters ---------- m1m3 : `SALComm object` SALComm communication object. """ def __init__(self, m1m3): super().__init__() self.m1m3 = m1m3 self.xIndex = self.yIndex = self.zIndex = self.sIndex = self.testedId = None self._testRunning = False actuatorBox = QGroupBox("Actuator") self.actuatorsTable = QTableWidget( max([row[FATABLE_ID] for row in FATABLE]) % 100, 12 ) self.actuatorsTable.setShowGrid(False) def setNone(r, c): item = QTableWidgetItem("") item.setFlags(Qt.NoItemFlags) self.actuatorsTable.setItem(r, c, item) for i in range(4): mr = min( [ row[FATABLE_ID] for row in FATABLE if row[FATABLE_ID] > (100 + 100 * i) ] ) for r in range(mr): for c in range(i * 3, (i * 3) + 2): setNone(r, c) for tr in range(len(FATABLE)): actuatorId = FATABLE[tr][FATABLE_ID] row = (actuatorId % 100) - 1 colOffset = 3 * (int(actuatorId / 100) - 1) def getItem(text): item = QTableWidgetItem(text) item.setData(Qt.UserRole, actuatorId) return item self.actuatorsTable.setItem(row, 0 + colOffset, getItem(str(actuatorId))) self.actuatorsTable.setItem(row, 1 + colOffset, getItem("P")) if FATABLE[tr][FATABLE_SINDEX] is None: setNone(row, 2 + colOffset) else: self.actuatorsTable.setItem( row, 2 + colOffset, getItem("Y" if (FATABLE[tr][FATABLE_XINDEX] is None) else "X"), ) self.actuatorsTable.horizontalHeader().hide() self.actuatorsTable.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents ) self.actuatorsTable.horizontalHeader().setStretchLastSection(False) self.actuatorsTable.verticalHeader().hide() self.actuatorsTable.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents ) self.actuatorsTable.itemSelectionChanged.connect(self.itemSelectionChanged) self.actuatorsTable.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.MinimumExpanding ) self.actuatorsTable.setFixedWidth( sum([self.actuatorsTable.columnWidth(c) for c in range(12)]) + self.actuatorsTable.verticalScrollBar().geometry().height() / 2 + 1 ) actuatorLayout = QVBoxLayout() actuatorLayout.addWidget(self.actuatorsTable) actuatorBox.setLayout(actuatorLayout) def testPB(): pb = QProgressBar() pb.setMaximum(6) return pb self.primaryPB = testPB() self.primaryLabelPB = QLabel("Primary") self.secondaryPB = testPB() self.secondaryLabelPB = QLabel("Seconday") self.progressGroup = QGroupBox("Test progress") progressLayout = QGridLayout() progressLayout.addWidget(self.primaryLabelPB, 0, 0) progressLayout.addWidget(self.primaryPB, 0, 1) progressLayout.addWidget(self.secondaryLabelPB, 1, 0) progressLayout.addWidget(self.secondaryPB, 1, 1) # progressLayout.addStretch(1) self.progressGroup.setLayout(progressLayout) self.progressGroup.setMaximumWidth(410) self.chart = None self.chart_view = TimeChartView() self.chart_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def makeButton(text, clicked): button = QPushButton(text) button.setEnabled(False) button.clicked.connect(clicked) return button self.bumpTestAllButton = makeButton("Bump test all", self.bumpTestAll) self.bumpTestButton = makeButton("Run bump test", self.issueCommandBumpTest) self.killBumpTestButton = makeButton( "Stop bump test", self.issueCommandKillBumpTest ) self.buttonLayout = QHBoxLayout() self.buttonLayout.addWidget(self.bumpTestAllButton) self.buttonLayout.addWidget(self.bumpTestButton) self.buttonLayout.addWidget(self.killBumpTestButton) self.layout = QVBoxLayout() self.forms = QHBoxLayout() self.forms.addWidget(actuatorBox) self.forms.addWidget(self.progressGroup) self.forms.addWidget(SALLog.Widget(self.m1m3)) self.layout.addLayout(self.forms) self.layout.addWidget(self.chart_view) self.layout.addLayout(self.buttonLayout) self.setLayout(self.layout) self.m1m3.detailedState.connect(self.detailedState) self.m1m3.forceActuatorBumpTestStatus.connect(self.forceActuatorBumpTestStatus) @Slot() def itemSelectionChanged(self): """Called when an actuator is selected from the list.""" items = self.actuatorsTable.selectedItems() if len(items) == 0: return if len(items) > 1: actuators = f"{items[0].data(Qt.UserRole)}..{items[-1].data(Qt.UserRole)}" else: actuators = f"{items[0].data(Qt.UserRole)}" self.bumpTestButton.setEnabled(not (self._anyCylinderRunning())) self.bumpTestButton.setText(f"Run bump test for FA ID {actuators}") def toggledTest(self, toggled): """Called when primary or secondary tests check box are toggled.""" self.bumpTestButton.setEnabled( self.actuatorsTable.currentItem() is not None and not (self._anyCylinderRunning()) ) @asyncSlot() async def bumpTestAll(self): for i in range(4): colOffset = i * 3 self.actuatorsTable.setRangeSelected( QTableWidgetSelectionRange( 0, 1 + colOffset, self.actuatorsTable.rowCount() - 1, 2 + colOffset, ), False, ) self.actuatorsTable.setRangeSelected( QTableWidgetSelectionRange( 0, colOffset, self.actuatorsTable.rowCount() - 1, colOffset ), True, ) await self._testItem(self.actuatorsTable.selectedItems()[0]) self.bumpTestButton.setEnabled(False) @asyncSlot() async def issueCommandBumpTest(self): """Call M1M3 bump test command.""" await self._testItem(self.actuatorsTable.selectedItems()[0]) async def _testItem(self, item): self.actuatorsTable.scrollToItem(item) self.testedId = item.data(Qt.UserRole) item.setSelected(False) self.zIndex = actuatorIDToIndex(self.testedId) self.xIndex = FATABLE[self.zIndex][FATABLE_XINDEX] self.yIndex = FATABLE[self.zIndex][FATABLE_YINDEX] self.sIndex = FATABLE[self.zIndex][FATABLE_SINDEX] items = [] if self.xIndex is not None: items.append("X") if self.yIndex is not None: items.append("Y") items.append("Z") items = ( list(map(lambda s: "Applied " + s, items)) + [None] + list(map(lambda s: "Measured " + s, items)) ) if self.chart is not None: self.chart.clearData() self.chart = TimeChart({"Force (N)": items}) self.chart_view.setChart(self.chart) self.progressGroup.setTitle(f"Test progress {self.testedId}") if self.sIndex is not None: self.secondaryLabelPB.setText("Y" if self.xIndex is None else "X") await self.m1m3.remote.cmd_forceActuatorBumpTest.set_start( actuatorId=self.testedId, testPrimary=not (item.text() == "X" or item.text() == "Y"), testSecondary=not (item.text() == "P") and self.sIndex is not None, ) self.killBumpTestButton.setText(f"Stop bump test FA ID {self.testedId}") @asyncSlot() async def issueCommandKillBumpTest(self): """Kill bump test.""" self.actuatorsTable.setRangeSelected( QTableWidgetSelectionRange(0, 0, self.actuatorsTable.rowCount() - 1, 11), False, ) await self.m1m3.remote.cmd_killForceActuatorBumpTest.start() @Slot(map) def detailedState(self, data): """Called when detailedState event is received. Intercept to enable/disable form buttons.""" if data.detailedState == MTM1M3.DetailedState.PARKEDENGINEERING: self.bumpTestAllButton.setEnabled(True) self.bumpTestButton.setEnabled( self.actuatorsTable.currentItem() is not None ) self.killBumpTestButton.setEnabled(False) self.xIndex = self.yIndex = self.zIndex = None else: self.bumpTestAllButton.setEnabled(False) self.bumpTestButton.setEnabled(False) self.killBumpTestButton.setEnabled(False) @Slot(map) def appliedForces(self, data): """Adds applied forces to graph.""" chartData = [] if self.xIndex is not None: chartData.append(data.xForces[self.xIndex]) if self.yIndex is not None: chartData.append(data.yForces[self.yIndex]) if self.zIndex is not None: chartData.append(data.zForces[self.zIndex]) self.chart.append(data.timestamp, chartData, cache_index=0) @Slot(map) def forceActuatorData(self, data): """Adds measured forces to graph.""" chartData = [] if self.xIndex is not None: chartData.append(data.xForce[self.xIndex]) if self.yIndex is not None: chartData.append(data.yForce[self.yIndex]) if self.zIndex is not None: chartData.append(data.zForce[self.zIndex]) self.chart.append(data.timestamp, chartData, cache_index=1) @asyncSlot(map) async def forceActuatorBumpTestStatus(self, data): """Received when an actuator finish/start running bump tests or the actuator reports progress of the bump test.""" testProgress = [ "Not tested", "Testing start zero", "Testing positive", "Positive wait zero", "Testing negative", "Negative wait zero", "Passed", "Failed", ] # test progress if self.zIndex is not None: self.primaryPB.setEnabled(True) val = data.primaryTest[self.zIndex] self.primaryPB.setFormat(f"ID {self.testedId} - {testProgress[val]} - %v") self.primaryPB.setValue(min(6, val)) else: self.primaryPB.setEnabled(False) if self.sIndex is not None: self.secondaryPB.setEnabled(True) val = data.secondaryTest[self.sIndex] self.secondaryPB.setFormat(f"ID {self.testedId} - {testProgress[val]} - %v") self.secondaryPB.setValue(min(6, val)) else: self.secondaryPB.setEnabled(False) # list display for index in range(156): actuatorId = FATABLE[index][FATABLE_ID] row = (actuatorId % 100) - 1 colOffset = 3 * (int(actuatorId / 100) - 1) def getColor(value): if value == 6: return Qt.green elif value == 7: return Qt.red elif not (value == 0): return Qt.magenta return Qt.transparent pColor = getColor(data.primaryTest[index]) self.actuatorsTable.item(row, colOffset + 1).setBackground(pColor) sIndex = FATABLE[index][FATABLE_SINDEX] if sIndex is not None: sColor = getColor(data.secondaryTest[sIndex]) self.actuatorsTable.item(row, colOffset + 2).setBackground(sColor) if pColor == sColor: self.actuatorsTable.item(row, colOffset).setBackground(pColor) else: self.actuatorsTable.item(row, colOffset).setBackground(pColor) # no tests running.. if data.actuatorId < 0: selected = self.actuatorsTable.selectedItems() if len(selected) > 0: await self._testItem(selected[0]) elif self._testRunning: self.bumpTestAllButton.setEnabled(True) self.bumpTestButton.setEnabled( self.actuatorsTable.currentItem() is not None and self._anyCylinder() ) self.killBumpTestButton.setEnabled(False) self.xIndex = self.yIndex = self.zIndex = None self.m1m3.appliedForces.disconnect(self.appliedForces) self.m1m3.forceActuatorData.disconnect(self.forceActuatorData) self._testRunning = False elif self._testRunning is False: self.bumpTestButton.setEnabled(False) self.killBumpTestButton.setEnabled(True) self.m1m3.appliedForces.connect(self.appliedForces) self.m1m3.forceActuatorData.connect(self.forceActuatorData) self._testRunning = True # helper functions. Helps correctly enable/disable Run bump test button. def _anyCylinderRunning(self): return self._testRunning is True and self._anyCylinder() def _anyCylinder(self): return len(self.actuatorsTable.selectedItems()) > 0
class AddRecipeWidget(QWidget): def __init__(self, database, parent): QWidget.__init__(self) self.recipe_ingredients = 0 self.add_recipe_win = QWidget() self.add_recipe_win.setFixedWidth(400) self.add_recipe_win.setWindowTitle("Add Recipe") add_rec_main_layout = QVBoxLayout() self.meal_planner_db = database self.setParent(parent) self.rec_name_input = QLineEdit() self.rec_desc_input = QLineEdit() self.rec_source_input = QLineEdit() rec_form_layout = QFormLayout() rec_form_layout.addRow(QLabel("Recipe Name"), self.rec_name_input) rec_form_layout.addRow(QLabel("Recipe Desc"), self.rec_desc_input) rec_form_layout.addRow(QLabel("Recipe Source"), self.rec_source_input) add_rec_main_layout.addLayout(rec_form_layout) rec_info_layout = QHBoxLayout() difficulty_layout = QVBoxLayout() self.difficulty_spinbox = QSpinBox() self.difficulty_spinbox.setRange(1, 5) self.difficulty_spinbox.setValue(3) difficulty_layout.addWidget(QLabel("Difficulty")) difficulty_layout.addWidget(self.difficulty_spinbox) prep_time_layout = QVBoxLayout() self.prep_time_spinbox = QSpinBox() self.prep_time_spinbox.setRange(0, 600) self.prep_time_spinbox.setValue(30) prep_time_layout.addWidget(QLabel("Prep. Time (min.)")) prep_time_layout.addWidget(self.prep_time_spinbox) rating_layout = QVBoxLayout() self.rating_spinbox = QSpinBox() self.rating_spinbox.setRange(1, 5) self.rating_spinbox.setValue(3) rating_layout.addWidget(QLabel("Rating")) rating_layout.addWidget(self.rating_spinbox) rec_info_layout.addLayout(difficulty_layout) rec_info_layout.addLayout(prep_time_layout) rec_info_layout.addLayout(rating_layout) add_rec_main_layout.addLayout(rec_info_layout) rec_tags_layout = QHBoxLayout() rec_cuisine_layout = QVBoxLayout() cuisines = [ "Mexican", "Swedish", "Austrian", "Italian", "Spanish", "American", "British", "Thai", "Greek", "Vietnamese", "Caribbean", "Japanese", "Chinese", "Indian", "French", "Swiss", "Portuguese", "Korean", "Turkish", "Moroccan", "Russian", "Malaysian", "Philippines", "Ethiopian", "Lebanese", "Arab", "Peruvian", "Brazilian", "Asian", "Middle Eastern", "South American", "African", "-" ] cuisines.sort() self.tag_cuisine = QComboBox() self.tag_cuisine.addItems(cuisines) rec_cuisine_layout.addWidget(QLabel("Cuisine")) rec_cuisine_layout.addWidget(self.tag_cuisine) rec_tags_layout.addLayout(rec_cuisine_layout) rec_category_layout = QVBoxLayout() categories = [ "Beef & Calf", "Chicken & Poultry", "Lamb", "Pork", "Preservation", "Salad", "Sandwich", "Soup", "Stew", "Pasta", "Rice", "Grain & Beans", "Fish & Seafood", "Vegetables", "Eggs & Cheese", "BBQ", "Fruits", "Cake & Pie (Sweet)", "Pie", "Bread", "Beverage", "Cookies & Sweets", "Sauce", "-" ] categories.sort() self.tag_category = QComboBox() self.tag_category.addItems(categories) rec_category_layout.addWidget(QLabel("Category")) rec_category_layout.addWidget(self.tag_category) rec_tags_layout.addLayout(rec_category_layout) rec_meal_type_layout = QVBoxLayout() meal_types = [ "Breakfast", "Brunch", "Lunch", "Dinner", "Dessert", "Starter", "Side", "Buffet", "Snack", "-" ] meal_types.sort() self.tag_meal_types = QComboBox() self.tag_meal_types.addItems(meal_types) rec_meal_type_layout.addWidget(QLabel("Meal Type")) rec_meal_type_layout.addWidget(self.tag_meal_types) rec_tags_layout.addLayout(rec_meal_type_layout) add_rec_main_layout.addLayout(rec_tags_layout) self.ingredient_name_input = QLineEdit() self.ingredient_qty_input = QDoubleSpinBox() self.ingredient_qty_input.setValue(1.0) self.ingredient_qty_input.setMaximum(1000) self.ingredient_qty_input.setDecimals(2) self.ingredient_unit_input = QComboBox() self.ingredient_unit_input.addItems( ["g", "ml", "dl", "l", "msk", "tsk", "st", "-"]) add_ingredient_btn = QPushButton("Create ingredient") add_ingredient_btn.clicked.connect(self.create_ingredient) add_ingredient_layout = QHBoxLayout() add_rec_main_layout.addWidget(QLabel("Ingredient")) add_ingredient_layout.addWidget(self.ingredient_name_input) add_ingredient_layout.addWidget(self.ingredient_qty_input) add_ingredient_layout.addWidget(self.ingredient_unit_input) add_ingredient_layout.addWidget(add_ingredient_btn) add_rec_main_layout.addLayout(add_ingredient_layout) btn_layout = QHBoxLayout() add_ingredient_to_recipe_btn = QPushButton("Add ingredient") add_ingredient_to_recipe_btn.clicked.connect( self.add_ingredient_to_recipe) del_ingredient_from_recipe_btn = QPushButton("Remove ingredient") del_ingredient_from_recipe_btn.clicked.connect( self.del_ingredient_from_recipe) btn_layout.addWidget(add_ingredient_to_recipe_btn) btn_layout.addWidget(del_ingredient_from_recipe_btn) add_rec_main_layout.addLayout(btn_layout) self.rec_ingredient_table = QTableWidget() self.rec_ingredient_table.setColumnCount(3) self.rec_ingredient_table.setHorizontalHeaderLabels( ["Amount", "Unit", "Ingredient"]) header = self.rec_ingredient_table.horizontalHeader() header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents) header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents) header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch) add_rec_main_layout.addWidget(self.rec_ingredient_table) self.step_count = 0 self.add_recipe_step_btn = QPushButton("Add recipe instruction") add_rec_main_layout.addWidget(self.add_recipe_step_btn) self.add_recipe_step_btn.clicked.connect(self.add_recipe_step_win) self.rec_step_table = QTableWidget() self.rec_step_table.setColumnCount(1) self.rec_step_table.setHorizontalHeaderLabels(["Instructions"]) self.rec_step_table.setWordWrap(True) header = self.rec_step_table.horizontalHeader() header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch) add_rec_main_layout.addWidget(self.rec_step_table) bottom_btn_layout = QHBoxLayout() self.add_rec_btn = QPushButton("Add recipe") self.add_rec_btn.clicked.connect(self.add_recipe_to_db) self.back_btn = QPushButton("Cancel") self.back_btn.clicked.connect(self.add_recipe_win.close) bottom_btn_layout.addWidget(self.add_rec_btn) bottom_btn_layout.addWidget(self.back_btn) add_rec_main_layout.addLayout(bottom_btn_layout) self.add_recipe_win.setLayout(add_rec_main_layout) self.add_recipe_win.show() @Slot() def add_recipe_step_win(self): self.rec_step_table.insertRow(self.step_count) self.step_count += 1 @Slot() def create_ingredient(self): self.add_ingredient_widget = AddIngredientWidget( self.meal_planner_db, self, self.ingredient_name_input.text()) @Slot() def add_ingredient_to_recipe(self): if self.meal_planner_db.ingredient_exists( self.ingredient_name_input.text()): self.rec_ingredient_table.insertRow(self.recipe_ingredients) self.rec_ingredient_table.setItem( self.recipe_ingredients, 0, QTableWidgetItem(str(self.ingredient_qty_input.value()))) self.rec_ingredient_table.setItem( self.recipe_ingredients, 1, QTableWidgetItem(self.ingredient_unit_input.currentText())) self.rec_ingredient_table.setItem( self.recipe_ingredients, 2, QTableWidgetItem(self.ingredient_name_input.text())) self.recipe_ingredients += 1 self.ingredient_name_input.clear() self.ingredient_qty_input.setValue(1.0) self.ingredient_unit_input.setCurrentIndex(0) else: print("Ingredient does not exist in database, please add it first") @Slot() def del_ingredient_from_recipe(self): recipe = self.rec_name_input.text() ingredient = self.rec_ingredient_table.currentItem().text() self.rec_ingredient_table.removeRow( self.rec_ingredient_table.currentRow()) self.meal_planner_db.del_recipe_ingredient(recipe, ingredient) @Slot() def add_recipe_to_db(self): rec_id = self.meal_planner_db.get_table_len("recipes") self.meal_planner_db.add_recipe(rec_id, self.rec_name_input.text(), self.rec_desc_input.text(), self.rec_source_input.text(), self.difficulty_spinbox.value(), self.prep_time_spinbox.value(), self.rating_spinbox.value(), "2000-01-01", 0) for row in range(self.rec_ingredient_table.rowCount()): qty_id = self.meal_planner_db.get_table_len("measurement_qty") qty_id = self.meal_planner_db.add_qty( qty_id, self.rec_ingredient_table.item(row, 0).text()) unit_id = self.meal_planner_db.get_table_len("measurement_units") unit_id = self.meal_planner_db.add_measurement( unit_id, self.rec_ingredient_table.item(row, 1).text()) ing_id = self.meal_planner_db.get_ingredient_id( self.rec_ingredient_table.item(row, 2).text()) if ing_id == -1: print("INGREDIENT DOES NOT EXIST! WE F****D UP!") break self.meal_planner_db.add_recipe_ingredient(rec_id, ing_id, unit_id, qty_id) for row in range(self.step_count): print(row, self.rec_step_table.item(row, 0).text()) self.meal_planner_db.add_step( rec_id, row, self.rec_step_table.item(row, 0).text()) # Cuisine tag tag_id = self.meal_planner_db.get_table_len("tags") tag_id = self.meal_planner_db.add_tag(tag_id, self.tag_cuisine.currentText()) self.meal_planner_db.add_recipe_tag(tag_id, rec_id) # Category tag tag_id = self.meal_planner_db.get_table_len("tags") tag_id = self.meal_planner_db.add_tag(tag_id, self.tag_category.currentText()) self.meal_planner_db.add_recipe_tag(tag_id, rec_id) # Meal type tag tag_id = self.meal_planner_db.get_table_len("tags") tag_id = self.meal_planner_db.add_tag( tag_id, self.tag_meal_types.currentText()) self.meal_planner_db.add_recipe_tag(tag_id, rec_id) self.rec_name_input.clear() self.rec_desc_input.clear() self.rec_ingredient_table.setRowCount(0) self.rec_step_table.setRowCount(0) self.step_count = 0 self.parent().update_recipe_table()
class GameControlPanel(QWidget): def __init__(self, first: str, second: str, parent=None): super(GameControlPanel, self).__init__(parent) # buttons on the top self.flipButton = QPushButton("*") self.toStartFenButton = QPushButton("<<") self.previousMoveButton = QPushButton("<") self.nextMoveButton = QPushButton(">") self.toCurrentFenButton = QPushButton(">>") self.flipButton.setFixedWidth(45) self.toStartFenButton.setFixedWidth(45) self.previousMoveButton.setFixedWidth(45) self.nextMoveButton.setFixedWidth(45) self.toStartFenButton.setFixedWidth(45) self.toStartFenButton.setDisabled(True) self.previousMoveButton.setDisabled(True) self.nextMoveButton.setDisabled(True) self.toCurrentFenButton.setDisabled(True) self.toolButtonsLayout = QHBoxLayout() self.toolButtonsLayout.setContentsMargins(0, 0, 0, 0) self.toolButtonsLayout.addWidget(self.flipButton) self.toolButtonsLayout.addWidget(self.toStartFenButton) self.toolButtonsLayout.addWidget(self.previousMoveButton) self.toolButtonsLayout.addWidget(self.nextMoveButton) self.toolButtonsLayout.addWidget(self.toCurrentFenButton) self.toolButtonsLayout.addStretch() self.toolButtonsLayout.setSpacing(14) # the column that contains the first empty cell. self.nextColumn = 0 self.firstMaterial = QLabel() self.firstName = QLabel(first) self.secondName = QLabel(second) self.secondMaterial = QLabel() self.moveTable = QTableWidget() self.moveTable.setEditTriggers(QTableWidget.NoEditTriggers) self.moveTable.setFocusPolicy(Qt.NoFocus) self.moveTable.setSelectionMode(QTableWidget.SingleSelection) self.moveTable.currentCellChanged.connect(self.onCurrentChanged) self.moveTable.setFixedWidth(320) self.moveTable.setColumnCount(2) self.moveTable.horizontalHeader().hide() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addStretch() layout.addWidget(self.firstMaterial) layout.addLayout(self.toolButtonsLayout) layout.addWidget(self.firstName) layout.addWidget(self.moveTable) layout.addWidget(self.secondName) layout.addWidget(self.secondMaterial) layout.addStretch() layout.setSpacing(0) self.setLayout(layout) def isLive(self) -> bool: if not self.moveTable.rowCount(): return True return (self.moveTable.currentRow() == self.moveTable.rowCount() - 1 and self.moveTable.currentColumn() != self.nextColumn) def reset(self): self.moveTable.setRowCount(0) self.nextColumn = 0 self.toStartFenButton.setDisabled(True) self.previousMoveButton.setDisabled(True) self.nextMoveButton.setDisabled(True) self.toCurrentFenButton.setDisabled(True) @Slot(int, int) def onCurrentChanged(self, row, column): self.toStartFenButton.setDisabled(self.moveTable.currentItem() is None) self.previousMoveButton.setDisabled(self.moveTable.currentItem() is None) def toPreviousCell(self): current = self.moveTable.currentItem() if current is not None: row = current.row() column = current.column() if row == column == 0: self.moveTable.setCurrentCell(-1, -1) else: prevCoord = row * 2 + column - 1 if prevCoord % 2: row -= 1 self.moveTable.setCurrentCell(row, not column) def toNextCell(self): current = self.moveTable.currentItem() if self.moveTable.rowCount(): if current is None: self.moveTable.setCurrentCell(0, 0) else: row = current.row() column = current.column() nextCoord = row * 2 + column + 1 if nextCoord % 2 == 0: row += 1 self.moveTable.setCurrentCell(row, not column) def addMove(self, move: str) -> QTableWidgetItem: if self.isLive(): if not self.nextColumn: self.moveTable.setRowCount(self.moveTable.rowCount() + 1) item = QTableWidgetItem(move) self.moveTable.setItem(self.moveTable.rowCount()-1, self.nextColumn, item) self.nextColumn = not self.nextColumn return item def popMove(self): if self.moveTable.rowCount(): if self.isLive(): self.toPreviousCell() self.nextColumn = not self.nextColumn self.moveTable.takeItem(self.moveTable.rowCount() - 1, self.nextColumn) if not self.nextColumn: self.moveTable.setRowCount(self.moveTable.rowCount()-1) def swapNames(self): tempFirstMaterial = self.firstMaterial.text() tempFirstName = self.firstName.text() self.firstMaterial.setText(self.secondMaterial.text()) self.secondMaterial.setText(tempFirstMaterial) self.firstName.setText(self.secondName.text()) self.secondName.setText(tempFirstName)