From a84ae874f0334172900d611fc098de8433f54e4c Mon Sep 17 00:00:00 2001
From: Chris Xiong <chirs241097@gmail.com>
Date: Thu, 12 May 2016 23:33:51 +0800
Subject: Now channel labels are displayed correctly. Add an option to change
 the tint of the chequer board. Show unsigned integer options in hexadecimal
 format. Fixed a crash caused by attemting seeking when no file is being
 played.

---
 ChangeLog                                 | 10 +++++++++
 qmidiplayer-desktop/qmpmainwindow.cpp     |  1 +
 qmidiplayer-desktop/qmpsettingswindow.cpp | 16 +++++++++-----
 qmidiplayer-desktop/qmpsettingswindow.hpp | 36 +++++++++++++++++++++++++++++++
 visualization/qmpvisualization.cpp        | 26 ++++++++++++++++------
 visualization/qmpvisualization.hpp        |  2 +-
 6 files changed, 79 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index cabc955..b6b2132 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2016-05-12 0.8.1 alpha
+Now channel labels are displayed correctly.
+Add an option to change the tint of the chequer board.
+Show unsigned integer options in hexadecimal format.
+Fixed a crash caused by attemting seeking when no file is
+being played.
+
 2016-05-11 0.8.1 alpha
 Fixed a bug when piano is hidden but the option "arrange
 channels on a stair" is enabled.
@@ -5,6 +12,9 @@ Fixed a crash caused by the visualization plugin.
 Add channel label display. However it's still buggy so it's
 currently disabled.
 
+2016-05-09 0.8.1 alpha
+Add visualization documentaion stub.
+
 2016-05-07 0.8.1 alpha
 Added two new options.
 Fixed several crashes related to options without a description.
diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp
index c377010..762da0f 100644
--- a/qmidiplayer-desktop/qmpmainwindow.cpp
+++ b/qmidiplayer-desktop/qmpmainwindow.cpp
@@ -409,6 +409,7 @@ void qmpMainWindow::on_hsTimer_sliderReleased()
 	}
 	else
 	{
+		if(stopped){ui->hsTimer->setValue(0);}return;
 		player->setTCeptr(player->getStamp(ui->hsTimer->value()),ui->hsTimer->value());
 		offset=ui->hsTimer->value()/100.*player->getFtime();
 		char ts[100];
diff --git a/qmidiplayer-desktop/qmpsettingswindow.cpp b/qmidiplayer-desktop/qmpsettingswindow.cpp
index 81ac364..2d6912c 100644
--- a/qmidiplayer-desktop/qmpsettingswindow.cpp
+++ b/qmidiplayer-desktop/qmpsettingswindow.cpp
@@ -328,12 +328,19 @@ void qmpSettingsWindow::updateCustomOptions()
 	for(auto i=customOptions.begin();i!=customOptions.end();++i)
 	switch(i->second.type)
 	{
-		case 0:case 1:
+		case 0:
 		{
 			QSpinBox* sb=(QSpinBox*)i->second.widget;if(!i->second.widget)break;
 			settings->setValue(QString(i->first.c_str()),sb->value());
 			break;
 		}
+		case 1:
+		{
+			QHexSpinBox* sb=(QHexSpinBox*)i->second.widget;if(!i->second.widget)break;
+			int v=sb->value();
+			settings->setValue(QString(i->first.c_str()),*reinterpret_cast<unsigned int*>(&v));
+			break;
+		}
 		case 2:
 		{
 			if(!i->second.widget)break;
@@ -418,7 +425,7 @@ void qmpSettingsWindow::registerOptionUint(std::string tab,std::string desc,std:
 			ui->tabWidget->addTab(w,QString(tab.c_str()));
 			customOptPages[tab]=page;
 		}
-		QSpinBox* sb=new QSpinBox(page->parentWidget());
+		QHexSpinBox* sb=new QHexSpinBox(page->parentWidget());
 		QLabel* lb=new QLabel(desc.c_str(),page->parentWidget());
 		customOptions[key].widget=sb;
 		sb->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed);
@@ -426,8 +433,7 @@ void qmpSettingsWindow::registerOptionUint(std::string tab,std::string desc,std:
 		int row=page->rowCount();
 		page->addWidget(lb,row,0);
 		page->addWidget(sb,row,1);
-		sb->setMaximum(max);
-		sb->setMinimum(min);
+		//sb->setMaximum(i(max));sb->setMinimum(i(min));
 		sb->setValue(settings->value(QString(key.c_str()),defaultval).toUInt());
 	}
 }
@@ -439,7 +445,7 @@ void qmpSettingsWindow::setOptionUint(std::string key,unsigned val)
 {
 	settings->setValue(QString(key.c_str()),val);
 	if(customOptions[key].widget)
-	((QSpinBox*)customOptions[key].widget)->setValue(val);
+	((QHexSpinBox*)customOptions[key].widget)->setValue(val);
 }
 
 void qmpSettingsWindow::registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval)
diff --git a/qmidiplayer-desktop/qmpsettingswindow.hpp b/qmidiplayer-desktop/qmpsettingswindow.hpp
index efa69d5..3820279 100644
--- a/qmidiplayer-desktop/qmpsettingswindow.hpp
+++ b/qmidiplayer-desktop/qmpsettingswindow.hpp
@@ -7,6 +7,7 @@
 #include <QSettings>
 #include <QListWidget>
 #include <QComboBox>
+#include <QSpinBox>
 #include <QFormLayout>
 #include "qmpplugin.hpp"
 
@@ -21,6 +22,41 @@ struct qmpCustomOption
 	QVariant defaultval,minv,maxv;
 };
 
+class QHexSpinBox:public QSpinBox
+{
+	public:
+		QHexSpinBox(QWidget *parent=0):QSpinBox(parent)
+		{
+			setPrefix("0x");
+			setDisplayIntegerBase(16);
+			setRange(-0x80000000,0x7FFFFFFF);
+		}
+	protected:
+		QString textFromValue(int value)const
+		{
+			return QString::number(u(value),16).toUpper();
+		}
+		int valueFromText(const QString &text)const
+		{
+			return i(text.toUInt(0,16));
+		}
+		QValidator::State validate(QString &input,int &pos)const
+		{
+			QString t=input;
+			if(t.startsWith("0x"))t.remove(0,2);
+			pos-=t.size()-t.trimmed().size();t=t.trimmed();
+			if(t.isEmpty())return QValidator::Intermediate;
+			input=QString("0x")+t.toUpper();
+			bool okay;t.toUInt(&okay,16);
+			if(!okay)return QValidator::Invalid;
+			return QValidator::Acceptable;
+		}
+		inline unsigned int u(int i)const
+		{return *reinterpret_cast<unsigned int*>(&i);}
+		inline int i(unsigned int u)const
+		{return *reinterpret_cast<int*>(&u);}
+};
+
 class qmpSettingsWindow:public QDialog
 {
 	Q_OBJECT
diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp
index 70299a6..f2c663e 100644
--- a/visualization/qmpvisualization.cpp
+++ b/visualization/qmpvisualization.cpp
@@ -8,9 +8,10 @@
 int viewdist=100;
 int notestretch=100;//length of quarter note
 int minnotelength=100;
-int noteappearance=1,showpiano=1,stairpiano=1,savevp=1;
+int noteappearance=1,showpiano=1,stairpiano=1,savevp=1,showlabel=1;
 int wwidth=800,wheight=600,wsupersample=1,wmultisample=1;
 int fov=60,vsync=1,tfps=60;
+DWORD chkrtint=0xFF999999;
 DWORD iccolors[]={0XFFFF0000,0XFFFF8000,0XFFFFBF00,0XFFFFFF00,
 				  0XFFBFFF00,0XFF80FF00,0XFF00FF00,0XFF00FFBF,
 				  0XFF00FFFF,0XFF333333,0XFF00BFFF,0XFF007FFF,
@@ -54,12 +55,14 @@ void qmpVisualization::showThread()
 	noteappearance=api->getOptionBool("Visualization/3dnotes");
 	showpiano=api->getOptionBool("Visualization/showpiano");
 	stairpiano=api->getOptionBool("Visualization/stairpiano");
+	showlabel=api->getOptionBool("Visualization/showlabel");
 	savevp=api->getOptionBool("Visualization/savevp");
 	vsync=api->getOptionBool("Visualization/vsync");
 	tfps=api->getOptionInt("Visualization/tfps");
 	viewdist=api->getOptionInt("Visualization/viewdist");
 	notestretch=api->getOptionInt("Visualization/notestretch");
 	minnotelength=api->getOptionInt("Visualization/minnotelen");
+	chkrtint=api->getOptionUint("Visualization/chkrtint");
 	sm=smGetInterface(SMELT_APILEVEL);
 	sm->smVidMode(wwidth,wheight,true);
 	sm->smUpdateFunc(h);sm->smQuitFunc(closeh);
@@ -77,6 +80,8 @@ void qmpVisualization::showThread()
 	tdscn=sm->smTargetCreate(wwidth*wsupersample,wheight*wsupersample,wmultisample);
 	if(!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",16))
 	printf("W: Font load failed.\n");
+	if(!fonthdpi.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",180))
+	printf("W: Font load failed.\n");
 	if(!font2.loadTTF("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",16))
 	printf("W: Font load failed.\n");
 	pos[0]=0;pos[1]=120;pos[2]=70;
@@ -120,6 +125,7 @@ void qmpVisualization::close()
 	}
 	font.releaseTTF();
 	font2.releaseTTF();
+	fonthdpi.releaseTTF();
 	sm->smTextureFree(chequer);
 	if(bgtex)sm->smTextureFree(bgtex);
 	sm->smTargetFree(tdscn);
@@ -142,7 +148,7 @@ bool qmpVisualization::update()
 {
 	smQuad q;
 	for(int i=0;i<4;++i)
-	{q.v[i].col=0xFF999999;q.v[i].z=showpiano?-5:0;}
+	{q.v[i].col=chkrtint;q.v[i].z=showpiano?-5:0;}
 	q.tex=chequer;q.blend=BLEND_ALPHABLEND;
 	q.v[0].x=q.v[3].x=-120;q.v[1].x=q.v[2].x=120;
 	q.v[0].y=q.v[1].y=-120;q.v[2].y=q.v[3].y=120;
@@ -212,10 +218,14 @@ bool qmpVisualization::update()
 			p3d[i]->setKeyTravelDist(j,traveld[i][j]/10.);
 		}
 		p3d[i]->render(smvec3d(0.756*api->getPitchBend(i),stairpiano?55-i*7:62-i*8,stairpiano*i*2));
-		std::string s=api->getChannelPresetString(i);
-		wchar_t ws[1024];mbstowcs(ws,s.c_str(),1024);
-		font.updateString(ws);
-		//font.render(-42,stairpiano?55-i*7:62-i*8,stairpiano*i*2,0xFFFFFFFF,ALIGN_RIGHT);
+		if(showlabel)
+		{
+			std::string s=api->getChannelPresetString(i);
+			wchar_t ws[1024];mbstowcs(ws,s.c_str(),1024);
+			fonthdpi.updateString(ws);
+			fonthdpi.render(-49,stairpiano?56-i*7:63-i*8,stairpiano*i*2+0.1,0xFFFFFFFF,ALIGN_RIGHT,.008,0.01);
+			fonthdpi.render(-49.05,stairpiano?56.05-i*7:63.05-i*8,stairpiano*i*2+0.2,0xFF000000,ALIGN_RIGHT,.008,0.01);
+		}
 	}
 	if(playing)ctk+=(int)(1e6/(api->getRawTempo()/api->getDivision())*sm->smGetDelta());
 	while(pool.size()&&elb<pool.size()&&((double)ctk-pool[elb]->tce)*lpt>viewdist*2)++elb;
@@ -291,6 +301,7 @@ void qmpVisualization::init()
 	api->registerOptionBool("Visualization-Appearance","Show Piano","Visualization/showpiano",true);
 	api->registerOptionBool("Visualization-Appearance","3D Notes","Visualization/3dnotes",true);
 	api->registerOptionBool("Visualization-Appearance","Arrange channels on a stair","Visualization/stairpiano",true);
+	api->registerOptionBool("Visualization-Appearance","Show channel labels","Visualization/showlabel",true);
 	api->registerOptionBool("Visualization-Video","Enable VSync","Visualization/vsync",true);
 	api->registerOptionBool("Visualization-Video","Save Viewport","Visualization/savevp",true);
 	api->registerOptionInt("Visualization-Video","Window Width","Visualization/wwidth",320,3200,800);
@@ -302,6 +313,7 @@ void qmpVisualization::init()
 	api->registerOptionInt("Visualization-Appearance","View distance","Visualization/viewdist",20,1000,100);
 	api->registerOptionInt("Visualization-Appearance","Note stretch","Visualization/notestretch",20,500,100);
 	api->registerOptionInt("Visualization-Appearance","Minimum note length","Visualization/minnotelen",20,500,100);
+	api->registerOptionUint("Visualization-Appearance","Chequer board tint","Visualization/chkrtint",0,0xFFFFFFFF,0xFF999999);
 	api->registerOptionString("Visualization-Appearance","Background Image","Visualization/background","");
 	api->registerOptionDouble("","","Visualization/px",-999999999,999999999,0);
 	api->registerOptionDouble("","","Visualization/py",-999999999,999999999,120);
@@ -317,12 +329,14 @@ void qmpVisualization::init()
 	noteappearance=api->getOptionBool("Visualization/3dnotes");
 	showpiano=api->getOptionBool("Visualization/showpiano");
 	stairpiano=api->getOptionBool("Visualization/stairpiano");
+	showlabel=api->getOptionBool("Visualization/showlabel");
 	savevp=api->getOptionBool("Visualization/savevp");
 	vsync=api->getOptionBool("Visualization/vsync");
 	tfps=api->getOptionInt("Visualization/tfps");
 	viewdist=api->getOptionInt("Visualization/viewdist");
 	notestretch=api->getOptionInt("Visualization/notestretch");
 	minnotelength=api->getOptionInt("Visualization/minnotelen");
+	chkrtint=api->getOptionUint("Visualization/chkrtint");
 }
 void qmpVisualization::deinit()
 {
diff --git a/visualization/qmpvisualization.hpp b/visualization/qmpvisualization.hpp
index 6cac638..3305f4f 100644
--- a/visualization/qmpvisualization.hpp
+++ b/visualization/qmpvisualization.hpp
@@ -49,7 +49,7 @@ class qmpVisualization:public qmpPluginIntf
 		SMELT *sm;
 		SMTRG tdscn;
 		SMTEX chequer,bgtex;
-		smTTFont font,font2;
+		smTTFont font,font2,fonthdpi;
 		qmpVirtualPiano3D* p3d[16];
 		smEntity3DBuffer* nebuf;
 		float pos[3],rot[3],lastx,lasty;
-- 
cgit v1.2.3