From 15fa7c4fe8dd098e9f9e28a032e16bba1948d2bb Mon Sep 17 00:00:00 2001 From: OSjoerdWie Date: Thu, 16 Feb 2023 08:40:00 +0100 Subject: [PATCH] Issue #68: Display durations in formatted manner on summary charts ('statistics' + hover overlay). --- oscar/Graphs/gSessionTimesChart.cpp | 9 +++++---- oscar/Graphs/gSummaryChart.cpp | 27 +++++++++++++++++++++++++++ oscar/Graphs/gSummaryChart.h | 4 ++++ oscar/Graphs/gTTIAChart.cpp | 7 ++----- oscar/Graphs/gUsageChart.cpp | 4 ++-- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/oscar/Graphs/gSessionTimesChart.cpp b/oscar/Graphs/gSessionTimesChart.cpp index 868a4949..35a82109 100644 --- a/oscar/Graphs/gSessionTimesChart.cpp +++ b/oscar/Graphs/gSessionTimesChart.cpp @@ -101,8 +101,8 @@ void gSessionTimesChart::afterDraw(QPainter & /*painter */, gGraph &graph, QRect QString txt = QObject::tr("Sessions: %1 / %2 / %3 Length: %4 / %5 / %6 Longest: %7 / %8 / %9") .arg(calc1.min, 0, 'f', 2).arg(mid1, 0, 'f', 2).arg(calc1.max, 0, 'f', 2) - .arg(calc.min, 0, 'f', 2).arg(mid, 0, 'f', 2).arg(calc.max, 0, 'f', 2) - .arg(calc2.min, 0, 'f', 2).arg(midlongest, 0, 'f', 2).arg(calc2.max, 0, 'f', 2); + .arg(durationInHoursToHhMmSs(calc.min)).arg(durationInHoursToHhMmSs(mid)).arg(durationInHoursToHhMmSs(calc.max)) + .arg(durationInHoursToHhMmSs(calc2.min)).arg(durationInHoursToHhMmSs(midlongest)).arg(durationInHoursToHhMmSs(calc2.max)); graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0); } @@ -216,9 +216,10 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion & float s1 = float(splittime.secsTo(st)) / 3600.0; float s2 = double(slice.end - slice.start) / 3600000.0; + float s2_display = double(slice.end - slice.start) / 1000.0; QColor col = (slice.status == MaskOn) ? goodcolor : Qt::black; - QString txt = QObject::tr("%1\nLength: %3\nStart: %2\n").arg(datestr).arg(st.time().toString("hh:mm:ss")).arg(s2,0,'f',2); + QString txt = QObject::tr("%1\nLength: %3\nStart: %2\n").arg(datestr).arg(st.time().toString("hh:mm:ss")).arg(durationInSecondsToHhMmSs(s2_display)); txt += (slice.status == MaskOn) ? QObject::tr("Mask On") : QObject::tr("Mask Off"); slices.append(SummaryChartSlice(&calcitems[0], s1, s2, txt, col)); @@ -231,7 +232,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion & float s2 = sess->hours(); - QString txt = QObject::tr("%1\nLength: %3\nStart: %2").arg(datestr).arg(st.time().toString("hh:mm:ss")).arg(s2,0,'f',2); + QString txt = QObject::tr("%1\nLength: %3\nStart: %2").arg(datestr).arg(st.time().toString("hh:mm:ss")).arg(durationInHoursToHhMmSs(s2)); slices.append(SummaryChartSlice(&calcitems[0], s1, s2, txt, goodcolor)); } diff --git a/oscar/Graphs/gSummaryChart.cpp b/oscar/Graphs/gSummaryChart.cpp index e4347553..ce733538 100644 --- a/oscar/Graphs/gSummaryChart.cpp +++ b/oscar/Graphs/gSummaryChart.cpp @@ -688,3 +688,30 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io } } + +QString gSummaryChart::durationInHoursToHhMmSs(double duration) { + return durationInSecondsToHhMmSs(duration * 3600); +} + +QString gSummaryChart::durationInMinutesToHhMmSs(double duration) { + return durationInSecondsToHhMmSs(duration * 60); +} + +QString gSummaryChart::durationInSecondsToHhMmSs(double duration) { + // ensure that a negative duration is supported (could potentially occur when start and end occur in different timezones without compensation) + double duration_abs = abs(duration); + int seconds_abs = static_cast(0.5 + duration_abs); + int daily_hours_abs = seconds_abs / 3600; + QString result; + if (daily_hours_abs < 24) { + result = QTime(0,0,0,0).addSecs(seconds_abs).toString("hh:mm:ss"); + } else { + result = QString::number(daily_hours_abs + seconds_abs % 86400 / 3600) + ":" + QTime(0, 0, 0, 0).addSecs(seconds_abs).toString("mm:ss"); + } + + if (duration == duration_abs) { + return result; + } else { + return "-" + result; + } +} diff --git a/oscar/Graphs/gSummaryChart.h b/oscar/Graphs/gSummaryChart.h index 35203bb2..4c6232b5 100644 --- a/oscar/Graphs/gSummaryChart.h +++ b/oscar/Graphs/gSummaryChart.h @@ -238,6 +238,10 @@ protected: //! \brief Mouse Button was released over this area. (jumps to daily view here) virtual bool mouseReleaseEvent(QMouseEvent *event, gGraph *graph); + QString durationInHoursToHhMmSs(double duration); + QString durationInMinutesToHhMmSs(double duration); + QString durationInSecondsToHhMmSs(double duration); + QString m_label; MachineType m_machtype; bool m_empty; diff --git a/oscar/Graphs/gTTIAChart.cpp b/oscar/Graphs/gTTIAChart.cpp index bb9ca91e..0d59343d 100644 --- a/oscar/Graphs/gTTIAChart.cpp +++ b/oscar/Graphs/gTTIAChart.cpp @@ -68,7 +68,7 @@ void gTTIAChart::afterDraw(QPainter &, gGraph &graph, QRectF rect) break; } - txtlist.append(QString("%1 %2 / %3 / %4").arg(QObject::tr("TTIA:")).arg(calc.min, 0, 'f', 2).arg(mid, 0, 'f', 2).arg(calc.max, 0, 'f', 2)); + txtlist.append(QString("%1 %2 / %3 / %4").arg(QObject::tr("TTIA:")).arg(durationInMinutesToHhMmSs(calc.min)).arg(durationInMinutesToHhMmSs(mid)).arg(durationInMinutesToHhMmSs(calc.max))); } QString txt = txtlist.join(", "); graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0); @@ -80,10 +80,7 @@ void gTTIAChart::populate(Day *day, int idx) // float ttia = day->sum(CPAP_AllApnea) + day->sum(CPAP_Obstructive) + day->sum(CPAP_ClearAirway) + day->sum(CPAP_Apnea) + day->sum(CPAP_Hypopnea); float ttia = day->sum(AllAhiChannels); - int h = ttia / 3600; - int m = int(ttia) / 60 % 60; - int s = int(ttia) % 60; - slices.append(SummaryChartSlice(&calcitems[0], ttia / 60.0, ttia / 60.0, QObject::tr("\nTTIA: %1").arg( QString().asprintf("%02i:%02i:%02i",h,m,s)) , QColor(255,147,150))); + slices.append(SummaryChartSlice(&calcitems[0], ttia / 60.0, ttia / 60.0, QObject::tr("\nTTIA: %1").arg(durationInSecondsToHhMmSs(ttia)), QColor(255,147,150))); } QString gTTIAChart::tooltipData(Day *, int idx) diff --git a/oscar/Graphs/gUsageChart.cpp b/oscar/Graphs/gUsageChart.cpp index 95eb6562..0847bd3c 100644 --- a/oscar/Graphs/gUsageChart.cpp +++ b/oscar/Graphs/gUsageChart.cpp @@ -27,7 +27,7 @@ extern MainWindow * mainwin; QString gUsageChart::tooltipData(Day * day, int) { - return QObject::tr("\nHours: %1").arg(day->hours(m_machtype), 0, 'f', 2); + return QObject::tr("\nLength: %1").arg(durationInHoursToHhMmSs(day->hours(m_machtype))); } void gUsageChart::populate(Day *day, int idx) @@ -94,7 +94,7 @@ void gUsageChart::afterDraw(QPainter &, gGraph &graph, QRectF rect) } QString txt = QObject::tr("%1 low usage, %2 no usage, out of %3 days (%4% compliant.) Length: %5 / %6 / %7"). - arg(incompdays).arg(nousedays).arg(totaldays).arg(comp,0,'f',1).arg(calc.min, 0, 'f', 2).arg(mid, 0, 'f', 2).arg(calc.max, 0, 'f', 2);; + arg(incompdays).arg(nousedays).arg(totaldays).arg(comp,0,'f',1).arg(durationInHoursToHhMmSs(calc.min)).arg(durationInHoursToHhMmSs(mid)).arg(durationInHoursToHhMmSs(calc.max)); graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0); } }