mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			614 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			614 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | ||
| #include "desktop-widgets/diveplanner.h"
 | ||
| #include "desktop-widgets/modeldelegates.h"
 | ||
| #include "desktop-widgets/mainwindow.h"
 | ||
| #include "core/planner.h"
 | ||
| #include "core/qthelper.h"
 | ||
| #include "core/units.h"
 | ||
| #include "core/settings/qPrefDivePlanner.h"
 | ||
| #include "core/gettextfromc.h"
 | ||
| #include "backend-shared/plannershared.h"
 | ||
| 
 | ||
| #include "qt-models/cylindermodel.h"
 | ||
| #include "qt-models/models.h"
 | ||
| #include "profile-widget/profilewidget2.h"
 | ||
| #include "qt-models/diveplannermodel.h"
 | ||
| 
 | ||
| #include <QGraphicsSceneMouseEvent>
 | ||
| #include <QMessageBox>
 | ||
| #include <QSettings>
 | ||
| #include <QShortcut>
 | ||
| 
 | ||
| #define TIME_INITIAL_MAX 30
 | ||
| 
 | ||
| #define MAX_DEPTH M_OR_FT(150, 450)
 | ||
| #define MIN_DEPTH M_OR_FT(20, 60)
 | ||
| 
 | ||
| DiveHandler::DiveHandler() : QGraphicsEllipseItem()
 | ||
| {
 | ||
| 	setRect(-5, -5, 10, 10);
 | ||
| 	setFlags(ItemIgnoresTransformations | ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges);
 | ||
| 	setBrush(Qt::white);
 | ||
| 	setZValue(2);
 | ||
| 	t.start();
 | ||
| }
 | ||
| 
 | ||
| int DiveHandler::parentIndex()
 | ||
| {
 | ||
| 	ProfileWidget2 *view = qobject_cast<ProfileWidget2 *>(scene()->views().first());
 | ||
| 	return view->handles.indexOf(this);
 | ||
| }
 | ||
| 
 | ||
| void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
 | ||
