# HG changeset patch # User Michiel Broek # Date 1652886185 -7200 # Node ID fa7cad488e271f0814c529a541abf2dc96c63c8f # Parent 725da10db56c04583de45a3ad149b45c72f7db84 Added fermentation stages data. The two graphs are for later. diff -r 725da10db56c -r fa7cad488e27 src/EditProduct.cpp --- a/src/EditProduct.cpp Wed May 18 08:59:54 2022 +0200 +++ b/src/EditProduct.cpp Wed May 18 17:03:05 2022 +0200 @@ -1117,6 +1117,27 @@ connect(ui->brew_topupwaterEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::brew_topupwater_changed); connect(ui->brew_logButton, SIGNAL(clicked()), this, SLOT(brew_log_button())); + /* All signals from tab Fermentation */ + connect(ui->prim_startCEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::primary_start_changed); + connect(ui->prim_maxCEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::primary_peak_changed); + connect(ui->prim_endCEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::primary_end_changed); + connect(ui->prim_endsgEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::primary_sg_changed); + connect(ui->prim_endsgButton, SIGNAL(clicked()), this, SLOT(primary_sg_button())); + connect(ui->prim_enddateEdit, &QDateEdit::dateChanged, this, &EditProduct::primary_date_changed); + connect(ui->prim_enddateButton, SIGNAL(clicked()), this, SLOT(primary_date_button())); + connect(ui->prim_ackButton, SIGNAL(clicked()), this, SLOT(primary_date_ack())); + connect(ui->sec_tempEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::secondary_temp_changed); + connect(ui->sec_sgEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::secondary_sg_changed); + connect(ui->sec_sgButton, SIGNAL(clicked()), this, SLOT(secondary_sg_button())); + connect(ui->sec_enddateEdit, &QDateEdit::dateChanged, this, &EditProduct::secondary_date_changed); + connect(ui->sec_enddateButton, SIGNAL(clicked()), this, SLOT(secondary_date_button())); + connect(ui->sec_ackButton, SIGNAL(clicked()), this, SLOT(secondary_date_ack())); + connect(ui->tert_tempEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::tertiary_temp_changed); + connect(ui->tert_sgEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::tertiary_sg_changed); + connect(ui->tert_sgButton, SIGNAL(clicked()), this, SLOT(tertiary_sg_button())); + connect(ui->ferm_log1Button, SIGNAL(clicked()), this, SLOT(ferm_log1_button())); + connect(ui->ferm_log2Button, SIGNAL(clicked()), this, SLOT(ferm_log2_button())); + setStage(); ui->saveButton->setEnabled(false); diff -r 725da10db56c -r fa7cad488e27 src/EditProduct.h --- a/src/EditProduct.h Wed May 18 08:59:54 2022 +0200 +++ b/src/EditProduct.h Wed May 18 17:03:05 2022 +0200 @@ -174,6 +174,26 @@ void brew_trubloss_changed(double val); void brew_topupwater_changed(double val); void brew_log_button(); + void brix_changed(double val); + void primary_start_changed(double val); + void primary_peak_changed(double val); + void primary_end_changed(double val); + void primary_sg_changed(double val); + void primary_sg_button(); + void primary_date_changed(QDate val); + void primary_date_button(); + void primary_date_ack(); + void secondary_temp_changed(double val); + void secondary_sg_changed(double val); + void secondary_sg_button(); + void secondary_date_changed(QDate val); + void secondary_date_button(); + void secondary_date_ack(); + void tertiary_temp_changed(double val); + void tertiary_sg_changed(double val); + void tertiary_sg_button(); + void ferm_log1_button(); + void ferm_log2_button(); /* Modified progress bars */ void ferment_perc_mash_valueChanged(int value); @@ -195,6 +215,7 @@ QString bar_100 = "QProgressBar::chunk {background: #80FF80;}"; int recno; bool textIsChanged = false; + double ret_fg; /* * Variables for popup ingredients editing. */ @@ -249,6 +270,7 @@ void calcEfficiencyBeforeBoil(); void calcEfficiencyAfterBoil(); void brew_volume_calc(double volume, double kettle_volume, double kettle_height, double est_volume, bool aboil); + double get_fg(double gravity); }; #endif diff -r 725da10db56c -r fa7cad488e27 src/EditProductTab1.cpp --- a/src/EditProductTab1.cpp Wed May 18 08:59:54 2022 +0200 +++ b/src/EditProductTab1.cpp Wed May 18 17:03:05 2022 +0200 @@ -202,6 +202,8 @@ stage = PROD_STAGE_BREW; if ((stage == PROD_STAGE_BREW) && (! product->brew_date_start.date().isValid())) stage = PROD_STAGE_WAIT; + /* from PROD_STAGE_BREW to PROD_STAGE_PRIMARY is handled in EditProductTab9.cpp */ + /* from PROD_STAGE_PRIMARY to PROD_STAGE_SECONDARY is handled in EditProductTab10.cpp */ if (product->stage != stage) { qDebug() << "setStage() change state:" << prod_stages[product->stage] << "to:" << prod_stages[stage]; @@ -312,6 +314,7 @@ ui->brew_startButton1->show(); ui->brew_startButton2->show(); ui->brew_startDate->setReadOnly(false); + ui->brew_startDate->setMinimumDate(product->birth.addDays(-1)); // The birth date is the first valid date. ui->brew_endButton1->hide(); ui->brew_startLabel2->hide(); ui->brew_endLabel->hide(); @@ -422,7 +425,63 @@ /* Tab 10, fermentation */ ui->tabWidget->setTabEnabled(9, stage > PROD_STAGE_WAIT); - + ui->prim_enddateEdit->setReadOnly(true); + ui->prim_enddateEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + ui->prim_enddateButton->hide(); + ui->prim_ackButton->hide(); + ui->sec_enddateEdit->setReadOnly(true); + ui->sec_enddateEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + ui->sec_enddateButton->hide(); + ui->sec_ackButton->hide(); + ui->prim_startCEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY); + ui->prim_startCEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + ui->prim_maxCEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY); + ui->prim_maxCEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + ui->prim_endCEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY); + ui->prim_endCEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + ui->prim_endsgEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY); + ui->prim_endsgEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + if (product->stage == PROD_STAGE_PRIMARY) + ui->prim_endsgButton->show(); + else + ui->prim_endsgButton->hide(); + if ((product->primary_start_temp > 0) && (product->primary_max_temp > 0) && (product->primary_end_temp > 0) && + (product->primary_end_sg > 0.980) && (product->stage == PROD_STAGE_PRIMARY)) { + ui->prim_enddateEdit->setReadOnly(false); + ui->prim_enddateEdit->setButtonSymbols(QAbstractSpinBox::UpDownArrows); + ui->prim_enddateEdit->setMinimumDate(product->brew_date_end.date()); + ui->prim_enddateEdit->setMaximumDate(QDate::currentDate()); + ui->prim_enddateButton->show(); + if (product->primary_end_date.isValid()) { + ui->prim_ackButton->show(); + } + } + ui->sec_tempEdit->setReadOnly(product->stage != PROD_STAGE_SECONDARY); + ui->sec_tempEdit->setButtonSymbols((product->stage == PROD_STAGE_SECONDARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + ui->sec_sgEdit->setReadOnly(product->stage != PROD_STAGE_SECONDARY); + ui->sec_sgEdit->setButtonSymbols((product->stage == PROD_STAGE_SECONDARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + if (product->stage == PROD_STAGE_SECONDARY) + ui->sec_sgButton->show(); + else + ui->sec_sgButton->hide(); + if ((product->secondary_end_sg > 0.980) && (product->secondary_temp > 0) && (product->stage == PROD_STAGE_SECONDARY)) { + ui->sec_enddateEdit->setReadOnly(false); + ui->sec_enddateEdit->setButtonSymbols(QAbstractSpinBox::UpDownArrows); + ui->sec_enddateEdit->setMinimumDate(product->primary_end_date.addDays(-1)); // Allow same date as primary end. + ui->sec_enddateEdit->setMaximumDate(QDate::currentDate()); + ui->sec_enddateButton->show(); + if (product->secondary_end_date.isValid()) { + ui->sec_ackButton->show(); + } + } + ui->tert_tempEdit->setReadOnly(product->stage != PROD_STAGE_TERTIARY); + ui->tert_tempEdit->setButtonSymbols((product->stage == PROD_STAGE_TERTIARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + ui->tert_sgEdit->setReadOnly(product->stage != PROD_STAGE_TERTIARY); + ui->tert_sgEdit->setButtonSymbols((product->stage == PROD_STAGE_TERTIARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); + if (product->stage == PROD_STAGE_TERTIARY) + ui->tert_sgButton->show(); + else + ui->tert_sgButton->hide(); /* Tab 11, packaging */ ui->tabWidget->setTabEnabled(10, stage > PROD_STAGE_PLAN); diff -r 725da10db56c -r fa7cad488e27 src/EditProductTab10.cpp --- a/src/EditProductTab10.cpp Wed May 18 08:59:54 2022 +0200 +++ b/src/EditProductTab10.cpp Wed May 18 17:03:05 2022 +0200 @@ -1,7 +1,7 @@ /** * EditProduct.cpp is part of bmsapp. * - * Tab 2, equipment settings. + * Tab 10, fermentation stages. * * bmsapp is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,3 +18,258 @@ */ +void EditProduct::brix_changed(double val) +{ + ret_fg = Utils::brix_to_fg(Utils::sg_to_plato(product->brew_fermenter_sg), val); + //qDebug() << "brix_changed" << val << product->brew_fermenter_sg << ret_fg; +} + + +double EditProduct::get_fg(double gravity) +{ + QDialog* dialog = new QDialog(this); + dialog->resize(360, 110); + QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); + buttonBox->setObjectName(QString::fromUtf8("buttonBox")); + buttonBox->setGeometry(QRect(30, 60, 300, 32)); + buttonBox->setLayoutDirection(Qt::LeftToRight); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + buttonBox->setCenterButtons(true); + + QLabel *brixLabel = new QLabel(dialog); + brixLabel->setObjectName(QString::fromUtf8("brixLabel")); + brixLabel->setText(tr("Refractometer Brix:")); + brixLabel->setGeometry(QRect(10, 20, 161, 24)); + brixLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + + QDoubleSpinBox *brixEdit = new QDoubleSpinBox(dialog); + brixEdit->setObjectName(QString::fromUtf8("brixEdit")); + brixEdit->setGeometry(QRect(180, 20, 101, 24)); + brixEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + brixEdit->setAccelerated(true); + brixEdit->setDecimals(1); + brixEdit->setMaximum(32.0); + brixEdit->setSingleStep(0.1); + /* + * Search the Brix value that is needed to get this gravity. + * Set the found value as preset in the spinbox. + */ + double brix = 0.0; + for (brix = 0.0; brix < 32.0; brix += 0.1) { + if (Utils::brix_to_fg(Utils::sg_to_plato(product->brew_fermenter_sg), brix) >= gravity) + break; + } + brixEdit->setValue(brix); + + connect(brixEdit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::brix_changed); + connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); + + dialog->setModal(true); + dialog->exec(); + if (dialog->result() == QDialog::Rejected) { + ret_fg = gravity; + } + + disconnect(brixEdit, nullptr, nullptr, nullptr); + disconnect(buttonBox, nullptr, nullptr, nullptr); + return ret_fg; +} + + +void EditProduct::primary_start_changed(double val) +{ + product->primary_start_temp = val; + is_changed(); + setStage(); +} + + +void EditProduct::primary_peak_changed(double val) +{ + product->primary_max_temp = val; + is_changed(); + setStage(); +} + + +void EditProduct::primary_end_changed(double val) +{ + product->primary_end_temp = val; + is_changed(); + setStage(); +} + + +void EditProduct::primary_sg_changed(double val) +{ + if (product->primary_end_sg == 0 && val == 0.001) { + product->primary_end_sg = 0.990; + const QSignalBlocker blocker1(ui->prim_endsgEdit); + ui->prim_endsgEdit->setValue(0.990); + } else { + product->primary_end_sg = val; + } + ui->prim_attShow->setValue(Utils::calc_svg(product->brew_fermenter_sg, product->primary_end_sg)); + is_changed(); + setStage(); +} + + +void EditProduct::primary_sg_button() +{ + double rc = get_fg(product->primary_end_sg); + ui->prim_endsgEdit->setValue(rc); +} + + +void EditProduct::primary_date_changed(QDate val) +{ + product->primary_end_date = ui->prim_enddateEdit->nullDate(); + is_changed(); + setStage(); +} + + +void EditProduct::primary_date_button() +{ + ui->prim_enddateEdit->setDate(QDate::currentDate()); +} + + +void EditProduct::primary_date_ack() +{ + int rc = QMessageBox::warning(this, tr("Confirm primary"), tr("Confirm that the primary fermentation data is correct"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (rc == QMessageBox::No) + return; + + product->stage = PROD_STAGE_SECONDARY; + setStage(); + is_changed(); +} + + +void EditProduct::secondary_temp_changed(double val) +{ + product->secondary_temp = val; + is_changed(); + setStage(); +} + + +void EditProduct::secondary_sg_changed(double val) +{ + if (product->secondary_end_sg == 0 && val == 0.001) { + product->secondary_end_sg = 0.990; + const QSignalBlocker blocker1(ui->sec_sgEdit); + ui->sec_sgEdit->setValue(0.990); + } else { + product->secondary_end_sg = val; + } + ui->sec_attShow->setValue(Utils::calc_svg(product->brew_fermenter_sg, product->secondary_end_sg)); + is_changed(); + setStage(); +} + + +void EditProduct::secondary_sg_button() +{ + double rc; + + /* + * Get a sensible start value. + */ + if (product->secondary_end_sg >= 0.990) + rc = get_fg(product->secondary_end_sg); + else + rc = get_fg(product->primary_end_sg); + qDebug() << "secondary_sg_button" << rc << product->secondary_end_sg; + ui->sec_sgEdit->setValue(rc); +} + + +void EditProduct::secondary_date_changed(QDate val) +{ + product->secondary_end_date = ui->sec_enddateEdit->nullDate(); + qDebug() << "secondary_date_changed" << val << product->secondary_end_date; + is_changed(); + setStage(); +} + + +void EditProduct::secondary_date_button() +{ + ui->sec_enddateEdit->setDate(QDate::currentDate()); +} + + +void EditProduct::secondary_date_ack() +{ + int rc = QMessageBox::warning(this, tr("Confirm secondary"), tr("Confirm that the secondary fermentation data is correct"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (rc == QMessageBox::No) + return; + + product->stage = PROD_STAGE_TERTIARY; + setStage(); + is_changed(); +} + + +void EditProduct::tertiary_temp_changed(double val) +{ + product->tertiary_temp = val; + is_changed(); + setStage(); +} + + +void EditProduct::tertiary_sg_changed(double val) +{ + qDebug() << "tertiary_sg_changed" << val; + if (product->fg == 0 && val == 0.001) { + product->fg = 0.990; + const QSignalBlocker blocker1(ui->tert_sgEdit); + ui->tert_sgEdit->setValue(0.990); + } else { + product->fg = val; + } + ui->tert_attShow->setValue(Utils::calc_svg(product->brew_fermenter_sg, product->fg)); + product->package_abv = Utils::abvol(product->brew_fermenter_sg, product->fg); + ui->tert_abvShow->setValue(product->package_abv); + ui->pack_abvShow->setValue(product->package_abv); + is_changed(); + setStage(); +} + + +void EditProduct::tertiary_sg_button() +{ + double rc; + + /* + * Get a sensible start value. + */ + if (product->fg >= 0.990) + rc = get_fg(product->fg); + else + rc = get_fg(product->secondary_end_sg); + qDebug() << "tertiary_sg_button" << rc << product->fg; + ui->tert_sgEdit->setValue(rc); +} + + +void EditProduct::ferm_log1_button() +{ +} + + +void EditProduct::ferm_log2_button() +{ +} + + diff -r 725da10db56c -r fa7cad488e27 src/EditProductTab3.cpp --- a/src/EditProductTab3.cpp Wed May 18 08:59:54 2022 +0200 +++ b/src/EditProductTab3.cpp Wed May 18 17:03:05 2022 +0200 @@ -440,7 +440,7 @@ /* * Calculate the final values if available. */ - if ((product->stage >= 6) && (product->fg > 0.990) && (product->fg < product->brew_fermenter_sg)) { + if ((product->stage >= PROD_STAGE_PACKAGE) && (product->fg > 0.990) && (product->fg < product->brew_fermenter_sg)) { } diff -r 725da10db56c -r fa7cad488e27 src/EditProductTab7.cpp --- a/src/EditProductTab7.cpp Wed May 18 08:59:54 2022 +0200 +++ b/src/EditProductTab7.cpp Wed May 18 17:03:05 2022 +0200 @@ -509,7 +509,7 @@ qDebug() << "stepbrix_changed" << product->mashs_row << val << "SG" << Utils::brix_to_sg(val); if ((product->mashs.at(product->mashs_row).step_sg == 0) && (product->mashs_row > 0)) { - /* If not thhe first step, and SG was not set, pickip previous step. */ + /* If not the first step, and SG was not set, pickup previous step. */ val = Utils::sg_to_brix(product->mashs.at(product->mashs_row - 1).step_sg); const QSignalBlocker blocker2(brixEdit); brixEdit->setValue(val); diff -r 725da10db56c -r fa7cad488e27 src/Utils.cpp --- a/src/Utils.cpp Wed May 18 08:59:54 2022 +0200 +++ b/src/Utils.cpp Wed May 18 17:03:05 2022 +0200 @@ -239,6 +239,23 @@ } +/* + * @brief Calculate Final Gravity. + * Formula by Petr Novotny, Zymurgy July/August 2017. + * @param o_plato Original Plato. + * @param refracto the refractometer reading. + * @return Final gravity. + */ +double Utils::brix_to_fg(double o_plato, double refracto) +{ + double FBc = refracto / my_brix_correction; + + double rc = round((1 + (0.006276 * FBc) - (0.002349 * o_plato)) * 10000.0) / 10000.0; +// qDebug() << "brix_to_plato" << o_plato << refracto << FBc << "rc" << rc; + return rc; +} + + double Utils::calc_svg(double og, double fg) { if (og == 0.0 || fg == 0.0) diff -r 725da10db56c -r fa7cad488e27 ui/EditProduct.ui --- a/ui/EditProduct.ui Wed May 18 08:59:54 2022 +0200 +++ b/ui/EditProduct.ui Wed May 18 17:03:05 2022 +0200 @@ -7955,6 +7955,9 @@ + + true + 10 @@ -8002,9 +8005,9 @@ - 160 + 140 30 - 351 + 391 241 @@ -8151,7 +8154,7 @@ 100000.000000000000000 - 1.000000000000000 + 0.500000000000000 @@ -8176,7 +8179,7 @@ 100000.000000000000000 - 1.000000000000000 + 0.500000000000000 @@ -8201,7 +8204,7 @@ 100000.000000000000000 - 1.000000000000000 + 0.500000000000000 @@ -8329,13 +8332,33 @@ true + + + + 340 + 170 + 28 + 22 + + + + Confirm the brew dates and times. + + + ... + + + + :/icons/silk/accept.png:/icons/silk/accept.png + + - 610 + 590 30 - 351 + 391 151 @@ -8412,7 +8435,7 @@ 100000.000000000000000 - 1.000000000000000 + 0.500000000000000 @@ -8540,13 +8563,33 @@ true + + + + 340 + 80 + 28 + 22 + + + + Confirm the brew dates and times. + + + ... + + + + :/icons/silk/accept.png:/icons/silk/accept.png + + - 610 + 590 200 - 351 + 391 181 @@ -8607,7 +8650,7 @@ 100000.000000000000000 - 1.000000000000000 + 0.500000000000000 @@ -9178,7 +9221,7 @@ % - 1 + 2 100.000000000000000