/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * * gXAxis Implementation * * Copyright (c) 2011-2014 Mark Watkins * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of the Linux * distribution for more details. */ #include #include #include "gXAxis.h" const quint64 divisors[]={ 15552000000ULL, 7776000000ULL, 5184000000ULL, 2419200000ULL, 1814400000ULL, 1209600000L, 604800000L, 259200000L, 172800000L, 86400000,2880000,14400000,7200000,3600000,2700000, 1800000,1200000,900000,600000,300000,120000,60000,45000,30000, 20000,15000,10000,5000,2000,1000,100,50,10 }; const int divcnt=sizeof(divisors)/sizeof(quint64); gXAxis::gXAxis(QColor col,bool fadeout) :Layer(NoChannel) { m_line_color=col; m_text_color=col; m_major_color=Qt::darkGray; m_minor_color=Qt::lightGray; m_show_major_lines=false; m_show_minor_lines=false; m_show_minor_ticks=true; m_show_major_ticks=true; m_utcfix=false; m_fadeout=fadeout; m_textureID=0; // QDateTime d=QDateTime::currentDateTime(); // QTime t1=d.time(); // QTime t2=d.toUTC().time(); // tz_offset=t2.secsTo(t1); // tz_hours=tz_offset/3600.0; // tz_offset*=1000L; tz_offset=timezoneOffset(); tz_hours=tz_offset/3600000.0; } gXAxis::~gXAxis() { } void gXAxis::paint(gGraph & w,int left,int top, int width, int height) { Q_UNUSED(height) QString months[]={ QObject::tr("Jan"), QObject::tr("Feb"), QObject::tr("Mar"), QObject::tr("Apr"), QObject::tr("May"), QObject::tr("Jun"), QObject::tr("Jul"), QObject::tr("Aug"), QObject::tr("Sep"), QObject::tr("Oct"), QObject::tr("Nov"),QObject::tr("Dec") }; //static QString dow[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; QPainter painter; // Only need this for pixmap caching // pixmap caching screws font size when printing bool usepixmap=w.graphView()->usePixmapCache(); // Whether or not to use pixmap caching if (!usepixmap || (usepixmap && w.invalidate_xAxisImage)) { if (usepixmap) { // Unbind any previous texture if (m_textureID) w.graphView()->deleteTexture(m_textureID); m_image=QImage(width+22,height+4,QImage::Format_ARGB32_Premultiplied); m_image.fill(Qt::transparent); painter.begin(&m_image); painter.setPen(Qt::black); painter.setFont(*defaultfont); } double px,py; 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()) { minx=w.rmin_x; maxx=w.rmax_x; } else { minx=w.min_x; maxx=w.max_x; } qint64 xx=maxx-minx; if (xx<=0) return; //Most of this could be precalculated when min/max is set.. QString fd,tmpstr; int divmax,dividx; int fitmode; if (xx>=86400000L) { // Day fd="Mjj 00"; dividx=0; divmax=10; fitmode=0; } else if (xx>600000) { // Minutes fd=" j0:00"; dividx=10; divmax=27; fitmode=1; } else if (xx>5000) { // Seconds fd=" j0:00:00"; dividx=16; divmax=27; fitmode=2; } else { // Microseconds fd="j0:00:00:000"; dividx=28; divmax=divcnt; fitmode=3; } //if (divmax>divcnt) divmax=divcnt; int x,y; GetTextExtent(fd,x,y); if (x<=0) { qWarning() << "gXAxis::Plot() x<=0 font size bug"; return; } int max_ticks=width/(x+15); // Max number of ticks that will fit int fit_ticks=0; int div=-1; qint64 closest=0,tmp,tmpft; for (int i=dividx;iclosest) { // Find the closest scale to the number closest=tmpft; // that will fit div=i; fit_ticks=tmpft; } } if (fit_ticks==0) { qDebug() << "gXAxis::Plot() Couldn't fit ticks.. Too short?" << minx << maxx << xx; return; } if ((div<0) || (div>divcnt)) { qDebug() << "gXAxis::Plot() div out of bounds"; return; } qint64 step=divisors[div]; //Align left minimum to divisor by losing precision qint64 aligned_start=minx/step; aligned_start*=step; while (aligned_startsetColor(Qt::black); //int utcoff=m_utcfix ? tz_hours : 0; //utcoff=0; int num_minor_ticks; if (step>=86400000) { qint64 i=step/86400000L; // number of days if (i>14) i/=2; if (i<0) i=1; num_minor_ticks=i; } else num_minor_ticks=10; float xmult=double(width)/double(xx); float step_pixels=double(step/float(num_minor_ticks))*xmult; py=left+float(aligned_start-minx)*xmult; //py+=usepixmap ? 20 : left; int mintop=top+4.0*(float(y)/10.0); int majtop=top+6.0*(float(y)/10.0); int texttop=majtop+y; // 18*w.printScaleY(); // Fill in the minor tick marks up to the first major alignment tick for (int i=0;iadd(py,top,py,mintop); } int ms,m,h,s,d; qint64 j; for (qint64 i=aligned_start;iadd(px,top,px,majtop); j=i; if (!m_utcfix) j+=tz_offset; ms=j % 1000; m=(j/60000L) % 60L; h=(j/3600000L) % 24L; s=(j/1000L) % 60L; //int d=(j/86400000) % 7; if (fitmode==0) { d=(j/1000); QDateTime dt=QDateTime::fromTime_t(d).toUTC(); QDate date=dt.date(); // SLOW SLOW SLOW!!! On Mac especially, this function is pathetically slow. //dt.toString("MMM dd"); // Doing it this way instead because it's MUUUUUUCH faster tmpstr=QString("%1 %2").arg(months[date.month()-1]).arg(date.day()); //} else if (fitmode==0) { // tmpstr=QString("%1 %2:%3").arg(dow[d]).arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')); } else if (fitmode==1) { // minute tmpstr=QString("%1:%2").arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')); } else if (fitmode==2) { // second tmpstr=QString("%1:%2:%3").arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')).arg(s,2,10,QChar('0')); } else if (fitmode==3) { // milli tmpstr=QString("%1:%2:%3:%4").arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')).arg(s,2,10,QChar('0')).arg(ms,3,10,QChar('0')); } int tx=px-x/2.0; if (m_utcfix) tx+=step_pixels/2.0; if ((tx+x)<(left+width)) { if (!usepixmap) w.renderText(tmpstr,tx,texttop,0,Qt::black,defaultfont); else painter.drawText(tx-left+20,texttop-top,tmpstr); } py=px; for (int j=1;j=left+width) break; if (usepixmap) { painter.drawLine(py-left+20,0,py-left+20,mintop-top); } else lines->add(py,top,py,mintop); } if (lines->full()) { qWarning() << "maxverts exceeded in gXAxis::Plot()"; break; } } if (usepixmap) { painter.end(); m_image=QGLWidget::convertToGLFormat(m_image); m_textureID=w.graphView()->bindTexture(m_image,GL_TEXTURE_2D,GL_RGBA,QGLContext::NoBindOption); } w.invalidate_xAxisImage=false; } if (usepixmap && !m_image.isNull()) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); w.graphView()->drawTexture(QPoint(left-20,(top+height)-m_image.height()+4),m_textureID); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } }