mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Added a ruler which can be dragged along the profile
This patch adds a ruler QGraphicsItem which can be dragged along the profile. The ruler displays minimum, maximum and average for depth and speed (ascent/descent rate). Also, all used gas will be displayed. This also adds a new attribute to struct plot_data to store the speed (not just as velocity_t). Signed-off-by: Maximilian Güntner <maximilian.guentner@gmail.com>
This commit is contained in:
parent
3312c9a3a4
commit
248f1b86d1
5 changed files with 411 additions and 8 deletions
4
dive.h
4
dive.h
|
@ -658,6 +658,10 @@ const char *weekday(int wday);
|
||||||
const char *monthname(int mon);
|
const char *monthname(int mon);
|
||||||
|
|
||||||
#define UTF8_DEGREE "\xc2\xb0"
|
#define UTF8_DEGREE "\xc2\xb0"
|
||||||
|
#define UTF8_DELTA "\xce\x94"
|
||||||
|
#define UTF8_UPWARDS_ARROW "\xE2\x86\x91"
|
||||||
|
#define UTF8_DOWNWARDS_ARROW "\xE2\x86\x93"
|
||||||
|
#define UTF8_AVERAGE "\xc3\xb8"
|
||||||
#define UCS4_DEGREE 0xb0
|
#define UCS4_DEGREE 0xb0
|
||||||
#define UTF8_SUBSCRIPT_2 "\xe2\x82\x82"
|
#define UTF8_SUBSCRIPT_2 "\xe2\x82\x82"
|
||||||
#define UTF8_WHITESTAR "\xe2\x98\x86"
|
#define UTF8_WHITESTAR "\xe2\x98\x86"
|
||||||
|
|
134
profile.c
134
profile.c
|
@ -3,6 +3,7 @@
|
||||||
* uses cairo to draw it
|
* uses cairo to draw it
|
||||||
*/
|
*/
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "dive.h"
|
#include "dive.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
@ -389,7 +390,8 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi)
|
||||||
/* vertical velocity in mm/sec */
|
/* vertical velocity in mm/sec */
|
||||||
/* Linus wants to smooth this - let's at least look at the samples that aren't FAST or CRAZY */
|
/* Linus wants to smooth this - let's at least look at the samples that aren't FAST or CRAZY */
|
||||||
if (entry[0].sec - entry[-1].sec) {
|
if (entry[0].sec - entry[-1].sec) {
|
||||||
entry->velocity = velocity((entry[0].depth - entry[-1].depth) / (entry[0].sec - entry[-1].sec));
|
entry->speed = (entry[0].depth - entry[-1].depth) / (entry[0].sec - entry[-1].sec);
|
||||||
|
entry->velocity = velocity(entry->speed);
|
||||||
/* if our samples are short and we aren't too FAST*/
|
/* if our samples are short and we aren't too FAST*/
|
||||||
if (entry[0].sec - entry[-1].sec < 15 && entry->velocity < FAST) {
|
if (entry[0].sec - entry[-1].sec < 15 && entry->velocity < FAST) {
|
||||||
int past = -2;
|
int past = -2;
|
||||||
|
@ -400,6 +402,7 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entry->velocity = STABLE;
|
entry->velocity = STABLE;
|
||||||
|
entry->speed = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,8 +852,8 @@ static struct plot_data *populate_plot_entries(struct dive *dive, struct divecom
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add two final surface events */
|
/* Add two final surface events */
|
||||||
plot_data[idx++].sec = lasttime+10;
|
plot_data[idx++].sec = lasttime+1;
|
||||||
plot_data[idx++].sec = lasttime+20;
|
plot_data[idx++].sec = lasttime+2;
|
||||||
pi->nr = idx;
|
pi->nr = idx;
|
||||||
|
|
||||||
return plot_data;
|
return plot_data;
|
||||||
|
@ -1212,14 +1215,16 @@ static void plot_string(struct plot_data *entry, char *buf, int bufsize,
|
||||||
int pressurevalue, mod, ead, end, eadd;
|
int pressurevalue, mod, ead, end, eadd;
|
||||||
const char *depth_unit, *pressure_unit, *temp_unit;
|
const char *depth_unit, *pressure_unit, *temp_unit;
|
||||||
char *buf2 = malloc(bufsize);
|
char *buf2 = malloc(bufsize);
|
||||||
double depthvalue, tempvalue;
|
double depthvalue, tempvalue, speedvalue;
|
||||||
|
|
||||||
depthvalue = get_depth_units(depth, NULL, &depth_unit);
|
depthvalue = get_depth_units(depth, NULL, &depth_unit);
|
||||||
snprintf(buf, bufsize, _("D:%.1f %s"), depthvalue, depth_unit);
|
snprintf(buf, bufsize, _("D:%.1f %s"), depthvalue, depth_unit);
|
||||||
|
|
||||||
if (prefs.show_time) {
|
if (prefs.show_time) {
|
||||||
memcpy(buf2, buf, bufsize);
|
memcpy(buf2, buf, bufsize);
|
||||||
snprintf(buf, bufsize, _("%s\nT:%d:%02d"), buf2, FRACTION(entry->sec, 60));
|
snprintf(buf, bufsize, _("%s\nT:%d:%02d"), buf2, FRACTION(entry->sec, 60));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressure) {
|
if (pressure) {
|
||||||
pressurevalue = get_pressure_units(pressure, &pressure_unit);
|
pressurevalue = get_pressure_units(pressure, &pressure_unit);
|
||||||
memcpy(buf2, buf, bufsize);
|
memcpy(buf2, buf, bufsize);
|
||||||
|
@ -1230,6 +1235,14 @@ static void plot_string(struct plot_data *entry, char *buf, int bufsize,
|
||||||
memcpy(buf2, buf, bufsize);
|
memcpy(buf2, buf, bufsize);
|
||||||
snprintf(buf, bufsize, _("%s\nT:%.1f %s"), buf2, tempvalue, temp_unit);
|
snprintf(buf, bufsize, _("%s\nT:%.1f %s"), buf2, tempvalue, temp_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
speedvalue = get_depth_units(abs(entry->speed), NULL, &depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
/* Ascending speeds are positive, descending are negative */
|
||||||
|
if (entry->speed > 0)
|
||||||
|
speedvalue *= -1;
|
||||||
|
snprintf(buf, bufsize, _("%s\nV:%.2f %s/s"), buf2, speedvalue, depth_unit);
|
||||||
|
|
||||||
if (entry->ceiling) {
|
if (entry->ceiling) {
|
||||||
depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit);
|
depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit);
|
||||||
memcpy(buf2, buf, bufsize);
|
memcpy(buf2, buf, bufsize);
|
||||||
|
@ -1330,3 +1343,116 @@ void get_plot_details(struct graphics_context *gc, int time, char *buf, int bufs
|
||||||
if (entry)
|
if (entry)
|
||||||
plot_string(entry, buf, bufsize, entry->depth, pressure, temp, pi->has_ndl);
|
plot_string(entry, buf, bufsize, entry->depth, pressure, temp, pi->has_ndl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compare two plot_data entries and writes the results into a string */
|
||||||
|
void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int bufsize, int sum)
|
||||||
|
{
|
||||||
|
struct plot_data *start, *stop, *data;
|
||||||
|
const char *depth_unit, *pressure_unit;
|
||||||
|
char *buf2 = malloc(bufsize);
|
||||||
|
int avg_speed, max_speed, min_speed;
|
||||||
|
int delta_depth, avg_depth, max_depth, min_depth;
|
||||||
|
int bar_used, last_pressure, pressurevalue;
|
||||||
|
int count, last_sec, delta_time;
|
||||||
|
|
||||||
|
double depthvalue, speedvalue;
|
||||||
|
|
||||||
|
if (bufsize > 0)
|
||||||
|
buf[0] = '\0';
|
||||||
|
if (e1 == NULL || e2 == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (e1->sec < e2->sec) {
|
||||||
|
start = e1;
|
||||||
|
stop = e2;
|
||||||
|
} else if (e1->sec > e2->sec) {
|
||||||
|
start = e2;
|
||||||
|
stop = e1;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
max_speed = 0;
|
||||||
|
min_speed = INT_MAX;
|
||||||
|
|
||||||
|
delta_depth = abs(start->depth-stop->depth);
|
||||||
|
delta_time = abs(start->sec-stop->sec);
|
||||||
|
avg_depth = 0;
|
||||||
|
max_depth = 0;
|
||||||
|
min_depth = INT_MAX;
|
||||||
|
bar_used = 0;
|
||||||
|
|
||||||
|
last_sec = start->sec;
|
||||||
|
last_pressure = GET_PRESSURE(start);
|
||||||
|
|
||||||
|
while (data != stop) {
|
||||||
|
data = start+count;
|
||||||
|
if (sum)
|
||||||
|
avg_speed += abs(data->speed)*(data->sec-last_sec);
|
||||||
|
else
|
||||||
|
avg_speed += data->speed*(data->sec-last_sec);
|
||||||
|
avg_depth += data->depth*(data->sec-last_sec);
|
||||||
|
|
||||||
|
if (abs(data->speed) < min_speed)
|
||||||
|
min_speed = abs(data->speed);
|
||||||
|
if (abs(data->speed) > max_speed)
|
||||||
|
max_speed = abs(data->speed);
|
||||||
|
|
||||||
|
if (data->depth < min_depth)
|
||||||
|
min_depth = data->depth;
|
||||||
|
if (data->depth > max_depth)
|
||||||
|
max_depth = data->depth;
|
||||||
|
/* Try to detect gas changes */
|
||||||
|
if (GET_PRESSURE(data) > last_pressure+2000)
|
||||||
|
last_pressure = GET_PRESSURE(data);
|
||||||
|
else
|
||||||
|
bar_used += last_pressure-GET_PRESSURE(data);
|
||||||
|
|
||||||
|
|
||||||
|
count+=1;
|
||||||
|
last_sec = data->sec;
|
||||||
|
last_pressure = GET_PRESSURE(data);
|
||||||
|
}
|
||||||
|
avg_depth /= stop->sec-start->sec;
|
||||||
|
avg_speed /= stop->sec-start->sec;
|
||||||
|
|
||||||
|
snprintf(buf, bufsize, _("%sT: %d:%02d min"), UTF8_DELTA, delta_time/60, delta_time%60);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
depthvalue = get_depth_units(delta_depth, NULL, &depth_unit);
|
||||||
|
snprintf(buf, bufsize, _("%s %sD:%.1f%s"), buf2, UTF8_DELTA, depthvalue, depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
depthvalue = get_depth_units(min_depth, NULL, &depth_unit);
|
||||||
|
snprintf(buf, bufsize, _("%s %sD:%.1f%s"), buf2, UTF8_DOWNWARDS_ARROW, depthvalue, depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
depthvalue = get_depth_units(max_depth, NULL, &depth_unit);
|
||||||
|
snprintf(buf, bufsize, _("%s %sD:%.1f %s"), buf2, UTF8_UPWARDS_ARROW, depthvalue, depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
depthvalue = get_depth_units(avg_depth, NULL, &depth_unit);
|
||||||
|
snprintf(buf, bufsize, _("%s %sD:%.1f%s\n"), buf2, UTF8_AVERAGE, depthvalue, depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
speedvalue = get_depth_units(min_speed, NULL, &depth_unit);
|
||||||
|
snprintf(buf, bufsize, _("%s%sV:%.2f%s/s"), buf2, UTF8_DOWNWARDS_ARROW, speedvalue, depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
speedvalue = get_depth_units(max_speed, NULL, &depth_unit);
|
||||||
|
snprintf(buf, bufsize, _("%s %sV:%.2f%s/s"), buf2, UTF8_UPWARDS_ARROW, speedvalue, depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
speedvalue = get_depth_units(avg_speed, NULL, &depth_unit);
|
||||||
|
snprintf(buf, bufsize, _("%s %sV:%.2f%s/s"), buf2, UTF8_AVERAGE, speedvalue, depth_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
|
||||||
|
/* Only print if gas has been used */
|
||||||
|
if (bar_used) {
|
||||||
|
pressurevalue = get_pressure_units(bar_used, &pressure_unit);
|
||||||
|
memcpy(buf2, buf, bufsize);
|
||||||
|
snprintf(buf, bufsize, _("%s %sP:%d %s"), buf2, UTF8_DELTA, pressurevalue, pressure_unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf2);
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct plot_data {
|
||||||
double po2, pn2, phe;
|
double po2, pn2, phe;
|
||||||
double mod, ead, end, eadd;
|
double mod, ead, end, eadd;
|
||||||
velocity_t velocity;
|
velocity_t velocity;
|
||||||
|
int speed;
|
||||||
struct plot_data *min[3];
|
struct plot_data *min[3];
|
||||||
struct plot_data *max[3];
|
struct plot_data *max[3];
|
||||||
int avg[3];
|
int avg[3];
|
||||||
|
@ -42,6 +43,7 @@ void calculate_max_limits(struct dive *dive, struct divecomputer *dc, struct gra
|
||||||
struct plot_info *create_plot_info(struct dive *dive, struct divecomputer *dc, struct graphics_context *gc);
|
struct plot_info *create_plot_info(struct dive *dive, struct divecomputer *dc, struct graphics_context *gc);
|
||||||
int setup_temperature_limits(struct graphics_context *gc);
|
int setup_temperature_limits(struct graphics_context *gc);
|
||||||
int get_cylinder_pressure_range(struct graphics_context *gc);
|
int get_cylinder_pressure_range(struct graphics_context *gc);
|
||||||
|
void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int bufsize, int sum);
|
||||||
|
|
||||||
struct ev_select {
|
struct ev_select {
|
||||||
char *ev_name;
|
char *ev_name;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <QGraphicsSceneHoverEvent>
|
#include <QGraphicsSceneHoverEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <qtextdocument.h>
|
#include <qtextdocument.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "../color.h"
|
#include "../color.h"
|
||||||
#include "../display.h"
|
#include "../display.h"
|
||||||
|
@ -43,10 +44,11 @@ extern struct ev_select *ev_namelist;
|
||||||
extern int evn_allocated;
|
extern int evn_allocated;
|
||||||
extern int evn_used;
|
extern int evn_used;
|
||||||
|
|
||||||
ProfileGraphicsView::ProfileGraphicsView(QWidget* parent) : QGraphicsView(parent), toolTip(0) , dive(0), diveDC(0)
|
ProfileGraphicsView::ProfileGraphicsView(QWidget* parent) : QGraphicsView(parent), toolTip(0) , dive(0), diveDC(0), rulerItem(0)
|
||||||
{
|
{
|
||||||
printMode = false;
|
printMode = false;
|
||||||
isGrayscale = false;
|
isGrayscale = false;
|
||||||
|
rulerEnabled = false;
|
||||||
gc.printer = false;
|
gc.printer = false;
|
||||||
fill_profile_color();
|
fill_profile_color();
|
||||||
setScene(new QGraphicsScene());
|
setScene(new QGraphicsScene());
|
||||||
|
@ -175,11 +177,18 @@ void ProfileGraphicsView::clear()
|
||||||
{
|
{
|
||||||
resetTransform();
|
resetTransform();
|
||||||
zoomLevel = 0;
|
zoomLevel = 0;
|
||||||
if(toolTip){
|
if(toolTip) {
|
||||||
scene()->removeItem(toolTip);
|
scene()->removeItem(toolTip);
|
||||||
toolTip->deleteLater();
|
toolTip->deleteLater();
|
||||||
toolTip = 0;
|
toolTip = 0;
|
||||||
}
|
}
|
||||||
|
if(rulerItem) {
|
||||||
|
remove_ruler();
|
||||||
|
rulerItem->destNode()->deleteLater();
|
||||||
|
rulerItem->sourceNode()->deleteLater();
|
||||||
|
rulerItem->deleteLater();
|
||||||
|
rulerItem=0;
|
||||||
|
}
|
||||||
scene()->clear();
|
scene()->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +223,7 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
|
||||||
dive = d;
|
dive = d;
|
||||||
diveDC = d ? dc : NULL;
|
diveDC = d ? dc : NULL;
|
||||||
|
|
||||||
if (!isVisible() || !dive) {
|
if (!isVisible() || !dive || !mainWindow()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setBackgroundBrush(getColor(BACKGROUND));
|
setBackgroundBrush(getColor(BACKGROUND));
|
||||||
|
@ -274,6 +283,9 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
|
||||||
|
|
||||||
plot_events(dc);
|
plot_events(dc);
|
||||||
|
|
||||||
|
if (rulerEnabled && !printMode)
|
||||||
|
create_ruler();
|
||||||
|
|
||||||
/* Temperature profile */
|
/* Temperature profile */
|
||||||
plot_temperature_profile();
|
plot_temperature_profile();
|
||||||
|
|
||||||
|
@ -336,6 +348,9 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
|
||||||
connect(timeEditor, SIGNAL(editingFinished(QString)), this, SLOT(edit_dive_time(QString)));
|
connect(timeEditor, SIGNAL(editingFinished(QString)), this, SLOT(edit_dive_time(QString)));
|
||||||
scene()->addItem(timeEditor);
|
scene()->addItem(timeEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rulerEnabled && !printMode)
|
||||||
|
add_ruler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileGraphicsView::plot_depth_scale()
|
void ProfileGraphicsView::plot_depth_scale()
|
||||||
|
@ -840,6 +855,57 @@ void ProfileGraphicsView::plot_one_event(struct event *ev)
|
||||||
item->setToolTip(name);
|
item->setToolTip(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProfileGraphicsView::create_ruler()
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
struct plot_info *pi = &gc.pi;
|
||||||
|
struct plot_data *data = pi->entry;
|
||||||
|
|
||||||
|
RulerNodeItem *first = new RulerNodeItem(0, gc);
|
||||||
|
RulerNodeItem *second = new RulerNodeItem(0, gc);
|
||||||
|
|
||||||
|
x = SCALEXGC(data->sec);
|
||||||
|
y = data->depth;
|
||||||
|
|
||||||
|
first->setPos(x,y);
|
||||||
|
|
||||||
|
data = pi->entry+(pi->nr-1);
|
||||||
|
x = SCALEXGC(data->sec);
|
||||||
|
y = data->depth;
|
||||||
|
|
||||||
|
second->setPos(x,y);
|
||||||
|
//Make sure that both points already have their entries
|
||||||
|
first->recalculate();
|
||||||
|
second->recalculate();
|
||||||
|
|
||||||
|
rulerItem = new RulerItem(0, first, second);
|
||||||
|
first->setRuler(rulerItem);
|
||||||
|
second->setRuler(rulerItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileGraphicsView::add_ruler()
|
||||||
|
{
|
||||||
|
if (! scene()->items().contains(rulerItem)) {
|
||||||
|
scene()->addItem(rulerItem->sourceNode());
|
||||||
|
scene()->addItem(rulerItem->destNode());
|
||||||
|
scene()->addItem(rulerItem);
|
||||||
|
rulerItem->recalculate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileGraphicsView::remove_ruler()
|
||||||
|
{
|
||||||
|
if (rulerItem) {
|
||||||
|
if (scene()->items().contains(rulerItem))
|
||||||
|
scene()->removeItem(rulerItem);
|
||||||
|
if (scene()->items().contains(rulerItem->sourceNode()))
|
||||||
|
scene()->removeItem(rulerItem->sourceNode());
|
||||||
|
if (scene()->items().contains(rulerItem->destNode()))
|
||||||
|
scene()->removeItem(rulerItem->destNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ProfileGraphicsView::plot_depth_profile()
|
void ProfileGraphicsView::plot_depth_profile()
|
||||||
{
|
{
|
||||||
int i, incr;
|
int i, incr;
|
||||||
|
@ -1131,7 +1197,7 @@ QGraphicsItemGroup *ProfileGraphicsView::plot_text(text_render_options_t *tro,co
|
||||||
|
|
||||||
void ProfileGraphicsView::resizeEvent(QResizeEvent *event)
|
void ProfileGraphicsView::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
fitInView(sceneRect());
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileGraphicsView::plot_temperature_profile()
|
void ProfileGraphicsView::plot_temperature_profile()
|
||||||
|
@ -1430,6 +1496,161 @@ EventItem::EventItem(QGraphicsItem* parent, bool grayscale): QGraphicsPolygonIte
|
||||||
ball->setPen(QPen(getColor(ALERT_FG)));
|
ball->setPen(QPen(getColor(ALERT_FG)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RulerNodeItem::RulerNodeItem(QGraphicsItem *parent, graphics_context context) : QGraphicsEllipseItem(parent), gc(context), entry(NULL) , ruler(NULL)
|
||||||
|
{
|
||||||
|
setRect(QRect(QPoint(-8,8),QPoint(8,-8)));
|
||||||
|
setBrush(QColor(0xff, 0, 0, 127));
|
||||||
|
setPen(QColor("#FF0000"));
|
||||||
|
setFlag(QGraphicsItem::ItemIsMovable);
|
||||||
|
setFlag(ItemSendsGeometryChanges);
|
||||||
|
setFlag(ItemIgnoresTransformations);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RulerNodeItem::setRuler(RulerItem *r)
|
||||||
|
{
|
||||||
|
ruler = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RulerNodeItem::recalculate()
|
||||||
|
{
|
||||||
|
struct plot_info *pi = &gc.pi;
|
||||||
|
struct plot_data *data = pi->entry+(pi->nr-1);
|
||||||
|
uint16_t count = 0;
|
||||||
|
if (x() < 0) {
|
||||||
|
setPos(0, y());
|
||||||
|
}
|
||||||
|
else if (x() > SCALEXGC(data->sec)) {
|
||||||
|
setPos(SCALEXGC(data->sec), y());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data = pi->entry;
|
||||||
|
count=0;
|
||||||
|
while (SCALEXGC(data->sec) < x() && count < pi->nr) {
|
||||||
|
data = pi->entry+count;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
setPos(SCALEGC(data->sec, data->depth));
|
||||||
|
entry=data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant RulerNodeItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||||
|
{
|
||||||
|
if(change == ItemPositionHasChanged) {
|
||||||
|
recalculate();
|
||||||
|
if(ruler != NULL)
|
||||||
|
ruler->recalculate();
|
||||||
|
if (scene()) {
|
||||||
|
scene()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QGraphicsEllipseItem::itemChange(change, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
RulerItem::RulerItem(QGraphicsItem *parent, RulerNodeItem *sourceNode, RulerNodeItem *destNode) : QGraphicsObject(parent), source(sourceNode), dest(destNode)
|
||||||
|
{
|
||||||
|
recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RulerItem::recalculate()
|
||||||
|
{
|
||||||
|
char buffer[500];
|
||||||
|
QPointF tmp;
|
||||||
|
QFont font;
|
||||||
|
QFontMetrics fm(font);
|
||||||
|
|
||||||
|
if (source == NULL || dest == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
prepareGeometryChange();
|
||||||
|
startPoint = mapFromItem(source, 0, 0);
|
||||||
|
endPoint = mapFromItem(dest, 0, 0);
|
||||||
|
if (startPoint.x() > endPoint.x()) {
|
||||||
|
tmp = endPoint;
|
||||||
|
endPoint = startPoint;
|
||||||
|
startPoint = tmp;
|
||||||
|
}
|
||||||
|
QLineF line(startPoint, endPoint);
|
||||||
|
|
||||||
|
compare_samples(source->entry, dest->entry, buffer, 500, 1);
|
||||||
|
text = QString(buffer);
|
||||||
|
|
||||||
|
QRect r = fm.boundingRect(QRect(QPoint(10,-1*INT_MAX), QPoint(line.length()-10, 0)), Qt::TextWordWrap, text);
|
||||||
|
if (r.height() < 10)
|
||||||
|
height = 10;
|
||||||
|
else
|
||||||
|
height = r.height();
|
||||||
|
|
||||||
|
QLineF line_n = line.normalVector();
|
||||||
|
line_n.setLength(height);
|
||||||
|
if (scene()) {
|
||||||
|
/* Determine whether we draw down or upwards */
|
||||||
|
if (scene()->sceneRect().contains(line_n.p2()) &&
|
||||||
|
scene()->sceneRect().contains(endPoint+QPointF(line_n.dx(),line_n.dy())))
|
||||||
|
paint_direction = -1;
|
||||||
|
else
|
||||||
|
paint_direction = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RulerNodeItem *RulerItem::sourceNode() const
|
||||||
|
{
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
RulerNodeItem *RulerItem::destNode() const
|
||||||
|
{
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RulerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||||
|
{
|
||||||
|
QLineF line(startPoint, endPoint);
|
||||||
|
QLineF line_n = line.normalVector();
|
||||||
|
painter->setPen(QColor(Qt::black));
|
||||||
|
painter->setBrush(Qt::NoBrush);
|
||||||
|
line_n.setLength(height);
|
||||||
|
|
||||||
|
if (paint_direction == 1)
|
||||||
|
line_n.setAngle(line_n.angle()+180);
|
||||||
|
painter->drawLine(line);
|
||||||
|
painter->drawLine(line_n);
|
||||||
|
painter->drawLine(line_n.p1() + QPointF(line.dx(), line.dy()), line_n.p2() + QPointF(line.dx(), line.dy()));
|
||||||
|
|
||||||
|
//Draw Text
|
||||||
|
painter->save();
|
||||||
|
painter->translate(startPoint.x(), startPoint.y());
|
||||||
|
painter->rotate(line.angle()*-1);
|
||||||
|
if (paint_direction == 1)
|
||||||
|
painter->translate(0, height);
|
||||||
|
painter->setPen(Qt::black);
|
||||||
|
painter->drawText(QRectF(QPointF(10,-1*height), QPointF(line.length()-10, 0)), Qt::TextWordWrap, text);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF RulerItem::boundingRect() const
|
||||||
|
{
|
||||||
|
return shape().controlPointRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath RulerItem::shape() const
|
||||||
|
{
|
||||||
|
QPainterPath path;
|
||||||
|
QLineF line(startPoint, endPoint);
|
||||||
|
QLineF line_n = line.normalVector();
|
||||||
|
line_n.setLength(height);
|
||||||
|
if (paint_direction == 1)
|
||||||
|
line_n.setAngle(line_n.angle()+180);
|
||||||
|
path.moveTo(startPoint);
|
||||||
|
path.lineTo(line_n.p2());
|
||||||
|
path.lineTo(line_n.p2() + QPointF(line.dx(), line.dy()));
|
||||||
|
path.lineTo(endPoint);
|
||||||
|
path.lineTo(startPoint);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
GraphicsTextEditor::GraphicsTextEditor(QGraphicsItem* parent): QGraphicsTextItem(parent)
|
GraphicsTextEditor::GraphicsTextEditor(QGraphicsItem* parent): QGraphicsTextItem(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,49 @@ private:
|
||||||
QRectF nextRectangle;
|
QRectF nextRectangle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RulerItem;
|
||||||
|
|
||||||
|
class RulerNodeItem : public QObject, public QGraphicsEllipseItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class RulerItem;
|
||||||
|
public:
|
||||||
|
explicit RulerNodeItem(QGraphicsItem* parent, graphics_context gc);
|
||||||
|
void setRuler(RulerItem *r);
|
||||||
|
void recalculate();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QVariant itemChange(GraphicsItemChange change, const QVariant & value );
|
||||||
|
|
||||||
|
private:
|
||||||
|
graphics_context gc;
|
||||||
|
struct plot_data *entry;
|
||||||
|
RulerItem* ruler;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RulerItem : public QGraphicsObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit RulerItem(QGraphicsItem* parent,
|
||||||
|
RulerNodeItem *sourceMarker,
|
||||||
|
RulerNodeItem *destMarker);
|
||||||
|
void recalculate();
|
||||||
|
|
||||||
|
RulerNodeItem* sourceNode() const;
|
||||||
|
RulerNodeItem* destNode() const;
|
||||||
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * widget = 0);
|
||||||
|
QRectF boundingRect() const;
|
||||||
|
QPainterPath shape() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointF startPoint, endPoint;
|
||||||
|
RulerNodeItem *source, *dest;
|
||||||
|
QString text;
|
||||||
|
int height;
|
||||||
|
int paint_direction;
|
||||||
|
};
|
||||||
|
|
||||||
class EventItem : public QGraphicsPolygonItem
|
class EventItem : public QGraphicsPolygonItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -128,6 +171,10 @@ private:
|
||||||
void plot_pp_text();
|
void plot_pp_text();
|
||||||
void plot_depth_scale();
|
void plot_depth_scale();
|
||||||
|
|
||||||
|
void create_ruler();
|
||||||
|
void add_ruler();
|
||||||
|
void remove_ruler();
|
||||||
|
|
||||||
QColor getColor(const color_indice_t i);
|
QColor getColor(const color_indice_t i);
|
||||||
QColor get_sac_color(int sac, int avg_sac);
|
QColor get_sac_color(int sac, int avg_sac);
|
||||||
void scrollViewTo(const QPoint pos);
|
void scrollViewTo(const QPoint pos);
|
||||||
|
@ -139,6 +186,8 @@ private:
|
||||||
struct dive *dive;
|
struct dive *dive;
|
||||||
struct divecomputer *diveDC;
|
struct divecomputer *diveDC;
|
||||||
int zoomLevel;
|
int zoomLevel;
|
||||||
|
|
||||||
|
bool rulerEnabled;
|
||||||
bool printMode;
|
bool printMode;
|
||||||
bool isGrayscale;
|
bool isGrayscale;
|
||||||
|
|
||||||
|
@ -147,6 +196,7 @@ private:
|
||||||
QGraphicsItem* timeMarkers;
|
QGraphicsItem* timeMarkers;
|
||||||
QGraphicsItem* depthMarkers;
|
QGraphicsItem* depthMarkers;
|
||||||
QGraphicsItem* diveComputer;
|
QGraphicsItem* diveComputer;
|
||||||
|
RulerItem *rulerItem;
|
||||||
|
|
||||||
// For 'Plan' mode.:
|
// For 'Plan' mode.:
|
||||||
GraphicsTextEditor *depthEditor;
|
GraphicsTextEditor *depthEditor;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue