/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQColourHelp.h"

#include <QDebug>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QRegExpValidator>
#include <QSpinBox>
#include <QTabWidget>
#include <QToolButton>
#include <QVBoxLayout>

#include <math.h>

#include "HelpFactory.h"
#include "RequestPanel.h"

#include "MvQPalette.h"

static const float toRadFactor=3.14159265359/180.;
static const float toDegFactor=180./3.14159265359;

//==============================
// 
// MvQColourGrid
//
//===============================

MvQColourGrid::MvQColourGrid(QWidget *parent) : 
  QWidget(parent),
  cellsPerRow_(8)
{
	MvQPalette::scan(*this);
	
	sort();
	
	setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
	setMinimumSize(QSize(128,128));
	
	setMouseTracking(true);
}  

//Soring the colours
void MvQColourGrid::sort()
{
 	QMap<float,MvQColourItem> sm;
	foreach(MvQColourItem item,items_) 
	{
	  	float sv=item.col_.hueF();
		//float sv=item.col_.lightnessF() * 5. + item.col_.hslSaturationF() * 2 + item.col_.hueF();
	  	//float sv=sqrt(0.299 * pow(item.col_.redF(),2.0) + 0.587 * pow(item.col_.greenF(),2.0) + 0.114 * pow(item.col_.blueF(),2.));	  	
	  	sm.insertMulti(sv,item);
	}
	
	items_.clear();
	QMap<float,MvQColourItem>::const_iterator it=sm.constBegin();
        while (it != sm.constEnd()) 
	{ 
		items_ << it.value();
		++it;
	}	
}  	

void MvQColourGrid::next(const string& name,QColor col,bool pseudo)
{
  	if(!pseudo)
  		items_ << MvQColourItem(col,QString::fromStdString(name));
}

void MvQColourGrid::resizeEvent(QResizeEvent */*event*/) 
{
	int w=width();
    	int h=height(); 
	gridSize_=(w<h)?w:h;
	cellSize_=gridSize_/cellsPerRow_;
    	
    	createGrid();
}

void MvQColourGrid::paintEvent(QPaintEvent */*event*/)
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing);

    	//Render ring pixmap
    	painter.drawPixmap(0,0,pix_);
}

void MvQColourGrid::createGrid()
{ 
	QPalette pal=palette();
	
    	pix_=QPixmap(gridSize_,gridSize_);
		
	QPainter painter(&pix_);   
    	//painter.setRenderHint(QPainter::Antialiasing);
        //pal.window().color()
	
    	pix_.fill(pal.window().color());

    	for(int i=0; i < items_.count(); i++)
	{
	  	int row=i/cellsPerRow_;
	        int col=i-row*cellsPerRow_;  
	  	painter.fillRect(col*cellSize_,row*cellSize_,cellSize_,cellSize_,items_[i].col_);
	}
	
	painter.setPen(pal.window().color());
	for(int i=1; i < cellsPerRow_; i++)
	{
	  	painter.drawLine(i*cellSize_,0,i*cellSize_,gridSize_);
		painter.drawLine(0,i*cellSize_,gridSize_,i*cellSize_);
	}		
}

void MvQColourGrid::mousePressEvent(QMouseEvent *event)
{
	int idx=index(event->pos());
	if(idx >= 0 && idx < items_.count())
	{	  
		emit selected(items_[idx].col_);

	}
}

void MvQColourGrid::mouseMoveEvent(QMouseEvent *event)
{
	if(event->buttons() != Qt::NoButton)
		return;
	
	int idx=index(event->pos());
	if(idx >= 0 && idx < items_.count())
	{	  
		setToolTip(items_[idx].name_);
	
	}
}	

int MvQColourGrid::index(QPoint pos)
{
  	int row=pos.y()/cellSize_;
  	int col=pos.x()/cellSize_;
	
	return row*cellsPerRow_+col;
}	

//==============================
// 
// MvQColourWheel
//
//===============================

MvQColourWheel::MvQColourWheel(QWidget *parent) : 
  QWidget(parent),
  ringWidth_(14),
  outerRadius_(128),
  innerRadius_(108),
  hue_(0),
  sat_(128),
  lgt_(128),
  lgtSatSelectorRadius_(4),
  dragType_(NoDrag)
{
	huePenBlack_=QPen(Qt::black,2.,Qt::SolidLine);
  	huePenWhite_=QPen(Qt::white,2.,Qt::SolidLine);
  
  	setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
	setMinimumSize(QSize(128,128));
	
	setMouseTracking(true);
}  
  
void MvQColourWheel::resizeEvent(QResizeEvent */*event*/) 
{
	int w=width();
    	int h=height(); 
	outerRadius_=(w<h)?w:h;
	outerRadius_/=2;
	innerRadius_=outerRadius_-ringWidth_;
	centre_=QPoint(w/2,h/2);
	
	//Create a hue ring pixmap
    	createRing();
		
	//Create the lgt-sat triangle pixmap
	createTriangle();	
}

void MvQColourWheel::paintEvent(QPaintEvent */*event*/)
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing);

    	//Render ring pixmap
    	painter.drawPixmap(centre_.x()-outerRadius_,centre_.y()-outerRadius_,ringPix_);
	
	//Render the hue selector onto the ring
	renderHueSelector(&painter);
	
	//Render lgt-sat triangle 
	painter.drawPixmap(centre_.x()-innerRadius_,centre_.y()-innerRadius_,triPix_);
		
	//Render the lgt-sat selector onto the triangle 
	renderLgtSatSelector(&painter);

}

//Render the ring into a pixmap  
void MvQColourWheel::createRing()
{ 
	QPalette pal=palette();
	
    	ringPix_=QPixmap(2*outerRadius_,2*outerRadius_);
		
	QPainter painter(&ringPix_);   
    	painter.setRenderHint(QPainter::Antialiasing);
        
    	ringPix_.fill(pal.window().color());

    	QConicalGradient cg(0, 0, 0);
    	cg.setColorAt(0.0, Qt::red);
    	cg.setColorAt(60.0/360.0, Qt::yellow);
    	cg.setColorAt(120.0/360.0, Qt::green);
    	cg.setColorAt(180.0/360.0, Qt::cyan);
    	cg.setColorAt(240.0/360.0, Qt::blue);
    	cg.setColorAt(300.0/360.0, Qt::magenta);
    	cg.setColorAt(1.0, Qt::red);
    
    	painter.translate(outerRadius_,outerRadius_);

    	//Coloured circle
   	QBrush brush(cg);
   	painter.setPen(Qt::NoPen);
    	painter.setBrush(brush);
    	painter.drawEllipse(QPoint(0,0),outerRadius_,outerRadius_);
    
    	//Inner clipping circle
   	painter.setBrush(pal.window());
   	painter.drawEllipse(QPoint(0,0),innerRadius_,innerRadius_);	
}

void MvQColourWheel::createTriangle()
{
	int nx=256;
    	int ny=256;
    	float tFactor=sqrt(3)/2.;
       	
	QImage img(nx,ny,QImage::Format_ARGB32_Premultiplied);

    	QColor col;   
    	for(int j=0;j<ny;j++)
    	{
		int chroma=255-j;				
		for(int i=0;i< nx; i++)
		{           				
			int lgt=i;
		  	if(abs(nx/2-i) < j/2)
			{  		  
		 		int sat=saturation(chroma,lgt);				
			  	col = QColor::fromHsl(hue_,sat,lgt);		
				img.setPixel(i,j,col.rgb());
			}
			else
			{
				img.setPixel(i,j,qRgba(0,0,0,0));			
			}		
       		}
	}
    
    	float h=innerRadius_*1.5;
    	float w=h/tFactor;   
    	img = img.scaled(w,h,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
    
	triPix_=QPixmap(innerRadius_*2,innerRadius_*2);
	triPix_.fill(Qt::transparent);
	
   	QPainter painter(&triPix_);   
    	painter.setRenderHint(QPainter::Antialiasing);
		
	painter.translate(innerRadius_,innerRadius_); 
    	painter.rotate(90-hue_);
    	painter.translate(-w/2,-(innerRadius_));    
    	painter.drawImage(0,0,img);
}

void MvQColourWheel::renderHueSelector(QPainter *painter)
{
	float alpha=-hue_*toRadFactor;
  	float x=innerRadius_*cos(alpha);
	float y=innerRadius_*sin(alpha);
	float x1=outerRadius_*cos(alpha);
	float y1=outerRadius_*sin(alpha);
	
	painter->translate(centre_.x(),centre_.y());
	
	if(hue_ > 20 && hue_ < 200)
		painter->setPen(huePenBlack_);
	else
	  	painter->setPen(huePenWhite_);
	painter->drawLine(x,y,x1,y1);
	painter->translate(-centre_.x(),-centre_.y());
}  
  
void MvQColourWheel::renderLgtSatSelector(QPainter *painter)
{
	QPointF pos;	
	lgtSatToPos(pos);	
	lgtSatPos_=pos.toPoint();
	
	painter->drawEllipse(centre_+ pos,lgtSatSelectorRadius_,lgtSatSelectorRadius_);
}  
      
void MvQColourWheel::mousePressEvent(QMouseEvent *event)
{
	QPoint delta=event->pos()-centre_-lgtSatPos_;
	
	if(delta.x()*delta.x()+delta.y()*delta.y() <= lgtSatSelectorRadius_*lgtSatSelectorRadius_)
	{
	  	lgtSatOffset_=delta;
		dragType_=TriangleDrag;
	}	
  	else
	{
	  	lgtSatOffset_=QPoint();
	  	dragType_=checkPoint(event->pos());
	}	
}

void MvQColourWheel::mouseMoveEvent(QMouseEvent *event)
{
	if(dragType_ == TriangleDrag)
	{
		dragTriangleSelector(event->pos());
	}
	else if(dragType_ == RingDrag)
	{  	  
	 	dragRingSelector(event->pos());
	}	
}

void MvQColourWheel::mouseReleaseEvent(QMouseEvent* /*event*/)
{
  	//Drag happened
	bool dragHappened=(dragType_ != NoDrag);
  	
  	dragType_ = NoDrag;
	lgtSatOffset_=QPoint(0,0);
	dragPos_=QPoint();	
	
	if(dragHappened)
	  	emit dragFinished();
}


void MvQColourWheel::dragRingSelector(QPoint pos)
{
	if(dragType_ != RingDrag)
	  	return;
	
	QPoint dp=pos-centre_;
	int hue =atan2(dp.x() ,dp.y())*toDegFactor-90.;
	if(hue < 0 ) hue+=360;
		
	setHue(hue);
}

void MvQColourWheel::dragTriangleSelector(QPoint pos)
{
	if(dragType_ != TriangleDrag)
	  	return;
	
	QPoint dp=pos-lgtSatOffset_-centre_;	

	int lgt,sat;
	if(projectPosToLgtSat(dp,lgt,sat))
	{
		setLgtSat(lgt,sat);	
	}		  
}

MvQColourWheel::DragType MvQColourWheel::checkPoint(QPoint pos)
{
	int fullRad=height()/2;
  	int rad=height()/2-ringWidth_;
	int dx=pos.x()-fullRad;
	int dy=pos.y()-fullRad;
	int d=sqrt(dx*dx+dy*dy);
	int ringTolerance=10;
	
	if(d > rad && d < rad+ringWidth_+ringTolerance && dragType_!= TriangleDrag)
	{
	  	int hue =atan2(dx ,dy)*180./3.14-90;
		if(hue < 0 ) hue+=360;
		
		setHue(hue);
		return RingDrag;
	}
	
	else if(d <= rad && dragType_!=RingDrag)
	{
		QPointF pp(dx,dy);
		int lgt,sat;
		if(posToLgtSat(pp,lgt,sat))
		{
			setLgtSat(lgt,sat);	
			return TriangleDrag;
		}		
		else if(d >= rad-ringTolerance && d < rad+ringWidth_+ringTolerance)
		{
		  	int hue =atan2(dx ,dy)*180./3.14-90;
			if(hue < 0 ) hue+=360;
		
			setHue(hue);
			return RingDrag;
		}
	}
	
	return NoDrag;
}	

bool MvQColourWheel::lgtSatToPos(QPointF &pos)
{
	int chromaVal=chroma(sat_,lgt_);
  
  	float yt=innerRadius_-(255.-chromaVal)*(1.5*static_cast<float>(innerRadius_))/255.;
	float xt=static_cast<float>(innerRadius_)*sqrt(3.)*(lgt_-128)/255.;
	
	float alpha=(hue_-90)*toRadFactor;
	float x=cos(alpha)*xt-sin(alpha)*yt;
	float y=sin(alpha)*xt+cos(alpha)*yt; 
	
	pos=QPointF(x,-y);
	
	//qDebug() << "lgtSat" << sat_ << lgt_ << pos;
	
	return true;
}

bool MvQColourWheel::posToLgtSat(QPointF pos,int &lgt, int &sat)
{
	//Transform coordinate system 
	float alpha=-(hue_-90)*toRadFactor;
	float xt=cos(alpha)*pos.x()+sin(alpha)*pos.y();
	float yt=sin(alpha)*pos.x()-cos(alpha)*pos.y(); 
		
	if(yt < innerRadius_ && yt > -innerRadius_/2. && 
	   fabs(xt)  <= (innerRadius_-yt)/2 )
	{
		int chroma=255.-255.*(innerRadius_-yt)/(1.5*static_cast<float>(innerRadius_));
		lgt=128.+255.*xt/(static_cast<float>(innerRadius_)*sqrt(3.));
		sat=saturation(chroma,lgt);
		
		return true;
	}
	
	return false;
}

bool MvQColourWheel::projectPosToLgtSat(QPointF pos,int &lgt, int &sat)
{
	//Transform coordinate system 
	float alpha=-(hue_-90)*toRadFactor;
	float xt=cos(alpha)*pos.x()+sin(alpha)*pos.y();
	float yt=sin(alpha)*pos.x()-cos(alpha)*pos.y(); 
		
	if(yt < innerRadius_ && yt > -innerRadius_/2. && 
	   fabs(xt)  <= (innerRadius_-yt)/2 )
	{
		int chroma=255.-255.*(innerRadius_-yt)/(1.5*static_cast<float>(innerRadius_));
		lgt=128.+255.*xt/(static_cast<float>(innerRadius_)*sqrt(3.));
		sat=saturation(chroma,lgt);
		
		return true;
	}
	else if(yt < innerRadius_ && yt > -innerRadius_/2.)
	{
	  	int chroma=255.-255.*(innerRadius_-yt)/(1.5*static_cast<float>(innerRadius_));
		
		lgt=128.+255.*((xt>0)?1:-1)*((innerRadius_-yt)/2)/(static_cast<float>(innerRadius_)*sqrt(3.));
		
		sat=saturation(chroma,lgt);		
		return true;
	}
	else if(fabs(xt)  <= (innerRadius_-yt)/2 )
	{
		int chromaVal=chroma(sat_,lgt_);
	  	lgt=128.+255.*xt/(static_cast<float>(innerRadius_)*sqrt(3.));
		sat=saturation(chromaVal,lgt);	
		return true;
	}
	
	return false;
}


void MvQColourWheel::setHue(int hue)
{
	hue_=hue;
	
	createTriangle();
	
	update();
	
	emit hslSelected(hue_,sat_,lgt_);
}	

void MvQColourWheel::setLgtSat(int lgt, int sat)
{
	lgt_=lgt;
	sat_=sat;
	
	update();
	
	emit hslSelected(hue_,sat_,lgt_);
}	

void MvQColourWheel::slotSetColour(int hue, int sat,int lgt)
{
  	hue_=hue;
	lgt_=lgt;
	sat_=sat;

	createTriangle();
	
	update();
}

void MvQColourWheel::initColour(QColor col)
{
  	int hue=col.hslHue();
	int lgt=col.lightness();
	int sat=col.hslSaturation();
	
	slotSetColour(hue,sat,lgt);
	//The problem is that several RGB valuse can be mapped to the same 
	//HSL value. So what we emit here is the original colour!
	//emit hslSelected(hue_,sat_,lgt_);
	emit colourSelected(col);
}

int MvQColourWheel::saturation(int chroma, int lgt)
{  
	float chromaNorm=static_cast<int>(chroma)/255.;
	float lgtNorm=static_cast<int>(lgt)/255.;
	
	return (chroma == 0)?0:255.*chromaNorm/(1-fabs(2.*lgtNorm-1));
}		
			
int MvQColourWheel::chroma(int sat, int lgt)
{  
	float satNorm=static_cast<int>(sat)/255.;
	float lgtNorm=static_cast<int>(lgt)/255.;
	
	return (sat == 0)?0:255.*satNorm*(1-fabs(2.*lgtNorm-1));
}

//==============================
// 
// MvQColourSelectionWidget
//
//===============================

MvQColourSelectionWidget::MvQColourSelectionWidget(QWidget *parent) : 
    QWidget(parent), 
    ignoreRgbSpin_(false),
    ignoreHslSpin_(false),
    ignoreHtmlEdit_(false),
    ignoreMacroEdit_(false)
{	
  	QLabel *label;
	
	QHBoxLayout *hb=new QHBoxLayout(this);
	
	//--------------
	// Left
	//--------------
	
	tab_=new QTabWidget(this);
	hb->addWidget(tab_);
	
	wheel_= new MvQColourWheel(this);
    	tab_->addTab(wheel_,tr("Wheel"));
		
	grid_= new MvQColourGrid(this);
    	tab_->addTab(grid_,tr("Grid"));
	
	//----------------
	// Right
	//----------------
	
	QVBoxLayout *rightVb=new QVBoxLayout(); 
	hb->addSpacing(4);
	hb->addLayout(rightVb);
	
	//Col def hb
	QHBoxLayout *colDefHb=new QHBoxLayout();
	rightVb->addLayout(colDefHb);
	
	//RGB
	QGridLayout *rgbGrid=new QGridLayout(); 
	colDefHb->addLayout(rgbGrid);
	
	QStringList rgbNames;
	rgbNames << tr("Red:") << tr("Green:")  << tr("Blue:"); 
	for(int i=0; i < 3; i++)
	{
		label = new QLabel(rgbNames[i],this);
		rgbGrid->addWidget(label,i,0);
		
		QSpinBox *sp=new QSpinBox(this);
		sp->setRange(0,255);
		rgbGrid->addWidget(sp,i,1);
		rgbSpin_ << sp;
	}	
	rgbGrid->setColumnStretch(2,1);
	
	colDefHb->addSpacing(20);
	
	
	//HSL
	QGridLayout *hslGrid=new QGridLayout();
	colDefHb->addLayout(hslGrid);
	
	QStringList hslNames;
	hslNames << tr("Hue:") << tr("Sat:")  << tr("Light:"); 
	for(int i=0; i < 3; i++)
	{
		//QHBoxLayout *colHb=new QHBoxLayout(this); 	  
		//hslgrid->addLayout(colHb,i,0);
		
		label = new QLabel(hslNames[i],this);
		hslGrid->addWidget(label,i,0);
		
		QSpinBox *sp=new QSpinBox(this);
		sp->setRange(0,(i==0)?359:255);
		hslGrid->addWidget(sp,i,1);
		hslSpin_ << sp;
	}
	hslGrid->setColumnStretch(2,1);	
	
	//
	QHBoxLayout *selHb=new QHBoxLayout();
	rightVb->addLayout(selHb);
	
	//Html
	label=new QLabel(tr("HTML:"),this);
	htmlEdit_=new QLineEdit(this);
	selHb->addWidget(label);
	selHb->addWidget(htmlEdit_);
	
	//HTML colour validator
	QRegExp rx("#?[A-f|0-9]{6}");
	QRegExpValidator *val=new QRegExpValidator(rx,this);
	htmlEdit_->setValidator(val);
	//selHb->addStretch(1);
	
	hb->addStretch(1);
		
	//Metview macro colour
	QHBoxLayout *macroHb=new QHBoxLayout();
	rightVb->addLayout(macroHb);
	
	label=new QLabel(tr("Macro:"),this);
	macroEdit_=new QLineEdit(this);
	macroHb->addWidget(label);
	macroHb->addWidget(macroEdit_);
	
	//Macro colour validator
	QRegExp rxMacro("\\'RGB\\(\\d*\\.?\\d*,\\d*\\.?\\d*,\\d*\\.?\\d*\\)\\'");
	QRegExpValidator *valMacro=new QRegExpValidator(rxMacro,this);
	macroEdit_->setValidator(valMacro);

	//----------------
	//Signals and slots
	//----------------

	//Wheel
   	connect(wheel_, SIGNAL(hslSelected(int,int,int)), 
		 this, SLOT(slotWheelChanged(int,int,int)));
  
		 
	connect(wheel_, SIGNAL(colourSelected(QColor)), 
		 this, SLOT(slotWheelChanged(QColor)));	 
		 
	for(int i=0; i < 3; i++)	 
	{
	  	connect(hslSpin_[i],SIGNAL(valueChanged(int)),
			this,SLOT(slotHslChanged(int)));
	}
	
	for(int i=0; i < 3; i++)	 
	{
	  	connect(rgbSpin_[i],SIGNAL(valueChanged(int)),
			this,SLOT(slotRgbChanged(int)));
	}
	
	connect(htmlEdit_,SIGNAL(textChanged(QString)),
			this,SLOT(slotHtmlChanged(QString)));
		 
	connect(macroEdit_,SIGNAL(textChanged(QString)),
			this,SLOT(slotMacroChanged(QString)));
						
	connect(this,SIGNAL(colourChanged(int,int,int)),
		wheel_,SLOT(slotSetColour(int,int,int)));
			
	
	//Grid	
	connect(grid_, SIGNAL(selected(QColor)), 
		 this, SLOT(slotGridSelected(QColor)));	
		 
	//Notify about drag finished
	connect(wheel_,SIGNAL(dragFinished()),
		this,SIGNAL(dragFinished()));
		 
		
}

void MvQColourSelectionWidget::setColour(QColor col)
{  	
  	wheel_->initColour(col);	
}  

void MvQColourSelectionWidget::setCurrentColour(QColor colour)
{
    	currentColour_ = colour;	
	emit colourSelected(currentColour_);
}

void MvQColourSelectionWidget::slotGridSelected(QColor col)
{
	ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreHtmlEdit_=true;
	ignoreMacroEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
	hslSpin_[0]->setValue(col.hslHue());
	hslSpin_[1]->setValue(col.hslSaturation());
	hslSpin_[2]->setValue(col.lightness());
	
	htmlEdit_->setText(col.name());
	macroEdit_->setText(macroToString(col));

	ignoreRgbSpin_=false;
	ignoreHslSpin_=false;
	ignoreHtmlEdit_=false;
	ignoreMacroEdit_=false; 	
	
	emit colourChanged(hslSpin_[0]->value(),
		   	hslSpin_[1]->value(),
		   	hslSpin_[2]->value());
			
			
	setCurrentColour(col);		
}

void MvQColourSelectionWidget::slotWheelChanged(int hue, int sat,int lgt)
{
	QColor col=QColor::fromHsl(hue,sat,lgt);

	ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreHtmlEdit_=true;
	ignoreMacroEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
	hslSpin_[0]->setValue(hue);
	hslSpin_[1]->setValue(sat);
	hslSpin_[2]->setValue(lgt);
	
	htmlEdit_->setText(col.name());
	macroEdit_->setText(macroToString(col));
	
	ignoreRgbSpin_=false;
	ignoreHslSpin_=false;
	ignoreHtmlEdit_=false;
	ignoreMacroEdit_=false; 
	
	setCurrentColour(col);		
}

void MvQColourSelectionWidget::slotWheelChanged(QColor col)
{
	ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreHtmlEdit_=true;
	ignoreMacroEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
	hslSpin_[0]->setValue(col.hslHue());
	hslSpin_[1]->setValue(col.hslSaturation());
	hslSpin_[2]->setValue(col.lightness());
	
	htmlEdit_->setText(col.name());
	macroEdit_->setText(macroToString(col));
	
	ignoreRgbSpin_=false;
	ignoreHslSpin_=false;
	ignoreHtmlEdit_=false;
	ignoreMacroEdit_=false; 
	
	setCurrentColour(col);	
	
}

void MvQColourSelectionWidget::slotRgbChanged(int)
{
	if(ignoreRgbSpin_)
	  	return;
		
	ignoreHslSpin_=true;
	ignoreHtmlEdit_=true;
	ignoreMacroEdit_=true;
	
	QColor col(rgbSpin_[0]->value(),
		   rgbSpin_[1]->value(),
		   rgbSpin_[2]->value());
	
	qDebug() << "RGB" << rgbSpin_[0]->value() << rgbSpin_[1]->value() << rgbSpin_[2]->value() <<col;	   
		   
	hslSpin_[0]->setValue(col.hslHue());
	hslSpin_[1]->setValue(col.hslSaturation());
	hslSpin_[2]->setValue(col.lightness());
		
	htmlEdit_->setText(col.name());
	macroEdit_->setText(macroToString(col));
		
	ignoreHslSpin_=false;
	ignoreHtmlEdit_=false;	
	ignoreMacroEdit_=false; 
	
	emit colourChanged(hslSpin_[0]->value(),
		   	hslSpin_[1]->value(),
		   	hslSpin_[2]->value());
			
	setCurrentColour(col);
}

void MvQColourSelectionWidget::slotHslChanged(int)
{
	if(ignoreHslSpin_)
	  	return;
	
	ignoreRgbSpin_=true;
	ignoreHtmlEdit_=true;
	ignoreMacroEdit_=true;
	
	QColor col=QColor::fromHsl(hslSpin_[0]->value(),
		   hslSpin_[1]->value(),
		   hslSpin_[2]->value());
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
	htmlEdit_->setText(col.name());
	macroEdit_->setText(macroToString(col));
	
	ignoreRgbSpin_=false;
	ignoreHtmlEdit_=false;
	ignoreMacroEdit_=false; 
	
	emit colourChanged(hslSpin_[0]->value(),
		   	hslSpin_[1]->value(),
		   	hslSpin_[2]->value());
			
	setCurrentColour(col);
}


void MvQColourSelectionWidget::slotHtmlChanged(QString txt)
{	
	if(ignoreHtmlEdit_)
	  	return;
	
	QColor col(txt);
	if(!col.isValid())
		return;
	
	ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreMacroEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
	hslSpin_[0]->setValue(col.hslHue());
	hslSpin_[1]->setValue(col.hslSaturation());
	hslSpin_[2]->setValue(col.lightness());
	
	macroEdit_->setText(macroToString(col));
	
	ignoreRgbSpin_=false;
	ignoreHslSpin_=false; 
	ignoreMacroEdit_=false; 
	
	emit colourChanged(hslSpin_[0]->value(),
		   	hslSpin_[1]->value(),
		   	hslSpin_[2]->value());
			
	setCurrentColour(col);
	
}

void MvQColourSelectionWidget::slotMacroChanged(QString txt)
{	
	if(ignoreMacroEdit_)
	  	return;
	
	QColor col(macroToColour(txt));
	if(!col.isValid())
		return;
	
	ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreHtmlEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
	hslSpin_[0]->setValue(col.hslHue());
	hslSpin_[1]->setValue(col.hslSaturation());
	hslSpin_[2]->setValue(col.lightness());
	
	htmlEdit_->setText(col.name());
	
	ignoreRgbSpin_=false;
	ignoreHslSpin_=false; 
	ignoreHtmlEdit_=false; 
	
	emit colourChanged(hslSpin_[0]->value(),
		   	hslSpin_[1]->value(),
		   	hslSpin_[2]->value());
			
	setCurrentColour(col);		
}


QString MvQColourSelectionWidget::macroToString(QColor col)
{
	QString txt="'RGB(";
	
	txt+=QString::number(col.redF(),'f',3)+",";
	txt+=QString::number(col.greenF(),'f',3)+",";
	txt+=QString::number(col.blueF(),'f',4)+")'";
		
	return txt;
}

QColor MvQColourSelectionWidget::macroToColour(QString name)
{
	QColor col;
	QRegExp rx("\\'RGB\\((\\d*\\.?\\d*),(\\d*\\.?\\d*),(\\d*\\.?\\d*)\\)\\'");
  		
	if(rx.indexIn(name) > -1 && rx.captureCount() == 3)
	{
	  	col=QColor::fromRgbF(rx.cap(1).toFloat(),
			      rx.cap(2).toFloat(),
			      rx.cap(3).toFloat());
			      
	}
	return col;	
}

//==================================================
//
//  MvQColourHelp
//
//==================================================

MvQColourHelp::MvQColourHelp(RequestPanel& owner,const Parameter& param) :
		   MvQRequestPanelHelp(owner,param)
{
	selector_=new MvQColourSelectionWidget(parentWidget_);//QWidget;
  		
	connect(selector_,SIGNAL(colourSelected(QColor)),
			this,SLOT(slotSelected(QColor)));
			
	connect(selector_,SIGNAL(dragFinished()),
			this,SIGNAL(editConfirmed()));		
}

void MvQColourHelp::slotSelected(QColor col)
{
    	vector <string> vs;
    
	if(MvQPalette::magics(oriName_.toStdString()) == col)
		vs.push_back(oriName_.toStdString());
	else	
    		vs.push_back(MvQPalette::toString(col));

    	emit edited(vs);
}

void MvQColourHelp::refresh(const vector<string>& values)
{
	if(values.size() == 0)
	  	return;
	
	oriName_=QString::fromStdString(values[0]);
	QColor col=MvQPalette::magics(values[0]);
	
	if( (selector_->currentColour() == col ||  
	    MvQPalette::toString(selector_->currentColour()) == values[0]))
		return;  
  	 	
	if(col.isValid())
	{
	  	selector_->setColour(col);
	}
}

//==================================================
//
//  MvQColourListHelp
//
//==================================================

MvQColourListHelp::MvQColourListHelp(RequestPanel& owner,const Parameter& param) :
		   MvQRequestPanelHelp(owner,param)
{
	w_=new QWidget(parentWidget_);
		
	QVBoxLayout* vb=new QVBoxLayout();
	w_->setLayout(vb);
	vb->setContentsMargins(1,1,1,1);
	vb->setSpacing(1);
	
	//Buttons
	
	QHBoxLayout *hb=new QHBoxLayout(w_);
	vb->addLayout(hb);
	hb->setContentsMargins(1,1,1,1);
	hb->setSpacing(1);
	
	resetLabel_=new QLabel(tr("Revert to:"),w_);
	hb->addWidget(resetLabel_);
	hb->addSpacing(2);
	
	oriColorBox_ = new QLabel(w_);
    	oriColorBox_->setFixedHeight(18);
	oriColorBox_->setFixedWidth(24);
     	hb->addWidget(oriColorBox_);
	
	resetTb_ = new QToolButton(w_);
	resetTb_->setToolTip(tr("Revert to original colour"));	
	resetTb_->setIcon(QPixmap(":/desktop/undo_grey.svg"));
	resetTb_->setAutoRaise(true);
	hb->addWidget(resetTb_);
	
	hb->addSpacing(16);
	
	resetLabel_->setEnabled(false);
	oriColorBox_->setEnabled(false);
	resetTb_->setEnabled(false);
	
	connect(resetTb_,SIGNAL(clicked(bool)),
		this,SLOT(slotReset(bool)));
	

	//Colour selector
		
	selector_=new MvQColourSelectionWidget(w_);
  	vb->addWidget(selector_);
	
	connect(selector_,SIGNAL(colourSelected(QColor)),
			this,SLOT(slotSelected(QColor)));		
}

QWidget* MvQColourListHelp::widget() 
{
  	return w_;
}

void MvQColourListHelp::setExternalActions(QList<QAction*> lst) 
{
	if(QHBoxLayout* hb=static_cast<QHBoxLayout*>(w_->layout()->itemAt(0)))
	{
	  	foreach(QAction* ac,lst)
		{
		  	QToolButton *tb=new QToolButton(w_);
			hb->addWidget(tb);
			tb->setDefaultAction(ac);
			//tb->setAutoRaise(true);
		}
		hb->addStretch(1);
	}	
	
	
}	

void MvQColourListHelp::slotSelected(QColor col)
{
    	vector <string> vs;
    
    	vs.push_back(MvQPalette::toString(col));

    	emit edited(vs);
	
	if(col == oriColour_)
	{  
	  	resetLabel_->setEnabled(false);
	  	resetTb_->setEnabled(false);
		oriColorBox_->setEnabled(false);
	}
	else
	{
	  	resetLabel_->setEnabled(true);
		resetTb_->setEnabled(true);
		oriColorBox_->setEnabled(true);
	}		
}

void MvQColourListHelp::refresh(const vector<string>& values)
{
	if(values.size() == 0)
	  	return;
	
  	QColor col=MvQPalette::magics(values[0]);
	
	setOriColourBox(col);
	
	if(MvQPalette::toString(selector_->currentColour()) != values[0] && col.isValid())
	{
	  	selector_->setColour(col);
	}
}

void MvQColourListHelp::setOriColourBox(QColor colour)
{
    	oriColour_=colour;
	
  	QPixmap pixmap(24, 18);
    	QPainter painter(&pixmap);
    	pixmap.fill(Qt::gray);
	
    	painter.fillRect(2, 2, 20, 14,colour);

   	oriColorBox_->setPixmap(pixmap);
}

void MvQColourListHelp::slotReset(bool)
{
  	if(oriColour_.isValid())
	{
	  	selector_->setColour(oriColour_);
	}
}

static HelpMaker<MvQColourHelp> maker1("colour");
static HelpMaker<MvQColourHelp> maker2("help_colour");
static HelpMaker<MvQColourListHelp> maker3("help_colourlist");
