core: move formatting of plot info to string-format.cpp

Arguably, string handling in C is painful. Move the function
that formats the "tooltip" of the current spot on the profile
to the C++ string-format.cpp.

Note: the actual code stays C with a few necessary adaptions
concerning the translation machinery.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2022-07-15 17:13:16 +02:00
parent 1faad2c1f1
commit ebfefbc736
6 changed files with 187 additions and 181 deletions

View File

@ -48,7 +48,7 @@ struct membuffer {
#ifdef __cplusplus
// In C++ code use this - it automatically frees the buffer, when going out of scope.
// In C++ code use this - it automatically frees the buffer when going out of scope.
struct membufferpp : public membuffer {
membufferpp();
~membufferpp();

View File

@ -26,8 +26,6 @@
//#define DEBUG_GAS 1
#define MAX_PROFILE_DECO 7200
extern int ascent_velocity(int depth, int avg_depth, int bottom_time);
struct dive *current_dive = NULL;
@ -59,7 +57,6 @@ static void dump_pi(struct plot_info *pi)
#endif
#define ROUND_UP(x, y) ((((x) + (y) - 1) / (y)) * (y))
#define DIV_UP(x, y) (((x) + (y) - 1) / (y))
/*
* When showing dive profiles, we scale things to the
@ -1328,176 +1325,6 @@ void create_plot_info_new(const struct dive *dive, const struct divecomputer *dc
analyze_plot_info(pi);
}
static void plot_string(const struct dive *d, const struct plot_info *pi, int idx, struct membuffer *b)
{
int pressurevalue, mod, ead, end, eadd;
const char *depth_unit, *pressure_unit, *temp_unit, *vertical_speed_unit;
double depthvalue, tempvalue, speedvalue, sacvalue;
int decimals, cyl;
const char *unit;
const struct plot_data *entry = pi->entry + idx;
depthvalue = get_depth_units(entry->depth, NULL, &depth_unit);
put_format_loc(b, translate("gettextFromC", "@: %d:%02d\nD: %.1f%s\n"), FRACTION(entry->sec, 60), depthvalue, depth_unit);
for (cyl = 0; cyl < pi->nr_cylinders; cyl++) {
int mbar = get_plot_pressure(pi, idx, cyl);
if (!mbar)
continue;
struct gasmix mix = get_cylinder(d, cyl)->gasmix;
pressurevalue = get_pressure_units(mbar, &pressure_unit);
put_format_loc(b, translate("gettextFromC", "P: %d%s (%s)\n"), pressurevalue, pressure_unit, gasname(mix));
}
if (entry->temperature) {
tempvalue = get_temp_units(entry->temperature, &temp_unit);
put_format_loc(b, translate("gettextFromC", "T: %.1f%s\n"), tempvalue, temp_unit);
}
speedvalue = get_vertical_speed_units(abs(entry->speed), NULL, &vertical_speed_unit);
/* Ascending speeds are positive, descending are negative */
if (entry->speed > 0)
speedvalue *= -1;
put_format_loc(b, translate("gettextFromC", "V: %.1f%s\n"), speedvalue, vertical_speed_unit);
sacvalue = get_volume_units(entry->sac, &decimals, &unit);
if (entry->sac && prefs.show_sac)
put_format_loc(b, translate("gettextFromC", "SAC: %.*f%s/min\n"), decimals, sacvalue, unit);
if (entry->cns)
put_format_loc(b, translate("gettextFromC", "CNS: %u%%\n"), entry->cns);
if (prefs.pp_graphs.po2 && entry->pressures.o2 > 0) {
put_format_loc(b, translate("gettextFromC", "pO₂: %.2fbar\n"), entry->pressures.o2);
if (entry->scr_OC_pO2.mbar)
put_format_loc(b, translate("gettextFromC", "SCR ΔpO₂: %.2fbar\n"), entry->scr_OC_pO2.mbar/1000.0 - entry->pressures.o2);
}
if (prefs.pp_graphs.pn2 && entry->pressures.n2 > 0)
put_format_loc(b, translate("gettextFromC", "pN₂: %.2fbar\n"), entry->pressures.n2);
if (prefs.pp_graphs.phe && entry->pressures.he > 0)
put_format_loc(b, translate("gettextFromC", "pHe: %.2fbar\n"), entry->pressures.he);
if (prefs.mod && entry->mod > 0) {
mod = lrint(get_depth_units(entry->mod, NULL, &depth_unit));
put_format_loc(b, translate("gettextFromC", "MOD: %d%s\n"), mod, depth_unit);
}
eadd = lrint(get_depth_units(entry->eadd, NULL, &depth_unit));
if (prefs.ead) {
switch (pi->dive_type) {
case NITROX:
if (entry->ead > 0) {
ead = lrint(get_depth_units(entry->ead, NULL, &depth_unit));
put_format_loc(b, translate("gettextFromC", "EAD: %d%s\nEADD: %d%s / %.1fg/\n"), ead, depth_unit, eadd, depth_unit, entry->density);
break;
}
case TRIMIX:
if (entry->end > 0) {
end = lrint(get_depth_units(entry->end, NULL, &depth_unit));
put_format_loc(b, translate("gettextFromC", "END: %d%s\nEADD: %d%s / %.1fg/\n"), end, depth_unit, eadd, depth_unit, entry->density);
break;
}
case AIR:
if (entry->density > 0) {
put_format_loc(b, translate("gettextFromC", "Density: %.1fg/\n"), entry->density);
}
case FREEDIVING:
/* nothing */
break;
}
}
if (entry->stopdepth) {
depthvalue = get_depth_units(entry->stopdepth, NULL, &depth_unit);
if (entry->ndl > 0) {
/* this is a safety stop as we still have ndl */
if (entry->stoptime)
put_format_loc(b, translate("gettextFromC", "Safety stop: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60),
depthvalue, depth_unit);
else
put_format_loc(b, translate("gettextFromC", "Safety stop: unknown time @ %.0f%s\n"),
depthvalue, depth_unit);
} else {
/* actual deco stop */
if (entry->stoptime)
put_format_loc(b, translate("gettextFromC", "Deco: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60),
depthvalue, depth_unit);
else
put_format_loc(b, translate("gettextFromC", "Deco: unknown time @ %.0f%s\n"),
depthvalue, depth_unit);
}
} else if (entry->in_deco) {
put_string(b, translate("gettextFromC", "In deco\n"));
} else if (entry->ndl >= 0) {
put_format_loc(b, translate("gettextFromC", "NDL: %umin\n"), DIV_UP(entry->ndl, 60));
}
if (entry->tts)
put_format_loc(b, translate("gettextFromC", "TTS: %umin\n"), DIV_UP(entry->tts, 60));
if (entry->stopdepth_calc && entry->stoptime_calc) {
depthvalue = get_depth_units(entry->stopdepth_calc, NULL, &depth_unit);
put_format_loc(b, translate("gettextFromC", "Deco: %umin @ %.0f%s (calc)\n"), DIV_UP(entry->stoptime_calc, 60),
depthvalue, depth_unit);
} else if (entry->in_deco_calc) {
/* This means that we have no NDL left,
* and we have no deco stop,
* so if we just accend to the surface slowly
* (ascent_mm_per_step / ascent_s_per_step)
* everything will be ok. */
put_string(b, translate("gettextFromC", "In deco (calc)\n"));
} else if (prefs.calcndltts && entry->ndl_calc != 0) {
if(entry->ndl_calc < MAX_PROFILE_DECO)
put_format_loc(b, translate("gettextFromC", "NDL: %umin (calc)\n"), DIV_UP(entry->ndl_calc, 60));
else
put_string(b, translate("gettextFromC", "NDL: >2h (calc)\n"));
}
if (entry->tts_calc) {
if (entry->tts_calc < MAX_PROFILE_DECO)
put_format_loc(b, translate("gettextFromC", "TTS: %umin (calc)\n"), DIV_UP(entry->tts_calc, 60));
else
put_string(b, translate("gettextFromC", "TTS: >2h (calc)\n"));
}
if (entry->rbt)
put_format_loc(b, translate("gettextFromC", "RBT: %umin\n"), DIV_UP(entry->rbt, 60));
if (prefs.decoinfo) {
if (entry->current_gf > 0.0)
put_format(b, translate("gettextFromC", "GF %d%%\n"), (int)(100.0 * entry->current_gf));
if (entry->surface_gf > 0.0)
put_format(b, translate("gettextFromC", "Surface GF %.0f%%\n"), entry->surface_gf);
if (entry->ceiling) {
depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit);
put_format_loc(b, translate("gettextFromC", "Calculated ceiling %.1f%s\n"), depthvalue, depth_unit);
if (prefs.calcalltissues) {
int k;
for (k = 0; k < 16; k++) {
if (entry->ceilings[k]) {
depthvalue = get_depth_units(entry->ceilings[k], NULL, &depth_unit);
put_format_loc(b, translate("gettextFromC", "Tissue %.0fmin: %.1f%s\n"), buehlmann_N2_t_halflife[k], depthvalue, depth_unit);
}
}
}
}
}
if (entry->icd_warning)
put_format(b, "%s", translate("gettextFromC", "ICD in leading tissue\n"));
if (entry->heartbeat && prefs.hrgraph)
put_format_loc(b, translate("gettextFromC", "heart rate: %d\n"), entry->heartbeat);
if (entry->bearing >= 0)
put_format_loc(b, translate("gettextFromC", "bearing: %d\n"), entry->bearing);
if (entry->running_sum) {
depthvalue = get_depth_units(entry->running_sum / entry->sec, NULL, &depth_unit);
put_format_loc(b, translate("gettextFromC", "mean depth to here %.1f%s\n"), depthvalue, depth_unit);
}
strip_mb(b);
}
int get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time, struct membuffer *mb)
{
int i;
/* The two first and the two last plot entries do not have useful data */
if (pi->nr <= 4)
return 0;
for (i = 2; i < pi->nr - 3; i++) {
if (pi->entry[i].sec >= time)
break;
}
plot_string(d, pi, i, mb);
return i;
}
/* Compare two plot_data entries and writes the results into a string */
void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, char *buf, int bufsize, bool sum)
{

View File

@ -95,12 +95,12 @@ struct plot_info {
};
#define AMB_PERCENTAGE 50.0
#define MAX_PROFILE_DECO 7200
extern void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, char *buf, int bufsize, bool sum);
extern void init_plot_info(struct plot_info *pi);
/* when planner_dc is non-null, this is called in planner mode. */
extern void create_plot_info_new(const struct dive *dive, const struct divecomputer *dc, struct plot_info *pi, const struct deco_state *planner_ds);
extern int get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time, struct membuffer *);
extern void free_plot_info_data(struct plot_info *pi);
/*

View File

@ -1,6 +1,9 @@
#include "string-format.h"
#include "deco.h"
#include "dive.h"
#include "divesite.h"
#include "membuffer.h"
#include "profile.h"
#include "qthelper.h"
#include "subsurface-string.h"
#include "trip.h"
@ -300,3 +303,178 @@ QString formatTripTitleWithDives(const dive_trip *trip)
return formatTripTitle(trip) + " " +
gettextFromC::tr("(%n dive(s))", "", nr);
}
#define DIV_UP(x, y) (((x) + (y) - 1) / (y))
#define translate(x,y) qPrintable(QCoreApplication::translate(x,y))
static QString formatPlotInfoInternal(const dive *d, const plot_info *pi, int idx)
{
membufferpp b;
int pressurevalue, mod, ead, end, eadd;
const char *depth_unit, *pressure_unit, *temp_unit, *vertical_speed_unit;
double depthvalue, tempvalue, speedvalue, sacvalue;
int decimals, cyl;
const char *unit;
const struct plot_data *entry = pi->entry + idx;
depthvalue = get_depth_units(entry->depth, NULL, &depth_unit);
put_format_loc(&b, translate("gettextFromC", "@: %d:%02d\nD: %.1f%s\n"), FRACTION(entry->sec, 60), depthvalue, depth_unit);
for (cyl = 0; cyl < pi->nr_cylinders; cyl++) {
int mbar = get_plot_pressure(pi, idx, cyl);
if (!mbar)
continue;
struct gasmix mix = get_cylinder(d, cyl)->gasmix;
pressurevalue = get_pressure_units(mbar, &pressure_unit);
put_format_loc(&b, translate("gettextFromC", "P: %d%s (%s)\n"), pressurevalue, pressure_unit, gasname(mix));
}
if (entry->temperature) {
tempvalue = get_temp_units(entry->temperature, &temp_unit);
put_format_loc(&b, translate("gettextFromC", "T: %.1f%s\n"), tempvalue, temp_unit);
}
speedvalue = get_vertical_speed_units(abs(entry->speed), NULL, &vertical_speed_unit);
/* Ascending speeds are positive, descending are negative */
if (entry->speed > 0)
speedvalue *= -1;
put_format_loc(&b, translate("gettextFromC", "V: %.1f%s\n"), speedvalue, vertical_speed_unit);
sacvalue = get_volume_units(entry->sac, &decimals, &unit);
if (entry->sac && prefs.show_sac)
put_format_loc(&b, translate("gettextFromC", "SAC: %.*f%s/min\n"), decimals, sacvalue, unit);
if (entry->cns)
put_format_loc(&b, translate("gettextFromC", "CNS: %u%%\n"), entry->cns);
if (prefs.pp_graphs.po2 && entry->pressures.o2 > 0) {
put_format_loc(&b, translate("gettextFromC", "pO₂: %.2fbar\n"), entry->pressures.o2);
if (entry->scr_OC_pO2.mbar)
put_format_loc(&b, translate("gettextFromC", "SCR ΔpO₂: %.2fbar\n"), entry->scr_OC_pO2.mbar/1000.0 - entry->pressures.o2);
}
if (prefs.pp_graphs.pn2 && entry->pressures.n2 > 0)
put_format_loc(&b, translate("gettextFromC", "pN₂: %.2fbar\n"), entry->pressures.n2);
if (prefs.pp_graphs.phe && entry->pressures.he > 0)
put_format_loc(&b, translate("gettextFromC", "pHe: %.2fbar\n"), entry->pressures.he);
if (prefs.mod && entry->mod > 0) {
mod = lrint(get_depth_units(entry->mod, NULL, &depth_unit));
put_format_loc(&b, translate("gettextFromC", "MOD: %d%s\n"), mod, depth_unit);
}
eadd = lrint(get_depth_units(entry->eadd, NULL, &depth_unit));
if (prefs.ead) {
switch (pi->dive_type) {
case plot_info::NITROX:
if (entry->ead > 0) {
ead = lrint(get_depth_units(entry->ead, NULL, &depth_unit));
put_format_loc(&b, translate("gettextFromC", "EAD: %d%s\nEADD: %d%s / %.1fg/\n"), ead, depth_unit, eadd, depth_unit, entry->density);
break;
}
case plot_info::TRIMIX:
if (entry->end > 0) {
end = lrint(get_depth_units(entry->end, NULL, &depth_unit));
put_format_loc(&b, translate("gettextFromC", "END: %d%s\nEADD: %d%s / %.1fg/\n"), end, depth_unit, eadd, depth_unit, entry->density);
break;
}
case plot_info::AIR:
if (entry->density > 0) {
put_format_loc(&b, translate("gettextFromC", "Density: %.1fg/\n"), entry->density);
}
case plot_info::FREEDIVING:
/* nothing */
break;
}
}
if (entry->stopdepth) {
depthvalue = get_depth_units(entry->stopdepth, NULL, &depth_unit);
if (entry->ndl > 0) {
/* this is a safety stop as we still have ndl */
if (entry->stoptime)
put_format_loc(&b, translate("gettextFromC", "Safety stop: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60),
depthvalue, depth_unit);
else
put_format_loc(&b, translate("gettextFromC", "Safety stop: unknown time @ %.0f%s\n"),
depthvalue, depth_unit);
} else {
/* actual deco stop */
if (entry->stoptime)
put_format_loc(&b, translate("gettextFromC", "Deco: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60),
depthvalue, depth_unit);
else
put_format_loc(&b, translate("gettextFromC", "Deco: unknown time @ %.0f%s\n"),
depthvalue, depth_unit);
}
} else if (entry->in_deco) {
put_string(&b, translate("gettextFromC", "In deco\n"));
} else if (entry->ndl >= 0) {
put_format_loc(&b, translate("gettextFromC", "NDL: %umin\n"), DIV_UP(entry->ndl, 60));
}
if (entry->tts)
put_format_loc(&b, translate("gettextFromC", "TTS: %umin\n"), DIV_UP(entry->tts, 60));
if (entry->stopdepth_calc && entry->stoptime_calc) {
depthvalue = get_depth_units(entry->stopdepth_calc, NULL, &depth_unit);
put_format_loc(&b, translate("gettextFromC", "Deco: %umin @ %.0f%s (calc)\n"), DIV_UP(entry->stoptime_calc, 60),
depthvalue, depth_unit);
} else if (entry->in_deco_calc) {
/* This means that we have no NDL left,
* and we have no deco stop,
* so if we just accend to the surface slowly
* (ascent_mm_per_step / ascent_s_per_step)
* everything will be ok. */
put_string(&b, translate("gettextFromC", "In deco (calc)\n"));
} else if (prefs.calcndltts && entry->ndl_calc != 0) {
if(entry->ndl_calc < MAX_PROFILE_DECO)
put_format_loc(&b, translate("gettextFromC", "NDL: %umin (calc)\n"), DIV_UP(entry->ndl_calc, 60));
else
put_string(&b, translate("gettextFromC", "NDL: >2h (calc)\n"));
}
if (entry->tts_calc) {
if (entry->tts_calc < MAX_PROFILE_DECO)
put_format_loc(&b, translate("gettextFromC", "TTS: %umin (calc)\n"), DIV_UP(entry->tts_calc, 60));
else
put_string(&b, translate("gettextFromC", "TTS: >2h (calc)\n"));
}
if (entry->rbt)
put_format_loc(&b, translate("gettextFromC", "RBT: %umin\n"), DIV_UP(entry->rbt, 60));
if (prefs.decoinfo) {
if (entry->current_gf > 0.0)
put_format(&b, translate("gettextFromC", "GF %d%%\n"), (int)(100.0 * entry->current_gf));
if (entry->surface_gf > 0.0)
put_format(&b, translate("gettextFromC", "Surface GF %.0f%%\n"), entry->surface_gf);
if (entry->ceiling) {
depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit);
put_format_loc(&b, translate("gettextFromC", "Calculated ceiling %.1f%s\n"), depthvalue, depth_unit);
if (prefs.calcalltissues) {
int k;
for (k = 0; k < 16; k++) {
if (entry->ceilings[k]) {
depthvalue = get_depth_units(entry->ceilings[k], NULL, &depth_unit);
put_format_loc(&b, translate("gettextFromC", "Tissue %.0fmin: %.1f%s\n"), buehlmann_N2_t_halflife[k], depthvalue, depth_unit);
}
}
}
}
}
if (entry->icd_warning)
put_format(&b, "%s", translate("gettextFromC", "ICD in leading tissue\n"));
if (entry->heartbeat && prefs.hrgraph)
put_format_loc(&b, translate("gettextFromC", "heart rate: %d\n"), entry->heartbeat);
if (entry->bearing >= 0)
put_format_loc(&b, translate("gettextFromC", "bearing: %d\n"), entry->bearing);
if (entry->running_sum) {
depthvalue = get_depth_units(entry->running_sum / entry->sec, NULL, &depth_unit);
put_format_loc(&b, translate("gettextFromC", "mean depth to here %.1f%s\n"), depthvalue, depth_unit);
}
strip_mb(&b);
return QString(mb_cstring(&b));
}
std::pair<QString, int> formatProfileInfo(const struct dive *d, const struct plot_info *pi, int time)
{
int i;
/* The two first and the two last plot entries do not have useful data */
if (pi->nr <= 4)
return std::make_pair(QString(), 0);
for (i = 2; i < pi->nr - 3; i++) {
if (pi->entry[i].sec >= time)
break;
}
QString res = formatPlotInfoInternal(d, pi, i);
return std::make_pair(res, i);
}

