/***************************** 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 <QAction>
#include <QDebug>
#include <QFrame>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QRegExpValidator>
#include <QSlider>
#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),
  margin_(4),
  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(150+2*margin_,150));
	
	setMouseTracking(true);
}  
  
void MvQColourWheel::resizeEvent(QResizeEvent */*event*/) 
{
    int w=width()-2*margin_;
    int h=height();
	outerRadius_=(w<h)?w:h;
	outerRadius_/=2;
	innerRadius_=outerRadius_-ringWidth_;
    centre_=QPoint(margin_+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();
	
	if(lgt_ > 110)
		painter->setPen(huePenBlack_);
	else
		painter->setPen(huePenWhite_);

	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=(width()-2*margin_)/2;
    int rad=width()/2-margin_-ringWidth_;
    int dx=pos.x()-width()/2;
    int dy=pos.y()-height()/2;
    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();
    if(hue < 0) hue=0;
	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<float>(chroma)/255.;
    float lgtNorm=static_cast<float>(lgt)/255.;
	
    return (chroma == 0)?0:255.*chromaNorm/(1-fabs(2.*lgtNorm-1));
}		
			
int MvQColourWheel::chroma(int sat, int lgt)
{  
    float satNorm=static_cast<float>(sat)/255.;
    float lgtNorm=static_cast<float>(lgt)/255.;
	
	return (sat == 0)?0:255.*satNorm*(1-fabs(2.*lgtNorm-1));
}

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

MvQColourSelectionWidget::MvQColourSelectionWidget(QWidget *parent) : 
    QWidget(parent), 
    ignoreRgbSpin_(false),
    ignoreHslSpin_(false),
    ignoreAlphaSpin_(false),
    ignoreAlphaSlider_(false),
    ignoreHtmlEdit_(false),
    ignoreMacroEdit_(false)
{	
    QFont sysFont;
    QFontMetrics sysFm(sysFont);

    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(sysFm.width("HH"));
	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(1,1);
	
    colDefHb->addSpacing(sysFm.width("HHHHH"));
    //colDefHb->addStretch(0.2);

	//HSL
	QGridLayout *hslGrid=new QGridLayout();
	colDefHb->addLayout(hslGrid);
	
	QStringList hslNames;
    hslNames << tr("Hue:") << tr("Saturation:")  << tr("Lightness:");
	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(1,1);
	
    //Separator
    QFrame *sep1=new QFrame(this);
    sep1->setFrameShape(QFrame::HLine);
    sep1->setFrameShadow(QFrame::Sunken);
    rightVb->addWidget(sep1);

    //Alpha
    QHBoxLayout *alphaHb=new QHBoxLayout();
    rightVb->addLayout(alphaHb);

    label=new QLabel("Opacity:",this);

    alphaSlider_=new QSlider(this);
    alphaSlider_->setOrientation(Qt::Horizontal);
    alphaSlider_->setMinimum(0);
    alphaSlider_->setMaximum(255);

    alphaSpin_=new QSpinBox(this);
    alphaSpin_->setRange(0,255);
    alphaSpin_->setValue(255);

    alphaHb->addWidget(label);
    alphaHb->addWidget(alphaSlider_);
    alphaHb->addWidget(alphaSpin_);

    //Separator
    QFrame *sep2=new QFrame(this);
    sep2->setFrameShape(QFrame::HLine);
    sep2->setFrameShadow(QFrame::Sunken);
    rightVb->addWidget(sep2);

    //Html
	QHBoxLayout *selHb=new QHBoxLayout();
	rightVb->addLayout(selHb);

	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|rgb]\\(\\d*\\.?\\d*,\\d*\\.?\\d*,\\d*\\.?\\d*\\)\\'");
    rxMacro.setCaseSensitivity(Qt::CaseInsensitive);
    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(alphaSpin_,SIGNAL(valueChanged(int)),
        this,SLOT(slotAlphaChanged(int)));

    connect(alphaSlider_,SIGNAL(valueChanged(int)),
        this,SLOT(slotAlphaSliderChanged(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)
{  	
    ignoreAlphaSpin_=true;
    ignoreAlphaSlider_=true;
    alphaSpin_->setValue(col.alpha());
    alphaSlider_->setValue(col.alpha());
    ignoreAlphaSpin_=false;
    ignoreAlphaSlider_=false;

    //This will set all the editors in the end
    //through the signal/slot mechanism
    wheel_->initColour(col);
}  

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

void MvQColourSelectionWidget::slotGridSelected(QColor col)
{
    col.setAlpha(alphaSpin_->value());

    ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreHtmlEdit_=true;
	ignoreMacroEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
    int hue=col.hslHue();
    if(hue < 0) hue=0;

    hslSpin_[0]->setValue(hue);
	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; 	
	
    //notify the wheel
	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);
    col.setAlpha(alphaSpin_->value());

	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)
{
    col.setAlpha(alphaSpin_->value());

    ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreHtmlEdit_=true;
	ignoreMacroEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
    int hue=col.hslHue();
    if(hue < 0) hue=0;

    hslSpin_[0]->setValue(hue);
	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(),
           alphaSpin_->value());

    int hue=col.hslHue();
    if(hue < 0) hue=0;

    hslSpin_[0]->setValue(hue);
	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(),
           alphaSpin_->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::slotAlphaChanged(int alpha)
{
    if(ignoreAlphaSpin_)
        return;

    ignoreAlphaSlider_=true;
    ignoreMacroEdit_=true;

    QColor col=currentColour_;
    col.setAlpha(alpha);

    alphaSlider_->setValue(alpha);
    macroEdit_->setText(macroToString(col));

    ignoreAlphaSlider_=false;
    ignoreMacroEdit_=false;

    setCurrentColour(col);
}

void MvQColourSelectionWidget::slotAlphaSliderChanged(int alpha)
{
    if(ignoreAlphaSlider_)
        return;

    ignoreAlphaSpin_=true;
    ignoreMacroEdit_=true;

    QColor col=currentColour_;
    col.setAlpha(alpha);

    alphaSpin_->setValue(alpha);
    macroEdit_->setText(macroToString(col));

    ignoreAlphaSpin_=false;
    ignoreMacroEdit_=false;

    setCurrentColour(col);
}

void MvQColourSelectionWidget::slotHtmlChanged(QString txt)
{	
	if(ignoreHtmlEdit_)
	  	return;
	
	QColor col(txt);
	if(!col.isValid())
		return;
	
    col.setAlpha(alphaSpin_->value());

	ignoreRgbSpin_=true;
	ignoreHslSpin_=true;
	ignoreMacroEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
    int hue=col.hslHue();
    if(hue <0) hue=0;

    hslSpin_[0]->setValue(hue);
	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;
    ignoreAlphaSpin_=true;
    ignoreAlphaSlider_=true;
	ignoreHtmlEdit_=true;
	
	rgbSpin_[0]->setValue(col.red());
	rgbSpin_[1]->setValue(col.green());
	rgbSpin_[2]->setValue(col.blue());
	
    int hue=col.hslHue();
    if(hue < 0) hue=0;

    hslSpin_[0]->setValue(hue);
	hslSpin_[1]->setValue(col.hslSaturation());
	hslSpin_[2]->setValue(col.lightness());
	
    alphaSpin_->setValue(col.alpha());
    alphaSlider_->setValue(col.alpha());

	htmlEdit_->setText(col.name());
	
	ignoreRgbSpin_=false;
	ignoreHslSpin_=false; 
    ignoreAlphaSpin_=false;
    ignoreAlphaSlider_=false;
    ignoreHtmlEdit_=false;
	
    //Notify the wheel
	emit colourChanged(hslSpin_[0]->value(),
		   	hslSpin_[1]->value(),
		   	hslSpin_[2]->value());
			
	setCurrentColour(col);		
}


QString MvQColourSelectionWidget::macroToString(QColor col)
{
    bool hasAlpha=(col.alpha() != 255);

    QString txt="'RGB(";

    if(hasAlpha)
    {
        txt="'RGBA(";
    }

    txt+=QString::number(col.redF(),'f',4)+",";
    txt+=QString::number(col.greenF(),'f',4)+",";
    txt+=QString::number(col.blueF(),'f',4);

    if(!hasAlpha)
        txt+=")'";
    else
        txt+=","+QString::number(col.alphaF(),'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)
    {
        int n=rx.captureCount();
        if(n == 3)
        {
            col=QColor::fromRgbF(rx.cap(1).toFloat(),
                  rx.cap(2).toFloat(),
                  rx.cap(3).toFloat());
            return col;
        }
    }

    rx=QRegExp("\\'RGBA\\((\\d*\\.?\\d*),(\\d*\\.?\\d*),(\\d*\\.?\\d*),(\\d*\\.?\\d*)\\)\\'");
    if(rx.indexIn(name) > -1)
    {
        int n=rx.captureCount();        
        if(n == 4)
        {
            col=QColor::fromRgbF(rx.cap(1).toFloat(),
                  rx.cap(2).toFloat(),
                  rx.cap(3).toFloat(),rx.cap(4).toFloat());
            return col;
        }
    }
	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)
		{
            if(!ac->isSeparator())
            {
                QToolButton *tb=new QToolButton(w_);
                hb->addWidget(tb);
                tb->setDefaultAction(ac);
            }
            else
            {
                hb->addSpacing(6);
            }
		}
		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_);
	}
}

//==================================================
//
//  MvQColourGradHelp
//
//==================================================

MvQColourGradHelp::MvQColourGradHelp(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* MvQColourGradHelp::widget()
{
    return w_;
}

void MvQColourGradHelp::setExternalActions(QList<QAction*> lst)
{
    if(QHBoxLayout* hb=static_cast<QHBoxLayout*>(w_->layout()->itemAt(0)))
    {
        foreach(QAction* ac,lst)
        {
            if(!ac->isSeparator())
            {
                QToolButton *tb=new QToolButton(w_);
                hb->addWidget(tb);
                tb->setDefaultAction(ac);
            }
            else
            {
                 hb->addSpacing(6);
            }
        }
        hb->addStretch(1);
    }
}

void MvQColourGradHelp::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 MvQColourGradHelp::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 MvQColourGradHelp::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 MvQColourGradHelp::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");
static HelpMaker<MvQColourGradHelp> maker4("help_colourgrad");
