Import upstream version 0.99.2
[fmit.git] / src / modules / GLStatistics.cpp
index 52df0b7..f468d11 100644 (file)
@@ -178,6 +178,8 @@ using namespace std;
 #include <qtimer.h>
 #include <qtooltip.h>
 #include <qimage.h>
+#include <qboxlayout.h>
+#include <qwidgetaction.h>
 #include <Music/Music.h>
 
 void GLStatistics::AverageNote::init()
@@ -209,7 +211,7 @@ GLStatistics::AverageNote::AverageNote(int h, float cents)
 }
 QString GLStatistics::AverageNote::getName() const
 {
-       return Music::h2n(ht)+factor;
+       return QString::fromStdString(Music::h2n(ht))+factor;
 }
 void GLStatistics::AverageNote::addErr(float err)
 {
@@ -229,22 +231,35 @@ void GLStatistics::AverageNote::addErr(float err)
        }
        if(errs.size()>1)
        {
-               err_std /= errs.size()-1;                                               // unbiased estimation of the variance
+               err_std /= errs.size()-1;               // unbiased estimation of the variance
                err_std = sqrt(err_std);
        }
 }
 
 void GLStatistics::addNote(int ht, float err)
 {
-       if(isHidden() && !setting_keep_hidden->isOn())
+       m_current_ht = ht;
+
+       if(isHidden() && !setting_keep_hidden->isChecked())
                return;
 
-       if(ht<setting_scale_min->minValue() || ht>setting_scale_max->maxValue())
+       if(ht<setting_scale_min->minimum() || ht>setting_scale_max->maximum())
                return;
 
 //     cerr << "ht=" << ht << endl;
 
-       if(setting_scale_auto->isOn())
+       if(!setting_scale_auto->isChecked())
+       {
+               resizeScale();
+
+               // drop ht outside of scale
+               if(ht<setting_scale_min->value() || ht>setting_scale_max->value())
+                       return;
+
+               // add note
+               m_avg_notes[ht-setting_scale_min->value()].addErr(err);
+       }
+       else
        {
                if(m_avg_notes.empty())
                {
@@ -291,118 +306,209 @@ void GLStatistics::addNote(int ht, float err)
 }
 void GLStatistics::addNote(int ht, int num, int den, float err)
 {
+       m_current_ht = ht;
 }
 void GLStatistics::addNote(int ht, float cents, float err)
 {
+       m_current_ht = ht;
+}
+
+void GLStatistics::resizeScale()
+{
+       if(setting_scale_auto->isChecked() || setting_scale_max->value()-setting_scale_min->value()+1<1)
+               return;
+
+       if(m_avg_notes.size()==0 || m_avg_notes[0].ht!=setting_scale_min->value() || m_avg_notes[m_avg_notes.size()-1].ht!=setting_scale_max->value())
+       {
+               vector<AverageNote> avg_notes(setting_scale_max->value()-setting_scale_min->value()+1);
+               for(int i=0; i<int(m_avg_notes.size()); i++)
+               {
+                       int in = i+m_avg_notes[0].ht-setting_scale_min->value();
+                       if(in>=0 && in<int(avg_notes.size()))
+                               avg_notes[in] = m_avg_notes[i];
+               }
+               for(size_t i=0; i<avg_notes.size(); i++)
+                       avg_notes[i].ht = setting_scale_min->value()+i;
+               m_avg_notes = avg_notes;
+       }
 }
 
 GLStatistics::GLStatistics(QWidget* parent)
-: QGLWidget(parent, "GLStatistics")
-, View("Statistics", this)
+: QGLWidget(parent)
+, View(tr("Statistics"), this)
 {
        // settings
-       QImage img;
+       QPixmap img;
        img.loadFromData(g_icon_statistics, sizeof(g_icon_statistics), "PNG");
-       setting_show->setIconSet(QIconSet(QImage(img)));
-       setting_show->setOn(false);
+       setting_show->setIcon(QIcon(img));
+       setting_show->setChecked(false);
        hide();
 
-       setting_reset = new QAction(this);
-       setting_reset->setMenuText(tr("Reset statistics"));
+       setting_reset = new QAction(tr("Reset statistics"), this);
+       setting_reset->setShortcut('r');
        connect(setting_reset, SIGNAL(activated()), this, SLOT(reset()));
-       setting_reset->addTo(&m_popup_menu);
+       m_popup_menu.addAction(setting_reset);
 
-       setting_keep_hidden = new QAction(this);
-       setting_keep_hidden->setMenuText(tr("Keep notes when hidden"));
-       setting_keep_hidden->setToggleAction(true);
-       setting_keep_hidden->setOn(false);
+       setting_keep_hidden = new QAction(tr("Keep notes when hidden"), this);
+       setting_keep_hidden->setCheckable(true);
+       setting_keep_hidden->setChecked(false);
        connect(setting_keep_hidden, SIGNAL(toggled(bool)), this, SLOT(update()));
-       setting_keep_hidden->addTo(&m_popup_menu);
+       m_popup_menu.addAction(setting_keep_hidden);
+
+       QHBoxLayout* keepActionLayout = new QHBoxLayout(&m_popup_menu);
+
+       QLabel* keepActionTitle = new QLabel(tr("Keep n values"), &m_popup_menu);
+       keepActionLayout->addWidget(keepActionTitle);
 
-       setting_show_std = new QAction(this);
-       setting_show_std->setMenuText(tr("Show standard deviation"));
-       setting_show_std->setToggleAction(true);
-       setting_show_std->setOn(true);
-       setting_show_std->setEnabled(true);
+       setting_keep_n_values = new QSpinBox(&m_popup_menu);
+       setting_keep_n_values->setObjectName("setting_keep_n_values");
+       setting_keep_n_values->setMinimum(1);
+       setting_keep_n_values->setMaximum(500);
+       setting_keep_n_values->setSingleStep(3);
+       setting_keep_n_values->setValue(100);
+       setting_keep_n_values->setToolTip(tr("Keep this number of values in the computation of the statistics"));
+       connect(setting_keep_n_values, SIGNAL(valueChanged(int)), this, SLOT(update()));
+       keepActionLayout->addWidget(setting_keep_n_values);
+
+       QWidget* keepActionWidget = new QWidget(&m_popup_menu);
+       keepActionWidget->setLayout(keepActionLayout);
+
+       QWidgetAction* keepAction = new QWidgetAction(&m_popup_menu);
+       keepAction->setDefaultWidget(keepActionWidget);
+       m_popup_menu.addAction(keepAction);
+
+       setting_keep_n_values->setEnabled(false);
+       s_settings->add(setting_keep_n_values);
+
+       setting_show_std = new QAction(tr("Show standard deviation"), this);
+       setting_show_std->setCheckable(true);
+       setting_show_std->setChecked(true);
        connect(setting_show_std, SIGNAL(toggled(bool)), this, SLOT(update()));
-       setting_show_std->addTo(&m_popup_menu);
+       m_popup_menu.addAction(setting_show_std);
 
-       setting_scale_auto = new QAction(this);
-       setting_scale_auto->setMenuText(tr("Scale auto"));
-       setting_scale_auto->setToggleAction(true);
-       setting_scale_auto->setOn(true);
+       setting_scale_auto = new QAction(tr("Scale auto"), this);
+       setting_scale_auto->setCheckable(true);
+       setting_scale_auto->setChecked(true);
        setting_scale_auto->setEnabled(false);
        connect(setting_scale_auto, SIGNAL(toggled(bool)), this, SLOT(update()));
-       setting_scale_auto->addTo(&m_popup_menu);
+       m_popup_menu.addAction(setting_scale_auto);
+
+       QHBoxLayout* scaleMinActionLayout = new QHBoxLayout(&m_popup_menu);
 
-       m_popup_menu.insertItem(new Title(tr("Scale min"), &m_popup_menu));
-       setting_scale_min = new QSpinBox(-96, 96, 1, &m_popup_menu);
-       setting_scale_min->setValue(0);
-       QToolTip::add(setting_scale_min, tr("Scale min value (in semi-tones)"));
+       QLabel* scaleMinActionTitle = new QLabel(tr("Scale min"), &m_popup_menu);
+       scaleMinActionLayout->addWidget(scaleMinActionTitle);
+
+       setting_scale_min = new QSpinBox(&m_popup_menu);
+       setting_scale_min->setObjectName("setting_scale_min");
+       setting_scale_min->setMinimum(-96);
+       setting_scale_min->setMaximum(96);
+       setting_scale_min->setSingleStep(6);
+       setting_scale_min->setValue(-12);
+       setting_scale_min->setToolTip(tr("Scale min value (in semi-tones)"));
        connect(setting_scale_min, SIGNAL(valueChanged(int)), this, SLOT(update()));
-       m_popup_menu.insertItem(setting_scale_min);
-       setting_scale_min->setEnabled(false);
+       scaleMinActionLayout->addWidget(setting_scale_min);
+
+       QWidget* scaleMinActionWidget = new QWidget(&m_popup_menu);
+       scaleMinActionWidget->setLayout(scaleMinActionLayout);
 
-       m_popup_menu.insertItem(new Title(tr("Scale max"), &m_popup_menu));
-       setting_scale_max = new QSpinBox(-96, 96, 1, &m_popup_menu);
-       setting_scale_max->setValue(0);
-       QToolTip::add(setting_scale_max, tr("Scale max value (in semi-tones)"));
+       QWidgetAction* scaleMinAction = new QWidgetAction(&m_popup_menu);
+       scaleMinAction->setDefaultWidget(scaleMinActionWidget);
+       m_popup_menu.addAction(scaleMinAction);
+
+       setting_scale_min->setEnabled(false);
+       s_settings->add(setting_scale_min);
+       connect(setting_scale_auto, SIGNAL(toggled(bool)), setting_scale_min, SLOT(setDisabled(bool)));
+       connect(setting_scale_min, SIGNAL(valueChanged(int)), this, SLOT(resizeScale()));
+
+       QHBoxLayout* scaleMaxActionLayout = new QHBoxLayout(&m_popup_menu);
+
+       QLabel* scaleMaxActionTitle = new QLabel(tr("Scale max"), &m_popup_menu);
+       scaleMaxActionLayout->addWidget(scaleMaxActionTitle);
+
+       setting_scale_max = new QSpinBox(&m_popup_menu);
+       setting_scale_max->setObjectName("setting_scale_max");
+       setting_scale_max->setMinimum(-96);
+       setting_scale_max->setMaximum(96);
+       setting_scale_max->setSingleStep(6);
+       setting_scale_max->setValue(+12);
+       setting_scale_max->setToolTip(tr("Scale max value (in semi-tones)"));
        connect(setting_scale_max, SIGNAL(valueChanged(int)), this, SLOT(update()));
-       m_popup_menu.insertItem(setting_scale_max);
+       scaleMaxActionLayout->addWidget(setting_scale_max);
+
+       QWidget* scaleMaxActionWidget = new QWidget(&m_popup_menu);
+       scaleMaxActionWidget->setLayout(scaleMaxActionLayout);
+
+       QWidgetAction* scaleMaxAction = new QWidgetAction(&m_popup_menu);
+       scaleMaxAction->setDefaultWidget(scaleMaxActionWidget);
+       m_popup_menu.addAction(scaleMaxAction);
+
        setting_scale_max->setEnabled(false);
+       s_settings->add(setting_scale_max);
+       connect(setting_scale_auto, SIGNAL(toggled(bool)), setting_scale_max, SLOT(setDisabled(bool)));
+       connect(setting_scale_max, SIGNAL(valueChanged(int)), this, SLOT(resizeScale()));
 
-       setting_showTolerance = new QAction(this);
-       setting_showTolerance->setMenuText(tr("Show tolerance"));
-       setting_showTolerance->setToggleAction(true);
-       setting_showTolerance->setOn(true);
+       setting_showTolerance = new QAction(tr("Show tolerance"), this);
+       setting_showTolerance->setCheckable(true);
+       setting_showTolerance->setChecked(true);
        connect(setting_showTolerance, SIGNAL(toggled(bool)), this, SLOT(update()));
-       setting_showTolerance->addTo(&m_popup_menu);
+       m_popup_menu.addAction(setting_showTolerance);
 
-       setting_useCents = new QAction(this);
-       setting_useCents->setMenuText(tr("Use cents"));
-       setting_useCents->setToggleAction(true);
-       setting_useCents->setOn(true);
+       setting_useCents = new QAction(tr("Use cents"), this);
+       setting_useCents->setCheckable(true);
+       setting_useCents->setChecked(true);
        connect(setting_useCents, SIGNAL(toggled(bool)), this, SLOT(update()));
-       setting_useCents->addTo(&m_popup_menu);
+       m_popup_menu.addAction(setting_useCents);
+
+       QHBoxLayout* scaleActionLayout = new QHBoxLayout(&m_popup_menu);
 
-       m_popup_menu.insertItem(new Title(tr("Scale range"), &m_popup_menu));
-       setting_spinScale = new QSpinBox(5, 50, 1, &m_popup_menu);
+       QLabel* scaleActionTitle = new QLabel(tr("Scale range"), &m_popup_menu);
+       scaleActionLayout->addWidget(scaleActionTitle);
+
+       setting_spinScale = new QSpinBox(&m_popup_menu);
+       setting_spinScale->setMinimum(5);
+       setting_spinScale->setMaximum(50);
+       setting_spinScale->setSingleStep(1);
        setting_spinScale->setValue(50);
-       QToolTip::add(setting_spinScale, tr("Scale range (in cents)"));
+       setting_spinScale->setToolTip(tr("Scale range (in cents)"));
        connect(setting_spinScale, SIGNAL(valueChanged(int)), this, SLOT(update()));
-       m_popup_menu.insertItem(setting_spinScale);
+       scaleActionLayout->addWidget(setting_spinScale);
+
+       QWidget* scaleActionWidget = new QWidget(&m_popup_menu);
+       scaleActionWidget->setLayout(scaleActionLayout);
+
+       QWidgetAction* scaleAction = new QWidgetAction(&m_popup_menu);
+       scaleAction->setDefaultWidget(scaleActionWidget);
+       m_popup_menu.addAction(scaleAction);
 }
 
 void GLStatistics::save()
 {
-       s_settings->writeEntry("setting_keep_hidden", setting_keep_hidden->isOn());
-       s_settings->writeEntry("setting_show_std", setting_show_std->isOn());
-       s_settings->writeEntry("setting_scale_auto", setting_scale_auto->isOn());
-       s_settings->writeEntry("setting_scale_min", setting_scale_min->value());
-       s_settings->writeEntry("setting_scale_max", setting_scale_max->value());
+       s_settings->setValue("setting_keep_hidden", setting_keep_hidden->isChecked());
+       s_settings->setValue("setting_show_std", setting_show_std->isChecked());
+       s_settings->setValue("setting_scale_auto", setting_scale_auto->isChecked());
 }
 void GLStatistics::load()
 {
-       setting_keep_hidden->setOn(s_settings->readBoolEntry("setting_keep_hidden", setting_keep_hidden->isOn()));
-       setting_show_std->setOn(s_settings->readBoolEntry("setting_show_std", setting_show_std->isOn()));
-       setting_scale_auto->setOn(s_settings->readBoolEntry("setting_scale_auto", setting_scale_auto->isOn()));
-       setting_scale_min->setValue(s_settings->readNumEntry("setting_scale_min", setting_scale_min->value()));
-       setting_scale_max->setValue(s_settings->readNumEntry("setting_scale_max", setting_scale_max->value()));
+       setting_keep_hidden->setChecked(s_settings->value("setting_keep_hidden", setting_keep_hidden->isChecked()).toBool());
+       setting_show_std->setChecked(s_settings->value("setting_show_std", setting_show_std->isChecked()).toBool());
+       setting_scale_auto->setChecked(s_settings->value("setting_scale_auto", setting_scale_auto->isChecked()).toBool());
 }
 void GLStatistics::clearSettings()
 {
-       s_settings->removeEntry("setting_keep_hidden");
-       s_settings->removeEntry("setting_show_std");
-       s_settings->removeEntry("setting_scale_auto");
-       s_settings->removeEntry("setting_scale_min");
-       s_settings->removeEntry("setting_scale_max");
+       s_settings->remove("setting_keep_hidden");
+       s_settings->remove("setting_show_std");
+       s_settings->remove("setting_scale_auto");
 }
 
 void GLStatistics::reset()
 {
        m_avg_notes.clear();
-       setting_scale_min->setValue(0);
-       setting_scale_max->setValue(0);
+       if(setting_scale_auto->isChecked())
+       {
+               setting_scale_min->setValue(0);
+               setting_scale_max->setValue(0);
+       }
+       resizeScale();
        updateGL();
 }
 
@@ -447,8 +553,9 @@ void GLStatistics::drawTextTickCent(int r, int dy)
                if(i>=0) txt = QString("  ")+txt;
                if(i==0) txt = QString("  ")+txt;
                glRasterPos2i(2, int((height()-dy)*i/100.0f*scale) + (height()-dy)/2 + dy - 4);
-               for(size_t i=0; i<txt.length(); i++)
-                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, txt.latin1()[i]);
+               string str = txt.toStdString();
+               for(size_t i=0; i<str.length(); i++)
+                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, (unsigned char)str[i]);
        }
 }
 
