subsurface/qt-ui/diveplanner.cpp
Tomaz Canabrava 8fcd465a65 Make skeleton of 'create_deco_stop'.
This is a skeleton of 'create_deco_stop' plus a bit of
code cleanup. I'v commented the create_deco_stop so that
the other developers can help me a bit here - since I don't
know too well the internals of subsurface. In the original
GTK code - a new dive was created every time a user changed
something on the dive, I don't know if this will be needed,
I jusst need two things: the correct time of dive calculated
by the app, and the points to put the decompression lines.

The usability of the widget right now is 'ok', nothing to
be proud of, it's ugly as hell too, and the Rules are in
the wrong position ( they are 'inside' the area where
the lines are being drawn, but htis is easily fixable. )

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2013-06-20 18:25:03 -03:00

308 lines
7.9 KiB
C++

#include "diveplanner.h"
#include <QMouseEvent>
#include <QDebug>
DivePlanner* DivePlanner::instance()
{
static DivePlanner *self = new DivePlanner();
return self;
}
DivePlanner::DivePlanner(QWidget* parent): QGraphicsView(parent), activeDraggedHandler(0)
{
setMouseTracking(true);
setScene( new QGraphicsScene());
scene()->setSceneRect(0,0,100,100);
verticalLine = new QGraphicsLineItem(0,0,0, 100);
verticalLine->setPen(QPen(Qt::DotLine));
scene()->addItem(verticalLine);
horizontalLine = new QGraphicsLineItem(0,0,100,0);
horizontalLine->setPen(QPen(Qt::DotLine));
scene()->addItem(horizontalLine);
timeLine = new Ruler();
timeLine->setMinimum(0);
timeLine->setMaximum(60);
timeLine->setTickInterval(10);
timeLine->setLine( 10, 90, 99, 90);
timeLine->setOrientation(Qt::Horizontal);
timeLine->updateTicks();
scene()->addItem(timeLine);
depthLine = new Ruler();
depthLine->setMinimum(0);
depthLine->setMaximum(400);
depthLine->setTickInterval(10);
depthLine->setLine( 10, 1, 10, 90);
depthLine->setOrientation(Qt::Vertical);
depthLine->updateTicks();
scene()->addItem(depthLine);
timeString = new QGraphicsSimpleTextItem();
timeString->setFlag(QGraphicsItem::ItemIgnoresTransformations);
scene()->addItem(timeString);
depthString = new QGraphicsSimpleTextItem();
depthString->setFlag(QGraphicsItem::ItemIgnoresTransformations);
scene()->addItem(depthString);
}
void DivePlanner::mouseDoubleClickEvent(QMouseEvent* event)
{
QPointF mappedPos = mapToScene(event->pos());
if(isPointOutOfBoundaries(mappedPos))
return;
if(handles.count() && handles.last()->x() > mappedPos.x()){
return;
}
DiveHandler *item = new DiveHandler ();
item->setRect(-5,-5,10,10);
item->setFlag(QGraphicsItem::ItemIgnoresTransformations);
item->setPos( mappedPos );
scene()->addItem(item);
handles << item;
if (lines.empty()){
QGraphicsLineItem *first = new QGraphicsLineItem(0,0, mappedPos.x(), mappedPos.y());
item->from = first;
lines.push_back(first);
create_deco_stop();
scene()->addItem(first);
}else{
clear_generated_deco();
DiveHandler *prevHandle = handles.at( handles.count()-2);
QGraphicsLineItem *line = new QGraphicsLineItem(prevHandle->x(), prevHandle->y(), item->x(), item->y());
prevHandle->to = line;
item->from = line;
lines.push_back(line);
scene()->addItem(line);
create_deco_stop();
}
item->time = (timeLine->valueAt(mappedPos));
item->depth = (depthLine->valueAt(mappedPos));
}
void DivePlanner::clear_generated_deco()
{
for(int i = handles.count(); i <= lines.count(); i++){
scene()->removeItem(lines.last());
delete lines.last();
lines.removeLast();
}
}
void DivePlanner::create_deco_stop()
{
// This needs to be done in the following steps:
// Get the user-input and calculate the dive info
Q_FOREACH(DiveHandler *h, handles){
// use this somewhere.
h->time;
h->depth;
}
// create the dive info here.
// set the new 'end time' of the dive.
// note that this is not the user end,
// but the real end of the dive.
timeLine->setMaximum(60);
timeLine->updateTicks();
// Re-position the user generated dive handlers
Q_FOREACH(DiveHandler *h, handles){
// uncomment this as soon as the posAtValue is implemented.
// h->setPos( timeLine->posAtValue(h->time),
// depthLine->posAtValue(h->depth));
}
// Create all 'deco' GraphicsLineItems and put it on the canvas.This following three lines will
// most probably need to enter on a loop.
QGraphicsLineItem *item = new QGraphicsLineItem(handles.last()->x(), handles.last()->y(), 100, 0);
scene()->addItem(item);
lines << item;
}
void DivePlanner::resizeEvent(QResizeEvent* event)
{
QGraphicsView::resizeEvent(event);
fitInView(sceneRect(), Qt::KeepAspectRatio);
}
void DivePlanner::showEvent(QShowEvent* event)
{
QGraphicsView::showEvent(event);
fitInView(sceneRect(), Qt::KeepAspectRatio);
}
void DivePlanner::mouseMoveEvent(QMouseEvent* event)
{
QPointF mappedPos = mapToScene(event->pos());
if (isPointOutOfBoundaries(mappedPos))
return;
verticalLine->setLine(mappedPos.x(), 0, mappedPos.x(), 100);
horizontalLine->setLine(0, mappedPos.y(), 100, mappedPos.y());
depthString->setText(QString::number(depthLine->valueAt(mappedPos)));
depthString->setPos(0, mappedPos.y());
timeString->setText(QString::number( (int) timeLine->valueAt(mappedPos)) + "min");
timeString->setPos(mappedPos.x()+1, 90);
if(activeDraggedHandler)
moveActiveHandler(mappedPos);
if (!handles.count())
return;
if (handles.last()->x() > mappedPos.x()){
verticalLine->setPen( QPen(QBrush(Qt::red), 0, Qt::SolidLine));
horizontalLine->setPen( QPen(QBrush(Qt::red), 0, Qt::SolidLine));
}else{
verticalLine->setPen(QPen(Qt::DotLine));
horizontalLine->setPen(QPen(Qt::DotLine));
}
}
void DivePlanner::moveActiveHandler(QPointF pos)
{
int idx = handles.indexOf(activeDraggedHandler);
bool moveLines = false;;
// do not allow it to move between handlers.
if (handles.count() > 1){
if (idx == 0 ){ // first
if (pos.x() < handles[1]->x()){
activeDraggedHandler->setPos(pos);
moveLines = true;
}
}else if (idx == handles.count()-1){ // last
if (pos.x() > handles[idx-1]->x()){
activeDraggedHandler->setPos(pos);
moveLines = true;
}
}else{ // middle
if (pos.x() > handles[idx-1]->x() && pos.x() < handles[idx+1]->x()){
activeDraggedHandler->setPos(pos);
moveLines = true;
}
}
}else{
activeDraggedHandler->setPos(pos);
moveLines = true;
}
if (moveLines){
if (activeDraggedHandler->from){
QLineF f = activeDraggedHandler->from->line();
activeDraggedHandler->from->setLine(f.x1(), f.y1(), pos.x(), pos.y());
}
if (activeDraggedHandler->to){
QLineF f = activeDraggedHandler->to->line();
activeDraggedHandler->to->setLine(pos.x(), pos.y(), f.x2(), f.y2());
}
if(activeDraggedHandler == handles.last()){
clear_generated_deco();
create_deco_stop();
}
}
}
bool DivePlanner::isPointOutOfBoundaries(QPointF point)
{
if (point.x() > sceneRect().width()
|| point.x() < 0
|| point.y() < 0
|| point.y() > sceneRect().height())
{
return true;
}
return false;
}
void DivePlanner::mousePressEvent(QMouseEvent* event)
{
QPointF mappedPos = mapToScene(event->pos());
Q_FOREACH(QGraphicsItem *item, scene()->items(mappedPos)){
if (DiveHandler *h = qgraphicsitem_cast<DiveHandler*>(item)){
activeDraggedHandler = h;
activeDraggedHandler->setBrush(Qt::red);
}
}
}
void DivePlanner::mouseReleaseEvent(QMouseEvent* event)
{
if (activeDraggedHandler){
QPointF mappedPos = mapToScene(event->pos());
activeDraggedHandler->time = (timeLine->valueAt(mappedPos));
activeDraggedHandler->depth = (depthLine->valueAt(mappedPos));
activeDraggedHandler->setBrush(QBrush());
activeDraggedHandler = 0;
}
}
DiveHandler::DiveHandler(): QGraphicsEllipseItem(), from(0), to(0)
{
}
void Ruler::setMaximum(double maximum)
{
max = maximum;
}
void Ruler::setMinimum(double minimum)
{
min = minimum;
}
Ruler::Ruler() : orientation(Qt::Horizontal)
{
}
void Ruler::setOrientation(Qt::Orientation o)
{
orientation = o;
}
void Ruler::updateTicks()
{
qDeleteAll(ticks);
QLineF m = line();
if(orientation == Qt::Horizontal){
double steps = (max - min) / interval;
double stepSize = (m.x2() - m.x1()) / steps;
for(qreal pos = m.x1(); pos < m.x2(); pos += stepSize){
QGraphicsLineItem *l = new QGraphicsLineItem(pos, m.y1(), pos, m.y1() + 1, this);
}
}else{
double steps = (max - min) / interval;
double stepSize = (m.y2() - m.y1()) / steps;
for(qreal pos = m.y1(); pos < m.y2(); pos += stepSize){
QGraphicsLineItem *l = new QGraphicsLineItem(m.x1(), pos, m.x1() - 1, pos, this);
}
}
}
void Ruler::setTickInterval(double i)
{
interval = i;
}
qreal Ruler::valueAt(const QPointF& p)
{
QLineF m = line();
return orientation == Qt::Horizontal
? max * (p.x() - m.x1()) / (m.x2() - m.x1())
: max * (p.y() - m.y1()) / (m.y2() - m.y1());
}
qreal Ruler::posAtValue(qreal value)
{
QLineF m = line();
// I need to finish this later. hungry as hell.
}