| {
 | ||
| 	QMenu m;
 | ||
| 	// Don't have a gas selection for the last point
 | ||
| 	emit released();
 | ||
| 	DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
 | ||
| 	QModelIndex index = plannerModel->index(parentIndex(), DivePlannerPointsModel::GAS);
 | ||
| 	if (index.sibling(index.row() + 1, index.column()).isValid()) {
 | ||
| 		GasSelectionModel *model = GasSelectionModel::instance();
 | ||
| 		model->repopulate();
 | ||
| 		int rowCount = model->rowCount();
 | ||
| 		for (int i = 0; i < rowCount; i++) {
 | ||
| 			QAction *action = new QAction(&m);
 | ||
| 			action->setText(model->data(model->index(i, 0), Qt::DisplayRole).toString());
 | ||
| 			action->setData(i);
 | ||
| 			connect(action, &QAction::triggered, this, &DiveHandler::changeGas);
 | ||
| 			m.addAction(action);
 | ||
| 		}
 | ||
| 	}
 | ||
| 	// don't allow removing the last point
 | ||
| 	if (plannerModel->rowCount() > 1) {
 | ||
| 		m.addSeparator();
 | ||
| 		m.addAction(gettextFromC::tr("Remove this point"), this, &DiveHandler::selfRemove);
 | ||
| 		m.exec(event->screenPos());
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void DiveHandler::selfRemove()
 | ||
| {
 | ||
| 	setSelected(true);
 | ||
| 	ProfileWidget2 *view = qobject_cast<ProfileWidget2 *>(scene()->views().first());
 | ||
| 	view->keyDeleteAction();
 | ||
| }
 | ||
| 
 | ||
| void DiveHandler::changeGas()
 | ||
| {
 | ||
| 	QAction *action = qobject_cast<QAction *>(sender());
 | ||
| 	DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
 | ||
| 	QModelIndex index = plannerModel->index(parentIndex(), DivePlannerPointsModel::GAS);
 | ||
| 	plannerModel->gasChange(index.sibling(index.row() + 1, index.column()), action->data().toInt());
 | ||
| }
 | ||
| 
 | ||
| void DiveHandler::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
 | ||
| {
 | ||
| 	if (t.elapsed() < 40)
 | ||
| 		return;
 | ||
| 	t.start();
 | ||
| 
 | ||
| 	ProfileWidget2 *view = qobject_cast<ProfileWidget2*>(scene()->views().first());
 | ||
| 	if(view->isPointOutOfBoundaries(event->scenePos()))
 | ||
| 		return;
 | ||
| 
 | ||
| 	QGraphicsEllipseItem::mouseMoveEvent(event);
 | ||
| 	emit moved();
 | ||
| }
 | ||
| 
 | ||
| void DiveHandler::mousePressEvent(QGraphicsSceneMouseEvent *event)
 | ||
| {
 | ||
| 	QGraphicsItem::mousePressEvent(event);
 | ||
| 	emit clicked();
 | ||
| }
 | ||
| 
 | ||
| void DiveHandler::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
 | ||
| {
 | ||
| 	QGraphicsItem::mouseReleaseEvent(event);
 | ||
| 	emit released();
 | ||
| }
 | ||
| 
 | ||
| DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
 | ||
| {
 | ||
| 	DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
 | ||
| 	CylindersModel *cylinders = DivePlannerPointsModel::instance()->cylindersModel();
 | ||
| 
 | ||
| 	ui.setupUi(this);
 | ||
| 	ui.dateEdit->setDisplayFormat(prefs.date_format);
 | ||
| 	ui.tableWidget->setTitle(tr("Dive planner points"));
 | ||
| 	ui.tableWidget->setModel(plannerModel);
 | ||
| 	connect(ui.tableWidget, &TableView::itemClicked, plannerModel, &DivePlannerPointsModel::remove);
 | ||
| 	plannerModel->setRecalc(true);
 | ||
| 	ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::GAS, new AirTypesDelegate(this));
 | ||
| 	ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::DIVEMODE, new DiveTypesDelegate(this));
 | ||
| 	ui.cylinderTableWidget->setTitle(tr("Available gases"));
 | ||
| 	ui.cylinderTableWidget->setBtnToolTip(tr("Add cylinder"));
 | ||
| 	ui.cylinderTableWidget->setModel(cylinders);
 | ||
| 	connect(ui.cylinderTableWidget, &TableView::itemClicked, cylinders, &CylindersModel::remove);
 | ||
| 	ui.waterType->setItemData(0, FRESHWATER_SALINITY);
 | ||
| 	ui.waterType->setItemData(1, SEAWATER_SALINITY);
 | ||
| 	ui.waterType->setItemData(2, EN13319_SALINITY);
 | ||
| 	waterTypeUpdateTexts();
 | ||
| 
 | ||
| 	QTableView *view = ui.cylinderTableWidget->view();
 | ||
| 	view->setColumnHidden(CylindersModel::START, true);
 | ||
| 	view->setColumnHidden(CylindersModel::END, true);
 | ||
| 	view->setColumnHidden(CylindersModel::DEPTH, false);
 | ||
| 	view->setItemDelegateForColumn(CylindersModel::TYPE, new TankInfoDelegate(this));
 | ||
| 	connect(ui.cylinderTableWidget, &TableView::addButtonClicked, plannerModel, &DivePlannerPointsModel::addCylinder_clicked);
 | ||
| 
 | ||
| 	// addStop actually accept a call with no parameters, due to default parameters, but the connect() syntax without SIGNAL/SLOT
 | ||
| 	// does not understand default parameters and causes errors to be thrown.
 | ||
| 	// Continue to use old syntax, to avoid problems.
 | ||
| 	connect(ui.tableWidget, SIGNAL(addButtonClicked()), plannerModel, SLOT(addStop()));
 | ||
| 
 | ||
| 	connect(cylinders, &CylindersModel::dataChanged, GasSelectionModel::instance(), &GasSelectionModel::repopulate);
 | ||
| 	connect(cylinders, &CylindersModel::rowsInserted, GasSelectionModel::instance(), &GasSelectionModel::repopulate);
 | ||
| 	connect(cylinders, &CylindersModel::rowsRemoved, GasSelectionModel::instance(), &GasSelectionModel::repopulate);
 | ||
| 	connect(cylinders, &CylindersModel::dataChanged, plannerModel, &DivePlannerPointsModel::emitDataChanged);
 | ||
| 	connect(cylinders, &CylindersModel::dataChanged, plannerModel, &DivePlannerPointsModel::cylinderModelEdited);
 | ||
| 	connect(cylinders, &CylindersModel::rowsInserted, plannerModel, &DivePlannerPointsModel::cylinderModelEdited);
 | ||
| 	connect(cylinders, &CylindersModel::rowsRemoved, plannerModel, &DivePlannerPointsModel::cylinderModelEdited);
 | ||
| 	connect(plannerModel, &DivePlannerPointsModel::calculatedPlanNotes, MainWindow::instance(), &MainWindow::setPlanNotes);
 | ||
| 
 | ||
| 
 | ||
| 	ui.tableWidget->setBtnToolTip(tr("Add dive data point"));
 | ||
| 	connect(ui.startTime, &QDateEdit::timeChanged, plannerModel, &DivePlannerPointsModel::setStartTime);
 | ||
| 	connect(ui.dateEdit, &QDateEdit::dateChanged, plannerModel, &DivePlannerPointsModel::setStartDate);
 | ||
| 	connect(ui.ATMPressure, QOverload<int>::of(&QSpinBox::valueChanged), this, &DivePlannerWidget::atmPressureChanged);
 | ||
| 	connect(ui.atmHeight, QOverload<int>::of(&QSpinBox::valueChanged), this, &DivePlannerWidget::heightChanged);
 | ||
| 	connect(ui.waterType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DivePlannerWidget::waterTypeChanged);
 | ||
| 	connect(ui.customSalinity, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &DivePlannerWidget::customSalinityChanged);
 | ||
| 	connect(plannerModel, &DivePlannerPointsModel::startTimeChanged, this, &DivePlannerWidget::setupStartTime);
 | ||
| 
 | ||
| 	// Creating (and canceling) the plan
 | ||
| 	replanButton = ui.buttonBox->addButton(tr("Save new"), QDialogButtonBox::ActionRole);
 | ||
| 	connect(replanButton, &QAbstractButton::clicked, plannerModel, &DivePlannerPointsModel::saveDuplicatePlan);
 | ||
| 	connect(ui.buttonBox, &QDialogButtonBox::accepted, plannerModel, &DivePlannerPointsModel::savePlan);
 | ||
| 	connect(ui.buttonBox, &QDialogButtonBox::rejected, plannerModel, &DivePlannerPointsModel::cancelPlan);
 | ||
| 	QShortcut *closeKey = new QShortcut(QKeySequence(Qt::Key_Escape), this);
 | ||
| 	connect(closeKey, &QShortcut::activated, plannerModel, &DivePlannerPointsModel::cancelPlan);
 | ||
| 
 | ||
| 	// This makes shure the spinbox gets a setMinimum(0) on it so we can't have negative time or depth.
 | ||
| 	ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::DEPTH, new SpinBoxDelegate(0, INT_MAX, 1, this));
 | ||