@@ -461,17 +568,17 @@ void GLStatistics::paintGL()
        glLineWidth(1.0f);
        float human_tol = Music::f2hf(441.0,440.0);
        float scale;
-       if(setting_useCents->isOn())
+       if(setting_useCents->isChecked())
                scale = 50.0f/setting_spinScale->value();
        else
                scale = int(50/setting_spinScale->value());
 
        // name
-       QString str = tr("Statistics");
+       string str = tr("Statistics").toStdString();
        glColor3f(0.75,0.75,0.75);
        glRasterPos2i(2, height()-20);
        for(size_t i = 0; i < str.length(); i++)
-               glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, str.latin1()[i]);
+               glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, (unsigned char)str[i]);
 
        int char_size = 9;
        int ticks_size = 2+3*char_size;
@@ -481,7 +588,7 @@ void GLStatistics::paintGL()
        int grid_height = height()-legend_height;
 
        // draw green rect
-       if(setting_showTolerance->isOn())
+       if(setting_showTolerance->isChecked())
        {
                int green_ytop = int((scale*human_tol+0.5)*grid_height) + legend_height;
                int green_ybottom = int((-scale*human_tol+0.5)*grid_height) + legend_height;
@@ -505,7 +612,7 @@ void GLStatistics::paintGL()
        }
 
        // std
