diff --git a/Graphs/gFlagsLine.cpp b/Graphs/gFlagsLine.cpp index 0a6a17ff..31292cab 100644 --- a/Graphs/gFlagsLine.cpp +++ b/Graphs/gFlagsLine.cpp @@ -8,6 +8,7 @@ #include #include "SleepLib/profiles.h" #include "gFlagsLine.h" +#include "gYAxis.h" gFlagsGroup::gFlagsGroup() { @@ -30,15 +31,10 @@ qint64 gFlagsGroup::Maxx() return 0; } -void gFlagsGroup::Plot(gGraphWindow &w, float scrx, float scry) +void gFlagsGroup::paint(gGraph &w, int left, int top, int width, int height) { if (!m_visible) return; //if (!m_day) return; - int start_px=w.GetLeftMargin(); - int start_py=w.GetBottomMargin(); - int width=scrx-(w.GetLeftMargin()+w.GetRightMargin())-1; - int height=scry-(w.GetTopMargin()+w.GetBottomMargin()); - QVector lvisible; for (int i=0;iline_num=i; - lvisible[i]->total_lines=vis; - lvisible[i]->Plot(w,scrx,scry); + // Alternating box color + QColor * barcol=&col2; + if (i & 1) + barcol=&col1; + + //int qo=0; + //if (evil_intel_graphics_card) qo=1; + + // Draw the bars with filled quads + w.qglColor(*barcol); + glBegin(GL_QUADS); + glVertex2f(left, linetop); + glVertex2f(left, linetop+barh); + glVertex2f(left+width-1, linetop+barh); + glVertex2f(left+width-1, linetop); + glEnd(); + + // Paint the actual flags + lvisible[i]->paint(w,left,linetop,width,barh); + linetop+=barh; } + + // Draw the outer rectangle outline glColor3f (0.0F, 0.0F, 0.0F); glLineWidth (1); glBegin (GL_LINE_LOOP); - glVertex2f (start_px-1, start_py); - glVertex2f (start_px-1, start_py+height); - glVertex2f (start_px+width,start_py+height); - glVertex2f (start_px+width, start_py); + glVertex2f (left-1, top); + glVertex2f (left-1, top+height); + glVertex2f (left+width, top+height); + glVertex2f (left+width, top); glEnd (); } gFlagsLine::gFlagsLine(ChannelID code,QColor flag_color,QString label,bool always_visible,FlagType flt) -:gLayer(code),m_label(label),m_always_visible(always_visible),m_flt(flt),m_flag_color(flag_color) +:Layer(code),m_label(label),m_always_visible(always_visible),m_flt(flt),m_flag_color(flag_color) { } gFlagsLine::~gFlagsLine() { } -void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry) +void gFlagsLine::paint(gGraph & w,int left, int top, int width, int height) { if (!m_visible) return; if (!m_day) return; @@ -82,7 +103,7 @@ void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry) double minx; double maxx; - if (w.BlockZoom()) { + if (w.blockZoom()) { minx=w.rmin_x; maxx=w.rmax_x; } else { @@ -93,38 +114,8 @@ void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry) double xx=maxx-minx; if (xx<=0) return; - int start_px=w.GetLeftMargin(); - int start_py=w.GetBottomMargin(); - int width=scrx-(w.GetLeftMargin()+w.GetRightMargin())-1; - int height=scry-(w.GetTopMargin()+w.GetBottomMargin()); - double xmult=width/xx; - static QColor col1=QColor(0xd0,0xff,0xd0,0xff); - static QColor col2=QColor(0xff,0xff,0xff,0xff); - - - float line_h=float(height-2)/float(total_lines); - line_h=line_h; - float line_top=(start_py+height-line_h)-line_num*line_h; - - // Alternating box color - QColor * barcol=&col2; - if (line_num & 1) - barcol=&col1; - - int qo=0; - //if (evil_intel_graphics_card) qo=1; - - // Filled rectangle - w.qglColor(*barcol); - glBegin(GL_QUADS); - glVertex2f(start_px+qo, line_top); - glVertex2f(start_px+qo, line_top+line_h); - glVertex2f(start_px+width-1, line_top+line_h); - glVertex2f(start_px+width-1, line_top); - glEnd(); - qint32 vertcnt=0; GLshort * vertarray=vertex_array[0]; qint32 quadcnt=0; @@ -137,13 +128,14 @@ void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry) // Draw text label float x,y; GetTextExtent(m_label,x,y); - //w.qglColor(Qt::black); + w.qglColor(Qt::black); //w.renderText(start_px-x-10,(scry-line_top)-(line_h/2)+(y/2),m_label); - DrawText(w,m_label,start_px-x-10,(scry-line_top)-(line_h/2)+(y/2)); + //DrawText(w,m_label); + w.renderText(m_label,left-x-10,top+(height/2)+(y/2)); float x1,x2; - float top=floor(line_top)+2; - float bottom=top+floor(line_h)-3; + float bartop=top+2; + float bottom=top+height-2; bool verts_exceeded=false; qint64 X,Y; for (QVector::iterator s=m_day->begin();s!=m_day->end(); s++) { @@ -156,24 +148,24 @@ void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry) Y=X-(el.data(i)*1000); if (Y < minx) continue; if (X > maxx) break; - x1=(X - minx) * xmult + w.GetLeftMargin(); + x1=(X - minx) * xmult + left; if (m_flt==FT_Bar) { vertarray[vertcnt++]=x1; - vertarray[vertcnt++]=top; + vertarray[vertcnt++]=bartop; vertarray[vertcnt++]=x1; vertarray[vertcnt++]=bottom; if (vertcnt>maxverts) { verts_exceeded=true; break; } } else if (m_flt==FT_Span) { - x2=(Y-minx)*xmult+w.GetLeftMargin(); + x2=(Y-minx)*xmult+left; //w1=x2-x1; quadarray[quadcnt++]=x1; - quadarray[quadcnt++]=top; + quadarray[quadcnt++]=bartop; quadarray[quadcnt++]=x1; quadarray[quadcnt++]=bottom; quadarray[quadcnt++]=x2; quadarray[quadcnt++]=bottom; quadarray[quadcnt++]=x2; - quadarray[quadcnt++]=top; + quadarray[quadcnt++]=bartop; if (quadcnt>maxverts) { verts_exceeded=true; break; } } } @@ -181,8 +173,8 @@ void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry) if (verts_exceeded) { qWarning() << "maxverts exceeded in gFlagsLine::plot()"; } - glScissor(w.GetLeftMargin(),w.GetBottomMargin(),width,height); - glEnable(GL_SCISSOR_TEST); + // glScissor(left,top,width,height); + //glEnable(GL_SCISSOR_TEST); bool antialias=pref["UseAntiAliasing"].toBool(); if (antialias) { @@ -209,5 +201,5 @@ void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry) glDisable(GL_BLEND); } - glDisable(GL_SCISSOR_TEST); + //glDisable(GL_SCISSOR_TEST); } diff --git a/Graphs/gFlagsLine.h b/Graphs/gFlagsLine.h index 8cce6e4e..ee414dc4 100644 --- a/Graphs/gFlagsLine.h +++ b/Graphs/gFlagsLine.h @@ -1,24 +1,24 @@ -/******************************************************************** +/* gFlagsLine Header Copyright (c)2011 Mark Watkins License: GPL -*********************************************************************/ +*/ #ifndef GFLAGSLINE_H #define GFLAGSLINE_H -#include "graphlayer.h" +#include "gGraphView.h" class gFlagsGroup; -class gFlagsLine:public gLayer +class gFlagsLine:public Layer { friend class gFlagsGroup; public: gFlagsLine(ChannelID code,QColor col=Qt::black,QString label="",bool always_visible=false,FlagType flt=FT_Bar); virtual ~gFlagsLine(); - virtual void Plot(gGraphWindow & w,float scrx,float scry); + virtual void paint(gGraph & w,int left, int top, int width, int height); bool isAlwaysVisible() { return m_always_visible; } void setAlwaysVisible(bool b) { m_always_visible=b; } QString label() { return m_label; } @@ -33,16 +33,15 @@ class gFlagsLine:public gLayer QColor m_flag_color; }; -class gFlagsGroup:public gLayerGroup +class gFlagsGroup:public LayerGroup { public: gFlagsGroup(); virtual ~gFlagsGroup(); - virtual void Plot(gGraphWindow &w, float scrx, float scry); + virtual void paint(gGraph & w,int left, int top, int width, int height); virtual qint64 Minx(); virtual qint64 Maxx(); - }; #endif // GFLAGSLINE_H diff --git a/Graphs/gGraphView.cpp b/Graphs/gGraphView.cpp new file mode 100644 index 00000000..15b9f358 --- /dev/null +++ b/Graphs/gGraphView.cpp @@ -0,0 +1,978 @@ +#include +#include "gGraphView.h" + +Layer::Layer(ChannelID code) +{ + m_code = code; + m_visible = true; + m_movable = false; + + m_day=NULL; + m_miny=m_maxy=0; + m_minx=m_maxx=0; + m_order=0; + m_width=m_height=0; + m_X=m_Y=0; + m_position=LayerCenter; +} + +Layer::~Layer() +{ +} + +void Layer::SetDay(Day * d) +{ + m_day=d; + if (!d) return; + + m_minx=d->first(m_code); + m_maxx=d->last(m_code); + m_miny=d->min(m_code); + m_maxy=d->max(m_code); +} + +bool Layer::isEmpty() +{ + if (m_day && (m_day->count(m_code)!=0)) + return false; + return true; +} +void Layer::setLayout(LayerPosition position, short width, short height, short order) +{ + m_position=position; + m_width=width; + m_height=height; + m_order=order; +} + +LayerGroup::LayerGroup() : + Layer(EmptyChannel) +{ +} +LayerGroup::~LayerGroup() +{ +} +bool LayerGroup::isEmpty() +{ + if (!m_day) + return true; + bool empty=true; + for (int i=0;iisEmpty()) { + empty=false; + break; + } + } + return empty; +} +void LayerGroup::SetDay(Day * d) +{ + for (int i=0;iSetDay(d); + } + m_day=d; +} + +void LayerGroup::AddLayer(Layer *l) +{ + layers.push_back(l); +} + +qint64 LayerGroup::Minx() +{ + bool first=true; + qint64 m=0,t; + for (int i=0;iMinx(); + if (!t) continue; + if (first) { + m=t; + first=false; + } else + if (m>t) m=t; + } + return m; +} +qint64 LayerGroup::Maxx() +{ + bool first=true; + qint64 m=0,t; + for (int i=0;iMaxx(); + if (!t) continue; + if (first) { + m=t; + first=false; + } else + if (mMiny(); + if (t==layers[i]->Minx()) continue; + if (first) { + m=t; + first=false; + } else { + if (m>t) m=t; + } + } + return m; +} +EventDataType LayerGroup::Maxy() +{ + bool first=true; + EventDataType m=0,t; + for (int i=0;iMaxy(); + if (t==layers[i]->Miny()) continue; + if (first) { + m=t; + first=false; + } else + if (mAddGraph(this); + } else { + qWarning() << "gGraph created without a gGraphView container.. Naughty programmer!! Bad!!!"; + } + m_margintop=10; + m_marginbottom=10; + m_marginleft=5; + m_marginright=10; +} +gGraph::~gGraph() +{ +} +bool gGraph::isEmpty() +{ + bool empty=true; + for (QVector::iterator l=m_layers.begin();l!=m_layers.end();l++) { + if (!(*l)->isEmpty()) { + empty=false; + break; + } + } + return empty; +} + +void gGraph::invalidate() +{ // this may not be necessary, as scrollbar & resize issues a full redraw.. + + //m_lastbounds.setWidth(m_graphview->width()); + m_lastbounds.setY(m_graphview->findTop(this)); + m_lastbounds.setX(gGraphView::titleWidth); + m_lastbounds.setHeight(m_height * m_graphview->scaleY()); + m_lastbounds.setWidth(m_graphview->width()-gGraphView::titleWidth); + int i=0; + //m_lastbounds.setHeight(0); +} + +void gGraph::repaint() +{ + if (m_lastbounds.height()>0) { + //glScissor(0,m_lastbounds.y(),m_lastbounds.width(),m_lastbounds.height()); +// m_graphview->swapBuffers(); // how fast is this?? + //glEnable(GL_SCISSOR_BOX); + + glBegin(GL_QUADS); + glColor4f(1,1,1,1.0); // Gradient End + glVertex2i(0,m_lastbounds.y()); + glVertex2i(gGraphView::titleWidth,m_lastbounds.y()); + glVertex2i(gGraphView::titleWidth,m_lastbounds.y()+height()); + glVertex2i(0,m_lastbounds.y()+height()); + glEnd(); + + paint(m_lastbounds.x(),m_lastbounds.y(),m_lastbounds.width(),m_lastbounds.height()); + m_graphview->swapBuffers(); + //glDisable(GL_SCISSOR_BOX); + } else { + qDebug() << "Wanted to redraw graph" << m_title << "but previous bounds were invalid.. Issuing a slower full redraw instead. Todo: Find out why."; + m_graphview->updateGL(); + } +} + +void gGraph::qglColor(QColor col) +{ + m_graphview->qglColor(col); +} +void gGraph::renderText(QString text, int x,int y, float angle, QColor color, QFont *font) +{ + // GL Font drawing is ass in Qt.. :( + // I tried queuing this but got crappy memory leaks.. for now I don't give a crap if this is slow. + + QPainter *painter=m_graphview->painter; + painter->endNativePainting(); + QBrush b(color); + painter->setBrush(b); + painter->setFont(*font); + if (angle==0) { + painter->drawText(x,y,text); + } else { + float w,h; + GetTextExtent(text, w, h, font); + + painter->translate(x,y); + painter->rotate(-angle); + painter->drawText(floor(-w/2.0),floor(-h/2.0),text); + painter->rotate(+angle); + painter->translate(-x,-y); + } + painter->beginNativePainting(); +} + + +void gGraph::paint(int originX, int originY, int width, int height) +{ + m_lastbounds=QRect(originX,originY,width,height); + + glBegin(GL_QUADS); + glColor4f(1,1,1,1.0); // Gradient End + glVertex2i(originX,originY); + glVertex2i(originX+width,originY); + glColor4f(1,1,1.0,1.0); // Gradient End + glVertex2i(originX+width,originY+height); + glVertex2i(originX,originY+height); + glEnd(); + glColor4f(0,0,0,1); + renderText(title(),20,originY+height/2,90); + + left=0,right=0,top=0,bottom=0; + + int tmp; + + originX+=m_marginleft; + originY+=m_margintop; + width-=m_marginleft+m_marginright; + height-=m_margintop+m_marginbottom; + + for (int i=0;iHeight(); + if (ll->position()==LayerTop) top+=tmp; + if (ll->position()==LayerBottom) bottom+=tmp; + } + + for (int i=0;iWidth(); + if (ll->position()==LayerLeft) { + ll->paint(*this,originX+left,originY+top,tmp,height-top-bottom); + left+=tmp; + } + if (ll->position()==LayerRight) { + right+=tmp; + ll->paint(*this,originX+width-right,originY+top,tmp,height-top-bottom); + } + } + + bottom=0; top=0; + for (int i=0;iHeight(); + if (ll->position()==LayerTop) { + ll->paint(*this,originX+left,originY+top,width-left-right,tmp); + top+=tmp; + } + if (ll->position()==LayerBottom) { + bottom+=tmp; + ll->paint(*this,originX+left,originY+height-bottom,width-left-right,tmp); + } + } + + for (int i=0;iposition()==LayerCenter) { + ll->paint(*this,originX+left,originY+top,width-left-right,height-top-bottom); + } + } +} + +void gGraph::AddLayer(Layer * l,LayerPosition position, short width, short height, short order, bool movable, short x, short y) +{ + l->setLayout(position,width,height,order); + l->setMovable(movable); + l->setPos(x,y); + m_layers.push_back(l); +} +void gGraph::mouseMoveEvent(QMouseEvent * event) +{ + // qDebug() << m_title << "Move" << event->pos() << m_graphview->pointClicked(); + int y=event->pos().y(); + int x=event->pos().x(); + int x2,y2; + int w=m_width-(m_graphview->titleWidth+right+m_marginright); + int h=m_height-(bottom+m_marginbottom); + double xx=max_x-min_x; + double xmult=xx/w; + if (x>left+m_marginleft && xtitleWidth+right+m_marginright) && y>top+m_margintop && ypos().y(); + int x=event->pos().x(); + int w=m_width-(m_graphview->titleWidth+right+m_marginright); + int h=m_height-(bottom+m_marginbottom); + int x2,y2; + double xx=max_x-min_x; + double xmult=xx/w; + if (x>left+m_marginleft && xtitleWidth+right+m_marginright) && y>top+m_margintop && ypos().y(); + int x=event->pos().x(); + int w=m_width-(m_graphview->titleWidth+m_marginleft+left+right+m_marginright); + int h=m_height-(bottom+m_marginbottom); + int x2,y2; + double xx=max_x-min_x; + double xmult=xx/double(w); + if (x>left+m_marginleft && xtop+m_margintop && ybutton() & Qt::RightButton) { + // zoom out. + } else if (event->button() & Qt::LeftButton) { + x-=left+m_marginleft; + y-=top+m_margintop; + x2=m_graphview->pointClicked().x()-left-m_marginleft; + y2=m_graphview->pointClicked().y()-top-m_margintop; + qint64 j1=min_x+xmult*x; + qint64 j2=min_x+xmult*x2; + qint64 a1=MIN(j1,j2) + qint64 a2=MAX(j1,j2) + m_graphview->SetXBounds(a1,a2); + qDebug() << m_title << "Released" << min_x << max_x << j1 << j2 << x << y << x2 << y2 << left << right << top << bottom << m_width << m_height; + } + // qDebug() << m_title << "Released" << event->pos() << m_graphview->pointClicked() << left << top; + } +} +void gGraph::mouseWheelEvent(QMouseEvent * event) +{ + qDebug() << m_title << "Wheel" << event->x() << event->y(); +} +void gGraph::mouseDoubleClickEvent(QMouseEvent * event) +{ + // qDebug() << m_title << "Double Clicked" << event->x() << event->y(); +} +void gGraph::keyPressEvent(QKeyEvent * event) +{ + qDebug() << m_title << "Key Pressed" << event->key(); +} + +// margin recalcs.. +void gGraph::resize(int width, int height) +{ + m_height=height; + m_width=width; +} + +qint64 gGraph::MinX() +{ + bool first=true; + qint64 val=0,tmp; + for (QVector::iterator l=m_layers.begin();l!=m_layers.end();l++) { + if ((*l)->isEmpty()) continue; + tmp=(*l)->Minx(); + if (!tmp) continue; + if (first) { + val=tmp; + first=false; + } else { + if (tmp < val) val = tmp; + } + } + if (val) rmin_x=val; + return val; +} +qint64 gGraph::MaxX() +{ + bool first=true; + qint64 val=0,tmp; + for (QVector::iterator l=m_layers.begin();l!=m_layers.end();l++) { + if ((*l)->isEmpty()) continue; + tmp=(*l)->Maxx(); + if (!tmp) continue; + if (first) { + val=tmp; + first=false; + } else { + if (tmp > val) val = tmp; + } + } + if (val) rmax_x=val; + return val; +} +EventDataType gGraph::MinY() +{ + bool first=true; + EventDataType val=0,tmp; + for (QVector::iterator l=m_layers.begin();l!=m_layers.end();l++) { + if ((*l)->isEmpty()) continue; + tmp=(*l)->Miny(); + if (tmp==0 && tmp==(*l)->Maxy()) continue; + if (first) { + val=tmp; + first=false; + } else { + if (tmp < val) val = tmp; + } + } + return rmin_y=val; +} +EventDataType gGraph::MaxY() +{ + bool first=true; + EventDataType val=0,tmp; + for (QVector::iterator l=m_layers.begin();l!=m_layers.end();l++) { + if ((*l)->isEmpty()) continue; + tmp=(*l)->Maxy(); + if (tmp==0 && tmp==(*l)->Miny()) continue; + if (first) { + val=tmp; + first=false; + } else { + if (tmp > val) val = tmp; + } + } + return rmax_y=val; +} + +void gGraph::SetMinX(qint64 v) +{ + min_x=v; +} +void gGraph::SetMaxX(qint64 v) +{ + max_x=v; +} +void gGraph::SetMinY(EventDataType v) +{ + min_y=v; +} +void gGraph::SetMaxY(EventDataType v) +{ + max_y=v; +} + +// Sets a new Min & Max X clipping, refreshing the graph and all it's layers. +void gGraph::SetXBounds(qint64 minx, qint64 maxx) +{ + min_x=minx; + max_x=maxx; + + //repaint(); + //m_graphview->updateGL(); +} +int gGraph::flipY(int y) +{ + return m_graphview->height()-y; +} + +void gGraph::ResetBounds() +{ + min_x=MinX(); + max_x=MaxX(); + min_y=MinY(); + max_y=MaxY(); +} + + +gGraphView::gGraphView(QWidget *parent) : + QGLWidget(parent), + m_offsetY(0),m_offsetX(0),m_scaleY(1.0),m_scrollbar(NULL) +{ + m_sizer_index=m_graph_index=0; + m_button_down=m_graph_dragging=m_sizer_dragging=false; + this->setMouseTracking(true); + InitGraphs(); +} +gGraphView::~gGraphView() +{ + for (int i=0;idisconnect(SIGNAL(sliderMoved(int)),this); + } +} + +void gGraphView::AddGraph(gGraph *g) +{ + if (!m_graphs.contains(g)) { + m_graphs.push_back(g); + + updateScrollBar(); + } +} +float gGraphView::totalHeight() +{ + float th=0; + for (int i=0;iisEmpty()) continue; + th += m_graphs[i]->height() + graphSpacer; + } + return ceil(th); +} +float gGraphView::findTop(gGraph * graph) +{ + float th=-m_offsetY; + for (int i=0;iisEmpty()) continue; + th += m_graphs[i]->height()*m_scaleY + graphSpacer; + } + //th-=m_offsetY; + return ceil(th); +} +float gGraphView::scaleHeight() +{ + float th=0; + for (int i=0;iisEmpty()) continue; + th += m_graphs[i]->height() * m_scaleY + graphSpacer; + } + return ceil(th); +} +void gGraphView::resizeEvent(QResizeEvent *e) +{ + QGLWidget::resizeEvent(e); // This ques a redraw event.. + + updateScale(); + for (int i=0;iresize(e->size().width(),m_graphs[i]->height()*m_scaleY); + } +} +void gGraphView::scrollbarValueChanged(int val) +{ + //qDebug() << "Scrollbar Changed" << val; + m_offsetY=val; + updateGL(); // do this on a timer? +} +void gGraphView::ResetBounds() +{ + for (int i=0;iResetBounds(); + } + updateScale(); +} + +void gGraphView::SetXBounds(qint64 minx, qint64 maxx) +{ + for (int i=0;iSetXBounds(minx,maxx); + } + updateGL(); +} +void gGraphView::updateScale() +{ + float th=totalHeight(); // height of all graphs + float h=height(); // height of main widget + + if (th < h) { + m_scaleY=h / th; // less graphs than fits on screen, so scale to fit + } else { + m_scaleY=1.0; + } + updateScrollBar(); +} + +void gGraphView::updateScrollBar() +{ + if (!m_scrollbar) return; + + if (!m_graphs.size()) return; + + float th=scaleHeight(); // height of all graphs + float h=height(); // height of main widget + + float vis=0; + for (int i=0;iisEmpty() ? 0 : 1; + + if (thsetMaximum(0); // turn scrollbar off. + + } else { // more graphs than fit on screen + //m_scaleY=1.0; + float avgheight=th/vis; + m_scrollbar->setPageStep(avgheight); + m_scrollbar->setSingleStep(avgheight/8.0); + m_scrollbar->setMaximum(th-height()); + if (m_offsetY>th-height()) { + m_offsetY=th-height(); + } + } +} + +void gGraphView::setScrollBar(MyScrollBar *sb) +{ + m_scrollbar=sb; + m_scrollbar->setMinimum(0); + updateScrollBar(); + this->connect(m_scrollbar,SIGNAL(valueChanged(int)),SLOT(scrollbarValueChanged(int))); +} +void gGraphView::initializeGL() +{ + setAutoFillBackground(false); + setAutoBufferSwap(false); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glDisable(GL_TEXTURE_2D); +} + +void gGraphView::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glOrtho(0, w, h, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void gGraphView::paintGL() +{ + if (width()<=0) return; + if (height()<=0) return; + + + QPainter qp(this); + qp.beginNativePainting(); + painter=&qp; + + glClearColor(255,255,255,255); + //glClearDepth(1); + glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT); + + //glEnable(GL_BLEND); + + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBegin(GL_QUADS); + glColor4f(1.0,1.0,1.0,1.0); // Gradient start + glVertex2f(0, height()); + glVertex2f(0, 0); + + glColor4f(0.8,0.8,1.0,1.0); // Gradient End + glVertex2f(width(), 0); + glVertex2f(width(), height()); + + glEnd(); + + float px=titleWidth-m_offsetX; + float py=-m_offsetY; + int numgraphs=m_graphs.size(); + float h,w; + //ax=px;//-m_offsetX; + if (!numgraphs) { + QString ts="No Data"; + + } else + for (int i=0;iisEmpty()) continue; + + h=m_graphs[i]->height() * m_scaleY; + + // set clipping? + + if (py > height()) + break; // we are done.. can't draw anymore + + if ((py + h + graphSpacer) >= 0) { + w=width(); + m_graphs[i]->paint(px,py,width()-titleWidth,h); + glColor4f(0,0,0,1); + //if (ix(); + int y=event->y(); + + if (m_sizer_dragging) { // Resize handle being dragged + float my=y - m_sizer_point.y(); + //qDebug() << "Sizer moved vertically" << m_sizer_index << my*m_scaleY; + float h=m_graphs[m_sizer_index]->height(); + h+=my / m_scaleY; + if (h > m_graphs[m_sizer_index]->minHeight()) { + m_graphs[m_sizer_index]->setHeight(h); + m_sizer_point.setX(x); + m_sizer_point.setY(y); + updateScrollBar(); + updateGL(); + } + return; + } + + if (m_graph_dragging) { // Title bar being dragged to reorder + gGraph *p; + int yy=m_sizer_point.y(); + bool empty; + if (y < yy) { + + for (int i=m_graph_index-1;i>=0;i--) { + empty=m_graphs[i]->isEmpty(); + // swapping upwards. + int yy2=yy-graphSpacer-m_graphs[i]->height()*m_scaleY; + yy2+=m_graphs[m_graph_index]->height()*m_scaleY; + if (yheight()*m_scaleY); + updateGL(); + } + m_graph_index--; + } + if (!empty) break; + + } + } else if (y > yy+graphSpacer+m_graphs[m_graph_index]->height()*m_scaleY) { + // swapping downwards + qDebug() << "Graph Reorder" << m_graph_index; + for (int i=m_graph_index+1;iisEmpty(); + p=m_graphs[m_graph_index]; + m_graphs[m_graph_index]=m_graphs[i]; + m_graphs[i]=p; + if (!empty) { + m_sizer_point.setY(yy+graphSpacer+m_graphs[m_graph_index]->height()*m_scaleY); + updateGL(); + } + m_graph_index++; + if (!empty) break; + } + } + return; + } + + float py = -m_offsetY; + float h; + + for (int i=0; i < m_graphs.size(); i++) { + + if (m_graphs[i]->isEmpty()) continue; + + h=m_graphs[i]->height() * m_scaleY; + if (py > height()) + break; // we are done.. can't draw anymore + + if ((py + h + graphSpacer) >= 0) { + if ((y >= py) && (y < py + h)) { + if (x >= titleWidth) { + this->setCursor(Qt::ArrowCursor); + QPoint p(x-titleWidth,y-py); + QMouseEvent e(event->type(),p,event->button(),event->buttons(),event->modifiers()); + m_graphs[i]->mouseMoveEvent(&e); + } else { + this->setCursor(Qt::OpenHandCursor); + } + } else if ((y >= py + h) && (y <= py + h + graphSpacer + 1)) { + this->setCursor(Qt::SplitVCursor); + } + + } + py+=h; + py+=graphSpacer; // do we want the extra spacer down the bottom? + } + +} + +void gGraphView::mousePressEvent(QMouseEvent * event) +{ + int x=event->x(); + int y=event->y(); + + float py=-m_offsetY; + float h; + + for (int i=0;iisEmpty()) continue; + + h=m_graphs[i]->height()*m_scaleY; + if (py>height()) + break; // we are done.. can't draw anymore + + if ((py + h + graphSpacer) >= 0) { + if ((y >= py) && (y < py + h)) { + //qDebug() << "Clicked" << i; + if (x < titleWidth) { // clicked on title to drag graph.. + m_graph_dragging=true; + m_graph_index=i; + m_sizer_point.setX(x); + m_sizer_point.setY(py); // point at top of graph.. + this->setCursor(Qt::ClosedHandCursor); + } else { // send event to graph.. + m_global_point_clicked=QPoint(x,y); + m_point_clicked=QPoint (x-titleWidth,y-py); + + QMouseEvent e(event->type(),m_point_clicked,event->button(),event->buttons(),event->modifiers()); + m_graphs[i]->mousePressEvent(&e); + m_graph_index=i; + m_button_down=true; + //m_graphs[i]->mousePressEvent(event); + } + } else if ((y >= py + h) && (y <= py + h + graphSpacer + 1)) { + this->setCursor(Qt::SplitVCursor); + m_sizer_dragging=true; + m_sizer_index=i; + m_sizer_point.setX(x); + m_sizer_point.setY(y); + //qDebug() << "Sizer clicked" << i; + } + + } + py+=h; + py+=graphSpacer; // do we want the extra spacer down the bottom? + + } +} + +void gGraphView::mouseReleaseEvent(QMouseEvent * event) +{ + this->setCursor(Qt::ArrowCursor); + + if (m_sizer_dragging) { + m_sizer_dragging=false; + return; + } + if (m_graph_dragging) { + m_graph_dragging=false; + return; + } + if (m_button_down) { + m_button_down=false; + int x1=m_global_point_clicked.x()-event->x(); + int y1=m_global_point_clicked.y()-event->y(); + + QPoint p(m_point_clicked.x()-x1,m_point_clicked.y()-y1); + QMouseEvent e(event->type(),p,event->button(),event->buttons(),event->modifiers()); + m_graphs[m_graph_index]->mouseReleaseEvent(&e); + } + int x=event->x(); + int y=event->y(); +} + +void gGraphView::mouseDoubleClickEvent(QMouseEvent * event) +{ + // A single click gets sent first.. Need to set a timer to check for this event.. + + int x=event->x(); + int y=event->y(); + + float py=-m_offsetY; + float h; + + for (int i=0;iisEmpty()) continue; + + h=m_graphs[i]->height()*m_scaleY; + if (py>height()) + break; // we are done.. can't draw anymore + + if ((py + h + graphSpacer) >= 0) { + if ((y >= py) && (y <= py + h)) { + if (x < titleWidth) { + // What to do when double clicked on the graph title ?? + } else { + // send event to graph.. + m_graphs[i]->mouseDoubleClickEvent(event); + } + } else if ((y >= py + h) && (y <= py + h + graphSpacer + 1)) { + // What to do when double clicked on the resize handle? + } + + } + py+=h; + py+=graphSpacer; // do we want the extra spacer down the bottom? + } +} +void gGraphView::wheelEvent(QWheelEvent * event) +{ + // Hmm.. I could optionalize this to change mousewheel behaviour without affecting the scrollbar now.. + + m_scrollbar->SendWheelEvent(event); // Just forwarding the event to scrollbar for now.. +} + +void gGraphView::keyPressEvent(QKeyEvent * event) +{ + +} + +MyScrollBar::MyScrollBar(QWidget * parent) + :QScrollBar(parent) +{ +} +void MyScrollBar::SendWheelEvent(QWheelEvent * e) +{ + wheelEvent(e); +} diff --git a/Graphs/gGraphView.h b/Graphs/gGraphView.h new file mode 100644 index 00000000..f75cf66c --- /dev/null +++ b/Graphs/gGraphView.h @@ -0,0 +1,255 @@ +#ifndef GGRAPHVIEW_H +#define GGRAPHVIEW_H + +#include +#include +#include +#include +#include + + +#define MIN(a,b) (((a)<(b)) ? (a) : (b)); +#define MAX(a,b) (((a)<(b)) ? (b) : (a)); + +class gGraphView; +class gGraph; + +class MyScrollBar:public QScrollBar +{ +public: + MyScrollBar(QWidget * parent=0); + void SendWheelEvent(QWheelEvent * e); +}; + +enum LayerPosition { LayerLeft, LayerRight, LayerTop, LayerBottom, LayerCenter, LayerOverlay }; + +class Layer +{ + friend class gGraph; +public: + Layer(ChannelID code); + virtual ~Layer(); + + virtual void SetDay(Day * d); + virtual void SetCode(ChannelID c) { m_code=c; } + const ChannelID & code() { return m_code; } + virtual bool isEmpty(); + + virtual qint64 Minx() { if (m_day) return m_day->first(); return m_minx; } + virtual qint64 Maxx() { if (m_day) return m_day->last(); return m_maxx; } + virtual EventDataType Miny() { return m_miny; } + virtual EventDataType Maxy() { return m_maxy; } + virtual void setMinY(EventDataType val) { m_miny=val; } + virtual void setMaxY(EventDataType val) { m_maxy=val; } + virtual void setMinX(qint64 val) { m_minx=val; } + virtual void setMaxX(qint64 val) { m_maxx=val; } + + void setVisible(bool b) { m_visible=b; } + bool visible() { return m_visible; } + + void setMovable(bool b) { m_movable=b; } + bool movable() { return m_movable; } + + virtual void paint(gGraph & gv,int left,int top,int width, int height)=0; + + void setLayout(LayerPosition position, short width, short height, short order); + void setPos(short x, short y) { m_X=x; m_Y=y; } + + int Width() { return m_width; } + int Height() { return m_height; } + + LayerPosition position() { return m_position; } + //void X() { return m_X; } + //void Y() { return m_Y; } + + +protected: + //QRect bounds; // bounds, relative to top of individual graph. + Day *m_day; + bool m_visible; + bool m_movable; + qint64 m_minx,m_maxx; + EventDataType m_miny,m_maxy; + ChannelID m_code; + short m_width; // reserved x pixels needed for this layer. 0==Depends on position.. + short m_height; // reserved y pixels needed for this layer. both 0 == expand to all free area. + short m_X; // offset for repositionable layers.. + short m_Y; + short m_order; // order for positioning.. + LayerPosition m_position; +}; + +class LayerGroup:public Layer +{ +public: + LayerGroup(); + virtual ~LayerGroup(); + virtual void AddLayer(Layer *l); + + virtual qint64 Minx(); + virtual qint64 Maxx(); + virtual EventDataType Miny(); + virtual EventDataType Maxy(); + virtual bool isEmpty(); + virtual void SetDay(Day * d); + +protected: + QVector layers; +}; + +class gGraph +{ + friend class gGraphView; +public: + gGraph(gGraphView * graphview=NULL, QString title="",int height=100); + virtual ~gGraph(); + + void setVisible(bool b) { m_visible=b; } + bool visible() { return m_visible; } + + float height() { return m_height; } + void setHeight(float height) { m_height=height; } + + int minHeight() { return m_min_height; } + void setMinHeight(int height) { m_min_height=height; } + + int maxHeight() { return m_max_height; } + void setMaxHeight(int height) { m_max_height=height; } + + bool isEmpty(); + + void AddLayer(Layer * l,LayerPosition position=LayerCenter, short pixelsX=0, short pixelsY=0, short order=0, bool movable=false, short x=0, short y=0); + + void qglColor(QColor col); + void renderText(QString text, int x,int y, float angle=0.0, QColor color=Qt::black, QFont *font=defaultfont); + + QString title() { return m_title; } + + virtual void repaint(); // Repaint individual graph.. + + virtual void ResetBounds(); + virtual void SetXBounds(qint64 minx, qint64 maxx); + + virtual qint64 MinX(); + virtual qint64 MaxX(); + virtual EventDataType MinY(); + virtual EventDataType MaxY(); + + virtual void SetMinX(qint64 v); + virtual void SetMaxX(qint64 v); + virtual void SetMinY(EventDataType v); + virtual void SetMaxY(EventDataType v); + + void resize(int width, int height); // margin recalcs.. + + qint64 max_x,min_x,max_y,min_y; + qint64 rmax_x,rmin_x,rmax_y,rmin_y; + + bool blockZoom() { return m_blockzoom; } + void setBlockZoom(bool b) { m_blockzoom=b; } + int flipY(int y); // flip GL coordinates + +protected: + virtual void paint(int originX, int originY, int width, int height); + void invalidate(); + + virtual void mouseWheelEvent(QMouseEvent * event); + virtual void mouseMoveEvent(QMouseEvent * event); + virtual void mousePressEvent(QMouseEvent * event); + virtual void mouseReleaseEvent(QMouseEvent * event); + virtual void mouseDoubleClickEvent(QMouseEvent * event); + virtual void keyPressEvent(QKeyEvent * event); + + gGraphView * m_graphview; + QString m_title; + QVector m_layers; + float m_height,m_width; + + int m_marginleft, m_marginright, m_margintop, m_marginbottom; + + int left,right,top,bottom; // dirty magin hacks.. + + int m_min_height; + int m_max_height; + bool m_visible; + bool m_blockzoom; + QRect m_lastbounds; + +}; + +class gGraphView : public QGLWidget +{ + Q_OBJECT +public: + explicit gGraphView(QWidget *parent = 0); + virtual ~gGraphView(); + void AddGraph(gGraph *g); + + void setScrollBar(MyScrollBar *sb); + MyScrollBar * scrollBar() { return m_scrollbar; } + static const int titleWidth=30; + static const int graphSpacer=4; + + float findTop(gGraph * graph); + + float scaleY() { return m_scaleY; } + + void ResetBounds(); + void SetXBounds(qint64 minx, qint64 maxx); + + bool hasGraphs() { return m_graphs.size()>0; } + + QPoint pointClicked() { return m_point_clicked; } + QPoint globalPointClicked() { return m_global_point_clicked; } + + QPainter *painter; +protected: + + float totalHeight(); + float scaleHeight(); + + virtual void initializeGL(); + virtual void paintGL(); + virtual void resizeGL(int width, int height); + virtual void resizeEvent(QResizeEvent *); + + + void setOffsetY(int offsetY); + void setOffsetX(int offsetX); + + virtual void mouseMoveEvent(QMouseEvent * event); + virtual void mousePressEvent(QMouseEvent * event); + virtual void mouseReleaseEvent(QMouseEvent * event); + virtual void mouseDoubleClickEvent(QMouseEvent * event); + virtual void wheelEvent(QWheelEvent * event); + virtual void keyPressEvent(QKeyEvent * event); + + void updateScrollBar(); + void updateScale(); // update scale & Scrollbar + + QVector m_graphs; + int m_offsetY,m_offsetX; // Scroll Offsets + float m_scaleY; + + bool m_sizer_dragging; + int m_sizer_index; + + bool m_button_down; + QPoint m_point_clicked; + QPoint m_global_point_clicked; + QPoint m_sizer_point; + + MyScrollBar * m_scrollbar; + + bool m_graph_dragging; + int m_graph_index; + +signals: + + +public slots: + void scrollbarValueChanged(int val); + +}; + +#endif // GGRAPHVIEW_H diff --git a/Graphs/gLineChart.cpp b/Graphs/gLineChart.cpp index 11678ac1..1c32e0e0 100644 --- a/Graphs/gLineChart.cpp +++ b/Graphs/gLineChart.cpp @@ -12,7 +12,7 @@ #define EXTRA_ASSERTS 1 gLineChart::gLineChart(ChannelID code,QColor col,bool square_plot, bool disable_accel) -:gLayer(code),m_square_plot(square_plot),m_disable_accel(disable_accel) +:Layer(code),m_square_plot(square_plot),m_disable_accel(disable_accel) { m_line_color=col; m_report_empty=false; @@ -23,21 +23,20 @@ gLineChart::~gLineChart() // Time Domain Line Chart -void gLineChart::Plot(gGraphWindow & w,float scrx,float scry) +void gLineChart::paint(gGraph & w,int left, int top, int width, int height) { const int max_drawlist_size=4096; QPoint m_drawlist[max_drawlist_size]; if (!m_visible) return; + if (!m_day) return; - int start_px=w.GetLeftMargin(); - int start_py=w.GetBottomMargin(); - int width=scrx-(w.GetLeftMargin()+w.GetRightMargin()); - int height=scry-(w.GetTopMargin()+w.GetBottomMargin())-2; - if (width<40) + + if (width<0) return; + EventDataType miny,maxy; double minx,maxx; miny=w.min_y, maxy=w.max_y, maxx=w.max_x, minx=w.min_x; @@ -80,10 +79,10 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry) } double xx=maxx-minx; - double xmult=double(width-1)/xx; + double xmult=double(width)/xx; EventDataType yy=maxy-miny; - EventDataType ymult=EventDataType(height)/yy; // time to pixel conversion multiplier + EventDataType ymult=EventDataType(height-2)/yy; // time to pixel conversion multiplier // Return on screwy min/max conditions if (xx<0) @@ -107,13 +106,14 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry) w.qglColor(Qt::black); glLineWidth (1); glBegin (GL_LINE_LOOP); - glVertex2f (start_px, start_py); - glVertex2f (start_px, start_py+height+2); - glVertex2f (start_px+width,start_py+height+2); - glVertex2f (start_px+width, start_py); + glVertex2i (left, top); + glVertex2i (left, top+height); + glVertex2i (left+width,top+height); + glVertex2i (left+width, top); glEnd (); } width--; + height-=2; qint32 vertcnt=0; GLshort * vertarray=vertex_array[0]; @@ -245,8 +245,8 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry) } // else just start from the beginning } - int xst=start_px+1; - int yst=start_py+1; + int xst=left+1; + int yst=top+height-1; double time; EventDataType data; @@ -307,19 +307,19 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry) } // Plot compressed accelerated vertex list if (maxz>width) { - qDebug() << "gLineChart::Plot() maxz exceeded graph width" << "maxz = " << maxz << "width =" << width << "scrx =" < #include "SleepLib/event.h" #include "SleepLib/day.h" -#include "graphwindow.h" -#include "graphlayer.h" +#include "gGraphView.h" +//#include "graphlayer.h" -class gLineChart:public gLayer +class gLineChart:public Layer { public: gLineChart(ChannelID code,const QColor col=QColor("black"), bool square_plot=false,bool disable_accel=false); virtual ~gLineChart(); - virtual void Plot(gGraphWindow & w,float scrx,float scry); + virtual void paint(gGraph & w,int left, int top, int width, int height); void SetSquarePlot(bool b) { m_square_plot=b; } bool GetSquarePlot() { return m_square_plot; } diff --git a/Graphs/gLineOverlay.cpp b/Graphs/gLineOverlay.cpp index eb8da10f..9d5fc176 100644 --- a/Graphs/gLineOverlay.cpp +++ b/Graphs/gLineOverlay.cpp @@ -1,15 +1,15 @@ -/******************************************************************** +/* gLineOverlayBar Implementation Copyright (c)2011 Mark Watkins License: GPL -*********************************************************************/ +*/ #include #include "SleepLib/profiles.h" #include "gLineOverlay.h" gLineOverlayBar::gLineOverlayBar(ChannelID code,QColor col,QString label,FlagType flt) -:gLayer(code),m_label(label),m_flt(flt) +:Layer(code),m_label(label),m_flt(flt) { m_flag_color=col; } @@ -17,17 +17,18 @@ gLineOverlayBar::~gLineOverlayBar() { } -void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry) +void gLineOverlayBar::paint(gGraph & w, int left, int topp, int width, int height) { if (!m_visible) return; if (!m_day) return; //int start_px=w.GetLeftMargin(); - int start_py=w.GetBottomMargin(); - int width=scrx-(w.GetLeftMargin()+w.GetRightMargin()); - int height=scry-(w.GetTopMargin()+w.GetBottomMargin()); + int start_py=topp; + //int width=scrx-(w.GetLeftMargin()+w.GetRightMargin()); + //int height=scry-(w.GetTopMargin()+w.GetBottomMargin()); double xx=w.max_x-w.min_x; + double yy=w.max_y-w.min_y; if (xx<=0) return; float x1,x2; @@ -35,8 +36,8 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry) float x,y; // Crop to inside the margins. - glScissor(w.GetLeftMargin(),w.GetBottomMargin(),width,height); - glEnable(GL_SCISSOR_TEST); + // glScissor(left,topp,width,height); + // glEnable(GL_SCISSOR_TEST); qint32 vertcnt=0; GLshort * vertarray=vertex_array[0]; @@ -49,7 +50,7 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry) return; } - float bottom=start_py+25, top=start_py+height-25; + float bottom=start_py+height-25, top=start_py+25; double X; double Y; @@ -75,9 +76,11 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry) if (X > w.max_x) break; } - x1=w.x2p(X); + //x1=w.x2p(X); + x1=double(width)/double(xx)*double(X-w.min_x)+left; if (m_flt==FT_Span) { - x2=w.x2p(Y); + //x2=w.x2p(Y); + x2=double(width)/double(xx)*double(X-w.min_x)+left; //double w1=x2-x1; quadarray[quadcnt++]=x1; quadarray[quadcnt++]=start_py; @@ -94,7 +97,7 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry) if (pref["AlwaysShowOverlayBars"].toBool() || (xx<3600000.0)) { // show the fat dots in the middle pointarray[pointcnt++]=x1; - pointarray[pointcnt++]=w.y2p(20); + pointarray[pointcnt++]=double(height)/double(yy)*double(-20-w.min_y)+topp; if (pointcnt>=maxverts) { verts_exceeded=true; break; } } else { // thin lines down the bottom @@ -126,7 +129,8 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry) if (vertcnt>=maxverts) { verts_exceeded=true; break; } if (xx<(1800000)) { GetTextExtent(m_label,x,y); - DrawText(w,m_label,x1-(x/2),scry-(start_py+height-30+y)); + //DrawText(w,m_label,x1-(x/2),scry-(start_py+height-30+y)); + w.renderText(m_label,x1-(x/2),top-y+3); //w.renderText(x1-(x/2),scry-(start_py+height-30+y),label); } @@ -168,6 +172,6 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry) glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } - glDisable(GL_SCISSOR_TEST); + //glDisable(GL_SCISSOR_TEST); } diff --git a/Graphs/gLineOverlay.h b/Graphs/gLineOverlay.h index afdd6e11..2e23dfe5 100644 --- a/Graphs/gLineOverlay.h +++ b/Graphs/gLineOverlay.h @@ -7,15 +7,15 @@ #ifndef GLINEOVERLAY_H #define GLINEOVERLAY_H -#include "graphlayer.h" +#include "gGraphView.h" -class gLineOverlayBar:public gLayer +class gLineOverlayBar:public Layer { public: gLineOverlayBar(ChannelID code,QColor col,QString _label="",FlagType _flt=FT_Bar); virtual ~gLineOverlayBar(); - virtual void Plot(gGraphWindow & w,float scrx,float scry); + virtual void paint(gGraph & w,int left, int top, int width, int height); virtual EventDataType Miny() { return 0; } virtual EventDataType Maxy() { return 0; } virtual bool isEmpty() { return true; } diff --git a/Graphs/gXAxis.cpp b/Graphs/gXAxis.cpp index 0d24451c..922da161 100644 --- a/Graphs/gXAxis.cpp +++ b/Graphs/gXAxis.cpp @@ -12,7 +12,7 @@ const int divisors[]={86400000,2880000,14400000,7200000,3600000,2700000,1800000, const int divcnt=sizeof(divisors)/sizeof(int); gXAxis::gXAxis(QColor col) -:gLayer(EmptyChannel) +:Layer(EmptyChannel) { m_line_color=col; m_text_color=col; @@ -27,26 +27,24 @@ gXAxis::gXAxis(QColor col) QTime t2=d.toUTC().time(); tz_offset=t2.secsTo(t1)/60L; tz_offset*=60000L; - //offset=0; - } gXAxis::~gXAxis() { } -void gXAxis::Plot(gGraphWindow & w,float scrx,float scry) +void gXAxis::paint(gGraph & w,int left,int top, int width, int height) { double px,py; - int start_px=w.GetLeftMargin(); - int start_py=w.GetBottomMargin(); - int width=scrx-(w.GetLeftMargin()+w.GetRightMargin()); + int start_px=left; + int start_py=top; + //int width=scrx-(w.GetLeftMargin()+w.GetRightMargin()); // float height=scry-(w.GetTopMargin()+w.GetBottomMargin()); if (width<40) return; qint64 minx; qint64 maxx; - if (w.BlockZoom()) { + if (w.blockZoom()) { minx=w.rmin_x; maxx=w.rmax_x; } else { @@ -132,23 +130,23 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry) double xmult=double(width)/double(xx); double step_pixels=double(step/10.0)*xmult; - py=start_px+double(aligned_start-minx)*xmult; + py=left+double(aligned_start-minx)*xmult; for (int i=0;i<10;i++) { py-=step_pixels; if (py=scrx-w.GetRightMargin()) break; + if (py>=left+width) break; vertarray[vertcnt++]=py; - vertarray[vertcnt++]=start_py; + vertarray[vertcnt++]=top; vertarray[vertcnt++]=py; - vertarray[vertcnt++]=start_py-4; + vertarray[vertcnt++]=top+4; if (vertcnt>=maxverts) { break; } diff --git a/Graphs/gXAxis.h b/Graphs/gXAxis.h index e57c4c73..f1a702c6 100644 --- a/Graphs/gXAxis.h +++ b/Graphs/gXAxis.h @@ -1,19 +1,19 @@ -/******************************************************************** +/* gXAxis Header Copyright (c)2011 Mark Watkins License: GPL -*********************************************************************/ +*/ #ifndef GXAXIS_H #define GXAXIS_H -#include "graphlayer.h" +#include "gGraphView.h" -class gXAxis:public gLayer +class gXAxis:public Layer { public: gXAxis(QColor col=QColor("black")); virtual ~gXAxis(); - virtual void Plot(gGraphWindow & w,float scrx,float scry); + virtual void paint(gGraph & w,int left,int top, int width, int height); static const int Margin=25; // How much room does this take up. (Bottom margin) void SetShowMinorLines(bool b) { m_show_minor_lines=b; } void SetShowMajorLines(bool b) { m_show_major_lines=b; } diff --git a/Graphs/gYAxis.cpp b/Graphs/gYAxis.cpp index bc01d96b..7f37b025 100644 --- a/Graphs/gYAxis.cpp +++ b/Graphs/gYAxis.cpp @@ -8,8 +8,13 @@ #include #include "gYAxis.h" +gYSpacer::gYSpacer(int spacer) + :Layer(EmptyChannel) +{ +}; + gYAxis::gYAxis(QColor col) -:gLayer(EmptyChannel) +:Layer(EmptyChannel) { m_line_color=col; m_text_color=col; @@ -23,7 +28,7 @@ gYAxis::gYAxis(QColor col) gYAxis::~gYAxis() { } -void gYAxis::Plot(gGraphWindow &w,float scrx,float scry) +void gYAxis::paint(gGraph & w,int left,int top, int width, int height) { float x,y; int labelW=0; @@ -79,11 +84,6 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry) //if ((w.max_x-w.min_x)==0) // return; - int start_px=w.GetLeftMargin(); - int start_py=w.GetBottomMargin(); - int width=scrx-(w.GetRightMargin()+start_px); - int topm=w.GetTopMargin(); - int height=scry-(topm+start_py); if (height<0) return; QString fd="0"; @@ -92,8 +92,6 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry) double max_yticks=round(height / (y+15.0)); // plus spacing between lines double yt=1/max_yticks; - - double mxy=MAX(fabs(maxy),fabs(miny)); double mny=miny; if (miny<0) { @@ -138,81 +136,57 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry) qDebug() << "Would exeed maxverts. Should be another two bounds exceeded messages after this. (I can do a minor optimisation by disabling the other checks if this turns out to be consistent)" << q << maxverts; } - - /*for (double i=miny+(min_ytick/2.0); i miny)) { - double z=(min_ytick/5)*ymult; - double g=h; - for (int i=0;i<4;i++) { - g+=z; - minorvertarray[minorvertcnt++]=start_px+1; - minorvertarray[minorvertcnt++]=g; - minorvertarray[minorvertcnt++]=start_px+width; - minorvertarray[minorvertcnt++]=g; - } - } - if (vertcnt>=maxverts) { // Should only need to check one.. The above check should be enough. - qWarning() << "vertarray bounds exceeded in gYAxis for " << w.Title() << "graph" << "MinY =" < License: GPL -*********************************************************************/ +*/ #include #include diff --git a/Graphs/glcommon.h b/Graphs/glcommon.h index b85173f4..6a598b58 100644 --- a/Graphs/glcommon.h +++ b/Graphs/glcommon.h @@ -1,8 +1,8 @@ -/******************************************************************** +/* glcommon GL code & font stuff Header Copyright (c)2011 Mark Watkins License: GPL -*********************************************************************/ +*/ #ifndef GLCOMMON_H #define GLCOMMON_H diff --git a/Graphs/graphlayer.h b/Graphs/graphlayer.h index 03dd3af0..782e834e 100644 --- a/Graphs/graphlayer.h +++ b/Graphs/graphlayer.h @@ -1,8 +1,8 @@ -/******************************************************************** +/* gLayer Headers Copyright (c)2011 Mark Watkins License: GPL -*********************************************************************/ +*/ #ifndef GRAPHLAYER_H #define GRAPHLAYER_H @@ -36,6 +36,7 @@ public: virtual bool isVisible() { return m_visible; } virtual bool isEmpty(); inline const ChannelID & code() { return m_code; } + protected: Day *m_day; bool m_visible; diff --git a/SleepLib/machine.cpp b/SleepLib/machine.cpp index 99e7b2e2..98d4619c 100644 --- a/SleepLib/machine.cpp +++ b/SleepLib/machine.cpp @@ -114,11 +114,11 @@ void InitMapsWithoutAwesomeInitializerLists() CPAP_PressureSupport=CPAP_CODES.Get(CT_Graph,QObject::tr("Pressure Support"),QObject::tr("Pressure Support"),"PS"), CPAP_Snore=CPAP_CODES.Get(CT_Graph,QObject::tr("Snore"),QObject::tr("Snore"),"Snore"), CPAP_Leak=CPAP_CODES.Get(CT_Graph,QObject::tr("Leak Rate"),QObject::tr("Leak Rate"),"Leak"), - CPAP_RespiratoryRate=CPAP_CODES.Get(CT_Graph,QObject::tr("Respiratory Rate"),QObject::tr("Respiratory Rate"),"RR"), + CPAP_RespiratoryRate=CPAP_CODES.Get(CT_Graph,QObject::tr("Respiratory Rate"),QObject::tr("Resp. Rate"),"RR"), CPAP_TidalVolume=CPAP_CODES.Get(CT_Graph,QObject::tr("Tidal Volume"),QObject::tr("Tidal Volume"),"TV"), - CPAP_MinuteVentilation=CPAP_CODES.Get(CT_Graph,QObject::tr("Minute Ventilation"),QObject::tr("Minute Ventilation"),"MV"), + CPAP_MinuteVentilation=CPAP_CODES.Get(CT_Graph,QObject::tr("Minute Ventilation"),QObject::tr("Minute Vent."),"MV"), CPAP_PatientTriggeredBreaths=CPAP_CODES.Get(CT_Graph,QObject::tr("Patient Triggered Breaths"),QObject::tr("Patient Trig Breaths"),"PTB"), - CPAP_FlowLimitGraph=CPAP_CODES.Get(CT_Graph,QObject::tr("Flow Limitation Graph"),QObject::tr("Flow Limitation"),"FLG"), + CPAP_FlowLimitGraph=CPAP_CODES.Get(CT_Graph,QObject::tr("Flow Limitation Graph"),QObject::tr("Flow Limit."),"FLG"), CPAP_TherapyPressure=CPAP_CODES.Get(CT_Graph,QObject::tr("Therapy Pressure"),QObject::tr("Therapy Pressure"),"TP"), CPAP_ExpiratoryPressure=CPAP_CODES.Get(CT_Graph,QObject::tr("Expiratory Pressure"),QObject::tr("Expiratory Pressure"),"EXP"), CPAP_RespiratoryEvent=CPAP_CODES.Get(CT_Graph,QObject::tr("Respiratory Event"),QObject::tr("Respiratory Event"),"RESPEv"), diff --git a/SleepyHeadQT.pro b/SleepyHeadQT.pro index fb7bfc1e..cf5bb85b 100644 --- a/SleepyHeadQT.pro +++ b/SleepyHeadQT.pro @@ -57,7 +57,8 @@ SOURCES += main.cpp\ Graphs/gSessionTime.cpp \ qextserialport/qextserialport.cpp \ Graphs/gSplitter.cpp \ - preferencesdialog.cpp + preferencesdialog.cpp \ + Graphs/gGraphView.cpp unix:SOURCES += qextserialport/posix_qextserialport.cpp unix:!macx:SOURCES += qextserialport/qextserialenumerator_unix.cpp @@ -108,7 +109,8 @@ HEADERS += \ qextserialport/qextserialport.h \ qextserialport/qextserialenumerator.h \ Graphs/gSplitter.h \ - preferencesdialog.h + preferencesdialog.h \ + Graphs/gGraphView.h FORMS += \ diff --git a/daily.cpp b/daily.cpp index 64a84b5b..9c71fb0b 100644 --- a/daily.cpp +++ b/daily.cpp @@ -29,40 +29,6 @@ const int min_height=150; const int default_height=150; -MyScrollArea::MyScrollArea(QWidget *parent, Daily * daily) - :QScrollArea(parent),m_daily(daily) -{ - timer=new QTimer(this); - m_time.start(); -} -MyScrollArea::~MyScrollArea() -{ - delete timer; -} -void MyScrollArea::scrollContentsBy(int dx, int dy) -{ - QScrollArea::scrollContentsBy(dx,dy); - //m_daily->RedrawGraphs(); - //gGraphWindow g; -#ifdef Q_WS_MAC - if (timer->isActive()) timer->stop(); - timer->setSingleShot(true); - timer->setInterval(200); - connect(timer,SIGNAL(timeout()),SLOT(UpdateGraphs())); - timer->start(); - m_time.start(); - //m_daily->RedrawGraphs(); -#endif -} -void MyScrollArea::UpdateGraphs() -{ - if (m_time.elapsed()<200) - return; - m_time.start(); - qDebug() << "Redraw!"; - m_daily->RedrawGraphs(); -} - Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) :QWidget(parent),mainwin(mw), ui(new Ui::Daily) { @@ -75,8 +41,125 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) exit(-1); } + layout=new QHBoxLayout(ui->graphMainArea); + layout->setSpacing(0); + layout->setMargin(0); + layout->setContentsMargins(0,0,0,0); + ui->graphMainArea->setLayout(layout); + //ui->graphMainArea->setLayout(layout); - scrollArea=new MyScrollArea(ui->graphMainArea,this); + ui->graphMainArea->setAutoFillBackground(false); + + GraphView=new gGraphView(ui->graphMainArea); + GraphView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + + scrollbar=new MyScrollBar(ui->graphMainArea); + scrollbar->setOrientation(Qt::Vertical); + scrollbar->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Expanding); + scrollbar->setMaximumWidth(20); + + GraphView->setScrollBar(scrollbar); + layout->addWidget(GraphView,1); + layout->addWidget(scrollbar,0); + + + SF=new gGraph(GraphView,"Event Flags",180); + FRW=new gGraph(GraphView,"Flow Rate",180); + MP=new gGraph(GraphView,"Mask Pressure",180); + PRD=new gGraph(GraphView,"Pressure",180); + LEAK=new gGraph(GraphView,"Leak",180); + SNORE=new gGraph(GraphView,"Snore",180); + RR=new gGraph(GraphView,"Respiratory Rate",180); + TV=new gGraph(GraphView,"Tidal Volume",180); + MV=new gGraph(GraphView,"Minute Ventilation",180); + FLG=new gGraph(GraphView,"Flow Limitation Graph",180); + + gFlagsGroup *fg=new gFlagsGroup(); + fg->AddLayer((new gFlagsLine(CPAP_CSR,QColor("light green"),"CSR",false,FT_Span))); + fg->AddLayer((new gFlagsLine(CPAP_ClearAirway,QColor("purple"),"CA",true))); + fg->AddLayer((new gFlagsLine(CPAP_Obstructive,QColor("#40c0ff"),"OA",true))); + fg->AddLayer((new gFlagsLine(CPAP_Apnea,QColor("dark green"),"A"))); + fg->AddLayer((new gFlagsLine(CPAP_Hypopnea,QColor("blue"),"H",true))); + fg->AddLayer((new gFlagsLine(CPAP_FlowLimit,QColor("black"),"FL"))); + fg->AddLayer((new gFlagsLine(CPAP_RERA,QColor("gold"),"RE"))); + fg->AddLayer((new gFlagsLine(CPAP_VSnore,QColor("red"),"VS"))); + //fg->AddLayer(AddCPAP(new gFlagsLine(flags[8],QColor("dark green"),"U0E"))); + //fg->AddLayer(AddCPAP(new gFlagsLine(flags[10],QColor("red"),"VS2")); + SF->AddLayer(AddCPAP(fg)); + SF->AddLayer(new gYSpacer(),LayerLeft,gYAxis::Margin); + SF->AddLayer(new gXAxis(),LayerBottom,0,gXAxis::Margin); + + PRD->AddLayer(AddCPAP(new gLineChart(CPAP_Pressure,QColor("dark green"),true))); + PRD->AddLayer(AddCPAP(new gLineChart(CPAP_EPAP,Qt::blue,true))); + PRD->AddLayer(AddCPAP(new gLineChart(CPAP_IPAP,Qt::red,true))); + PRD->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + PRD->AddLayer(new gXAxis(),LayerBottom,0,20); + + gLineChart *l; + l=new gLineChart(CPAP_FlowRate,Qt::black,false,false); + AddCPAP(l); + FRW->AddLayer(l); + FRW->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + FRW->AddLayer(new gXAxis(),LayerBottom,0,20); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_CSR,QColor("light green"),"CSR",FT_Span))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Hypopnea,QColor("blue"),"H"))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_PressurePulse,QColor("red"),"PR",FT_Dot))); + //FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Pressure,QColor("white"),"P",FT_Dot))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(PRS1_Unknown0B,QColor("blue"),"0B",FT_Dot))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(PRS1_Unknown10,QColor("orange"),"10",FT_Dot))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(PRS1_Unknown0E,QColor("yellow"),"0E",FT_Dot))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_RERA,QColor("gold"),"RE"))); + //FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Unknown0E,QColor("dark green"),"U0E"))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Apnea,QColor("dark green"),"A"))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_VSnore,QColor("red"),"VS"))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_FlowLimit,QColor("black"),"FL"))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Obstructive,QColor("#40c0ff"),"OA"))); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_ClearAirway,QColor("purple"),"CA"))); + + LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_Leak,Qt::darkYellow,true))); + LEAK->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + LEAK->AddLayer(new gXAxis(),LayerBottom,0,20); + + SNORE->AddLayer(AddCPAP(new gLineChart(CPAP_Snore,Qt::darkGray,true))); + SNORE->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + SNORE->AddLayer(new gXAxis(),LayerBottom,0,20); + + MP->AddLayer(AddCPAP(new gLineChart(CPAP_MaskPressure,Qt::blue,false))); + MP->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + MP->AddLayer(new gXAxis(),LayerBottom,0,20); + + RR->AddLayer(AddCPAP(new gLineChart(CPAP_RespiratoryRate,Qt::darkMagenta,true))); + RR->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + RR->AddLayer(new gXAxis(),LayerBottom,0,20); + + MV->AddLayer(AddCPAP(new gLineChart(CPAP_MinuteVentilation,Qt::darkCyan,true))); + MV->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + MV->AddLayer(new gXAxis(),LayerBottom,0,20); + + TV->AddLayer(AddCPAP(new gLineChart(CPAP_TidalVolume,Qt::magenta,true))); + TV->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + TV->AddLayer(new gXAxis(),LayerBottom,0,20); + + FLG->AddLayer(AddCPAP(new gLineChart(CPAP_FlowLimitGraph,Qt::darkBlue,true))); + FLG->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); + FLG->AddLayer(new gXAxis(),LayerBottom,0,20); + + //AddGraph(SF); + //AddGraph(FRW); + //AddGraph(PRD); + + NoData=new QLabel(tr("No data"),ui->graphMainArea); + NoData->setAlignment(Qt::AlignCenter); + QFont font("FreeSans",20); //NoData->font(); + //font.setBold(true); + NoData->setFont(font); + layout->addWidget(NoData,1); + NoData->hide(); + + layout->layout(); + + +/* scrollArea=new MyScrollArea(ui->graphMainArea,this); ui->graphLayout->addWidget(scrollArea,1); ui->graphLayout->setSpacing(0); ui->graphLayout->setMargin(0); @@ -98,9 +181,6 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) //gSplitter(Qt::Vertical,ui->scrollArea); //splitter->setStyleSheet("QSplitter::handle { background-color: 'light grey'; }"); //splitter->setHandleWidth(3); -#ifdef Q_WS_MAC - //splitter->setOpaqueResize(false); -#endif scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -142,7 +222,7 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) TAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL); TAP_EAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL); TAP_IAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL); - G_AHI=new gGraphWindow(NULL,"",(QGLWidget* )NULL); + G_AHI=new gGraphWindow(NULL,"",(QGLWidget* )NULL); */ /*QGLFormat fmt; fmt.setDepth(false); @@ -153,7 +233,7 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) //fmt.setDefaultFormat(fmt); offscreen_context=new QGLContext(fmt); */ - SF->SetLeftMargin(SF->GetLeftMargin()+gYAxis::Margin); + /*SF->SetLeftMargin(SF->GetLeftMargin()+gYAxis::Margin); SF->SetBlockZoom(true); SF->AddLayer(new gXAxis()); SF->setMinimumHeight(min_height); @@ -220,6 +300,7 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) g->ReportEmpty(true); AddCPAP(g); FRW->AddLayer(g); + FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_CSR,QColor("light green"),"CSR",FT_Span))); FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Hypopnea,QColor("blue"),"H"))); FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_PressurePulse,QColor("red"),"PR",FT_Dot))); //FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Pressure,QColor("white"),"P",FT_Dot))); @@ -313,7 +394,7 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) SPO2->AddLayer(new gYAxis()); SPO2->AddLayer(AddOXI(new gLineChart(OXI_SPO2,Qt::blue,true))); SPO2->AddLayer(AddOXI(new gLineOverlayBar(OXI_SPO2Drop,Qt::red,"SC",FT_Bar))); - SPO2->setMinimumHeight(min_height); + SPO2->setMinimumHeight(min_height); */ /*fg=new gFlagsGroup(); fg->AddLayer(AddOXI(new gFlagsLine(OXI_PulseChange,QColor("orange"),"PUL",true))); @@ -332,7 +413,7 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) // SPO2->hide(); // PULSE->hide(); - gSegmentChart *seg; + /*gSegmentChart *seg; TAP_EAP->SetMargins(0,0,0,0); TAP_EAP->AddLayer(AddCPAP(seg=new gTAPGraph(CPAP_EPAP))); @@ -362,12 +443,6 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) G_AHI->SetGradientBackground(false); G_AHI->hide(); - NoData=new QLabel(tr("No data"),parental); - NoData->setAlignment(Qt::AlignCenter); - QFont font("FreeSans",20); //NoData->font(); - //font.setBold(true); - NoData->setFont(font); - NoData->hide(); splitter->addWidget(NoData); //int i=splitter->indexOf(NoData); @@ -444,7 +519,7 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw) GraphAction.push_back(action); } - } else show_graph_menu=NULL; + } else show_graph_menu=NULL; */ } Daily::~Daily() @@ -456,13 +531,7 @@ Daily::~Daily() // delete splitter; delete ui; } -void Daily::AddGraph(gGraphWindow *w) -{ - Graphs.push_back(w); - splitter->addWidget(w); - w->SetSplitter(splitter); -} void Daily::resizeEvent (QResizeEvent * event) { //const QSize &size=event->size(); @@ -603,7 +672,7 @@ void Daily::ResetGraphLayout() } void Daily::ShowHideGraphs() { - int vis=0; +/* int vis=0; for (int i=0;iisEmpty()) { GraphAction[i]->setVisible(false); @@ -623,7 +692,7 @@ void Daily::ShowHideGraphs() //splitter->setMaximumHeight(vis*default_height); splitter->layout(); //splitter->update(); - RedrawGraphs(); + RedrawGraphs(); */ } void Daily::Load(QDate date) { @@ -652,78 +721,22 @@ void Daily::Load(QDate date) UpdateCPAPGraphs(cpap); UpdateEventsTree(ui->treeWidget,cpap); + GraphView->ResetBounds(); + + GraphView->updateGL(); if (!cpap && !oxi) { - GraphLayout->setMinimumHeight(0); //splitter->setMinimumHeight(0); + scrollbar->hide(); + GraphView->hide(); NoData->setText(tr("No data for ")+date.toString(Qt::SystemLocaleLongDate)); NoData->show(); - - for (int i=0;isetVisible(false); - Graphs[i]->hide(); - } - spacer->hide(); - } else { NoData->hide(); - int vis=0; - scrollArea->setUpdatesEnabled(false); - for (int i=0;isetUpdatesEnabled(false); - if (Graphs[i]->isEmpty()) { - GraphAction[i]->setVisible(false); - Graphs[i]->hide(); - } else { - GraphAction[i]->setVisible(true); - if (GraphAction[i]->isChecked()) { - Graphs[i]->ResetBounds(); - Graphs[i]->show(); - vis++; - } else { - Graphs[i]->hide(); - } - } - } - if (!cpap) { - GraphAction[0]->setVisible(false); - SF->hide(); - vis--; - - } - //splitter->layout(); - for (int i=0;isetUpdatesEnabled(true); - } - spacer->show(); - //splitter->addStrut(vis*default_height); - //QSize aa(this->width(),vis*default_height); - //splitter->SetMinimumSize(aa); - //splitter->SetFixedSize(aa); - - GraphLayout->setMinimumHeight(vis*default_height+20); - - - //splitter->setMinimumHeight(0); - //splitter->setMinimumHeight(vis*default_height); - //if (vis>4) { - //splitter->setMaximumHeight(vis*default_height); - //} //else { - // } -// splitter->blockSignals(true); - - splitter->setSpacing(0); - splitter->setMargin(0); - splitter->layout(); - scrollArea->setUpdatesEnabled(true); - scrollArea->update(); - //ui->scrollArea->update(); - //splitter->layout(); - - // spacer->show(); + GraphView->show(); + scrollbar->show(); } - //splitter->update(); - RedrawGraphs(); + //RedrawGraphs(); QString epr,modestr; float iap90,eap90; @@ -740,7 +753,6 @@ void Daily::Load(QDate date) } modestr=channel[CPAP_Mode].optionString(mode); - float ahi=(cpap->count(CPAP_Obstructive)+cpap->count(CPAP_Hypopnea)+cpap->count(CPAP_ClearAirway)+cpap->count(CPAP_Apnea))/cpap->hours(); float csr=(100.0/cpap->hours())*(cpap->sum(CPAP_CSR)/3600.0); float uai=cpap->count(CPAP_Apnea)/cpap->hours(); @@ -808,34 +820,25 @@ void Daily::Load(QDate date) // ^^ Scratch that.. pie now includes text.. if (pref["EnableGraphSnapshots"].toBool()) { // AHI Pie Chart - if (ahi+rei+fli>0) { - html+="\n"+tr("Event Breakdown")+"\n"; - G_AHI->setFixedSize(gwwidth,120); - QPixmap pixmap=G_AHI->renderPixmap(gwwidth,120,false); //gwwidth,gwheight,false); - QByteArray byteArray; - QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray - buffer.open(QIODevice::WriteOnly); - pixmap.save(&buffer, "PNG"); - html += "\n"; - } else { - html += "\n"; - } +// if (ahi+rei+fli>0) { +// html+="\n"+tr("Event Breakdown")+"\n"; +// G_AHI->setFixedSize(gwwidth,120); +// QPixmap pixmap=G_AHI->renderPixmap(gwwidth,120,false); //gwwidth,gwheight,false); +// QByteArray byteArray; +// QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray +// buffer.open(QIODevice::WriteOnly); +// pixmap.save(&buffer, "PNG"); +// html += "\n"; +// } else { +// html += "\n"; +// } } } - html+="" - "\n"; + html+="
"; + html+="\n"; if (cpap || oxi) { html+="\n"; -/* if (mode==MODE_BIPAP) { - html+="\n" - "\n"; - } else if (mode==MODE_APAP) { - html+=("\n"); //cpap->summary_weighted_avg(CPAP_PressurePercentValue) - } else if (mode==MODE_CPAP) { - html+=("\n"); - }*/ - //html+=("\n"); html+=(""); @@ -876,7 +879,7 @@ void Daily::Load(QDate date) if (cpap) { if (pref["EnableGraphSnapshots"].toBool()) { - if (cpap->channelExists(CPAP_Pressure)) { + /* if (cpap->channelExists(CPAP_Pressure)) { html+=("\n"); TAP->setFixedSize(gwwidth,30); QPixmap pixmap=TAP->renderPixmap(gwwidth,30,false); @@ -906,7 +909,8 @@ void Daily::Load(QDate date) buffer.open(QIODevice::WriteOnly); pixmap.save(&buffer, "PNG"); html+="\n"; - } + } */ + } html+="

