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()
예제 #3
0
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)