subsurface/qt-ui/profile/divecartesianaxis.cpp
Tomaz Canabrava c99089e1fa Add settings awareness for the PP graph
This commit is rather big, and I forgot to cut it in pieces.
The first part creates a new 'calculate_gas_information' that will not
fill the profile_info->maxpp member ( that should be removed from it as
soon as the new dialog is finished ). The reason for that is that all of
the profile data will be calculated and the graph needs to update
dynamically, so whenever the settings changes, I ask for the model which
is the biggest graph and replot only the ones we need.

The second part adds a new animation function 'animdelete' to fade-out and
delete the item when it's done. the old function 'hide' did just that but
a hide shouldn't delete anything.

The third part is preferenes awareness for the PP graphs. I created two
new functions that receive the settings key for visibility and use the
QSettings to show / hide them. This also works quite well for the axis;
if no graph is visible, the axis will also hide itself.

The fourth part is colors. The pp graphs now have the correct colors.

And a bit of code cleanup too.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-01-27 09:15:28 -08:00

410 lines
9.7 KiB
C++

#include "divecartesianaxis.h"
#include "divelineitem.h"
#include "divetextitem.h"
#include "helpers.h"
#include "preferences.h"
#include "diveplotdatamodel.h"
#include "animationfunctions.h"
#include <QPen>
#include <QGraphicsScene>
#include <QDebug>
#include <QGraphicsView>
#include <QStyleOption>
#include <QSettings>
static QPen gridPen(){
QPen pen;
pen.setColor(getColor(TIME_GRID));
pen.setWidth(2);
pen.setCosmetic(true);
return pen;
}
void DiveCartesianAxis::setMaximum(double maximum)
{
max = maximum;
emit maxChanged();
}
void DiveCartesianAxis::setMinimum(double minimum)
{
min = minimum;
}
void DiveCartesianAxis::setTextColor(const QColor& color)
{
textColor = color;
}
DiveCartesianAxis::DiveCartesianAxis() : orientation(LeftToRight), showTicks(true), showText(true)
{
setPen(gridPen());
}
DiveCartesianAxis::~DiveCartesianAxis()
{
}
void DiveCartesianAxis::setOrientation(Orientation o)
{
orientation = o;
}
QColor DiveCartesianAxis::colorForValue(double value)
{
return QColor(Qt::black);
}
void DiveCartesianAxis::updateTicks()
{
if (!scene())
return;
QLineF m = line();
// unused so far:
// QGraphicsView *view = scene()->views().first();
double steps = (max - min) / interval;
double currValue = min;
if(!showText && !labels.isEmpty()){
qDeleteAll(labels);
labels.clear();
}
if (steps < 1)
return;
if (!labels.isEmpty() && labels.size() > steps) {
while (labels.size() > steps) {
DiveTextItem *removedText = labels.takeLast();
Animations::animDelete(removedText);
}
}
// Move the remaining Ticks / Text to it's corerct position
// Regartind the possibly new values for the Axis
qreal begin, stepSize;
if (orientation == TopToBottom) {
begin = m.y1();
stepSize = (m.y2() - m.y1());
} else if (orientation == BottomToTop) {
begin = m.y2();
stepSize = (m.y2() - m.y1());
} else if (orientation == LeftToRight ) {
begin = m.x1();
stepSize = (m.x2() - m.x1());
} else if (orientation == RightToLeft) {
begin = m.x2();
stepSize = (m.x2() - m.x1());
}
stepSize = stepSize / steps;
for (int i = 0, count = labels.size(); i < count; i++, currValue += interval) {
qreal childPos;
if (orientation == TopToBottom || orientation == LeftToRight) {
childPos = begin + i * stepSize;
} else {
childPos = begin - i * stepSize;
}
labels[i]->setText(textForValue(currValue));
if ( orientation == LeftToRight || orientation == RightToLeft) {
labels[i]->animateMoveTo(childPos, m.y1() + tickSize);
} else {
labels[i]->animateMoveTo(m.x1() - tickSize, childPos);
}
}
// Add's the rest of the needed Ticks / Text.
for (int i = labels.size(); i < steps; i++, currValue += interval) {
qreal childPos;
if (orientation == TopToBottom || orientation == LeftToRight) {
childPos = begin + i * stepSize;
} else {
childPos = begin - i * stepSize;
}
DiveTextItem *label = NULL;
if (showText){
label = new DiveTextItem(this);
label->setText(textForValue(currValue));
label->setBrush(QBrush(textColor));
label->setBrush(colorForValue(currValue));
}
labels.push_back(label);
if (orientation == RightToLeft || orientation == LeftToRight) {
if(showText){
label->setAlignment(Qt::AlignBottom | Qt::AlignHCenter);
label->setPos(scene()->sceneRect().width() + 10, m.y1() + tickSize); // position it outside of the scene);
label->animateMoveTo(childPos, m.y1() + tickSize);
}
} else {
if(showText){
label->setAlignment(Qt::AlignVCenter| Qt::AlignRight);
label->setPos(m.x1() - tickSize, scene()->sceneRect().height() + 10);
label->animateMoveTo(m.x1() - tickSize, childPos);
}
}
}
}
void DiveCartesianAxis::animateChangeLine(const QLineF& newLine)
{
setLine(newLine);
updateTicks();
sizeChanged();
}
void DiveCartesianAxis::setShowText(bool show)
{
showText = show;
updateTicks();
}
void DiveCartesianAxis::setShowTicks(bool show)
{
showTicks = show;
updateTicks();
}
QString DiveCartesianAxis::textForValue(double value)
{
return QString::number(value);
}
void DiveCartesianAxis::setTickSize(qreal size)
{
tickSize = size;
}
void DiveCartesianAxis::setTickInterval(double i)
{
interval = i;
}
qreal DiveCartesianAxis::valueAt(const QPointF& p)
{
QLineF m = line();
double retValue = orientation == LeftToRight || RightToLeft?
max * (p.x() - m.x1()) / (m.x2() - m.x1()) :
max * (p.y() - m.y1()) / (m.y2() - m.y1());
return retValue;
}
qreal DiveCartesianAxis::posAtValue(qreal value)
{
QLineF m = line();
QPointF p = pos();
double size = max - min;
// unused for now:
// double distanceFromOrigin = value - min;
double percent = IS_FP_SAME(min,max) ? 0.0 : (value - min) / size;
double realSize = orientation == LeftToRight || orientation == RightToLeft?
m.x2() - m.x1() :
m.y2() - m.y1();
// Inverted axis, just invert the percentage.
if (orientation == RightToLeft || orientation == BottomToTop)
percent = 1 - percent;
double retValue = realSize * percent;
double adjusted =
orientation == LeftToRight ? retValue + m.x1() + p.x() :
orientation == RightToLeft ? retValue + m.x1() + p.x() :
orientation == TopToBottom ? retValue + m.y1() + p.y() :
/* entation == BottomToTop */ retValue + m.y1() + p.y() ;
return adjusted;
}
qreal DiveCartesianAxis::percentAt(const QPointF& p)
{
qreal value = valueAt(p);
double size = max - min;
double percent = value / size;
return percent;
}
double DiveCartesianAxis::maximum() const
{
return max;
}
double DiveCartesianAxis::minimum() const
{
return min;
}
void DiveCartesianAxis::setColor(const QColor& color)
{
QPen defaultPen(color);
defaultPen.setJoinStyle(Qt::RoundJoin);
defaultPen.setCapStyle(Qt::RoundCap);
defaultPen.setWidth(2);
defaultPen.setCosmetic(true);
setPen(defaultPen);
}
QString DepthAxis::textForValue(double value)
{
return get_depth_string(value, false, false);
}
QColor DepthAxis::colorForValue(double value)
{
Q_UNUSED(value);
return QColor(Qt::red);
}
DepthAxis::DepthAxis()
{
connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged()));
settingsChanged(); // force the correct size of the line.
}
void DepthAxis::settingsChanged()
{
QSettings s;
s.beginGroup("TecDetails");
bool ppGraph = s.value("phegraph").toBool() || s.value("po2graph").toBool() || s.value("pn2graph").toBool();
if (ppGraph) {
animateChangeLine(QLineF(0,2,0,60));
} else {
animateChangeLine(QLineF(0,2,0,98));
}
}
QColor TimeAxis::colorForValue(double value)
{
Q_UNUSED(value);
return QColor(Qt::blue);
}
QString TimeAxis::textForValue(double value)
{
return QString::number(value / 60);
}
QString TemperatureAxis::textForValue(double value)
{
return QString::number(mkelvin_to_C( (int) value));
}
void DiveCartesianPlane::setLeftAxis(DiveCartesianAxis* axis)
{
leftAxis = axis;
connect(leftAxis, SIGNAL(maxChanged()), this, SLOT(setup()));
if (bottomAxis)
setup();
}
void DiveCartesianPlane::setBottomAxis(DiveCartesianAxis* axis)
{
bottomAxis = axis;
connect(bottomAxis, SIGNAL(maxChanged()), this, SLOT(setup()));
if (leftAxis)
setup();
}
QLineF DiveCartesianPlane::horizontalLine() const
{
return (bottomAxis) ? bottomAxis->line() : QLineF();
}
void DiveCartesianPlane::setHorizontalLine(QLineF line)
{
if ( horizontalSize == line.length())
return;
horizontalSize = line.length();
setup();
}
void DiveCartesianPlane::setVerticalLine(QLineF line)
{
if (verticalSize == line.length())
return;
verticalSize = line.length();
setup();
}
QLineF DiveCartesianPlane::verticalLine() const
{
return (leftAxis) ? leftAxis->line() : QLineF();
}
void DiveCartesianPlane::setup()
{
if (!leftAxis || !bottomAxis || !scene())
return;
// This creates a Grid around the axis, creating the cartesian plane.
const int top = leftAxis->posAtValue(leftAxis->minimum());
// unused for now:
// const int bottom = leftAxis->posAtValue(leftAxis->maximum());
const int left = bottomAxis->posAtValue(bottomAxis->minimum());
// unused for now:
// const int right = bottomAxis->posAtValue(bottomAxis->maximum());
setRect(0, 0, horizontalSize, verticalSize);
setPos(left, top);
qDeleteAll(horizontalLines);
qDeleteAll(verticalLines);
horizontalLines.clear();
verticalLines.clear();
// DEPTH is M_OR_FEET(10,30), Minutes are 600, per line.
for (int i = leftAxis->minimum(), max = leftAxis->maximum(); i < max; i += M_OR_FT(10,30)) {
DiveLineItem *line = new DiveLineItem();
line->setLine(0, 0, horizontalSize, 0);
line->setPos(left,leftAxis->posAtValue(i));
line->setZValue(-1);
line->setPen(gridPen());
horizontalLines.push_back(line);
scene()->addItem(line);
}
for (int i = bottomAxis->minimum(), max = bottomAxis->maximum(); i < max; i += 600) { // increments by 10 minutes.
DiveLineItem *line = new DiveLineItem();
line->setLine(0, 0, 0, verticalSize);
line->setPos(bottomAxis->posAtValue(i), top);
line->setZValue(-1);
line->setPen(gridPen());
verticalLines.push_back(line);
scene()->addItem(line);
}
}
PartialGasPressureAxis::PartialGasPressureAxis()
{
connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(preferencesChanged()));
}
void PartialGasPressureAxis::setModel(DivePlotDataModel* m)
{
model = m;
connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(preferencesChanged()));
preferencesChanged();
}
void PartialGasPressureAxis::preferencesChanged()
{
QSettings s;
s.beginGroup("TecDetails");
bool showPhe = s.value("phegraph").toBool();
bool showPn2 = s.value("pn2graph").toBool();
bool showPo2 = s.value("po2graph").toBool();
setVisible(showPhe || showPn2 || showPo2);
if (!model->rowCount())
return;
double max = showPhe ? model->pheMax() : -1;
if (showPn2 && model->pn2Max() > max)
max = model->pn2Max();
if( showPo2 && model->po2Max() > max)
max = model->po2Max();
qreal pp = floor(max * 10.0) / 10.0 + 0.2;
setMaximum(pp);
setTickInterval( pp > 4 ? 0.5 : 0.25 );
updateTicks();
}