"+tr("90%  EPAP ")+QString().sprintf("%.2f",eap90)+tr("cmH2O")+"
"+tr("90%  IPAP ")+QString().sprintf("%.2f",iap90)+tr("cmH2O")+"
")+tr("90%  Auto Pressure ")+QString().sprintf("%.2f",p90)+("
")+tr("CPAP Pressure ")+QString().sprintf("%.2f",cpap->max(CPAP_Pressure))+("
 
MinAvg90%Max
")+tr("Time@Pressure")+("

"; html+=""; @@ -925,7 +929,7 @@ void Daily::Load(QDate date) html+="
One or more waveform record for this session had faulty source data. Some waveform overlay points may not match up correctly.
"; } } - html+=""; + html+=""; ui->webView->setHtml(html); @@ -1084,7 +1088,7 @@ void Daily::UpdateCPAPGraphs(Day *day) if (day) { day->OpenEvents(); } - for (QList::iterator g=CPAPData.begin();g!=CPAPData.end();g++) { + for (QList::iterator g=CPAPData.begin();g!=CPAPData.end();g++) { (*g)->SetDay(day); } }; @@ -1096,16 +1100,16 @@ void Daily::UpdateOXIGraphs(Day *day) if (day) { day->OpenEvents(); } - for (QList::iterator g=OXIData.begin();g!=OXIData.end();g++) { + for (QList::iterator g=OXIData.begin();g!=OXIData.end();g++) { (*g)->SetDay(day); } } void Daily::RedrawGraphs() { - for (int i=0;iupdateGL(); - } + } */ } void Daily::on_treeWidget_itemSelectionChanged() @@ -1118,7 +1122,8 @@ void Daily::on_treeWidget_itemSelectionChanged() d=d.fromString(item->text(1),"yyyy-MM-dd HH:mm:ss"); double st=(d.addSecs(-120)).toMSecsSinceEpoch(); double et=(d.addSecs(120)).toMSecsSinceEpoch(); - FRW->SetXBounds(st,et); + GraphView->SetXBounds(st,et); + /*FRW->SetXBounds(st,et); MP->SetXBounds(st,et); SF->SetXBounds(st,et); PRD->SetXBounds(st,et); @@ -1127,7 +1132,7 @@ void Daily::on_treeWidget_itemSelectionChanged() MV->SetXBounds(st,et); TV->SetXBounds(st,et); RR->SetXBounds(st,et); - FLG->SetXBounds(st,et); + FLG->SetXBounds(st,et); */ } } diff --git a/daily.h b/daily.h index d28e9752..ff928a00 100644 --- a/daily.h +++ b/daily.h @@ -8,40 +8,27 @@ #define DAILY_H -#include #include #include #include #include #include #include +#include #include + #include -#include +//#include #include "mainwindow.h" -#include "Graphs/gSplitter.h" +#include "Graphs/gGraphView.h" + +//#include "Graphs/gSplitter.h" #include "Graphs/gLineChart.h" -#include "Graphs/gFlagsLine.h" +//#include "Graphs/gFlagsLine.h" namespace Ui { class Daily; } -class Daily; -class MyScrollArea:public QScrollArea -{ - Q_OBJECT -public: - MyScrollArea(QWidget * parent, Daily * daily); - virtual ~MyScrollArea(); -protected slots: - void UpdateGraphs(); -protected: - virtual void scrollContentsBy(int dx, int dy); - - Daily *m_daily; - QTimer *timer; - QTime m_time; -}; class MainWindow; class Daily : public QWidget @@ -53,7 +40,7 @@ public: ~Daily(); void ReloadGraphs(); void ResetGraphLayout(); - QGLWidget *SharedWidget() { return SF; } + QGLWidget *SharedWidget() { return GraphView; } void RedrawGraphs(); private slots: @@ -86,23 +73,23 @@ private: //gPointData *tap,*tap_eap,*tap_iap,*g_ahi,*frw,*prd,*leak,*pressure_iap,*pressure_eap,*snore; //gPointData *pulse,*spo2,*rr,*mv,*tv,*mp,*flg,*ptb; - gFlagsGroup *fg; - gGraphWindow *PRD,*FRW,*G_AHI,*TAP,*LEAK,*SF,*TAP_EAP,*TAP_IAP,*PULSE,*SPO2, - *SNORE,*RR,*MP,*MV,*TV,*FLG,*PTB,*OF,*INTPULSE,*INTSPO2, *THPR, - *PLETHY,*TI,*TE, *RE, *IE; + //gFlagsGroup *fg; + gGraph *PRD,*FRW,*G_AHI,*TAP,*LEAK,*SF,*TAP_EAP,*TAP_IAP,*PULSE,*SPO2, + *SNORE,*RR,*MP,*MV,*TV,*FLG,*PTB,*OF,*INTPULSE,*INTSPO2, *THPR, + *PLETHY,*TI,*TE, *RE, *IE; - gLineChart *pressure, *epap, *ipap; + //gLineChart *pressure, *epap, *ipap; - QList OXIData; - QList CPAPData; - QVector Graphs; + QList OXIData; + QList CPAPData; + //QVector Graphs; QVector GraphAction; QGLContext *offscreen_context; QList splitter_sizes; - gLayer * AddCPAP(gLayer *d) { CPAPData.push_back(d); return d; } - gLayer * AddOXI(gLayer *d) { OXIData.push_back(d); return d; } - void AddGraph(gGraphWindow *w); + Layer * AddCPAP(Layer *d) { CPAPData.push_back(d); return d; } + Layer * AddOXI(Layer *d) { OXIData.push_back(d); return d; } + //void AddGraph(gGraph *w); void UpdateCPAPGraphs(Day *day); void UpdateOXIGraphs(Day *day); @@ -110,22 +97,15 @@ private: Ui::Daily *ui; Profile *profile; QDate previous_date; - QScrollArea *scrollArea; - QVBoxLayout *splitter; + //QScrollArea *scrollArea; + //QVBoxLayout *splitter; QLabel *NoData; QWidget *spacer; QMenu *show_graph_menu; QWidget *GraphLayout; + gGraphView *GraphView; + MyScrollBar *scrollbar; + QHBoxLayout *layout; }; -/*class AHIGraph:public QWebPluginFactory -{ -public: - AHIGraph(QObject * parent = 0); - virtual ~AHIGraph(); - virtual QObject * create ( const QString & mimeType, const QUrl & url, const QStringList & argumentNames, const QStringList & argumentValues) const; - virtual QList plugins () const; - //virtual void refreshPlugins (); -}; */ - #endif // DAILY_H diff --git a/daily.ui b/daily.ui index 405b805d..d9ca84c2 100644 --- a/daily.ui +++ b/daily.ui @@ -32,22 +32,10 @@ Qt::Horizontal - - - 300 - 16777215 - - Qt::Vertical - - - 0 - 0 - - 0 @@ -57,7 +45,13 @@ 300 - 180 + 16777215 + + + + + 0 + 0 @@ -67,7 +61,7 @@ - Qt::Sunday + Qt::Monday false @@ -83,12 +77,24 @@ + + + 0 + 0 + + 300 16777215 + + + 300 + 0 + + Sans Serif @@ -114,6 +120,12 @@ + + + 0 + 0 + + Sans Serif @@ -476,14 +488,12 @@ - - - 0 - - - 0 - - + + + 0 + 0 + + diff --git a/mainwindow.cpp b/mainwindow.cpp index 97a5be5c..c69179c0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -83,9 +83,10 @@ MainWindow::MainWindow(QWidget *parent) : pref["AppName"]="SleepyHead"; QString Version=QString("%1.%2.%3").arg(major_version).arg(minor_version).arg(revision_number); - if (pref.Exists("VersionString") && pref["VersionString"]!=Version) { - QMessageBox::warning(this,"Potential Crash Warning","This is a new version of SleepyHead. If you experience a crash right after clicking Ok, you will need to manually delete the SleepApp folder (it's located in your Documents folder), and things should then work normally.",QMessageBox::Ok); - } + //if (pref.Exists("VersionString") && pref["VersionString"]!=Version) { + //QMessageBox::warning(this,"Potential Crash Warning","This is a new version of SleepyHead. If you experience a crash right after clicking Ok, you will need to manually delete the SleepApp folder (it's located in your Documents folder), and things should then work normally.",QMessageBox::Ok); + QMessageBox::warning(this,"Notice","Hi, I'm currently in the middle of a large rewrite of graphing system components. Things aren't finished and some features are missing.. The mac/windows scrolling glitches show be gone now, but the new mouse handling isn't complete (ie, things will suck). This annoying message will go away when I'm done with it.",QMessageBox::Ok); + //} pref["VersionString"]=Version; if (!pref.Exists("Profile")) pref["Profile"]=getUserName(); @@ -122,9 +123,10 @@ MainWindow::MainWindow(QWidget *parent) : //overview=new Overview(ui->tabWidget,daily->SharedWidget()); //ui->tabWidget->insertTab(2,overview,tr("Overview")); - - oximetry=new Oximetry(ui->tabWidget,daily->SharedWidget()); - ui->tabWidget->insertTab(3,oximetry,tr("Oximetry")); + oximetry=NULL; + //overview=NULL; + // oximetry=new Oximetry(ui->tabWidget,daily->SharedWidget()); + //ui->tabWidget->insertTab(3,oximetry,tr("Oximetry")); ui->tabWidget->setCurrentWidget(ui->welcome); diff --git a/mainwindow.h b/mainwindow.h index 44216b95..fc141224 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -16,7 +16,7 @@ const int major_version=0; const int minor_version=8; -const int revision_number=2; +const int revision_number=4; namespace Ui { class MainWindow; diff --git a/oximetry.cpp b/oximetry.cpp index 9b3440a1..8696a7ec 100644 --- a/oximetry.cpp +++ b/oximetry.cpp @@ -19,7 +19,7 @@ Oximetry::Oximetry(QWidget *parent,QGLWidget * shared) : ui(new Ui::Oximetry) { ui->setupUi(this); - port=NULL; +/* port=NULL; portname=""; QString prof=pref["Profile"].toString(); profile=Profiles::Get(prof); @@ -91,7 +91,7 @@ Oximetry::Oximetry(QWidget *parent,QGLWidget * shared) : Graphs[i]->SetSplitter(splitter); } - on_RefreshPortsButton_clicked(); + on_RefreshPortsButton_clicked(); */ } Oximetry::~Oximetry()
SessionIDDateStartEnd