-       if(setting_show_std->isOn())
+       if(setting_show_std->isChecked())
        {
                glBegin(GL_QUADS);
                glLineWidth(1.0f);
@@ -531,7 +638,7 @@ void GLStatistics::paintGL()
        }
 
        // horiz lines
-       if(setting_useCents->isOn())
+       if(setting_useCents->isChecked())
        {
                glBegin(GL_LINES);
                float gray = 0.87;
@@ -581,7 +688,7 @@ void GLStatistics::paintGL()
        // text marks
        float gray = 0.5;
        glColor3f(gray, gray, gray);
-       if(setting_useCents->isOn())
+       if(setting_useCents->isChecked())
        {
                int grad = 10;
                if(setting_spinScale->value() <= 25) grad=5;
@@ -591,25 +698,25 @@ void GLStatistics::paintGL()
        else
        {
                string sfraq, sufraq;
-               sufraq = string("1/")+QString::number(int(50/setting_spinScale->value())*2).latin1();
+               sufraq = string("1/")+QString::number(int(50/setting_spinScale->value())*2).toStdString();
                sfraq = string("+")+sufraq;
                glRasterPos2i(2, 3*grid_height/4-dy+legend_height);
                for(size_t i = 0; i < sfraq.size(); i++)
-                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, sfraq[i]);
+                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, (unsigned char)sfraq[i]);
                sfraq = string("-")+sufraq;
                glRasterPos2i(2, grid_height/4-dy+legend_height);
                for(size_t i = 0; i < sfraq.size(); i++)
-                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, sfraq[i]);
+                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, (unsigned char)sfraq[i]);
 
-               sufraq = string("1/")+QString::number(int(50/setting_spinScale->value())*4).latin1();
+               sufraq = string("1/")+QString::number(int(50/setting_spinScale->value())*4).toStdString();
                sfraq = string("+")+sufraq;
                glRasterPos2i(2, 5*grid_height/8-dy+legend_height);
                for(size_t i = 0; i < sfraq.size(); i++)
-                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, sfraq[i]);
+                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, (unsigned char)sfraq[i]);
                sfraq = string("-")+sufraq;
                glRasterPos2i(2, 3*grid_height/8-dy+legend_height);
                for(size_t i = 0; i < sfraq.size(); i++)
-                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, sfraq[i]);
+                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, (unsigned char)sfraq[i]);
        }
 
        // vertical lines
@@ -628,12 +735,12 @@ void GLStatistics::paintGL()
        glColor3f(0, 0, 1);
        for(size_t i=0; i<m_avg_notes.size(); i++)
        {
-               string str = m_avg_notes[i].getName();
+               string str = m_avg_notes[i].getName().toStdString();
 
                glRasterPos2f(ticks_size+(i+0.5)*float(grid_width)/m_avg_notes.size(), 2);
 
                for(size_t c=0; c<str.length(); c++)
-                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, str[c]);
+                       glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, (unsigned char)str[c]);
        }
 
        // sizes
@@ -643,12 +750,12 @@ void GLStatistics::paintGL()
                if(!m_avg_notes[i].errs.empty())
                {
 
-                       string str = QString::number(m_avg_notes[i].errs.size());
+                       string str = QString::number(m_avg_notes[i].errs.size()).toStdString();
 
                        glRasterPos2f(ticks_size+(i+0.5)*float(grid_width)/m_avg_notes.size(), 4+legend_height/2);
 
                        for(size_t c=0; c<str.length(); c++)
-                               glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, str[c]);
+                               glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, (unsigned char)str[c]);
                }
        }
 
@@ -670,6 +777,24 @@ void GLStatistics::paintGL()
        }
        glEnd();
 
+       // Marks around current note
+       glBegin(GL_LINES);
+       gray = 0;
+       glColor3f(gray, gray, gray);
+       for(size_t i=0; i<m_avg_notes.size(); i++)
+       {
+               if(m_avg_notes[i].ht==m_current_ht)
+               {
+                       int x = ticks_size+int(i*float(grid_width)/m_avg_notes.size());
+                       glVertex2i(x, legend_height);
+                       glVertex2i(x, height());
+                       x = ticks_size+int((i+1)*float(grid_width)/m_avg_notes.size());
+                       glVertex2i(x, legend_height);
+                       glVertex2i(x, height());
+               }
+       }
+       glEnd();
+
        glFlush();
 }