| 	ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::RUNTIME, new SpinBoxDelegate(0, INT_MAX, 1, this));
 | ||
| 	ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::DURATION, new SpinBoxDelegate(0, INT_MAX, 1, this));
 | ||
| 	ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::CCSETPOINT, new DoubleSpinBoxDelegate(0, 2, 0.1, this));
 | ||
| 
 | ||
| 	/* set defaults. */
 | ||
| 	ui.ATMPressure->setValue(1013);
 | ||
| 	ui.atmHeight->setValue(0);
 | ||
| 
 | ||
| 	setMinimumWidth(0);
 | ||
| 	setMinimumHeight(0);
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::setReplanButton(bool replan)
 | ||
| {
 | ||
| 	replanButton->setVisible(replan);
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::setupStartTime(QDateTime startTime)
 | ||
| {
 | ||
| 	ui.startTime->setTime(startTime.time());
 | ||
| 	ui.dateEdit->setDate(startTime.date());
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::setSurfacePressure(int surface_pressure)
 | ||
| {
 | ||
| 	ui.ATMPressure->setValue(surface_pressure);
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::setDiveMode(int mode)
 | ||
| {
 | ||
| 	ui.rebreathermode->setCurrentIndex(mode);
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::setSalinity(int salinity)
 | ||
| {
 | ||
| 	bool mapped = false;
 | ||
| 	for (int i = 0; i < ui.waterType->count(); i++) {
 | ||
| 		if (salinity == ui.waterType->itemData(i).toInt()) {
 | ||
| 			mapped = true;
 | ||
| 			ui.waterType->setCurrentIndex(i);
 | ||
| 			break;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	
 | ||
| 	if (!mapped) {
 | ||
| 		/* Assign to last element "custom" in combo box */
 | ||
| 		ui.waterType->setItemData(ui.waterType->count()-1, salinity);
 | ||
| 		ui.waterType->setCurrentIndex(ui.waterType->count()-1);
 | ||
| 		ui.customSalinity->setEnabled(true);
 | ||
| 		ui.customSalinity->setValue(salinity / 10000.0);
 | ||
| 	}
 | ||
| 	DivePlannerPointsModel::instance()->setSalinity(salinity);
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::settingsChanged()
 | ||
| {
 | ||
| 	// Adopt units
 | ||
| 	if (get_units()->length == units::FEET) {
 | ||
| 		ui.atmHeight->setSuffix("ft");
 | ||
| 		ui.atmHeight->setMinimum(-300);
 | ||
| 		ui.atmHeight->setMaximum(10000);
 | ||
| 	} else {
 | ||
| 		ui.atmHeight->setSuffix(("m"));
 | ||
| 		ui.atmHeight->setMinimum(-100);
 | ||
| 		ui.atmHeight->setMaximum(3000);
 | ||
| 	}
 | ||
| 	ui.atmHeight->blockSignals(true);
 | ||
| 	ui.atmHeight->setValue((int) get_depth_units((int) pressure_to_altitude(DivePlannerPointsModel::instance()->getSurfacePressure()), NULL,NULL));
 | ||
| 	ui.atmHeight->blockSignals(false);
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::atmPressureChanged(const int pressure)
 | ||
| {
 | ||
| 	DivePlannerPointsModel::instance()->setSurfacePressure(pressure);
 | ||
| 	ui.atmHeight->blockSignals(true);
 | ||
| 	ui.atmHeight->setValue((int) get_depth_units((int) pressure_to_altitude(pressure), NULL,NULL));
 | ||
| 	ui.atmHeight->blockSignals(false);
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::heightChanged(const int height)
 | ||
| {						// height is in ft or in meters
 | ||
| 	int pressure = (int) (altitude_to_pressure(units_to_depth((double) height).mm));
 | ||
| 	ui.ATMPressure->blockSignals(true);
 | ||
| 	ui.ATMPressure->setValue(pressure);
 | ||
| 	ui.ATMPressure->blockSignals(false);
 | ||
| 	DivePlannerPointsModel::instance()->setSurfacePressure(pressure);
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::waterTypeUpdateTexts()
 | ||
| {
 | ||
| 	double density;
 | ||
| 	/* Do not set text in last/custom element */
 | ||
| 	for (int i = 0; i < ui.waterType->count()-1; i++) {
 | ||
| 		if (ui.waterType->itemData(i) != QVariant::Invalid) {
 | ||
| 			QString densityText = ui.waterType->itemText(i).split("(")[0].trimmed();
 | ||
| 			density = ui.waterType->itemData(i).toInt() / 10000.0;
 | ||
| 			densityText.append(QString(" (%L1%2)").arg(density, 0, 'f', 2).arg(tr("kg/ℓ")));
 | ||
| 			ui.waterType->setItemText(i, densityText);
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::waterTypeChanged(const int index)
 | ||
| {
 | ||
| 	ui.customSalinity->setEnabled(index == ui.waterType->count() - 1);
 | ||
| 	ui.customSalinity->setValue(ui.waterType->itemData(index).toInt() / 10000.0);
 | ||
| 	DivePlannerPointsModel::instance()->setSalinity(ui.waterType->itemData(index).toInt());
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::customSalinityChanged(double density)
 | ||
| {
 | ||
| 	if (ui.customSalinity->isEnabled()) {
 | ||
| 		int newSalinity = (int)(density * 10000.0);
 | ||
| 		ui.waterType->setItemData(ui.waterType->count() - 1, newSalinity);
 | ||
| 		DivePlannerPointsModel::instance()->setSalinity(newSalinity);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::disableDecoElements(int mode)
 | ||
| {
 | ||
| 	if (mode == RECREATIONAL) {
 | ||
| 		ui.label_gflow->setDisabled(false);
 | ||
| 		ui.label_gfhigh->setDisabled(false);
 | ||
| 		ui.gflow->setDisabled(false);
 | ||
| 		ui.gfhigh->setDisabled(false);
 | ||
| 		ui.lastStop->setDisabled(true);
 | ||
| 		ui.backgasBreaks->setDisabled(true);
 | ||
| 		ui.backgasBreaks->blockSignals(true);
 | ||
| 		ui.backgasBreaks->setChecked(false);
 | ||
| 		ui.backgasBreaks->blockSignals(false);
 | ||
| 		ui.bailout->setDisabled(true);
 | ||
| 		ui.bailout->blockSignals(true);
 | ||
| 		ui.bailout->setChecked(false);
 | ||
| 		ui.bailout->blockSignals(false);
 | ||
| 		ui.bottompo2->setDisabled(false);
 | ||
| 		ui.decopo2->setDisabled(true);
 | ||
| 		ui.safetystop->setDisabled(false);
 | ||
| 		ui.label_reserve_gas->setDisabled(false);
 | ||
| 		ui.reserve_gas->setDisabled(false);
 | ||
| 		ui.label_vpmb_conservatism->setDisabled(true);
 | ||
| 		ui.vpmb_conservatism->setDisabled(true);
 | ||
| 		ui.switch_at_req_stop->setDisabled(true);
 | ||
| 		ui.min_switch_duration->setDisabled(true);
 | ||
| 		ui.surface_segment->setDisabled(true);
 | ||
| 		ui.label_min_switch_duration->setDisabled(true);
 | ||
| 		ui.sacfactor->setDisabled(true);
 | ||
| 		ui.problemsolvingtime->setDisabled(true);
 | ||
| 		ui.sacfactor->blockSignals(true);
 | ||
| 		ui.problemsolvingtime->blockSignals(true);
 | ||
| 		ui.sacfactor->setValue(2.0);
 | ||
| 		ui.problemsolvingtime->setValue(0);
 | ||
| 		ui.sacfactor->blockSignals(false);
 | ||
| 		ui.problemsolvingtime->blockSignals(false);
 | ||
| 		ui.display_variations->setDisabled(true);
 | ||
| 	}
 | ||
| 	else if (mode == VPMB) {
 | ||
| 		ui.label_gflow->setDisabled(true);
 | ||
| 		ui.label_gfhigh->setDisabled(true);
 | ||
| 		ui.gflow->setDisabled(true);
 | ||
| 		ui.gfhigh->setDisabled(true);
 | ||
| 		ui.lastStop->setDisabled(false);
 | ||
| 		if (prefs.last_stop) {
 | ||
| 			ui.backgasBreaks->setDisabled(false);
 | ||
| 			ui.backgasBreaks->blockSignals(true);
 | ||
| 			ui.backgasBreaks->setChecked(prefs.doo2breaks);
 | ||
| 			ui.backgasBreaks->blockSignals(false);
 | ||
| 		} else {
 | ||
| 			ui.backgasBreaks->setDisabled(true);
 | ||
| 			ui.backgasBreaks->blockSignals(true);
 | ||
| 			ui.backgasBreaks->setChecked(false);
 | ||
| 			ui.backgasBreaks->blockSignals(false);
 | ||
| 		}
 | ||
| 		ui.bailout->setDisabled(!(displayed_dive.dc.divemode == CCR || displayed_dive.dc.divemode == PSCR));
 | ||
| 		ui.bottompo2->setDisabled(false);
 | ||
| 		ui.decopo2->setDisabled(false);
 | ||
| 		ui.safetystop->setDisabled(true);
 | ||
| 		ui.label_reserve_gas->setDisabled(true);
 | ||
| 		ui.reserve_gas->setDisabled(true);
 | ||
| 		ui.label_vpmb_conservatism->setDisabled(false);
 | ||
| 		ui.vpmb_conservatism->setDisabled(false);
 | ||
| 		ui.switch_at_req_stop->setDisabled(false);
 | ||
| 		ui.min_switch_duration->setDisabled(false);
 | ||
| 		ui.surface_segment->setDisabled(false);
 | ||
| 		ui.label_min_switch_duration->setDisabled(false);
 | ||
| 		ui.sacfactor->setDisabled(false);
 | ||
| 		ui.problemsolvingtime->setDisabled(false);
 | ||
| 		ui.sacfactor->setValue(PlannerShared::sacfactor());
 | ||
| 		ui.problemsolvingtime->setValue(prefs.problemsolvingtime);
 | ||
| 		ui.display_variations->setDisabled(false);
 | ||
| 	}
 | ||
| 	else if (mode == BUEHLMANN) {
 | ||
| 		ui.label_gflow->setDisabled(false);
 | ||
| 		ui.label_gfhigh->setDisabled(false);
 | ||
| 		ui.gflow->setDisabled(false);
 | ||
| 		ui.gfhigh->setDisabled(false);
 | ||
| 		ui.lastStop->setDisabled(false);
 | ||
| 		if (prefs.last_stop) {
 | ||
| 			ui.backgasBreaks->setDisabled(false);
 | ||
| 			ui.backgasBreaks->blockSignals(true);
 | ||
| 			ui.backgasBreaks->setChecked(prefs.doo2breaks);
 | ||
| 			ui.backgasBreaks->blockSignals(false);
 | ||
| 		} else {
 | ||
| 			ui.backgasBreaks->setDisabled(true);
 | ||
| 			ui.backgasBreaks->blockSignals(true);
 | ||
| 			ui.backgasBreaks->setChecked(false);
 | ||
| 			ui.backgasBreaks->blockSignals(false);
 | ||
| 		}
 | ||
| 		ui.bailout->setDisabled(!(displayed_dive.dc.divemode == CCR || displayed_dive.dc.divemode == PSCR));
 | ||
| 		ui.bottompo2->setDisabled(false);
 | ||
| 		ui.decopo2->setDisabled(false);
 | ||
| 		ui.safetystop->setDisabled(true);
 | ||
| 		ui.label_reserve_gas->setDisabled(true);
 | ||
| 		ui.reserve_gas->setDisabled(true);
 | ||
| 		ui.label_vpmb_conservatism->setDisabled(true);
 | ||
| 		ui.vpmb_conservatism->setDisabled(true);
 | ||
| 		ui.switch_at_req_stop->setDisabled(false);
 | ||
| 		ui.min_switch_duration->setDisabled(false);
 | ||
| 		ui.surface_segment->setDisabled(false);
 | ||
| 		ui.label_min_switch_duration->setDisabled(false);
 | ||
| 		ui.sacfactor->setDisabled(false);
 | ||
| 		ui.problemsolvingtime->setDisabled(false);
 | ||
| 		ui.sacfactor->setValue(PlannerShared::sacfactor());
 | ||
| 		ui.problemsolvingtime->setValue(prefs.problemsolvingtime);
 | ||
| 		ui.display_variations->setDisabled(false);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::disableBackgasBreaks(bool enabled)
 | ||
| {
 | ||
| 	if (prefs.planner_deco_mode == RECREATIONAL)
 | ||
| 		return;
 | ||
| 
 | ||
| 	if (enabled) {
 | ||
| 		ui.backgasBreaks->setDisabled(false);
 | ||
| 		ui.backgasBreaks->blockSignals(true);
 | ||
| 		ui.backgasBreaks->setChecked(prefs.doo2breaks);
 | ||
| 		ui.backgasBreaks->blockSignals(false);
 | ||
| 	} else {
 | ||
| 		ui.backgasBreaks->setDisabled(true);
 | ||
| 		ui.backgasBreaks->blockSignals(true);
 | ||
| 		ui.backgasBreaks->setChecked(false);
 | ||
| 		ui.backgasBreaks->blockSignals(false);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void DivePlannerWidget::printDecoPlan()
 | ||
| {
 | ||
| 	MainWindow::instance()->printPlan();
 | ||
| }
 | ||
| 
 | ||
| PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
 | ||
| {
 | ||
| 	ui.setupUi(this);
 | ||
| 
 | ||
| 	DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
 | ||
| 	plannerModel->getDiveplan().bottomsac = prefs.bottomsac;
 | ||
| 	plannerModel->getDiveplan().decosac = prefs.decosac;
 | ||
| 
 | ||
| 	updateUnitsUI();
 | ||
| 	ui.lastStop->setChecked(prefs.last_stop);
 | ||
| 	ui.verbatim_plan->setChecked(prefs.verbatim_plan);
 | ||
| 	ui.display_duration->setChecked(prefs.display_duration);
 | ||
| 	ui.display_runtime->setChecked(prefs.display_runtime);
 | ||
| 	ui.display_transitions->setChecked(prefs.display_transitions);
 | ||
| 	ui.display_variations->setChecked(prefs.display_variations);
 | ||
| 	ui.safetystop->setChecked(prefs.safetystop);
 | ||
| 	ui.sacfactor->setValue(PlannerShared::sacfactor());
 | ||
| 	ui.problemsolvingtime->setValue(prefs.problemsolvingtime);
 | ||
| 	ui.bottompo2->setValue(PlannerShared::bottompo2());
 | ||
| 	ui.decopo2->setValue(PlannerShared::decopo2());
 | ||
| 	ui.backgasBreaks->setChecked(prefs.doo2breaks);
 | ||
| 	PlannerShared::set_dobailout(false);
 | ||
| 	setBailoutVisibility(false);
 | ||
| 	ui.o2narcotic->setChecked(prefs.o2narcotic);
 | ||
| 	ui.drop_stone_mode->setChecked(prefs.drop_stone_mode);
 | ||
| 	ui.switch_at_req_stop->setChecked(prefs.switch_at_req_stop);
 | ||
| 	ui.min_switch_duration->setValue(PlannerShared::min_switch_duration());
 | ||
| 	ui.surface_segment->setValue(PlannerShared::surface_segment());
 | ||
| 	ui.recreational_deco->setChecked(prefs.planner_deco_mode == RECREATIONAL);
 | ||
| 	ui.buehlmann_deco->setChecked(prefs.planner_deco_mode == BUEHLMANN);
 | ||
| 	ui.vpmb_deco->setChecked(prefs.planner_deco_mode == VPMB);
 | ||
| 	disableDecoElements((int) prefs.planner_deco_mode);
 | ||
| 
 | ||
| 	// should be the same order as in dive_comp_type!
 | ||
| 	QStringList rebreather_modes = QStringList();
 | ||
| 	for (int i = 0; i < FREEDIVE; i++)
 | ||
| 		rebreather_modes.append(gettextFromC::tr(divemode_text_ui[i]));
 | ||
| 	ui.rebreathermode->insertItems(0, rebreather_modes);
 | ||
| 
 | ||
| 	connect(ui.recreational_deco, &QAbstractButton::clicked, [] { PlannerShared::set_planner_deco_mode(RECREATIONAL); });
 | ||
| 	connect(ui.buehlmann_deco, &QAbstractButton::clicked, [] { PlannerShared::set_planner_deco_mode(BUEHLMANN); });
 | ||
| 	connect(ui.vpmb_deco, &QAbstractButton::clicked, [] { PlannerShared::set_planner_deco_mode(VPMB); });
 | ||
| 
 | ||
| 	connect(ui.lastStop, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setLastStop6m);
 | ||
| 	connect(ui.lastStop, &QAbstractButton::toggled, this, &PlannerSettingsWidget::disableBackgasBreaks);
 | ||
| 	connect(ui.verbatim_plan, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setVerbatim);
 | ||
| 	connect(ui.display_duration, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setDisplayDuration);
 | ||
| 	connect(ui.display_runtime, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setDisplayRuntime);
 | ||
| 	connect(ui.display_transitions, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setDisplayTransitions);
 | ||
| 	connect(ui.display_variations, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setDisplayVariations);
 | ||
| 	connect(ui.safetystop, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setSafetyStop);
 | ||
| 	connect(ui.reserve_gas, QOverload<int>::of(&QSpinBox::valueChanged), &PlannerShared::set_reserve_gas);
 | ||
| 	connect(ui.ascRate75, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setAscrate75Display);
 | ||
| 	connect(ui.ascRate50, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setAscrate50Display);
 | ||
| 	connect(ui.ascRateStops, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setAscratestopsDisplay);
 | ||
| 	connect(ui.ascRateLast6m, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setAscratelast6mDisplay);
 | ||
| 	connect(ui.descRate, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setDescrateDisplay);
 | ||
| 	connect(ui.drop_stone_mode, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setDropStoneMode);
 | ||
| 	connect(ui.gfhigh, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setGFHigh);
 | ||
| 	connect(ui.gflow, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setGFLow);
 | ||
| 	connect(ui.vpmb_conservatism, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setVpmbConservatism);
 | ||
| 	connect(ui.backgasBreaks, &QAbstractButton::toggled, this, &PlannerSettingsWidget::setBackgasBreaks);
 | ||
| 	connect(ui.bailout, &QAbstractButton::toggled, &PlannerShared::set_dobailout);
 | ||
| 	connect(ui.o2narcotic, &QAbstractButton::toggled, &PlannerShared::set_o2narcotic);
 | ||
| 	connect(ui.switch_at_req_stop, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setSwitchAtReqStop);
 | ||
| 	connect(ui.min_switch_duration, QOverload<int>::of(&QSpinBox::valueChanged), &PlannerShared::set_min_switch_duration);
 | ||
| 	connect(ui.surface_segment, QOverload<int>::of(&QSpinBox::valueChanged), &PlannerShared::set_surface_segment);
 | ||
| 	connect(ui.rebreathermode, QOverload<int>::of(&QComboBox::currentIndexChanged), plannerModel, &DivePlannerPointsModel::setRebreatherMode);
 | ||
| 	connect(ui.rebreathermode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PlannerSettingsWidget::setBailoutVisibility);
 | ||
| 
 | ||
| 	connect(ui.recreational_deco, &QAbstractButton::clicked, [this] { disableDecoElements(RECREATIONAL); });
 | ||
| 	connect(ui.buehlmann_deco, &QAbstractButton::clicked, [this] { disableDecoElements(BUEHLMANN); });
 | ||
| 	connect(ui.vpmb_deco, &QAbstractButton::clicked, [this] { disableDecoElements(VPMB); });
 | ||
| 
 | ||
| 	connect(ui.sacfactor, QOverload<double>::of(&QDoubleSpinBox::valueChanged), &PlannerShared::set_sacfactor);
 | ||
| 	connect(ui.problemsolvingtime, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setProblemSolvingTime);
 | ||
| 	connect(ui.bottompo2, QOverload<double>::of(&QDoubleSpinBox::valueChanged), &PlannerShared::set_bottompo2);
 | ||
| 	connect(ui.decopo2, QOverload<double>::of(&QDoubleSpinBox::valueChanged), &PlannerShared::set_decopo2);
 | ||
| 	connect(ui.bestmixEND, QOverload<int>::of(&QSpinBox::valueChanged), &PlannerShared::set_bestmixend);
 | ||
| 	connect(ui.bottomSAC, QOverload<double>::of(&QDoubleSpinBox::valueChanged), &PlannerShared::set_bottomsac);
 | ||
| 	connect(ui.decoStopSAC, QOverload<double>::of(&QDoubleSpinBox::valueChanged), &PlannerShared::set_decosac);
 | ||
| 
 | ||
| 	settingsChanged();
 | ||
| 	ui.gflow->setValue(prefs.gflow);
 | ||
| 	ui.gfhigh->setValue(prefs.gfhigh);
 | ||
| 	ui.vpmb_conservatism->setValue(prefs.vpmb_conservatism);
 | ||
| 
 | ||
| 	ui.ascRate75->setKeyboardTracking(false);
 | ||
| 	ui.ascRate50->setKeyboardTracking(false);
 | ||
| 	ui.ascRateLast6m->setKeyboardTracking(false);
 | ||
| 	ui.ascRateStops->setKeyboardTracking(false);
 | ||
| 	ui.descRate->setKeyboardTracking(false);
 | ||
| 	ui.gfhigh->setKeyboardTracking(false);
 | ||
| 	ui.gflow->setKeyboardTracking(false);
 | ||
| 
 | ||
| 	setMinimumWidth(0);
 | ||
| 	setMinimumHeight(0);
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::updateUnitsUI()
 | ||
| {
 | ||
| 	DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
 | ||
| 	ui.ascRate75->setValue(plannerModel->ascrate75Display());
 | ||
| 	ui.ascRate50->setValue(plannerModel->ascrate50Display());
 | ||
| 	ui.ascRateStops->setValue(plannerModel->ascratestopsDisplay());
 | ||
| 	ui.ascRateLast6m->setValue(plannerModel->ascratelast6mDisplay());
 | ||
| 	ui.descRate->setValue(lrint(plannerModel->descrateDisplay()));
 | ||
| 	ui.bestmixEND->setValue(lrint(get_depth_units(prefs.bestmixend.mm, NULL, NULL)));
 | ||
| }
 | ||
| 
 | ||
| PlannerSettingsWidget::~PlannerSettingsWidget()
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::settingsChanged()
 | ||
| {
 | ||
| 	QString vs;
 | ||
| 	// don't recurse into setting the value from the ui when setting the ui from the value
 | ||
| 	ui.bottomSAC->blockSignals(true);
 | ||
| 	ui.decoStopSAC->blockSignals(true);
 | ||
| 	if (get_units()->length == units::FEET) {
 | ||
| 		vs.append(tr("ft/min"));
 | ||
| 		ui.lastStop->setText(tr("Last stop at 20ft"));
 | ||
| 		ui.asc50to6->setText(tr("50% avg. depth to 20ft"));
 | ||
| 		ui.asc6toSurf->setText(tr("20ft to surface"));
 | ||
| 		ui.bestmixEND->setSuffix(tr("ft"));
 | ||
| 	} else {
 | ||
| 		vs.append(tr("m/min"));
 | ||
| 		ui.lastStop->setText(tr("Last stop at 6m"));
 | ||
| 		ui.asc50to6->setText(tr("50% avg. depth to 6m"));
 | ||
| 		ui.asc6toSurf->setText(tr("6m to surface"));
 | ||
| 		ui.bestmixEND->setSuffix(tr("m"));
 | ||
| 	}
 | ||
| 	if(get_units()->volume == units::CUFT) {
 | ||
| 		ui.bottomSAC->setSuffix(tr("cuft/min"));
 | ||
| 		ui.decoStopSAC->setSuffix(tr("cuft/min"));
 | ||
| 		ui.bottomSAC->setDecimals(2);
 | ||
| 		ui.bottomSAC->setSingleStep(0.1);
 | ||
| 		ui.decoStopSAC->setDecimals(2);
 | ||
| 		ui.decoStopSAC->setSingleStep(0.1);
 | ||
| 		ui.bottomSAC->setValue(PlannerShared::bottomsac());
 | ||
| 		ui.decoStopSAC->setValue(PlannerShared::decosac());
 | ||
| 	} else {
 | ||
| 		ui.bottomSAC->setSuffix(tr("ℓ/min"));
 | ||
| 		ui.decoStopSAC->setSuffix(tr("ℓ/min"));
 | ||
| 		ui.bottomSAC->setDecimals(0);
 | ||
| 		ui.bottomSAC->setSingleStep(1);
 | ||
| 		ui.decoStopSAC->setDecimals(0);
 | ||
| 		ui.decoStopSAC->setSingleStep(1);
 | ||
| 		ui.bottomSAC->setValue(PlannerShared::bottomsac());
 | ||
| 		ui.decoStopSAC->setValue(PlannerShared::decosac());
 | ||
| 	}
 | ||
| 	if(get_units()->pressure == units::BAR) {
 | ||
| 		ui.reserve_gas->setSuffix(tr("bar"));
 | ||
| 		ui.reserve_gas->setSingleStep(1);
 | ||
| 		ui.reserve_gas->setValue(prefs.reserve_gas / 1000);
 | ||
| 		ui.reserve_gas->setMaximum(300);
 | ||
| 	} else {
 | ||
| 		ui.reserve_gas->setSuffix(tr("psi"));
 | ||
| 		ui.reserve_gas->setSingleStep(10);
 | ||
| 		ui.reserve_gas->setMaximum(5000);
 | ||
| 		ui.reserve_gas->setValue(mbar_to_PSI(prefs.reserve_gas));
 | ||
| 	}
 | ||
| 
 | ||
| 	ui.bottomSAC->blockSignals(false);
 | ||
| 	ui.decoStopSAC->blockSignals(false);
 | ||
| 	updateUnitsUI();
 | ||
| 	ui.ascRate75->setSuffix(vs);
 | ||
| 	ui.ascRate50->setSuffix(vs);
 | ||
| 	ui.ascRateStops->setSuffix(vs);
 | ||
| 	ui.ascRateLast6m->setSuffix(vs);
 | ||
| 	ui.descRate->setSuffix(vs);
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::printDecoPlan()
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::setBackgasBreaks(bool dobreaks)
 | ||
| {
 | ||
| 	PlannerShared::set_doo2breaks(dobreaks);
 | ||
| }
 | ||
| 
 | ||
| void PlannerSettingsWidget::setBailoutVisibility(int mode)
 | ||
| {
 | ||
| 		ui.bailout->setDisabled(!(mode == CCR || mode == PSCR));
 | ||
| }
 | ||
| 
 | ||
| PlannerDetails::PlannerDetails(QWidget *parent) : QWidget(parent)
 | ||
| {
 | ||
| 	ui.setupUi(this);
 | ||
| }
 |