Add time display and verticle line in alt-select mode, plus userflags in piechart option

This commit is contained in:
Mark Watkins 2014-07-20 19:22:31 +10:00
parent 164d70c026
commit 0bf8d8833a
12 changed files with 142 additions and 26 deletions

View File

@ -792,7 +792,7 @@ void gGraph::mouseMoveEvent(QMouseEvent *event)
//if (!nolayer) { // no mouse button
if (doredraw) {
m_graphview->redraw();
m_graphview->timedRedraw(30);
}
//}
@ -1060,7 +1060,7 @@ void gGraph::keyReleaseEvent(QKeyEvent *event)
if (!m_graphview) return;
if (m_graphview->selectionInProgress() && m_graphview->metaSelect()) {
if (!(event->modifiers() & Qt::ShiftModifier)) {
if (!(event->modifiers() & Qt::AltModifier)) {
}
}

View File

@ -1094,6 +1094,8 @@ void gGraphView::setOffsetX(int offsetX)
void gGraphView::mouseMoveEvent(QMouseEvent *event)
{
this->setFocus();
int x = event->x();
int y = event->y();
@ -1397,7 +1399,7 @@ void gGraphView::mousePressEvent(QMouseEvent *event)
m_button_down = true;
m_metaselect = event->modifiers() && Qt::ShiftModifier;
m_metaselect = event->modifiers() && Qt::AltModifier;
m_horiz_travel = 0;
m_graph_index = i;
m_selected_graph = m_graphs[i];
@ -1459,7 +1461,7 @@ void gGraphView::mousePressEvent(QMouseEvent *event)
m_point_clicked = QPoint(event->x(), event->y());
//QMouseEvent e(event->type(),m_point_clicked,event->button(),event->buttons(),event->modifiers());
m_button_down = true;
m_metaselect = event->modifiers() && Qt::ShiftModifier;
m_metaselect = event->modifiers() && Qt::AltModifier;
m_horiz_travel = 0;
m_graph_index = i;
@ -1573,7 +1575,7 @@ void gGraphView::mouseReleaseEvent(QMouseEvent *event)
// The graph that got the button press gets the release event
if (m_button_down) {
m_button_down = false;
m_metaselect = event->modifiers() & Qt::ShiftModifier;
m_metaselect = event->modifiers() & Qt::AltModifier;
saveHistory();
if (m_metaselect) {
@ -1586,7 +1588,7 @@ void gGraphView::mouseReleaseEvent(QMouseEvent *event)
void gGraphView::keyReleaseEvent(QKeyEvent *event)
{
if (m_metaselect && !(event->modifiers() & Qt::ShiftModifier)) {
if (m_metaselect && !(event->modifiers() & Qt::AltModifier)) {
QMouseEvent mevent(QEvent::MouseButtonRelease, m_point_released, Qt::LeftButton, Qt::LeftButton, event->modifiers());
if (m_graph_index>=0)
m_graphs[m_graph_index]->mouseReleaseEvent(&mevent);
@ -1819,8 +1821,11 @@ void gGraphView::wheelEvent(QWheelEvent *event)
void gGraphView::keyPressEvent(QKeyEvent *event)
{
if (m_button_down) {
m_metaselect = event->modifiers() & Qt::ShiftModifier;
bool meta = m_metaselect;
m_metaselect = event->modifiers() & Qt::AltModifier;
if (meta != m_metaselect) {
timedRedraw(30);
}
if (event->key() == Qt::Key_Tab) {

View File

@ -157,6 +157,14 @@ EventDataType gLineChart::Maxy()
return Layer::Maxy() - subtract_offset;
}
bool gLineChart::mouseMoveEvent(QMouseEvent *event, gGraph *graph)
{
Q_UNUSED(event)
if (graph->graphView()->metaSelect())
graph->timedRedraw(30);
return true;
}
// Time Domain Line Chart
void gLineChart::paint(QPainter &painter, gGraph &w, const QRegion &region)
{
@ -226,6 +234,27 @@ void gLineChart::paint(QPainter &painter, gGraph &w, const QRegion &region)
}
}
if (w.graphView()->metaSelect()) {
QPoint mouse = w.graphView()->currentMousePos();
double pos = mouse.x() - left;
if (pos > 0) {
double xval = minx + (pos * (xx / double(width)));
painter.setPen(QPen(QBrush(QColor(Qt::gray)),1));
painter.drawLine(mouse.x(), top-w.marginTop()-3, mouse.x(), top+height+w.bottom-1);
QDateTime dt=QDateTime::fromMSecsSinceEpoch(xval);
QString text = dt.toString("MMM dd - HH:mm:ss:zzz");
int wid, h;
GetTextExtent(text, wid, h);
w.renderText(text, left + width/2 - wid/2, top -h);
}
}
EventDataType lastpx, lastpy;
EventDataType px, py;
int idx;

View File

@ -79,6 +79,9 @@ class gLineChart: public Layer
void setPlotEnabled(ChannelID code, bool b) { m_enabled[code] = b; }
protected:
//! \brief Mouse moved over this layers area (shows the hover-over tooltips here)
virtual bool mouseMoveEvent(QMouseEvent *event, gGraph *graph);
bool m_report_empty;
bool m_square_plot;
bool m_disable_accel;

View File

@ -21,6 +21,8 @@ gLineOverlayBar::~gLineOverlayBar()
{
}
QColor brighten(QColor color);
void gLineOverlayBar::paint(QPainter &painter, gGraph &w, const QRegion &region)
{
int left = region.boundingRect().left();
@ -145,10 +147,10 @@ void gLineOverlayBar::paint(QPainter &painter, gGraph &w, const QRegion &region)
if (x1 > width + left) {
x1 = width + left;
}
QRect rect(x2, start_py, x1-x2, height);
QColor col = m_flag_color;
if (rect.contains(mouse)) {
col = QColor("gold");
hover = true;
}
@ -263,7 +265,6 @@ void gLineOverlayBar::paint(QPainter &painter, gGraph &w, const QRegion &region)
bool gLineOverlayBar::mouseMoveEvent(QMouseEvent *event, gGraph *graph)
{
Q_UNUSED(event)
graph->timedRedraw(0);
return true;
}

View File

@ -21,18 +21,71 @@
extern double round(double number);
bool SearchApnea(Session *session, qint64 time, qint64 dist)
bool SearchEvent(Session * session, ChannelID code, qint64 time, EventStoreType dur, qint64 dist)
{
if (session->SearchEvent(CPAP_Obstructive, time, dist))
qint64 t, start;
QHash<ChannelID, QVector<EventList *> >::iterator it;
it = session->eventlist.find(code);
quint32 *tptr;
EventStoreType *dptr;
int cnt;
//qint64 rate;
QHash<ChannelID, QVector<EventList *> >::iterator evend = session->eventlist.end();
if (it != evend) {
int el_size=it.value().size();
for (int i = 0; i < el_size; i++) {
EventList *el = it.value()[i];
// rate=el->rate();
cnt = el->count();
// why would this be necessary???
if (el->type() == EVL_Waveform) {
qDebug() << "Called SearchEvent on a waveform object!";
return false;
} else {
start = el->first();
tptr = el->rawTime();
dptr = el->rawData();
for (int j = 0; j < cnt; j++) {
t = start + *tptr;
if (qAbs(time - t) < dist) {
// Move the position and set the duration
if (dur>0) {
*tptr = time - start;
*dptr = (EventStoreType)dur;
}
return true;
}
tptr++;
dptr++;
}
}
}
}
return false;
}
bool SearchApnea(Session *session, qint64 time, double dur, qint64 dist)
{
if (SearchEvent(session, CPAP_Obstructive, time, dur, dist))
return true;
if (session->SearchEvent(CPAP_Apnea, time, dist))
if (SearchEvent(session, CPAP_Apnea, time, dur, dist))
return true;
if (session->SearchEvent(CPAP_ClearAirway, time, dist))
if (SearchEvent(session, CPAP_ClearAirway, time, dur, dist))
return true;
if (session->SearchEvent(CPAP_Hypopnea, time, dist))
if (SearchEvent(session, CPAP_Hypopnea, time, 0, dist))
return true;
if (session->SearchEvent(CPAP_UserFlag1, time, dist))
@ -724,7 +777,7 @@ void FlowParser::flagUserEvents(ChannelID code, EventDataType restriction, Event
dur = len / 1000.0;
if (dur >= duration) {
if (allowDuplicates || !SearchApnea(m_session, et - len / 2, 15000)) {
if (allowDuplicates || !SearchApnea(m_session, et, dur, 15000)) {
if (!uf) {
uf = m_session->AddEventList(code, EVL_Event);
}

View File

@ -140,7 +140,7 @@ class FlowParser
EventDataType *m_buffers[num_filter_buffers];
};
bool SearchApnea(Session *session, qint64 time, qint64 dist = 15000);
bool SearchApnea(Session *session, qint64 time, double dur, qint64 dist = 15000);
//! \brief Calculate Respiratory Rate, Tidal Volume & Minute Ventilation for PRS1 data
void calcRespRate(Session *session, FlowParser *flowparser = nullptr);

View File

@ -271,6 +271,8 @@ const QString STR_CS_UntreatedAHI = "UntreatedAHI";
const QString STR_CS_Notes = "CPAPNotes";
const QString STR_CS_DateDiagnosed = "DateDiagnosed";
const QString STR_CS_UserEventFlagging = "UserEventFlagging";
const QString STR_CS_UserEventPieChart = "UserEventPieChart";
const QString STR_CS_UserFlowRestriction = "UserFlowRestriction";
const QString STR_CS_UserEventDuration = "UserEventDuration";
const QString STR_CS_UserFlowRestriction2 = "UserFlowRestriction2";
@ -525,6 +527,7 @@ class CPAPSettings : public ProfileSettings
initPref(STR_CS_AHIReset, false);
initPref(STR_CS_LeakRedline, 24.0);
initPref(STR_CS_ShowLeakRedline, true);
initPref(STR_CS_UserEventPieChart, false);
initPref(STR_CS_ClockDrift, (int)0);
m_clock_drift = getPref(STR_CS_ClockDrift).toInt();
@ -554,6 +557,7 @@ class CPAPSettings : public ProfileSettings
int clockDrift() const { return m_clock_drift; }
EventDataType leakRedline() const { return getPref(STR_CS_LeakRedline).toFloat(); }
bool showLeakRedline() const { return getPref(STR_CS_ShowLeakRedline).toBool(); }
bool userEventPieChart() const { return getPref(STR_CS_UserEventPieChart).toBool(); }
//Setters
void setMode(CPAPMode mode) { setPref(STR_CS_PrescribedMode, (int)mode); }
@ -583,6 +587,7 @@ class CPAPSettings : public ProfileSettings
}
void setLeakRedline(EventDataType value) { setPref(STR_CS_LeakRedline, value); }
void setShowLeakRedline(bool reset) { setPref(STR_CS_ShowLeakRedline, reset); }
void setUserEventPieChart(bool b) { setPref(STR_CS_UserEventPieChart, b); }
public:
int m_clock_drift;

View File

@ -211,12 +211,12 @@ void init()
schema::channel.add(GRP_CPAP, new Channel(CPAP_UserFlag1 = 0x101e, FLAG, SESSION,
"UserFlag1", QObject::tr("User Flag #1"),
QObject::tr("A user definable event detected by SleepyHead's flow waveform processor."),
QObject::tr("UF1"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark cyan")));
QObject::tr("UF1"), STR_UNIT_EventsPerHour, DEFAULT, QColor(0xc0,0xc0,0xe0)));
schema::channel.add(GRP_CPAP, new Channel(CPAP_UserFlag2 = 0x101f, FLAG, SESSION,
"UserFlag2", QObject::tr("User Flag #2"),
QObject::tr("A user definable event detected by SleepyHead's flow waveform processor."),
QObject::tr("UF2"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark blue")));
QObject::tr("UF2"), STR_UNIT_EventsPerHour, DEFAULT, QColor(0xa0,0xa0,0xc0)));
schema::channel.add(GRP_CPAP, new Channel(CPAP_UserFlag3 = 0x1024, FLAG, SESSION,
"UserFlag3", QObject::tr("User Flag #3"),

View File

@ -192,7 +192,10 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
evseg->AddSlice(CPAP_NRI,QColor(0x00,0x80,0x40,0xff),STR_TR_NR);
evseg->AddSlice(CPAP_FlowLimit,QColor(0x40,0x40,0x40,0xff),STR_TR_FL);
evseg->AddSlice(CPAP_SensAwake,QColor(0x40,0xC0,0x40,0xff),STR_TR_SA);
//evseg->AddSlice(CPAP_UserFlag1,QColor(0x40,0x40,0x40,0xff),tr("UF"));
if (p_profile->cpap->userEventPieChart()) {
evseg->AddSlice(CPAP_UserFlag1,QColor(0xe0,0xe0,0xe0,0xff),tr("UF1"));
evseg->AddSlice(CPAP_UserFlag2,QColor(0xc0,0xc0,0xe0,0xff),tr("UF2"));
}
GAHI->AddLayer(AddCPAP(evseg));
GAHI->setMargins(0,0,0,0);
@ -1393,8 +1396,6 @@ void Daily::Load(QDate date)
{ CPAP_Apnea, COLOR_Apnea, Qt::black, uai=cpap->count(CPAP_Apnea)/hours },
{ CPAP_ClearAirway, COLOR_ClearAirway, Qt::black, cai=cpap->count(CPAP_ClearAirway)/hours },
{ CPAP_NRI, COLOR_NRI, Qt::black, nri=cpap->count(CPAP_NRI)/hours },
{ CPAP_UserFlag1, COLOR_UserFlag1, Qt::black, uf1=cpap->count(CPAP_UserFlag1)/hours },
{ CPAP_UserFlag2, COLOR_UserFlag2, Qt::black, uf2=cpap->count(CPAP_UserFlag2)/hours },
{ CPAP_FlowLimit, COLOR_FlowLimit, Qt::white, fli=cpap->count(CPAP_FlowLimit)/hours },
{ CPAP_SensAwake, COLOR_SensAwake, Qt::black, sai=cpap->count(CPAP_SensAwake)/hours },
{ CPAP_ExP, COLOR_ExP, Qt::black, exp=cpap->count(CPAP_ExP)/hours },
@ -1403,7 +1404,10 @@ void Daily::Load(QDate date)
{ CPAP_VSnore2, COLOR_VibratorySnore, Qt::black, vs2=cpap->count(CPAP_VSnore2)/cpap->hours() },
{ CPAP_LeakFlag, COLOR_LeakFlag, Qt::black, lki=cpap->count(CPAP_LeakFlag)/hours },
{ CPAP_LargeLeak, COLOR_LargeLeak, Qt::black, lk2=(100.0/cpap->hours())*(cpap->sum(CPAP_LargeLeak)/3600.0) },
{ CPAP_CSR, COLOR_CSR, Qt::black, csr=(100.0/cpap->hours())*(cpap->sum(CPAP_CSR)/3600.0) }
{ CPAP_CSR, COLOR_CSR, Qt::black, csr=(100.0/cpap->hours())*(cpap->sum(CPAP_CSR)/3600.0) },
{ CPAP_UserFlag1, COLOR_UserFlag1, Qt::black, uf1=cpap->count(CPAP_UserFlag1)/hours },
{ CPAP_UserFlag2, COLOR_UserFlag2, Qt::black, uf2=cpap->count(CPAP_UserFlag2)/hours },
};
int numchans=sizeof(chans)/sizeof(ChannelInfo);

View File

@ -247,6 +247,8 @@ PreferencesDialog::PreferencesDialog(QWidget *parent, Profile *_profile) :
ui->userEventDuplicates->setChecked(profile->cpap->userEventDuplicates());
ui->userEventDuplicates->setVisible(false);
ui->showUserFlagsInPie->setChecked(profile->cpap->userEventPieChart());
ui->eventTable->setColumnWidth(0, 40);
ui->eventTable->setColumnWidth(1, 55);
ui->eventTable->setColumnHidden(3, true);
@ -344,6 +346,11 @@ bool PreferencesDialog::Save()
needs_restart = true;
}
if (profile->cpap->userEventPieChart() != ui->showUserFlagsInPie->isChecked()) {
// lazy.. fix me
needs_restart = true;
}
if (profile->general->calculateRDI() != ui->AddRERAtoAHI->isChecked()) {
//recalc_events=true;
needs_restart = true;
@ -393,6 +400,8 @@ bool PreferencesDialog::Save()
}
}
profile->cpap->setUserEventPieChart(ui->showUserFlagsInPie->isChecked());
profile->appearance->setAllowYAxisScaling(ui->allowYAxisScaling->isChecked());
profile->appearance->setGraphTooltips(ui->graphTooltips->isChecked());
@ -551,11 +560,11 @@ bool PreferencesDialog::Save()
PREF.Save();
p_profile->Save();
if (recalc_events) {
// send a signal instead?
mainwin->reprocessEvents(needs_restart);
} else if (needs_restart) {
p_profile->removeLock();
mainwin->RestartApplication();
} else {
mainwin->getDaily()->LoadDate(mainwin->getDaily()->getDate());

View File

@ -992,6 +992,13 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="5" column="1" colspan="4">
<widget class="QCheckBox" name="userEventDuplicates">
<property name="text">
<string>Allow duplicates near machine events.</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QDoubleSpinBox" name="apneaDuration2">
<property name="suffix">
@ -1010,9 +1017,9 @@ p, li { white-space: pre-wrap; }
</widget>
</item>
<item row="4" column="1" colspan="4">
<widget class="QCheckBox" name="userEventDuplicates">
<widget class="QCheckBox" name="showUserFlagsInPie">
<property name="text">
<string>Allow duplicates near machine events.</string>
<string>Show in Event Breakdown Piechart</string>
</property>
</widget>
</item>