mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Merge branch 'toolbar-ruler-rb' of github.com:mguentner/subsurface
This commit is contained in:
commit
ff0b2745a7
9 changed files with 626 additions and 11 deletions
4
dive.h
4
dive.h
|
@ -658,6 +658,10 @@ const char *weekday(int wday);
|
|||
const char *monthname(int mon);
|
||||
|
||||
#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 UTF8_SUBSCRIPT_2 "\xe2\x82\x82"
|
||||
#define UTF8_WHITESTAR "\xe2\x98\x86"
|
||||
|
|
91
icons/ruler.svg
Normal file
91
icons/ruler.svg
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="256"
|
||||
height="256"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="Neues Dokument 1">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.979899"
|
||||
inkscape:cx="82.200797"
|
||||
inkscape:cy="132.66914"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1060"
|
||||
inkscape:window-x="1917"
|
||||
inkscape:window-y="-3"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-796.36218)">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:26;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 25,855.87869 0,136.96699 206,0 0,-136.96699"
|
||||
id="path2985"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3755"
|
||||
sodipodi:cx="109.60155"
|
||||
sodipodi:cy="121.64971"
|
||||
sodipodi:rx="24.748737"
|
||||
sodipodi:ry="24.748737"
|
||||
d="m 134.35028,121.64971 a 24.748737,24.748737 0 1 1 -49.49747,0 24.748737,24.748737 0 1 1 49.49747,0 z"
|
||||
transform="matrix(0.80812204,0,0,0.80812204,142.42857,894.53737)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3755-9"
|
||||
sodipodi:cx="109.60155"
|
||||
sodipodi:cy="121.64971"
|
||||
sodipodi:rx="24.748737"
|
||||
sodipodi:ry="24.748737"
|
||||
d="m 134.35028,121.64971 a 24.748737,24.748737 0 1 1 -49.49747,0 24.748737,24.748737 0 1 1 49.49747,0 z"
|
||||
transform="matrix(0.80812204,0,0,0.80812204,-63.571426,894.53737)" />
|
||||
<g
|
||||
transform="scale(0.93424041,1.0703883)"
|
||||
style="font-size:167.5866394px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
|
||||
id="text3793">
|
||||
<path
|
||||
d="m 128.45853,792.84841 17.75698,0 41.733,103.7597 0,11.53795 -101.877616,0 0.08183,-11.53795 42.305806,-103.7597 m 43.1241,102.53226 -27.65834,-70.53696 c -1.63665,-4.03683 -3.16413,-8.2374 -4.58245,-12.60173 -1.36388,-4.41868 -2.10034,-6.95539 -2.20939,-7.61013 l -0.73647,2.61854 c -1.69119,6.05547 -3.70965,11.97446 -6.05537,17.75698 l -27.74017,70.3733 68.98219,0"
|
||||
style=""
|
||||
id="path3817" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
71
icons/scale.svg
Normal file
71
icons/scale.svg
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="256"
|
||||
height="256"
|
||||
id="svg3838"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="Neues Dokument 7">
|
||||
<defs
|
||||
id="defs3840" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="33.080739"
|
||||
inkscape:cy="132.08746"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1060"
|
||||
inkscape:window-x="1917"
|
||||
inkscape:window-y="-3"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3843">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-796.36218)">
|
||||
<path
|
||||
style="fill:#009aff;fill-opacity:1;stroke:#bebebe;stroke-width:6.52823304999999987;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 3.8355452,827.43445 c 18.0403128,23.04384 34.6170948,48.35081 45.4644808,77.56 14.699861,49.43778 21.075276,130.56465 70.722524,130.56465 35.82631,0 76.39924,-153.38199 131.14189,-208.12465"
|
||||
id="path3848"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<g
|
||||
style="font-size:233.09231567px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
|
||||
id="text4358"
|
||||
transform="matrix(1.2570811,0,0,1.2570811,-32.90638,-237.63608)">
|
||||
<path
|
||||
d="m 195.09371,960.32762 c -1.4e-4,14.79593 -5.80468,26.25325 -17.41364,34.37201 -11.53332,8.11877 -27.8088,12.17817 -48.82646,12.17817 -39.07639,0 -61.725474,-13.58187 -67.947322,-40.74564 l 21.055702,-4.21114 c 2.428011,9.63634 7.587601,16.73078 15.478787,21.28334 7.891093,4.47672 18.627593,6.71507 32.209533,6.71506 14.03704,1e-5 24.84942,-2.39009 32.43716,-7.17032 7.6634,-4.85607 11.49516,-11.9505 11.49528,-21.28333 -1.2e-4,-5.23543 -1.21415,-9.4845 -3.64207,-12.74724 -2.35228,-3.26263 -5.69084,-5.95624 -10.01568,-8.08084 -4.32506,-2.12447 -9.48465,-3.90756 -15.47879,-5.34928 -5.99432,-1.44159 -12.6335,-2.99705 -19.91756,-4.6664 -12.67142,-2.80735 -22.30771,-5.61478 -28.908907,-8.42228 -6.52541,-2.80735 -11.685,-5.91828 -15.478787,-9.3328 -3.793846,-3.49022 -6.715084,-7.5496 -8.763724,-12.17816 -1.972806,-4.62836 -2.959198,-9.9397 -2.95918,-15.93405 -1.8e-5,-13.7335 5.235449,-24.31824 15.706416,-31.75428 10.546776,-7.43572 25.608222,-11.15366 45.184402,-11.15383 18.21024,1.7e-4 32.13354,2.80759 41.76996,8.42228 9.63617,5.53913 16.38916,15.02367 20.259,28.45366 l -21.39715,3.75588 c -2.35228,-8.49803 -6.82899,-14.64401 -13.43012,-18.43797 -6.60135,-3.86955 -15.74445,-5.8044 -27.42932,-5.80454 -12.82318,1.4e-4 -22.61123,2.12468 -29.364171,6.37361 -6.753043,4.24922 -10.129539,10.58489 -10.1295,19.00704 -3.9e-5,4.93209 1.289858,9.02941 3.869697,12.29198 2.655628,3.18692 6.449444,5.91846 11.381464,8.19465 4.9319,2.20052 14.75789,4.93207 29.47798,8.19465 4.93188,1.13824 9.8259,2.31433 14.68208,3.52826 4.93187,1.13823 9.6362,2.54194 14.11302,4.21114 4.47659,1.59349 8.64978,3.49039 12.5196,5.69073 3.94545,2.20049 7.35988,4.8941 10.24332,8.08084 2.88316,3.18687 5.12151,6.94275 6.71506,11.26764 1.66914,4.32501 2.50378,9.40873 2.50392,15.25116"
|
||||
id="path4382"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
134
profile.c
134
profile.c
|
@ -3,6 +3,7 @@
|
|||
* uses cairo to draw it
|
||||
*/
|
||||
#include <glib/gi18n.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "dive.h"
|
||||
#include "display.h"
|
||||
|
@ -389,7 +390,8 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi)
|
|||
/* vertical velocity in mm/sec */
|
||||
/* 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) {
|
||||
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 (entry[0].sec - entry[-1].sec < 15 && entry->velocity < FAST) {
|
||||
int past = -2;
|
||||
|
@ -400,6 +402,7 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi)
|
|||
}
|
||||
} else {
|
||||
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 */
|
||||
plot_data[idx++].sec = lasttime+10;
|
||||
plot_data[idx++].sec = lasttime+20;
|
||||
plot_data[idx++].sec = lasttime+1;
|
||||
plot_data[idx++].sec = lasttime+2;
|
||||
pi->nr = idx;
|
||||
|
||||
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;
|
||||
const char *depth_unit, *pressure_unit, *temp_unit;
|
||||
char *buf2 = malloc(bufsize);
|
||||
double depthvalue, tempvalue;
|
||||
double depthvalue, tempvalue, speedvalue;
|
||||
|
||||
depthvalue = get_depth_units(depth, NULL, &depth_unit);
|
||||
snprintf(buf, bufsize, _("D:%.1f %s"), depthvalue, depth_unit);
|
||||
|
||||
if (prefs.show_time) {
|
||||
memcpy(buf2, buf, bufsize);
|
||||
snprintf(buf, bufsize, _("%s\nT:%d:%02d"), buf2, FRACTION(entry->sec, 60));
|
||||
}
|
||||
|
||||
if (pressure) {
|
||||
pressurevalue = get_pressure_units(pressure, &pressure_unit);
|
||||
memcpy(buf2, buf, bufsize);
|
||||
|
@ -1230,6 +1235,14 @@ static void plot_string(struct plot_data *entry, char *buf, int bufsize,
|
|||
memcpy(buf2, buf, bufsize);
|
||||
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) {
|
||||
depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit);
|
||||
memcpy(buf2, buf, bufsize);
|
||||
|
@ -1330,3 +1343,116 @@ void get_plot_details(struct graphics_context *gc, int time, char *buf, int bufs
|
|||
if (entry)
|
||||
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 mod, ead, end, eadd;
|
||||
velocity_t velocity;
|
||||
int speed;
|
||||
struct plot_data *min[3];
|
||||
struct plot_data *max[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);
|
||||
int setup_temperature_limits(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 {
|
||||
char *ev_name;
|
||||
|
|
|
@ -294,7 +294,8 @@ void MainWindow::on_actionAutoGroup_triggered()
|
|||
|
||||
void MainWindow::on_actionToggleZoom_triggered()
|
||||
{
|
||||
qDebug("actionToggleZoom");
|
||||
zoomed_plot = !zoomed_plot;
|
||||
ui->ProfileWidget->refresh();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionYearlyStatistics_triggered()
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
#include <QPropertyAnimation>
|
||||
#include <QGraphicsSceneHoverEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QToolBar>
|
||||
#include <qtextdocument.h>
|
||||
#include <limits>
|
||||
|
||||
#include "../color.h"
|
||||
#include "../display.h"
|
||||
|
@ -43,10 +45,11 @@ extern struct ev_select *ev_namelist;
|
|||
extern int evn_allocated;
|
||||
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), toolBarProxy(0)
|
||||
{
|
||||
printMode = false;
|
||||
isGrayscale = false;
|
||||
rulerEnabled = false;
|
||||
gc.printer = false;
|
||||
fill_profile_color();
|
||||
setScene(new QGraphicsScene());
|
||||
|
@ -175,11 +178,23 @@ void ProfileGraphicsView::clear()
|
|||
{
|
||||
resetTransform();
|
||||
zoomLevel = 0;
|
||||
if(toolTip){
|
||||
if(toolTip) {
|
||||
scene()->removeItem(toolTip);
|
||||
toolTip->deleteLater();
|
||||
toolTip = 0;
|
||||
}
|
||||
if(toolBarProxy) {
|
||||
scene()->removeItem(toolBarProxy);
|
||||
toolBarProxy->deleteLater();
|
||||
toolBarProxy = 0;
|
||||
}
|
||||
if(rulerItem) {
|
||||
remove_ruler();
|
||||
rulerItem->destNode()->deleteLater();
|
||||
rulerItem->sourceNode()->deleteLater();
|
||||
rulerItem->deleteLater();
|
||||
rulerItem=0;
|
||||
}
|
||||
scene()->clear();
|
||||
}
|
||||
|
||||
|
@ -214,7 +229,7 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
|
|||
dive = d;
|
||||
diveDC = d ? dc : NULL;
|
||||
|
||||
if (!isVisible() || !dive) {
|
||||
if (!isVisible() || !dive || !mainWindow()) {
|
||||
return;
|
||||
}
|
||||
setBackgroundBrush(getColor(BACKGROUND));
|
||||
|
@ -274,6 +289,9 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
|
|||
|
||||
plot_events(dc);
|
||||
|
||||
if (rulerEnabled && !printMode)
|
||||
create_ruler();
|
||||
|
||||
/* Temperature profile */
|
||||
plot_temperature_profile();
|
||||
|
||||
|
@ -336,6 +354,12 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
|
|||
connect(timeEditor, SIGNAL(editingFinished(QString)), this, SLOT(edit_dive_time(QString)));
|
||||
scene()->addItem(timeEditor);
|
||||
}
|
||||
|
||||
if (!printMode)
|
||||
addControlItems();
|
||||
|
||||
if (rulerEnabled && !printMode)
|
||||
add_ruler();
|
||||
}
|
||||
|
||||
void ProfileGraphicsView::plot_depth_scale()
|
||||
|
@ -368,11 +392,29 @@ void ProfileGraphicsView::plot_depth_scale()
|
|||
depthMarkers->setPos(depthMarkers->pos().x() - 10, 0);
|
||||
}
|
||||
|
||||
void ProfileGraphicsView::addControlItems()
|
||||
{
|
||||
QAction *scaleAction = new QAction(QIcon(":scale"), tr("Scale"), this);
|
||||
QAction *rulerAction = new QAction(QIcon(":ruler"), tr("Ruler"), this);
|
||||
QToolBar *toolBar = new QToolBar("", 0);
|
||||
toolBar->addAction(rulerAction);
|
||||
toolBar->addAction(scaleAction);
|
||||
//make toolbar transparent
|
||||
toolBar->setStyleSheet(QString::fromUtf8 ("background-color: rgba(255,255,255,0);"));
|
||||
|
||||
connect(scaleAction, SIGNAL(triggered()), this, SLOT(on_scaleAction()));
|
||||
connect(rulerAction, SIGNAL(triggered()), this, SLOT(on_rulerAction()));
|
||||
toolBarProxy = scene()->addWidget(toolBar);
|
||||
//Put it into the lower right corner of the profile
|
||||
toolBarProxy->setPos(gc.maxx-toolBar->width(), gc.maxy-toolBar->height());
|
||||
}
|
||||
|
||||
void ProfileGraphicsView::plot_pp_text()
|
||||
{
|
||||
double pp, dpp, m;
|
||||
int hpos;
|
||||
static text_render_options_t tro = {PP_TEXT_SIZE, PP_LINES, LEFT, MIDDLE};
|
||||
QGraphicsRectItem *pressureMarkers = new QGraphicsRectItem();
|
||||
|
||||
setup_pp_limits(&gc);
|
||||
pp = floor(gc.pi.maxpp * 10.0) / 10.0 + 0.2;
|
||||
|
@ -386,8 +428,10 @@ void ProfileGraphicsView::plot_pp_text()
|
|||
pen.setColor(c);
|
||||
item->setPen(pen);
|
||||
scene()->addItem(item);
|
||||
plot_text(&tro, QPointF(hpos + 30, m), QString::number(m));
|
||||
plot_text(&tro, QPointF(hpos, m), QString::number(m), pressureMarkers);
|
||||
}
|
||||
scene()->addItem(pressureMarkers);
|
||||
pressureMarkers->setPos(pressureMarkers->pos().x() + 10, 0);
|
||||
}
|
||||
|
||||
void ProfileGraphicsView::plot_add_line(int sec, double val, QColor c, QPointF &from)
|
||||
|
@ -840,6 +884,57 @@ void ProfileGraphicsView::plot_one_event(struct event *ev)
|
|||
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()
|
||||
{
|
||||
int i, incr;
|
||||
|
@ -888,7 +983,7 @@ void ProfileGraphicsView::plot_depth_profile()
|
|||
if (maxtime < 600) {
|
||||
/* Be a bit more verbose with shorter dives */
|
||||
for (i = incr; i < maxtime; i += incr)
|
||||
plot_text(&tro, QPointF(i, 0), QString("%1:%2").arg(i/60).arg(i%60), timeMarkers);
|
||||
plot_text(&tro, QPointF(i, 0), QString("%1:%2").arg(i/60).arg(i%60, 2, 10, QChar('0')), timeMarkers);
|
||||
} else {
|
||||
/* Only render the time on every second marker for normal dives */
|
||||
for (i = incr; i < maxtime; i += 2 * incr)
|
||||
|
@ -1131,7 +1226,7 @@ QGraphicsItemGroup *ProfileGraphicsView::plot_text(text_render_options_t *tro,co
|
|||
|
||||
void ProfileGraphicsView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
fitInView(sceneRect());
|
||||
refresh();
|
||||
}
|
||||
|
||||
void ProfileGraphicsView::plot_temperature_profile()
|
||||
|
@ -1175,6 +1270,18 @@ void ProfileGraphicsView::edit_dive_time(const QString& time)
|
|||
refresh();
|
||||
}
|
||||
|
||||
void ProfileGraphicsView::on_rulerAction()
|
||||
{
|
||||
rulerEnabled = !rulerEnabled;
|
||||
refresh();
|
||||
}
|
||||
|
||||
void ProfileGraphicsView::on_scaleAction()
|
||||
{
|
||||
zoomed_plot = !zoomed_plot;
|
||||
refresh();
|
||||
}
|
||||
|
||||
void ToolTipItem::addToolTip(const QString& toolTip, const QIcon& icon)
|
||||
{
|
||||
QGraphicsPixmapItem *iconItem = 0;
|
||||
|
@ -1430,6 +1537,161 @@ EventItem::EventItem(QGraphicsItem* parent, bool grayscale): QGraphicsPolygonIte
|
|||
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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -57,6 +57,49 @@ private:
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -106,6 +149,8 @@ protected:
|
|||
public slots:
|
||||
void refresh();
|
||||
void edit_dive_time(const QString& time);
|
||||
void on_rulerAction();
|
||||
void on_scaleAction();
|
||||
|
||||
private:
|
||||
void plot_depth_profile();
|
||||
|
@ -128,6 +173,13 @@ private:
|
|||
void plot_pp_text();
|
||||
void plot_depth_scale();
|
||||
|
||||
|
||||
void addControlItems();
|
||||
|
||||
void create_ruler();
|
||||
void add_ruler();
|
||||
void remove_ruler();
|
||||
|
||||
QColor getColor(const color_indice_t i);
|
||||
QColor get_sac_color(int sac, int avg_sac);
|
||||
void scrollViewTo(const QPoint pos);
|
||||
|
@ -139,6 +191,8 @@ private:
|
|||
struct dive *dive;
|
||||
struct divecomputer *diveDC;
|
||||
int zoomLevel;
|
||||
|
||||
bool rulerEnabled;
|
||||
bool printMode;
|
||||
bool isGrayscale;
|
||||
|
||||
|
@ -147,6 +201,8 @@ private:
|
|||
QGraphicsItem* timeMarkers;
|
||||
QGraphicsItem* depthMarkers;
|
||||
QGraphicsItem* diveComputer;
|
||||
RulerItem *rulerItem;
|
||||
QGraphicsProxyWidget *toolBarProxy;
|
||||
|
||||
// For 'Plan' mode.:
|
||||
GraphicsTextEditor *depthEditor;
|
||||
|
|
|
@ -12,5 +12,7 @@
|
|||
<file alias="average">icons/average.svg</file>
|
||||
<file alias="warning">icons/warning.png</file>
|
||||
<file alias="table-css">qt-ui/css/tableviews.css</file>
|
||||
<file alias="scale">icons/scale.svg</file>
|
||||
<file alias="ruler">icons/ruler.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
Loading…
Add table
Reference in a new issue