2014-01-14 19:17:17 +00:00
|
|
|
#include "diveprofileitem.h"
|
|
|
|
#include "diveplotdatamodel.h"
|
|
|
|
#include "divecartesianaxis.h"
|
|
|
|
#include "graphicsview-common.h"
|
2014-01-17 19:54:47 +00:00
|
|
|
#include "divetextitem.h"
|
2014-01-17 17:34:15 +00:00
|
|
|
#include "profile.h"
|
2014-01-17 19:54:47 +00:00
|
|
|
#include "dive.h"
|
|
|
|
#include "profilegraphics.h"
|
2014-01-21 19:07:22 +00:00
|
|
|
#include "preferences.h"
|
2014-01-22 17:08:19 +00:00
|
|
|
#include "helpers.h"
|
2014-01-14 19:17:17 +00:00
|
|
|
|
|
|
|
#include <QPen>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QLinearGradient>
|
2014-01-16 20:39:13 +00:00
|
|
|
#include <QDebug>
|
2014-01-17 19:54:47 +00:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QGraphicsItem>
|
2014-01-22 19:54:24 +00:00
|
|
|
#include <QSettings>
|
2014-01-14 19:17:17 +00:00
|
|
|
|
2014-01-16 18:21:23 +00:00
|
|
|
AbstractProfilePolygonItem::AbstractProfilePolygonItem(): QObject(), QGraphicsPolygonItem(),
|
2014-01-16 05:44:18 +00:00
|
|
|
hAxis(NULL), vAxis(NULL), dataModel(NULL), hDataColumn(-1), vDataColumn(-1)
|
2014-01-14 19:17:17 +00:00
|
|
|
{
|
2014-01-21 20:16:19 +00:00
|
|
|
connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(preferencesChanged()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractProfilePolygonItem::preferencesChanged()
|
|
|
|
{
|
2014-01-14 19:17:17 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 18:21:23 +00:00
|
|
|
void AbstractProfilePolygonItem::setHorizontalAxis(DiveCartesianAxis* horizontal)
|
2014-01-14 19:17:17 +00:00
|
|
|
{
|
|
|
|
hAxis = horizontal;
|
2014-01-27 17:14:42 +00:00
|
|
|
connect(hAxis, SIGNAL(sizeChanged()), this, SLOT(modelDataChanged()));
|
2014-01-14 19:17:17 +00:00
|
|
|
modelDataChanged();
|
|
|
|
}
|
|
|
|
|
2014-01-16 18:21:23 +00:00
|
|
|
void AbstractProfilePolygonItem::setHorizontalDataColumn(int column)
|
2014-01-14 19:17:17 +00:00
|
|
|
{
|
|
|
|
hDataColumn = column;
|
|
|
|
modelDataChanged();
|
|
|
|
}
|
|
|
|
|
2014-01-21 16:05:29 +00:00
|
|
|
void AbstractProfilePolygonItem::setModel(DivePlotDataModel* model)
|
2014-01-14 19:17:17 +00:00
|
|
|
{
|
|
|
|
dataModel = model;
|
2014-02-04 19:34:16 +00:00
|
|
|
connect(dataModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelDataChanged(QModelIndex, QModelIndex)));
|
2014-02-10 16:41:59 +00:00
|
|
|
connect(dataModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(modelDataRemoved(QModelIndex, int, int)));
|
2014-01-14 19:17:17 +00:00
|
|
|
modelDataChanged();
|
|
|
|
}
|
|
|
|
|
2014-02-10 16:41:59 +00:00
|
|
|
void AbstractProfilePolygonItem::modelDataRemoved(const QModelIndex& parent, int from, int to)
|
|
|
|
{
|
|
|
|
setPolygon(QPolygonF());
|
|
|
|
qDeleteAll(texts);
|
|
|
|
texts.clear();
|
|
|
|
}
|
|
|
|
|
2014-01-16 18:21:23 +00:00
|
|
|
void AbstractProfilePolygonItem::setVerticalAxis(DiveCartesianAxis* vertical)
|
2014-01-14 19:17:17 +00:00
|
|
|
{
|
|
|
|
vAxis = vertical;
|
2014-01-27 17:14:42 +00:00
|
|
|
connect(vAxis, SIGNAL(sizeChanged()), this, SLOT(modelDataChanged()));
|
|
|
|
connect(vAxis, SIGNAL(maxChanged()), this, SLOT(modelDataChanged()));
|
2014-01-14 19:17:17 +00:00
|
|
|
modelDataChanged();
|
|
|
|
}
|
|
|
|
|
2014-01-16 18:21:23 +00:00
|
|
|
void AbstractProfilePolygonItem::setVerticalDataColumn(int column)
|
2014-01-14 19:17:17 +00:00
|
|
|
{
|
|
|
|
vDataColumn = column;
|
|
|
|
modelDataChanged();
|
|
|
|
}
|
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
bool AbstractProfilePolygonItem::shouldCalculateStuff(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
|
|
|
{
|
|
|
|
if (!hAxis || !vAxis)
|
|
|
|
return false;
|
|
|
|
if (!dataModel || dataModel->rowCount() == 0)
|
|
|
|
return false;
|
|
|
|
if (hDataColumn == -1 || vDataColumn == -1)
|
|
|
|
return false;
|
|
|
|
if ( topLeft.isValid() && bottomRight.isValid()){
|
|
|
|
if ((topLeft.column() >= vDataColumn || topLeft.column() >= hDataColumn ) &&
|
|
|
|
(bottomRight.column() <= vDataColumn || topLeft.column() <= hDataColumn )){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractProfilePolygonItem::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
2014-01-14 19:17:17 +00:00
|
|
|
{
|
|
|
|
// We don't have enougth data to calculate things, quit.
|
|
|
|
|
|
|
|
// Calculate the polygon. This is the polygon that will be painted on screen
|
|
|
|
// on the ::paint method. Here we calculate the correct position of the points
|
|
|
|
// regarting our cartesian plane ( made by the hAxis and vAxis ), the QPolygonF
|
|
|
|
// is an array of QPointF's, so we basically get the point from the model, convert
|
|
|
|
// to our coordinates, store. no painting is done here.
|
|
|
|
QPolygonF poly;
|
2014-01-16 04:50:56 +00:00
|
|
|
for (int i = 0, modelDataCount = dataModel->rowCount(); i < modelDataCount; i++) {
|
2014-01-14 19:17:17 +00:00
|
|
|
qreal horizontalValue = dataModel->index(i, hDataColumn).data().toReal();
|
|
|
|
qreal verticalValue = dataModel->index(i, vDataColumn).data().toReal();
|
|
|
|
QPointF point( hAxis->posAtValue(horizontalValue), vAxis->posAtValue(verticalValue));
|
|
|
|
poly.append(point);
|
|
|
|
}
|
|
|
|
setPolygon(poly);
|
2014-01-21 16:05:29 +00:00
|
|
|
|
|
|
|
qDeleteAll(texts);
|
|
|
|
texts.clear();
|
2014-01-14 19:17:17 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 17:54:25 +00:00
|
|
|
DiveProfileItem::DiveProfileItem() : show_reported_ceiling(0), reported_ceiling_in_red(0)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-01-16 04:50:56 +00:00
|
|
|
void DiveProfileItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
2014-01-14 19:17:17 +00:00
|
|
|
Q_UNUSED(widget);
|
2014-02-10 16:41:59 +00:00
|
|
|
if(polygon().isEmpty())
|
|
|
|
return;
|
2014-01-14 19:17:17 +00:00
|
|
|
|
|
|
|
// This paints the Polygon + Background. I'm setting the pen to QPen() so we don't get a black line here,
|
|
|
|
// after all we need to plot the correct velocities colors later.
|
2014-01-21 19:07:22 +00:00
|
|
|
setPen(Qt::NoPen);
|
2014-01-14 19:17:17 +00:00
|
|
|
QGraphicsPolygonItem::paint(painter, option, widget);
|
|
|
|
|
|
|
|
// Here we actually paint the boundaries of the Polygon using the colors that the model provides.
|
|
|
|
// Those are the speed colors of the dives.
|
|
|
|
QPen pen;
|
|
|
|
pen.setCosmetic(true);
|
|
|
|
pen.setWidth(2);
|
2014-02-05 17:45:23 +00:00
|
|
|
QPolygonF poly = polygon();
|
2014-01-14 19:17:17 +00:00
|
|
|
// This paints the colors of the velocities.
|
2014-01-16 04:50:56 +00:00
|
|
|
for (int i = 1, count = dataModel->rowCount(); i < count; i++) {
|
2014-01-14 19:17:17 +00:00
|
|
|
QModelIndex colorIndex = dataModel->index(i, DivePlotDataModel::COLOR);
|
|
|
|
pen.setBrush(QBrush(colorIndex.data(Qt::BackgroundRole).value<QColor>()));
|
|
|
|
painter->setPen(pen);
|
2014-02-05 17:45:23 +00:00
|
|
|
painter->drawLine(poly[i-1],poly[i]);
|
2014-01-14 19:17:17 +00:00
|
|
|
}
|
|
|
|
}
|
2014-01-16 18:21:23 +00:00
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
void DiveProfileItem::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
2014-01-21 22:27:44 +00:00
|
|
|
{
|
2014-02-04 19:34:16 +00:00
|
|
|
if(!shouldCalculateStuff(topLeft, bottomRight))
|
2014-01-23 18:03:19 +00:00
|
|
|
return;
|
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
AbstractProfilePolygonItem::modelDataChanged(topLeft, bottomRight);
|
2014-01-21 22:27:44 +00:00
|
|
|
if (polygon().isEmpty())
|
2014-01-16 18:21:23 +00:00
|
|
|
return;
|
2014-01-21 19:07:22 +00:00
|
|
|
|
2014-01-21 20:16:19 +00:00
|
|
|
show_reported_ceiling = prefs.profile_dc_ceiling;
|
|
|
|
reported_ceiling_in_red = prefs.profile_red_ceiling;
|
|
|
|
|
2014-01-21 19:07:22 +00:00
|
|
|
/* Show any ceiling we may have encountered */
|
2014-01-21 19:11:04 +00:00
|
|
|
if (prefs.profile_dc_ceiling && !prefs.profile_red_ceiling) {
|
2014-01-21 19:07:22 +00:00
|
|
|
QPolygonF p = polygon();
|
2014-02-04 19:34:16 +00:00
|
|
|
plot_data *entry = dataModel->data().entry + dataModel->rowCount()-1;
|
2014-01-21 19:07:22 +00:00
|
|
|
for (int i = dataModel->rowCount() - 1; i >= 0; i--, entry--) {
|
|
|
|
if (!entry->in_deco) {
|
|
|
|
/* not in deco implies this is a safety stop, no ceiling */
|
|
|
|
p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(0)));
|
|
|
|
} else if (entry->stopdepth < entry->depth) {
|
|
|
|
p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->stopdepth)));
|
|
|
|
} else {
|
|
|
|
p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->depth)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setPolygon(p);
|
|
|
|
}
|
|
|
|
|
2014-01-16 18:21:23 +00:00
|
|
|
// This is the blueish gradient that the Depth Profile should have.
|
|
|
|
// It's a simple QLinearGradient with 2 stops, starting from top to bottom.
|
|
|
|
QLinearGradient pat(0, polygon().boundingRect().top(), 0, polygon().boundingRect().bottom());
|
|
|
|
pat.setColorAt(1, getColor(DEPTH_BOTTOM));
|
|
|
|
pat.setColorAt(0, getColor(DEPTH_TOP));
|
2014-01-21 22:27:44 +00:00
|
|
|
setBrush(QBrush(pat));
|
2014-01-21 15:27:08 +00:00
|
|
|
|
|
|
|
int last = -1;
|
|
|
|
for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
|
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
struct plot_data *entry = dataModel->data().entry+i;
|
2014-01-21 15:27:08 +00:00
|
|
|
if (entry->depth < 2000)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((entry == entry->max[2]) && entry->depth / 100 != last) {
|
2014-01-29 15:48:06 +00:00
|
|
|
plot_depth_sample(entry, Qt::AlignHCenter | Qt::AlignBottom, getColor(SAMPLE_DEEP));
|
2014-01-21 15:27:08 +00:00
|
|
|
last = entry->depth / 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((entry == entry->min[2]) && entry->depth / 100 != last) {
|
2014-01-29 15:48:06 +00:00
|
|
|
plot_depth_sample(entry, Qt::AlignHCenter | Qt::AlignTop, getColor(SAMPLE_SHALLOW));
|
2014-01-21 15:27:08 +00:00
|
|
|
last = entry->depth / 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->depth != last)
|
|
|
|
last = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-21 20:16:19 +00:00
|
|
|
void DiveProfileItem::preferencesChanged()
|
|
|
|
{
|
|
|
|
//TODO: Only modelDataChanged() here if we need to rebuild the graph ( for instance,
|
|
|
|
// if the prefs.profile_dc_ceiling are enabled, but prefs.profile_red_ceiling is disabled
|
|
|
|
// and only if it changed something. let's not waste cpu cycles repoloting something we don't need to.
|
|
|
|
modelDataChanged();
|
|
|
|
}
|
|
|
|
|
2014-01-21 15:27:08 +00:00
|
|
|
void DiveProfileItem::plot_depth_sample(struct plot_data *entry,QFlags<Qt::AlignmentFlag> flags,const QColor& color)
|
|
|
|
{
|
|
|
|
int decimals;
|
|
|
|
double d = get_depth_units(entry->depth, &decimals, NULL);
|
|
|
|
DiveTextItem *item = new DiveTextItem(this);
|
|
|
|
item->setPos(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->depth));
|
|
|
|
item->setText(QString("%1").arg(d, 0, 'f', 1));
|
|
|
|
item->setAlignment(flags);
|
|
|
|
item->setBrush(color);
|
|
|
|
texts.append(item);
|
2014-01-16 20:39:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DiveTemperatureItem::DiveTemperatureItem()
|
|
|
|
{
|
|
|
|
QPen pen;
|
|
|
|
pen.setBrush(QBrush(getColor(::TEMP_PLOT)));
|
|
|
|
pen.setCosmetic(true);
|
|
|
|
pen.setWidth(2);
|
|
|
|
setPen(pen);
|
|
|
|
}
|
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
void DiveTemperatureItem::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
2014-01-16 20:39:13 +00:00
|
|
|
{
|
2014-02-14 23:17:31 +00:00
|
|
|
int last = -300, last_printed_temp = 0, sec = 0, last_valid_temp = 0;
|
2014-01-16 20:39:13 +00:00
|
|
|
// We don't have enougth data to calculate things, quit.
|
2014-02-04 19:34:16 +00:00
|
|
|
if (!shouldCalculateStuff(topLeft, bottomRight))
|
2014-01-16 20:39:13 +00:00
|
|
|
return;
|
|
|
|
|
2014-01-19 19:38:22 +00:00
|
|
|
qDeleteAll(texts);
|
|
|
|
texts.clear();
|
2014-01-16 20:39:13 +00:00
|
|
|
// Ignore empty values. things do not look good with '0' as temperature in kelvin...
|
|
|
|
QPolygonF poly;
|
|
|
|
for (int i = 0, modelDataCount = dataModel->rowCount(); i < modelDataCount; i++) {
|
2014-01-17 19:54:47 +00:00
|
|
|
int mkelvin = dataModel->index(i, vDataColumn).data().toInt();
|
2014-01-21 22:27:44 +00:00
|
|
|
if (!mkelvin)
|
2014-01-16 20:39:13 +00:00
|
|
|
continue;
|
2014-02-14 23:17:31 +00:00
|
|
|
last_valid_temp = mkelvin;
|
2014-02-11 22:01:53 +00:00
|
|
|
sec = dataModel->index(i, hDataColumn).data().toInt();
|
2014-01-17 19:54:47 +00:00
|
|
|
QPointF point( hAxis->posAtValue(sec), vAxis->posAtValue(mkelvin));
|
2014-01-16 20:39:13 +00:00
|
|
|
poly.append(point);
|
2014-01-17 19:54:47 +00:00
|
|
|
|
|
|
|
/* don't print a temperature
|
|
|
|
* if it's been less than 5min and less than a 2K change OR
|
|
|
|
* if it's been less than 2min OR if the change from the
|
|
|
|
* last print is less than .4K (and therefore less than 1F) */
|
|
|
|
if (((sec < last + 300) && (abs(mkelvin - last_printed_temp) < 2000)) ||
|
|
|
|
(sec < last + 120) ||
|
|
|
|
(abs(mkelvin - last_printed_temp) < 400))
|
|
|
|
continue;
|
|
|
|
last = sec;
|
|
|
|
if (mkelvin > 200000)
|
|
|
|
createTextItem(sec,mkelvin);
|
|
|
|
last_printed_temp = mkelvin;
|
2014-01-16 20:39:13 +00:00
|
|
|
}
|
|
|
|
setPolygon(poly);
|
2014-01-17 19:54:47 +00:00
|
|
|
|
|
|
|
/* it would be nice to print the end temperature, if it's
|
|
|
|
* different or if the last temperature print has been more
|
|
|
|
* than a quarter of the dive back */
|
2014-02-14 23:17:31 +00:00
|
|
|
if (last_valid_temp > 200000 &&
|
|
|
|
((abs(last_valid_temp - last_printed_temp) > 500) || ((double)last / (double)sec < 0.75))) {
|
|
|
|
createTextItem(sec, last_valid_temp);
|
2014-01-17 19:54:47 +00:00
|
|
|
}
|
2014-02-15 22:44:49 +00:00
|
|
|
if( texts.count())
|
|
|
|
texts.last()->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
|
2014-01-17 19:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiveTemperatureItem::createTextItem(int sec, int mkelvin)
|
|
|
|
{
|
|
|
|
double deg;
|
|
|
|
const char *unit;
|
|
|
|
deg = get_temp_units(mkelvin, &unit);
|
2014-01-19 19:38:22 +00:00
|
|
|
|
|
|
|
DiveTextItem *text = new DiveTextItem(this);
|
2014-02-07 23:38:06 +00:00
|
|
|
text->setAlignment(Qt::AlignRight | Qt::AlignBottom);
|
2014-01-19 19:38:22 +00:00
|
|
|
text->setBrush(getColor(TEMP_TEXT));
|
|
|
|
text->setPos(QPointF(hAxis->posAtValue(sec), vAxis->posAtValue(mkelvin)));
|
|
|
|
text->setText(QString("%1%2").arg(deg, 0, 'f', 1).arg(unit));
|
|
|
|
// text->setSize(TEMP_TEXT_SIZE); //TODO: TEXT SIZE!
|
2014-01-23 18:07:22 +00:00
|
|
|
texts.append(text);
|
2014-01-16 20:39:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiveTemperatureItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
|
|
|
{
|
2014-02-10 16:41:59 +00:00
|
|
|
if(polygon().isEmpty())
|
|
|
|
return;
|
2014-01-16 20:39:13 +00:00
|
|
|
painter->setPen(pen());
|
|
|
|
painter->drawPolyline(polygon());
|
|
|
|
}
|
2014-01-17 17:34:15 +00:00
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
void DiveGasPressureItem::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
2014-01-17 17:34:15 +00:00
|
|
|
{
|
|
|
|
// We don't have enougth data to calculate things, quit.
|
2014-02-04 19:34:16 +00:00
|
|
|
if (!shouldCalculateStuff(topLeft, bottomRight))
|
2014-01-17 17:34:15 +00:00
|
|
|
return;
|
|
|
|
int last_index = -1;
|
|
|
|
QPolygonF boundingPoly; // This is the "Whole Item", but a pressure can be divided in N Polygons.
|
|
|
|
polygons.clear();
|
|
|
|
|
2014-01-21 15:35:40 +00:00
|
|
|
for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
|
2014-02-04 19:34:16 +00:00
|
|
|
plot_data* entry = dataModel->data().entry + i;
|
2014-01-21 15:35:40 +00:00
|
|
|
int mbar = GET_PRESSURE(entry);
|
|
|
|
|
|
|
|
if (entry->cylinderindex != last_index) {
|
2014-01-17 17:34:15 +00:00
|
|
|
polygons.append(QPolygonF()); // this is the polygon that will be actually drawned on screen.
|
2014-01-21 15:35:40 +00:00
|
|
|
last_index = entry->cylinderindex;
|
2014-01-17 17:34:15 +00:00
|
|
|
}
|
|
|
|
if (!mbar) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-01-21 15:35:40 +00:00
|
|
|
QPointF point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(mbar));
|
2014-01-17 17:34:15 +00:00
|
|
|
boundingPoly.push_back(point); // The BoundingRect
|
|
|
|
polygons.last().push_back(point); // The polygon thta will be plotted.
|
|
|
|
}
|
|
|
|
setPolygon(boundingPoly);
|
2014-01-23 17:37:50 +00:00
|
|
|
qDeleteAll(texts);
|
|
|
|
texts.clear();
|
2014-01-21 16:05:29 +00:00
|
|
|
int mbar, cyl;
|
|
|
|
int seen_cyl[MAX_CYLINDERS] = { false, };
|
|
|
|
int last_pressure[MAX_CYLINDERS] = { 0, };
|
|
|
|
int last_time[MAX_CYLINDERS] = { 0, };
|
|
|
|
struct plot_data *entry;
|
|
|
|
struct dive *dive = getDiveById(dataModel->id());
|
|
|
|
Q_ASSERT(dive != NULL);
|
|
|
|
|
|
|
|
cyl = -1;
|
|
|
|
for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
|
2014-02-04 19:34:16 +00:00
|
|
|
entry = dataModel->data().entry + i;
|
2014-01-21 16:05:29 +00:00
|
|
|
mbar = GET_PRESSURE(entry);
|
|
|
|
|
|
|
|
if (!mbar)
|
|
|
|
continue;
|
|
|
|
if (cyl != entry->cylinderindex) {
|
|
|
|
cyl = entry->cylinderindex;
|
|
|
|
if (!seen_cyl[cyl]) {
|
2014-01-29 15:48:06 +00:00
|
|
|
plot_pressure_value(mbar, entry->sec, Qt::AlignRight | Qt::AlignTop);
|
|
|
|
plot_gas_value(mbar, entry->sec, Qt::AlignRight | Qt::AlignBottom,
|
2014-01-21 16:14:52 +00:00
|
|
|
get_o2(&dive->cylinder[cyl].gasmix),
|
|
|
|
get_he(&dive->cylinder[cyl].gasmix));
|
2014-01-21 16:05:29 +00:00
|
|
|
seen_cyl[cyl] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
last_pressure[cyl] = mbar;
|
|
|
|
last_time[cyl] = entry->sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
|
|
|
|
if (last_time[cyl]) {
|
2014-02-15 00:04:18 +00:00
|
|
|
plot_pressure_value(last_pressure[cyl], last_time[cyl], Qt::AlignLeft | Qt::AlignTop);
|
2014-01-21 16:05:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiveGasPressureItem::plot_pressure_value(int mbar, int sec, QFlags<Qt::AlignmentFlag> flags)
|
|
|
|
{
|
|
|
|
const char *unit;
|
|
|
|
int pressure = get_pressure_units(mbar, &unit);
|
|
|
|
DiveTextItem *text = new DiveTextItem(this);
|
2014-01-29 15:48:06 +00:00
|
|
|
text->setPos(hAxis->posAtValue(sec), vAxis->posAtValue(mbar)-0.5);
|
2014-01-21 16:05:29 +00:00
|
|
|
text->setText(QString("%1 %2").arg(pressure).arg(unit));
|
|
|
|
text->setAlignment(flags);
|
|
|
|
text->setBrush(getColor(PRESSURE_TEXT));
|
|
|
|
texts.push_back(text);
|
2014-01-17 17:34:15 +00:00
|
|
|
}
|
|
|
|
|
2014-01-21 16:14:52 +00:00
|
|
|
void DiveGasPressureItem::plot_gas_value(int mbar, int sec, QFlags<Qt::AlignmentFlag> flags, int o2, int he)
|
|
|
|
{
|
|
|
|
QString gas = (is_air(o2, he)) ? tr("air") :
|
|
|
|
(he == 0) ? QString(tr("EAN%1")).arg((o2 + 5) / 10) :
|
|
|
|
QString("%1/%2").arg((o2 + 5) / 10).arg((he + 5) / 10);
|
|
|
|
DiveTextItem *text = new DiveTextItem(this);
|
|
|
|
text->setPos(hAxis->posAtValue(sec), vAxis->posAtValue(mbar));
|
|
|
|
text->setText(gas);
|
|
|
|
text->setAlignment(flags);
|
|
|
|
text->setBrush(getColor(PRESSURE_TEXT));
|
|
|
|
texts.push_back(text);
|
|
|
|
}
|
|
|
|
|
2014-01-17 17:34:15 +00:00
|
|
|
void DiveGasPressureItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
|
|
|
{
|
2014-02-10 16:41:59 +00:00
|
|
|
if(polygon().isEmpty())
|
|
|
|
return;
|
2014-01-17 17:34:15 +00:00
|
|
|
QPen pen;
|
|
|
|
pen.setCosmetic(true);
|
|
|
|
pen.setWidth(2);
|
2014-01-27 18:17:08 +00:00
|
|
|
struct dive *d = getDiveById(dataModel->id());
|
2014-02-10 08:40:54 +00:00
|
|
|
if (!d)
|
|
|
|
return;
|
2014-02-04 19:34:16 +00:00
|
|
|
struct plot_data *entry = dataModel->data().entry;
|
2014-01-21 22:27:44 +00:00
|
|
|
Q_FOREACH(const QPolygonF& poly, polygons) {
|
2014-01-27 18:17:08 +00:00
|
|
|
for (int i = 1, count = poly.count(); i < count; i++, entry++) {
|
|
|
|
pen.setBrush(getSacColor(entry->sac, d->sac));
|
2014-01-17 17:34:15 +00:00
|
|
|
painter->setPen(pen);
|
|
|
|
painter->drawLine(poly[i-1],poly[i]);
|
|
|
|
}
|
|
|
|
}
|
2014-01-17 19:54:47 +00:00
|
|
|
}
|
2014-01-21 16:59:19 +00:00
|
|
|
|
2014-02-09 17:54:25 +00:00
|
|
|
DiveCalculatedCeiling::DiveCalculatedCeiling() : is3mIncrement(false), gradientFactor(new DiveTextItem(this))
|
2014-01-29 12:53:40 +00:00
|
|
|
{
|
|
|
|
gradientFactor->setY(0);
|
|
|
|
gradientFactor->setBrush(getColor(PRESSURE_TEXT));
|
|
|
|
gradientFactor->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
2014-01-29 15:48:06 +00:00
|
|
|
preferencesChanged();
|
2014-01-29 12:53:40 +00:00
|
|
|
}
|
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
void DiveCalculatedCeiling::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
2014-01-21 16:59:19 +00:00
|
|
|
{
|
|
|
|
// We don't have enougth data to calculate things, quit.
|
2014-02-04 19:34:16 +00:00
|
|
|
if (!shouldCalculateStuff(topLeft, bottomRight))
|
2014-01-21 16:59:19 +00:00
|
|
|
return;
|
2014-02-04 19:34:16 +00:00
|
|
|
AbstractProfilePolygonItem::modelDataChanged(topLeft, bottomRight);
|
2014-01-21 16:59:19 +00:00
|
|
|
// Add 2 points to close the polygon.
|
|
|
|
QPolygonF poly = polygon();
|
2014-01-22 20:25:35 +00:00
|
|
|
if (poly.isEmpty())
|
|
|
|
return;
|
2014-01-21 16:59:19 +00:00
|
|
|
QPointF p1 = poly.first();
|
|
|
|
QPointF p2 = poly.last();
|
|
|
|
|
|
|
|
poly.prepend(QPointF(p1.x(), vAxis->posAtValue(0)));
|
|
|
|
poly.append(QPointF(p2.x(), vAxis->posAtValue(0)));
|
|
|
|
setPolygon(poly);
|
|
|
|
|
|
|
|
QLinearGradient pat(0, polygon().boundingRect().top(), 0, polygon().boundingRect().bottom());
|
|
|
|
pat.setColorAt(0, getColor(CALC_CEILING_SHALLOW));
|
|
|
|
pat.setColorAt(1, getColor(CALC_CEILING_DEEP));
|
|
|
|
setPen(QPen(QBrush(Qt::NoBrush),0));
|
|
|
|
setBrush(pat);
|
2014-01-29 12:53:40 +00:00
|
|
|
|
2014-01-29 15:48:06 +00:00
|
|
|
gradientFactor->setX(poly.boundingRect().width()/2 + poly.boundingRect().x());
|
2014-01-29 12:53:40 +00:00
|
|
|
gradientFactor->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh));
|
2014-01-21 16:59:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiveCalculatedCeiling::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
|
|
|
{
|
2014-02-10 16:41:59 +00:00
|
|
|
if(polygon().isEmpty())
|
|
|
|
return;
|
2014-01-21 16:59:19 +00:00
|
|
|
QGraphicsPolygonItem::paint(painter, option, widget);
|
|
|
|
}
|
2014-01-21 19:34:36 +00:00
|
|
|
|
2014-01-22 21:22:07 +00:00
|
|
|
DiveCalculatedTissue::DiveCalculatedTissue()
|
|
|
|
{
|
|
|
|
preferencesChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiveCalculatedTissue::preferencesChanged()
|
|
|
|
{
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup("TecDetails");
|
2014-02-04 23:24:08 +00:00
|
|
|
setVisible(s.value("calcalltissues").toBool() && s.value("calcceiling").toBool());
|
2014-01-22 21:22:07 +00:00
|
|
|
}
|
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
void DiveReportedCeiling::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
2014-01-21 19:34:36 +00:00
|
|
|
{
|
2014-02-04 19:34:16 +00:00
|
|
|
if(!shouldCalculateStuff(topLeft, bottomRight))
|
2014-01-21 19:34:36 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
QPolygonF p;
|
|
|
|
p.append(QPointF(hAxis->posAtValue(0), vAxis->posAtValue(0)));
|
2014-02-04 19:34:16 +00:00
|
|
|
plot_data *entry = dataModel->data().entry;
|
2014-01-21 19:34:36 +00:00
|
|
|
for (int i = 0, count = dataModel->rowCount(); i < count; i++, entry++) {
|
|
|
|
if (entry->in_deco && entry->stopdepth) {
|
|
|
|
if (entry->stopdepth < entry->depth) {
|
|
|
|
p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->stopdepth)));
|
|
|
|
} else {
|
|
|
|
p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(entry->depth)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
p.append(QPointF(hAxis->posAtValue(entry->sec), vAxis->posAtValue(0)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setPolygon(p);
|
|
|
|
QLinearGradient pat(0, p.boundingRect().top(), 0, p.boundingRect().bottom());
|
|
|
|
pat.setColorAt(0, getColor(CEILING_SHALLOW));
|
|
|
|
pat.setColorAt(1, getColor(CEILING_DEEP));
|
|
|
|
setPen(QPen(QBrush(Qt::NoBrush),0));
|
|
|
|
setBrush(pat);
|
|
|
|
}
|
|
|
|
|
2014-01-28 22:48:41 +00:00
|
|
|
void DiveCalculatedCeiling::preferencesChanged()
|
|
|
|
{
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup("TecDetails");
|
2014-02-04 19:34:16 +00:00
|
|
|
|
|
|
|
bool shouldShow3mIncrement = s.value("calcceiling3m").toBool();
|
|
|
|
if ( dataModel && is3mIncrement != shouldShow3mIncrement){
|
|
|
|
// recalculate that part.
|
|
|
|
dataModel->calculateDecompression();
|
|
|
|
}
|
2014-02-04 21:21:57 +00:00
|
|
|
is3mIncrement = shouldShow3mIncrement;
|
2014-01-28 22:48:41 +00:00
|
|
|
setVisible(s.value("calcceiling").toBool());
|
|
|
|
}
|
|
|
|
|
2014-01-21 20:16:19 +00:00
|
|
|
void DiveReportedCeiling::preferencesChanged()
|
|
|
|
{
|
2014-01-22 19:54:24 +00:00
|
|
|
QSettings s;
|
|
|
|
s.beginGroup("TecDetails");
|
|
|
|
setVisible(s.value("redceiling").toBool());
|
2014-01-21 20:16:19 +00:00
|
|
|
}
|
|
|
|
|
2014-01-21 19:34:36 +00:00
|
|
|
void DiveReportedCeiling::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
|
|
|
{
|
2014-02-10 16:41:59 +00:00
|
|
|
if(polygon().isEmpty())
|
|
|
|
return;
|
2014-01-21 19:34:36 +00:00
|
|
|
QGraphicsPolygonItem::paint(painter, option, widget);
|
|
|
|
}
|
2014-01-22 17:08:19 +00:00
|
|
|
|
2014-02-09 17:54:25 +00:00
|
|
|
MeanDepthLine::MeanDepthLine() : meanDepth(0), leftText(new DiveTextItem(this)), rightText(new DiveTextItem(this))
|
2014-01-22 17:08:19 +00:00
|
|
|
{
|
|
|
|
leftText->setAlignment(Qt::AlignRight | Qt::AlignBottom);
|
|
|
|
leftText->setBrush(getColor(MEAN_DEPTH));
|
|
|
|
rightText->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
|
|
|
|
rightText->setBrush(getColor(MEAN_DEPTH));
|
|
|
|
leftText->setPos(0, 0);
|
|
|
|
rightText->setPos(line().length(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeanDepthLine::setLine(qreal x1, qreal y1, qreal x2, qreal y2)
|
|
|
|
{
|
|
|
|
QGraphicsLineItem::setLine(x1, y1, x2, y2);
|
|
|
|
leftText->setPos(x1, 0);
|
|
|
|
rightText->setPos(x2, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeanDepthLine::setMeanDepth(int value)
|
|
|
|
{
|
2014-02-16 18:57:11 +00:00
|
|
|
leftText->setText(get_depth_string(value, false, true));
|
|
|
|
rightText->setText(get_depth_string(value, false, true));
|
2014-02-12 16:41:59 +00:00
|
|
|
meanDepth = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeanDepthLine::setAxis(DiveCartesianAxis* a)
|
|
|
|
{
|
|
|
|
connect(a, SIGNAL(sizeChanged()), this, SLOT(axisLineChanged()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeanDepthLine::axisLineChanged()
|
|
|
|
{
|
|
|
|
DiveCartesianAxis *axis = qobject_cast<DiveCartesianAxis*>(sender());
|
|
|
|
animateMoveTo(x(),axis->posAtValue(meanDepth));
|
2014-01-22 17:08:19 +00:00
|
|
|
}
|
2014-01-23 19:54:34 +00:00
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
void PartialPressureGasItem::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
2014-01-23 19:54:34 +00:00
|
|
|
{
|
|
|
|
//AbstractProfilePolygonItem::modelDataChanged();
|
2014-02-04 19:34:16 +00:00
|
|
|
if (!shouldCalculateStuff(topLeft, bottomRight))
|
2014-01-23 19:54:34 +00:00
|
|
|
return;
|
|
|
|
|
2014-02-04 19:34:16 +00:00
|
|
|
plot_data *entry = dataModel->data().entry;
|
2014-01-23 19:54:34 +00:00
|
|
|
QPolygonF poly;
|
|
|
|
alertPoly.clear();
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup("TecDetails");
|
|
|
|
double threshould = s.value(threshouldKey).toDouble();
|
|
|
|
for(int i = 0; i < dataModel->rowCount(); i++, entry++){
|
|
|
|
double value = dataModel->index(i, vDataColumn).data().toDouble();
|
|
|
|
int time = dataModel->index(i, hDataColumn).data().toInt();
|
|
|
|
QPointF point(hAxis->posAtValue(time), vAxis->posAtValue(value));
|
|
|
|
poly.push_back( point );
|
|
|
|
if (value >= threshould)
|
|
|
|
alertPoly.push_back(point);
|
|
|
|
}
|
|
|
|
setPolygon(poly);
|
|
|
|
/*
|
|
|
|
createPPLegend(trUtf8("pN" UTF8_SUBSCRIPT_2),getColor(PN2), legendPos);
|
|
|
|
*/
|
|
|
|
}
|
2014-01-27 17:14:42 +00:00
|
|
|
|
2014-01-23 19:54:34 +00:00
|
|
|
void PartialPressureGasItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
2014-01-27 17:14:42 +00:00
|
|
|
{
|
|
|
|
painter->setPen(normalColor);
|
2014-01-23 19:54:34 +00:00
|
|
|
painter->drawPolyline(polygon());
|
2014-01-27 17:14:42 +00:00
|
|
|
painter->setPen(alertColor);
|
2014-01-23 19:54:34 +00:00
|
|
|
painter->drawPolyline(alertPoly);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartialPressureGasItem::setThreshouldSettingsKey(const QString& threshouldSettingsKey)
|
|
|
|
{
|
|
|
|
threshouldKey = threshouldSettingsKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
PartialPressureGasItem::PartialPressureGasItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartialPressureGasItem::preferencesChanged()
|
|
|
|
{
|
2014-01-27 17:14:42 +00:00
|
|
|
QSettings s;
|
|
|
|
s.beginGroup("TecDetails");
|
|
|
|
setVisible( s.value(visibilityKey).toBool() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartialPressureGasItem::setVisibilitySettingsKey(const QString& key)
|
|
|
|
{
|
|
|
|
visibilityKey = key;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartialPressureGasItem::setColors(const QColor& normal, const QColor& alert)
|
|
|
|
{
|
|
|
|
normalColor = normal;
|
|
|
|
alertColor = alert;
|
2014-01-23 19:54:34 +00:00
|
|
|
}
|