View File

@ -3,10 +3,12 @@
#ifndef STRING_FORMAT_H
#define STRING_FORMAT_H
#include <utility>
#include <QStringList>
struct dive;
struct dive_trip;
struct plot_info;
QString formatSac(const dive *d);
QString formatNotes(const dive *d);
@ -29,5 +31,6 @@ QString formatDiveDateTime(const dive *d);
QString formatDayOfWeek(int day);
QString formatTripTitle(const dive_trip *trip);
QString formatTripTitleWithDives(const dive_trip *trip);
std::pair<QString, int> formatProfileInfo(const dive *d, const plot_info *pi, int time);
#endif

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
#include "profile-widget/divetooltipitem.h"
#include "profile-widget/divecartesianaxis.h"
#include "core/membuffer.h"
#include "core/metrics.h"
#include "core/settings/qPrefDisplay.h"
#include "core/qthelper.h"
#include "core/string-format.h"
#include <QPropertyAnimation>
#include <QGraphicsView>
#include "core/qthelper.h"
ToolTipItem::ToolTip ToolTipItem::makeToolTip(const QString &toolTip, const QPixmap &pixmap)
{
@ -203,8 +203,6 @@ void ToolTipItem::setTimeAxis(DiveCartesianAxis *axis)
void ToolTipItem::refresh(const dive *d, const QPointF &pos, bool inPlanner)
{
struct membufferpp mb;
if(refreshTime.elapsed() < 40)
return;
refreshTime.start();
@ -214,7 +212,7 @@ void ToolTipItem::refresh(const dive *d, const QPointF &pos, bool inPlanner)
lastTime = time;
clear();
int idx = get_plot_details_new(d, &pInfo, time, &mb);
auto [text, idx] = formatProfileInfo(d, &pInfo, time);
tissues.fill();
painter.setPen(QColor(0, 0, 0, 0));
@ -234,7 +232,7 @@ void ToolTipItem::refresh(const dive *d, const QPointF &pos, bool inPlanner)
painter.setPen(QColor(0, 0, 0, 127));
for (int i = 0; i < 16; i++)
painter.drawLine(i, 60, i, 60 - entry->percentages[i] / 2);
entryToolTip.text->setText(QString::fromUtf8(mb.buffer, mb.len));
entryToolTip.text->setText(text);
}
entryToolTip.pixmap->setPixmap(tissues);