From 3c3997b24ea2912b0baa8ffe3cee74fcb6272909 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Sat, 13 Jan 2024 17:25:24 +0100 Subject: [PATCH] profile: use QString to format profile data This tries to stay as close as possible to the original. Ultimately, the whole formatting code should be reworked. Signed-off-by: Berthold Stoeger --- core/profile.cpp | 227 ++++++++++++++++----------------- core/profile.h | 8 +- profile-widget/ruleritem.cpp | 46 +++---- profile-widget/tooltipitem.cpp | 38 ++---- 4 files changed, 145 insertions(+), 174 deletions(-) diff --git a/core/profile.cpp b/core/profile.cpp index 6765e2949..68747db2f 100644 --- a/core/profile.cpp +++ b/core/profile.cpp @@ -3,7 +3,7 @@ /* creates all the necessary data for drawing the dive profile */ #include "ssrf.h" -#include "gettextfromc.h" +#include "gettext.h" #include #include #include @@ -23,7 +23,6 @@ #include "errorhelper.h" #include "libdivecomputer/parser.h" #include "libdivecomputer/version.h" -#include "membuffer.h" #include "qthelper.h" #include "format.h" @@ -58,8 +57,18 @@ 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)) + +template +static T round_up(T x, T y) +{ + return ((x + y - 1) / y) * y; +} + +template +static T div_up(T x, T y) +{ + return (x + y - 1) / y; +} /* * When showing dive profiles, we scale things to the @@ -854,7 +863,7 @@ static void calculate_ndl_tts(struct deco_state *ds, const struct dive *dive, st const int time_stepsize = 60; const int deco_stepsize = M_OR_FT(3, 10); /* at what depth is the current deco-step? */ - int next_stop = ROUND_UP(deco_allowed_depth( + int next_stop = round_up(deco_allowed_depth( tissue_tolerance_calc(ds, dive, depth_to_bar(entry->depth, dive), in_planner), surface_pressure, dive, 1), deco_stepsize); int ascent_depth = entry->depth; @@ -889,7 +898,7 @@ static void calculate_ndl_tts(struct deco_state *ds, const struct dive *dive, st for (; ascent_depth > next_stop; ascent_depth -= ascent_s_per_step * ascent_velocity(ascent_depth, entry->running_sum / entry->sec, 0), entry->tts_calc += ascent_s_per_step) { add_segment(ds, depth_to_bar(ascent_depth, dive), gasmix, ascent_s_per_step, entry->o2pressure.mbar, divemode, prefs.decosac, in_planner); - next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth, dive), in_planner), + next_stop = round_up(deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth, dive), in_planner), surface_pressure, dive, 1), deco_stepsize); } ascent_depth = next_stop; @@ -1011,7 +1020,7 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_ vpmb_start_gradient(ds); /* For CVA calculations, deco time = dive time remaining is a good guess, but we want to over-estimate deco_time for the first iteration so it - converges correctly, so add 30min*/ + converges correctly, so add 30min */ if (!in_planner) ds->deco_time = pi->maxtime - t1 + 1800; vpmb_next_gradient(ds, ds->deco_time, surface_pressure / 1000.0, in_planner); @@ -1096,7 +1105,7 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_ * at end of whole minute after clearing ceiling. The deepest ceiling when planning a dive * comes typically 10-60s after the end of the bottom time, so add 20s to the calculated * deco time. */ - ds->deco_time = ROUND_UP(time_clear_ceiling - time_deep_ceiling + 20, 60) + 20; + ds->deco_time = round_up(time_clear_ceiling - time_deep_ceiling + 20, 60) + 20; vpmb_next_gradient(ds, ds->deco_time, surface_pressure / 1000.0, in_planner); final_tts = 0; last_ndl_tts_calc_time = 0; @@ -1361,7 +1370,7 @@ 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) +static std::vector plot_string(const struct dive *d, const struct plot_info *pi, int idx) { int pressurevalue, mod, ead, end, eadd; const char *depth_unit, *pressure_unit, *temp_unit, *vertical_speed_unit; @@ -1369,43 +1378,45 @@ static void plot_string(const struct dive *d, const struct plot_info *pi, int id int decimals, cyl; const char *unit; const struct plot_data *entry = pi->entry + idx; + std::vector res; depthvalue = get_depth_units(entry->depth, NULL, &depth_unit); - put_format_loc(b, qPrintable(gettextFromC::tr("@: %d:%02d\nD: %.1f%s\n")), FRACTION(entry->sec, 60), depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "@: %d:%02d"), FRACTION(entry->sec, 60), depthvalue)); + res.push_back(qasprintf_loc(translate("gettextFromC", "D: %.1f%s"), 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, qPrintable(gettextFromC::tr("P: %d%s (%s)\n")), pressurevalue, pressure_unit, gasname(mix)); + res.push_back(qasprintf_loc(translate("gettextFromC", "P: %d%s (%s)"), pressurevalue, pressure_unit, gasname(mix))); } if (entry->temperature) { tempvalue = get_temp_units(entry->temperature, &temp_unit); - put_format_loc(b, qPrintable(gettextFromC::tr("T: %.1f%s\n")), tempvalue, temp_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "T: %.1f%s"), 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, qPrintable(gettextFromC::tr("V: %.1f%s\n")), speedvalue, vertical_speed_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "V: %.1f%s"), speedvalue, vertical_speed_unit)); sacvalue = get_volume_units(entry->sac, &decimals, &unit); if (entry->sac && prefs.show_sac) - put_format_loc(b, qPrintable(gettextFromC::tr("SAC: %.*f%s/min\n")), decimals, sacvalue, unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "SAC: %.*f%s/min"), decimals, sacvalue, unit)); if (entry->cns) - put_format_loc(b, qPrintable(gettextFromC::tr("CNS: %u%%\n")), entry->cns); + res.push_back(qasprintf_loc(translate("gettextFromC", "CNS: %u%%"), entry->cns)); if (prefs.pp_graphs.po2 && entry->pressures.o2 > 0) { - put_format_loc(b, qPrintable(gettextFromC::tr("pO₂: %.2fbar\n")), entry->pressures.o2); + res.push_back(qasprintf_loc(translate("gettextFromC", "pO₂: %.2fbar"), entry->pressures.o2)); if (entry->scr_OC_pO2.mbar) - put_format_loc(b, qPrintable(gettextFromC::tr("SCR ΔpO₂: %.2fbar\n")), entry->scr_OC_pO2.mbar/1000.0 - entry->pressures.o2); + res.push_back(qasprintf_loc(translate("gettextFromC", "SCR ΔpO₂: %.2fbar"), entry->scr_OC_pO2.mbar/1000.0 - entry->pressures.o2)); } if (prefs.pp_graphs.pn2 && entry->pressures.n2 > 0) - put_format_loc(b, qPrintable(gettextFromC::tr("pN₂: %.2fbar\n")), entry->pressures.n2); + res.push_back(qasprintf_loc(translate("gettextFromC", "pN₂: %.2fbar"), entry->pressures.n2)); if (prefs.pp_graphs.phe && entry->pressures.he > 0) - put_format_loc(b, qPrintable(gettextFromC::tr("pHe: %.2fbar\n")), entry->pressures.he); + res.push_back(qasprintf_loc(translate("gettextFromC", "pHe: %.2fbar"), entry->pressures.he)); if (prefs.mod && entry->mod > 0) { mod = lrint(get_depth_units(entry->mod, NULL, &depth_unit)); - put_format_loc(b, qPrintable(gettextFromC::tr("MOD: %d%s\n")), mod, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "MOD: %d%s"), mod, depth_unit)); } eadd = lrint(get_depth_units(entry->eadd, NULL, &depth_unit)); @@ -1414,18 +1425,20 @@ static void plot_string(const struct dive *d, const struct plot_info *pi, int id case plot_info::NITROX: if (entry->ead > 0) { ead = lrint(get_depth_units(entry->ead, NULL, &depth_unit)); - put_format_loc(b, qPrintable(gettextFromC::tr("EAD: %d%s\nEADD: %d%s / %.1fg/ℓ\n")), ead, depth_unit, eadd, depth_unit, entry->density); + res.push_back(qasprintf_loc(translate("gettextFromC", "EAD: %d%s"), ead, depth_unit)); + res.push_back(qasprintf_loc(translate("gettextFromC", "EADD: %d%s / %.1fg/ℓ"), 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, qPrintable(gettextFromC::tr("END: %d%s\nEADD: %d%s / %.1fg/ℓ\n")), end, depth_unit, eadd, depth_unit, entry->density); + res.push_back(qasprintf_loc(translate("gettextFromC", "END: %d%s"), end, depth_unit)); + res.push_back(qasprintf_loc(translate("gettextFromC", "EADD: %d%s / %.1fg/ℓ"), eadd, depth_unit, entry->density)); break; } case plot_info::AIR: if (entry->density > 0) { - put_format_loc(b, qPrintable(gettextFromC::tr("Density: %.1fg/ℓ\n")), entry->density); + res.push_back(qasprintf_loc(translate("gettextFromC", "Density: %.1fg/ℓ"), entry->density)); } case plot_info::FREEDIVING: /* nothing */ @@ -1437,151 +1450,143 @@ static void plot_string(const struct dive *d, const struct plot_info *pi, int id if (entry->ndl > 0) { /* this is a safety stop as we still have ndl */ if (entry->stoptime) - put_format_loc(b, qPrintable(gettextFromC::tr("Safety stop: %umin @ %.0f%s\n")), DIV_UP(entry->stoptime, 60), - depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "Safety stop: %umin @ %.0f%s"), div_up(entry->stoptime, 60), + depthvalue, depth_unit)); else - put_format_loc(b, qPrintable(gettextFromC::tr("Safety stop: unknown time @ %.0f%s\n")), - depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "Safety stop: unknown time @ %.0f%s"), + depthvalue, depth_unit)); } else { /* actual deco stop */ if (entry->stoptime) - put_format_loc(b, qPrintable(gettextFromC::tr("Deco: %umin @ %.0f%s\n")), DIV_UP(entry->stoptime, 60), - depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "Deco: %umin @ %.0f%s"), div_up(entry->stoptime, 60), + depthvalue, depth_unit)); else - put_format_loc(b, qPrintable(gettextFromC::tr("Deco: unknown time @ %.0f%s\n")), - depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "Deco: unknown time @ %.0f%s"), + depthvalue, depth_unit)); } } else if (entry->in_deco) { - put_string(b, qPrintable(gettextFromC::tr("In deco\n"))); + res.push_back(translate("gettextFromC", "In deco")); } else if (entry->ndl >= 0) { - put_format_loc(b, qPrintable(gettextFromC::tr("NDL: %umin\n")), DIV_UP(entry->ndl, 60)); + res.push_back(qasprintf_loc(translate("gettextFromC", "NDL: %umin"), div_up(entry->ndl, 60))); } if (entry->tts) - put_format_loc(b, qPrintable(gettextFromC::tr("TTS: %umin\n")), DIV_UP(entry->tts, 60)); + res.push_back(qasprintf_loc(translate("gettextFromC", "TTS: %umin"), 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, qPrintable(gettextFromC::tr("Deco: %umin @ %.0f%s (calc)\n")), DIV_UP(entry->stoptime_calc, 60), - depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "Deco: %umin @ %.0f%s (calc)"), 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, qPrintable(gettextFromC::tr("In deco (calc)\n"))); + res.push_back(translate("gettextFromC", "In deco (calc)")); } else if (prefs.calcndltts && entry->ndl_calc != 0) { if(entry->ndl_calc < MAX_PROFILE_DECO) - put_format_loc(b, qPrintable(gettextFromC::tr("NDL: %umin (calc)\n")), DIV_UP(entry->ndl_calc, 60)); + res.push_back(qasprintf_loc(translate("gettextFromC", "NDL: %umin (calc)"), div_up(entry->ndl_calc, 60))); else - put_string(b, qPrintable(gettextFromC::tr("NDL: >2h (calc)\n"))); + res.push_back(translate("gettextFromC", "NDL: >2h (calc)")); } if (entry->tts_calc) { if (entry->tts_calc < MAX_PROFILE_DECO) - put_format_loc(b, qPrintable(gettextFromC::tr("TTS: %umin (calc)\n")), DIV_UP(entry->tts_calc, 60)); + res.push_back(qasprintf_loc(translate("gettextFromC", "TTS: %umin (calc)"), div_up(entry->tts_calc, 60))); else - put_string(b, qPrintable(gettextFromC::tr("TTS: >2h (calc)\n"))); + res.push_back(translate("gettextFromC", "TTS: >2h (calc)")); } if (entry->rbt) - put_format_loc(b, qPrintable(gettextFromC::tr("RBT: %umin\n")), DIV_UP(entry->rbt, 60)); + res.push_back(qasprintf_loc(translate("gettextFromC", "RBT: %umin"), div_up(entry->rbt, 60))); if (prefs.decoinfo) { if (entry->current_gf > 0.0) - put_format(b, qPrintable(gettextFromC::tr("GF %d%%\n")), (int)(100.0 * entry->current_gf)); + res.push_back(qasprintf_loc(translate("gettextFromC", "GF %d%%"), (int)(100.0 * entry->current_gf))); if (entry->surface_gf > 0.0) - put_format(b, qPrintable(gettextFromC::tr("Surface GF %.0f%%\n")), entry->surface_gf); + res.push_back(qasprintf_loc(translate("gettextFromC", "Surface GF %.0f%%"), entry->surface_gf)); if (entry->ceiling) { depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit); - put_format_loc(b, qPrintable(gettextFromC::tr("Calculated ceiling %.1f%s\n")), depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "Calculated ceiling %.1f%s"), 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, qPrintable(gettextFromC::tr("Tissue %.0fmin: %.1f%s\n")), buehlmann_N2_t_halflife[k], depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "Tissue %.0fmin: %.1f%s"), buehlmann_N2_t_halflife[k], depthvalue, depth_unit)); } } } } } if (entry->icd_warning) - put_format(b, "%s", qPrintable(gettextFromC::tr("ICD in leading tissue\n"))); + res.push_back(translate("gettextFromC", "ICD in leading tissue")); if (entry->heartbeat && prefs.hrgraph) - put_format_loc(b, qPrintable(gettextFromC::tr("heart rate: %d\n")), entry->heartbeat); + res.push_back(qasprintf_loc(translate("gettextFromC", "heart rate: %d"), entry->heartbeat)); if (entry->bearing >= 0) - put_format_loc(b, qPrintable(gettextFromC::tr("bearing: %d\n")), entry->bearing); + res.push_back(qasprintf_loc(translate("gettextFromC", "bearing: %d"), entry->bearing)); if (entry->running_sum) { depthvalue = get_depth_units(entry->running_sum / entry->sec, NULL, &depth_unit); - put_format_loc(b, qPrintable(gettextFromC::tr("mean depth to here %.1f%s\n")), depthvalue, depth_unit); + res.push_back(qasprintf_loc(translate("gettextFromC", "mean depth to here %.1f%s"), depthvalue, depth_unit)); } - strip_mb(b); + return res; } -extern "C" -int get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time, struct membuffer *mb) +std::pair> get_plot_details_new(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 0; - for (i = 2; i < pi->nr - 3; i++) { - if (pi->entry[i].sec >= time) - break; - } - plot_string(d, pi, i, mb); - return i; + return { 0, {} }; + + // binary search for sample index + auto it = std::lower_bound(pi->entry + 2, pi->entry + pi->nr - 3, time, + [] (const plot_data &d, int time) + { return d.sec < time; }); + int idx = it - pi->entry; + + auto strings = plot_string(d, pi, idx); + return std::make_pair(idx, strings); } -/* Compare two plot_data entries and writes the results into a string */ -extern "C" -void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, char *buf, int bufsize, bool sum) -{ - struct plot_data *start, *stop, *data; - const char *depth_unit, *pressure_unit, *vertical_speed_unit; - std::vector buf2(bufsize); - int avg_speed, max_asc_speed, max_desc_speed; - int delta_depth, avg_depth, max_depth, min_depth; - int pressurevalue; - int last_sec, delta_time; +static QString space = QStringLiteral(" "); +/* Compare two plot_data entries and writes the results into a set of strings */ +std::vector compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, bool sum) +{ + const char *depth_unit, *pressure_unit, *vertical_speed_unit; double depthvalue, speedvalue; - if (bufsize > 0) - buf[0] = '\0'; - if (idx1 < 0 || idx2 < 0) { - return; - } + std::vector res; + if (idx1 < 0 || idx2 < 0) + return res; if (pi->entry[idx1].sec > pi->entry[idx2].sec) { int tmp = idx2; idx2 = idx1; idx1 = tmp; } else if (pi->entry[idx1].sec == pi->entry[idx2].sec) { - return; + return res; } - start = pi->entry + idx1; - stop = pi->entry + idx2; + struct plot_data *start = pi->entry + idx1; + struct plot_data *stop = pi->entry + idx2; - avg_speed = 0; - max_asc_speed = 0; - max_desc_speed = 0; + int avg_speed = 0; + int max_asc_speed = 0; + int max_desc_speed = 0; - delta_depth = abs(start->depth - stop->depth); - delta_time = abs(start->sec - stop->sec); - avg_depth = 0; - max_depth = 0; - min_depth = INT_MAX; + int delta_depth = abs(start->depth - stop->depth); + int delta_time = abs(start->sec - stop->sec); + int avg_depth = 0; + int max_depth = 0; + int min_depth = INT_MAX; - last_sec = start->sec; + int last_sec = start->sec; volume_t cylinder_volume = { .mliter = 0, }; std::vector start_pressures(pi->nr_cylinders, 0); std::vector last_pressures(pi->nr_cylinders, 0); std::vector bar_used(pi->nr_cylinders, 0); std::vector volumes_used(pi->nr_cylinders, 0); - std::vector cylinder_is_used(pi->nr_cylinders, 0); + std::vector cylinder_is_used(pi->nr_cylinders, false); - data = start; + struct plot_data *data = start; for (int i = idx1; i < idx2; ++i) { data = pi->entry + i; if (sum) @@ -1629,35 +1634,29 @@ void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, avg_depth /= stop->sec - start->sec; avg_speed /= stop->sec - start->sec; - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("ΔT:%d:%02dmin")), delta_time / 60, delta_time % 60); - memcpy(&buf2[0], buf, bufsize); + QString l = qasprintf_loc(translate("gettextFromC", "ΔT:%d:%02dmin"), delta_time / 60, delta_time % 60); depthvalue = get_depth_units(delta_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s ΔD:%.1f%s")), &buf2[0], depthvalue, depth_unit); - memcpy(&buf2[0], buf, bufsize); + l += space + qasprintf_loc(translate("gettextFromC", "ΔD:%.1f%s"), depthvalue, depth_unit); depthvalue = get_depth_units(min_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s ↓D:%.1f%s")), &buf2[0], depthvalue, depth_unit); - memcpy(&buf2[0], buf, bufsize); + l += space + qasprintf_loc(translate("gettextFromC", "↓D:%.1f%s"), depthvalue, depth_unit); depthvalue = get_depth_units(max_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s ↑D:%.1f%s")), &buf2[0], depthvalue, depth_unit); - memcpy(&buf2[0], buf, bufsize); + l += space + qasprintf_loc(translate("gettextFromC", "↑D:%.1f%s"), depthvalue, depth_unit); depthvalue = get_depth_units(avg_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s øD:%.1f%s\n")), &buf2[0], depthvalue, depth_unit); - memcpy(&buf2[0], buf, bufsize); + l += space + qasprintf_loc(translate("gettextFromC", "øD:%.1f%s"), depthvalue, depth_unit); + res.push_back(l); speedvalue = get_vertical_speed_units(abs(max_desc_speed), NULL, &vertical_speed_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s ↓V:%.2f%s")), &buf2[0], speedvalue, vertical_speed_unit); - memcpy(&buf2[0], buf, bufsize); + l = qasprintf_loc(translate("gettextFromC", "↓V:%.2f%s"), speedvalue, vertical_speed_unit); speedvalue = get_vertical_speed_units(abs(max_asc_speed), NULL, &vertical_speed_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s ↑V:%.2f%s")), &buf2[0], speedvalue, vertical_speed_unit); - memcpy(&buf2[0], buf, bufsize); + l += space + qasprintf_loc(translate("gettextFromC", "↑V:%.2f%s"), speedvalue, vertical_speed_unit); speedvalue = get_vertical_speed_units(abs(avg_speed), NULL, &vertical_speed_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s øV:%.2f%s")), &buf2[0], speedvalue, vertical_speed_unit); + l += space + qasprintf_loc(translate("gettextFromC", "øV:%.2f%s"), speedvalue, vertical_speed_unit); int total_bar_used = 0; int total_volume_used = 0; @@ -1683,14 +1682,12 @@ void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, // No point printing 'bar used' if we know it's meaningless because cylinders of different size were used if (cylindersizes_are_identical && total_bar_used) { - pressurevalue = get_pressure_units(total_bar_used, &pressure_unit); - memcpy(&buf2[0], buf, bufsize); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s ΔP:%d%s")), &buf2[0], pressurevalue, pressure_unit); + int pressurevalue = get_pressure_units(total_bar_used, &pressure_unit); + l += space + qasprintf_loc(translate("gettextFromC", "ΔP:%d%s"), pressurevalue, pressure_unit); } // We can't calculate the SAC if the volume for some of the cylinders used is unknown if (sac_is_determinable && total_volume_used) { - double volume_value; int volume_precision; const char *volume_unit; @@ -1699,8 +1696,10 @@ void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, /* milliliters per minute */ int sac = lrint(total_volume_used / atm * 60 / delta_time); - memcpy(&buf2[0], buf, bufsize); - volume_value = get_volume_units(sac, &volume_precision, &volume_unit); - snprintf_loc(buf, bufsize, qPrintable(gettextFromC::tr("%s SAC:%.*f%s/min")), &buf2[0], volume_precision, volume_value, volume_unit); + double volume_value = get_volume_units(sac, &volume_precision, &volume_unit); + l += space + qasprintf_loc(translate("gettextFromC", "SAC:%.*f%s/min"), volume_precision, volume_value, volume_unit); } + res.push_back(l); + + return res; } diff --git a/core/profile.h b/core/profile.h index d3c7316d5..61be2827e 100644 --- a/core/profile.h +++ b/core/profile.h @@ -97,11 +97,9 @@ struct plot_info { #define AMB_PERCENTAGE 50.0 -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); /* @@ -144,6 +142,12 @@ static inline int get_plot_pressure(const struct plot_info *pi, int idx, int cyl } #ifdef __cplusplus +// C++ only formatting functions +#include +// Returns index of sample and array of strings describing the dive details at given time +std::pair> get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time); +std::vector compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, bool sum); + } #endif #endif // PROFILE_H diff --git a/profile-widget/ruleritem.cpp b/profile-widget/ruleritem.cpp index a4fb00438..277367865 100644 --- a/profile-widget/ruleritem.cpp +++ b/profile-widget/ruleritem.cpp @@ -70,28 +70,6 @@ static ChartItemPtr makeHandle(ProfileView &view, double dpr) return res; } -// Split a membuffer into strings, skip empty lines. -// Return string / width (in pixels) pairs. -// TODO: Don't concatenate in the first place -static std::vector> split_string(const char *buf, const QFontMetrics &fm) -{ - std::vector> res; - for (size_t i = 0; buf[i] != '\0'; ++i) { - size_t j; - for (j = i; buf[j] != '\0' && buf[j] != '\n'; ++j) - ; - if (j > i) { - QString s = QString::fromUtf8(buf + i, j - i); - int width = fm.size(Qt::TextSingleLine, s).width(); - res.emplace_back(s, width); - } - if (!buf[j]) - break; - i = j; // Note: loop iteration will skip over '\n' - } - return res; -} - RulerItem::RulerItem(ProfileView &view, double dpr) : line(view.createChartItem(ProfileZValue::RulerItem, lineColor, lineWidth * dpr)), @@ -154,15 +132,23 @@ void RulerItem::update(const dive *d, double dpr, const ProfileScene &scene, con tooltip->setVisible(false); return; } + + auto strings = compare_samples(d, &info, idx1, idx2, true); + if (strings.empty()) { + tooltip->setVisible(false); + return; + } tooltip->setVisible(true); - char buffer[500]; - compare_samples(d, &info, idx1, idx2, buffer, 500, 1); - auto strings = split_string(buffer, fm); - double width = 0; - for (auto &[s,w]: strings) + std::vector string_widths; + string_widths.reserve(strings.size()); + for (const QString &s: strings) { + int w = fm.size(Qt::TextSingleLine, s).width(); width = std::max(width, static_cast(w)); + string_widths.push_back(w); + } + width += 6.0 * tooltipBorder * dpr; double height = static_cast(strings.size()) * fontHeight + @@ -176,9 +162,9 @@ void RulerItem::update(const dive *d, double dpr, const ProfileScene &scene, con painter.setPen(QPen(tooltipFontColor)); // QPainter uses QPen to set text color! double x = 4.0 * tooltipBorder * dpr; double y = 2.0 * tooltipBorder * dpr; - for (auto &[s,w]: strings) { - QRectF rect(x, y, w, fontHeight); - painter.drawText(rect, s); + for (size_t i = 0; i < strings.size(); ++i) { + QRectF rect(x, y, string_widths[i], fontHeight); + painter.drawText(rect, strings[i]); y += fontHeight; } diff --git a/profile-widget/tooltipitem.cpp b/profile-widget/tooltipitem.cpp index c5c97f0b5..3bc1ae195 100644 --- a/profile-widget/tooltipitem.cpp +++ b/profile-widget/tooltipitem.cpp @@ -63,26 +63,6 @@ QPixmap ToolTipItem::stringToPixmap(const QString &str) const return res; } -// Split a membuffer into strings, skip empty lines. -// Return string / width (in pixels) pairs. -// TODO: Don't concatenate in the first place -static std::vector> split_mb_into_strings(const membuffer &mb, const QFontMetrics &fm) -{ - std::vector> res; - for (size_t i = 0; i < mb.len; ++i) { - size_t j; - for (j = i; j < mb.len && mb.buffer[j] != '\n'; ++j) - ; - if (j > i) { - QString s = QString::fromUtf8(mb.buffer + i, j - i); - int width = fm.size(Qt::TextSingleLine, s).width(); - res.emplace_back(s, width); - } - i = j; // Note: loop iteration will skip over '\n' - } - return res; -} - static QPixmap drawTissues(const plot_info &pInfo, double dpr, int idx, bool inPlanner) { QPixmap tissues(16,60); @@ -121,17 +101,19 @@ static QPixmap drawTissues(const plot_info &pInfo, double dpr, int idx, bool inP void ToolTipItem::update(const dive *d, double dpr, int time, const plot_info &pInfo, const std::vector> &events, bool inPlanner, int animSpeed) { - struct membufferpp mb; - - int idx = get_plot_details_new(d, &pInfo, time, &mb); + auto [idx, strings] = get_plot_details_new(d, &pInfo, time); QPixmap tissues = drawTissues(pInfo, dpr, idx, inPlanner); - std::vector> strings = split_mb_into_strings(mb, fm); std::vector event_sizes; + std::vector string_widths; + string_widths.reserve(strings.size()); width = title.size().width(); - for (auto &[s,w]: strings) + for (const QString &s: strings) { + int w = fm.size(Qt::TextSingleLine, s).width(); width = std::max(width, static_cast(w)); + string_widths.push_back(w); + } height = (static_cast(strings.size()) + 1.0) * fontHeight; @@ -162,9 +144,9 @@ void ToolTipItem::update(const dive *d, double dpr, int time, const plot_info &p y += round(fontHeight); painter.drawPixmap(lrint(2.0 * tooltipBorder * dpr), lrint(y), tissues, 0, 0, tissues.width(), tissues.height()); y += round(fontHeight); - for (auto &[s,w]: strings) { - QRectF rect(x, y, w, fontHeight); - painter.drawText(rect, s); + for (size_t i = 0; i < strings.size(); ++i) { + QRectF rect(x, y, string_widths[i], fontHeight); + painter.drawText(rect, strings[i]); y += fontHeight; } for (size_t i = 0; i < events.size(); ++i) {